天天看点

定位方法,以及纠偏的调用

// 开发调试环境: win8.1+Delphi XE8+TCL M3GS(android 5.0.2 X64)  

// 已实现功能  

// 1.获取手机GPS定位得到的坐标  

// 2.纠偏系统获取的坐标为腾讯地图坐标  

// 3.用纠偏后的坐标简单调用腾讯地图并定位  

// 4.判断开启系统是否打开定位,如未打开则弹出系统位置服务设置界面  

unit Unit1;  

interface  

uses  

  System.SysUtils, System.Types, System.UITypes, System.Classes,  

  System.Variants,  

  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Sensors,  

  System.Sensors.Components, FMX.WebBrowser, FMX.StdCtrls, FMX.ListBox,  

  FMX.Controls.Presentation, FMX.Layouts, FMX.ScrollBox, FMX.Memo;  

type  

  TForm1 = class(TForm)  

    ListBox1: TListBox;  

    ListBoxHeader1: TListBoxHeader;  

    Label1: TLabel;  

    ListBoxItem1: TListBoxItem;  

    ListBoxItem2: TListBoxItem;  

    ListBoxItem3: TListBoxItem;  

    Switch1: TSwitch;  

    Label2: TLabel;  

    Label3: TLabel;  

    WebBrowser1: TWebBrowser;  

    LocationSensor1: TLocationSensor;  

    Memo1: TMemo;  

    procedure Switch1Switch(Sender: TObject);  

    procedure LocationSensor1LocationChanged(Sender: TObject;  

      const OldLocation, NewLocation: TLocationCoord2D);  

  private  

    { Private declarations }  

  public  

    { Public declarations }  

  end;  

var  

  Form1: TForm1;  

implementation  

{$R *.fmx}  

uses GLGSPCorrect, // GPS 纠偏及逆转单元文件  

  Androidapi.JNI.GraphicsContentViewText,  

  Androidapi.Helpers,  

  Androidapi.JNI.Provider;  

procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;  

  const OldLocation, NewLocation: TLocationCoord2D);  

// 申明腾讯地图地址为常量  

const  

  sTencentMapURL: String = 'http://apis.map.qq.com/uri/v1/geocoder?coord=%s,%s';  

var  

  lat: Double;  

  lon: Double;  

begin  

  // 标签控件显示经度和纬度  

  Label2.Text := NewLocation.Latitude.ToString;  

  Label3.Text := NewLocation.Longitude.ToString;  

  // 赋值给经度变量和纬度变量  

  lat := NewLocation.Latitude;  

  lon := NewLocation.Longitude;  

  // 纠偏GPS坐标为腾讯坐标  

  GLGSPCorrect.TGLGPSCorrect.GPS_to_Google(lat, lon);  

  // web控件定位并显示纠偏后的地图  

  WebBrowser1.Navigate(Format(sTencentMapURL, [lat.ToString, lon.ToString]));  

end;  

procedure TForm1.Switch1Switch(Sender: TObject);  

var  

  Provider: string;  

  Settings_secure: TJSettings_Secure;  

  Intent: JIntent;  

begin  

  // 获取已开启的定位方式(gps,network)  

  Provider := JStringToString(Settings_secure.JavaClass.getString  

    (SharedActivityContext.getContentResolver,  

    TJSettings_system.JavaClass.LOCATION_PROVIDERS_ALLOWED));  

  // 输出获取到的定位方式  

  Memo1.Lines.Add(Provider);  

  // 判断返回的定位方式中是否有GPS或network定位  

  if pos('gps', Provider) or pos('network', Provider) = 0 then  

  begin  

    // 如无定位则弹出位置设置界面  

    Intent := TJIntent.Create;  

    Intent.setAction(TJSettings.JavaClass.ACTION_LOCATION_SOURCE_SETTINGS);  

    SharedActivity.startActivity(Intent);  

  end;  

  // 通过滑动按钮控制GPS控件  

  LocationSensor1.Active := Switch1.IsChecked;  

end;  

end.

===================================

/// <remarks>

/// 由网上算法翻译过来

/// 谷哥,高德,腾讯,百度地图纠偏与逆转算法

/// 翻译人: /tp机器猫(5909386)  如有不对,请发邮件

/// </remarks>

unit GLGSPCorrect;

interface

const

  PI = 3.14159265358979324;

  x_pi = 3.14159265358979324 * 3000.0 / 180.0;

type

  TGLGPSCorrect = class

  private

    class procedure delta(var lat, lng: Double);

    class function transformLon(lat, lng: Double): Double;

    class function transformlat(lat, lng: Double): Double;

    /// <remarks>

    /// GPS坐标转到 Google Map、高德、腾讯

    /// </remarks>

    class procedure WGS84_to_GCJ02(var lat, lng: Double);

    /// <remarks>

    /// 从Google Map、高德、腾讯转到GPS坐标

    /// </remarks>

    class procedure GCJ02_to_WGS84(var lat, lng: Double); // 粗略

    class procedure GCJ02_to_WGS84Ex(var lat, lng: Double); // 精确

    /// <remarks>

    /// 从Google Map、高德、腾讯转到百度坐标

    /// </remarks>

    class procedure GCJ02_to_BD09(var lat, lng: Double);

    /// <remarks>

    /// 从百度转到 Google Map、高德、腾讯坐标

    /// </remarks>

    class procedure BD09_to_GCJ02(var lat, lng: Double);

  public

    class function OutOfChina(lat, lng: Double): Boolean;

    class function Distance(latA, lngA, latB, lngB: Double): Double;

    class procedure GPS_to_Google(var lat, lng: Double);

    class procedure Google_to_GPS(var lat, lng: Double);

    class procedure Gps_to_Baidu(var lat, lng: Double);

    class procedure Baidu_to_Gps(var lat, lng: Double);

    class procedure Google_to_Baidu(var lat, lng: Double);

    class procedure Baidu_to_Google(var lat, lng: Double);

  end;

implementation

uses

  Math;

class procedure TGLGPSCorrect.Baidu_to_Google(var lat, lng: Double);

begin

  BD09_to_GCJ02(lat, lng);

end;

class procedure TGLGPSCorrect.Baidu_to_Gps(var lat, lng: Double);

begin

  BD09_to_GCJ02(lat, lng);

  GCJ02_to_WGS84Ex(lat, lng);

end;

class procedure TGLGPSCorrect.BD09_to_GCJ02(var lat, lng: Double);

var

  x, y, z, theta: Double;

begin

  x := lng - 0.0065;

  y := lat - 0.006;

  z := sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);

  theta := ArcTan2(y, x) - 0.000003 * cos(x * x_pi);

  lng := z * cos(theta);

  lat := z * sin(theta);

end;

class procedure TGLGPSCorrect.delta(var lat, lng: Double);

const

  a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。

  ee = 0.00669342162296594323; // ee: 椭球的偏心率。

var

  dLat, dLng, radLat, magic, sqrtMagic: Double;

begin

  dLat := transformlat(lng - 105.0, lat - 35.0);

  dLng := transformLon(lng - 105.0, lat - 35.0);

  radLat := lat / 180.0 * PI;

  magic := sin(radLat);

  magic := 1 - ee * magic * magic;

  sqrtMagic := sqrt(magic);

  dLat := (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);

  dLng := (dLng * 180.0) / (a / sqrtMagic * cos(radLat) * PI);

  lat := dLat;

  lng := dLng;

end;

class function TGLGPSCorrect.Distance(latA, lngA, latB, lngB: Double): Double;

const

  earthR = 6371000.0;

var

  x, y, s, alpha: Double;

begin

  x := cos(latA * PI / 180.0) * cos(latB * PI / 180.0) *

    cos((lngA - lngB) * PI / 180);

  y := sin(latA * PI / 180.0) * sin(latB * PI / 180.0);

  s := x + y;

  if (s > 1) then

    s := 1;

  if (s < -1) then

    s := -1;

  alpha := ArcCos(s);

  result := alpha * earthR;

end;

class procedure TGLGPSCorrect.GCJ02_to_BD09(var lat, lng: Double);

var

  x, y, z, theta: Double;

begin

  x := lng;

  y := lat;

  z := sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);

  theta := ArcTan2(y, x) + 0.000003 * cos(x * x_pi);

  lng := z * cos(theta) + 0.0065;

  lat := z * sin(theta) + 0.006;

end;

class procedure TGLGPSCorrect.GCJ02_to_WGS84(var lat, lng: Double);

var

  deltalat, delatlng: Double;

begin

  if OutOfChina(lat, lng) then

    exit;

  deltalat := lat;

  delatlng := lng;

  delta(deltalat, delatlng);

  lat := lat - deltalat;

  lng := lng - delatlng;

end;

class procedure TGLGPSCorrect.GCJ02_to_WGS84Ex(var lat, lng: Double);

const

  initDelta = 0.01;

  threshold = 0.000000001;

var

  dLat, dLon, mLat, mLon, pLat, pLon, wgsLat, wgsLon: Double;

  i: integer;

begin

  dLat := initDelta;

  dLon := initDelta;

  mLat := lat - dLat;

  mLon := lng - dLon;

  pLat := lat + dLat;

  pLon := lng + dLon;

  i := 0;

  while true do

  begin

    wgsLat := (mLat + pLat) / 2;

    wgsLon := (mLon + pLon) / 2;

    WGS84_to_GCJ02(wgsLat, wgsLon);

    dLat := wgsLat - lat;

    dLon := wgsLon - lng;

    if ((abs(dLat) < threshold) and (abs(dLon) < threshold)) then

      break;

    if (dLat > 0) then

      pLat := wgsLat

    else

      mLat := wgsLat;

    if (dLon > 0) then

      pLon := wgsLon

    else

      mLon := wgsLon;

    Inc(i);

    if i > 10000 then

      break;

  end;

  lat := wgsLat;

  lng := wgsLon;

end;

class procedure TGLGPSCorrect.Google_to_Baidu(var lat, lng: Double);

begin

  GCJ02_to_BD09(lat, lng);

end;

class procedure TGLGPSCorrect.Google_to_GPS(var lat, lng: Double);

begin

  GCJ02_to_WGS84Ex(lat, lng);

end;

class procedure TGLGPSCorrect.Gps_to_Baidu(var lat, lng: Double);

begin

  WGS84_to_GCJ02(lat, lng);

  GCJ02_to_BD09(lat, lng);

end;

class procedure TGLGPSCorrect.GPS_to_Google(var lat, lng: Double);

begin

  WGS84_to_GCJ02(lat, lng);

end;

class function TGLGPSCorrect.OutOfChina(lat, lng: Double): Boolean;

begin

  result := False;

  if (lng < 72.004) or (lng > 137.8347) then

    result := true;

  if (lat < 0.8293) or (lat > 55.8271) then

    result := true;

end;

class function TGLGPSCorrect.transformlat(lat, lng: Double): Double;

begin

  result := -100.0 + 2.0 * lat + 3.0 * lng + 0.2 * lng * lng + 0.1 * lat * lng +

    0.2 * sqrt(abs(lat));

  result := result + (20.0 * sin(6.0 * lat * PI) + 20.0 * sin(2.0 * lat * PI)) *

    2.0 / 3.0;

  result := result + (20.0 * sin(lng * PI) + 40.0 * sin(lng / 3.0 * PI)) *

    2.0 / 3.0;

  result := result + (160.0 * sin(lng / 12.0 * PI) + 320 * sin(lng * PI / 30.0))

    * 2.0 / 3.0;

end;

class function TGLGPSCorrect.transformLon(lat, lng: Double): Double;

begin

  result := 300.0 + lat + 2.0 * lng + 0.1 * lat * lat + 0.1 * lat * lng + 0.1 *

    sqrt(abs(lat));

  result := result + (20.0 * sin(6.0 * lat * PI) + 20.0 * sin(2.0 * lat * PI)) *

    2.0 / 3.0;

  result := result + (20.0 * sin(lat * PI) + 40.0 * sin(lat / 3.0 * PI)) *

    2.0 / 3.0;

  result := result + (150.0 * sin(lat / 12.0 * PI) + 300.0 *

    sin(lat / 30.0 * PI)) * 2.0 / 3.0;

end;

class procedure TGLGPSCorrect.WGS84_to_GCJ02(var lat, lng: Double);

var

  deltalat, delatlng: Double;

begin

  if (OutOfChina(lat, lng)) then

    exit;

  deltalat := lat;

  delatlng := lng;

  delta(deltalat, delatlng);

  lat := lat + deltalat;

  lng := lng + delatlng;

end;

end.

继续阅读