// 开发调试环境: 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.
// 已实现功能
// 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.
/// 由网上算法翻译过来
/// 谷哥,高德,腾讯,百度地图纠偏与逆转算法
/// 翻译人: /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.