我有一个位置列表,我希望能够输入一个位置,以及我指定位置X英里半径范围内的位置,以填充数据网格。有没有人有任何编写C#代码的经验来实现这个目标?
我确实拥有数据的纬度和经度。
任何帮助将不胜感激!谢谢!
我明白了!这似乎有效。我输入一个位置,然后将lat / long与其余1300个字段进行比较,显示表中的数据。如果有人有任何建议来缩小代码将是惊人的!!
private void btnSubmit_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex != 0)
{
lblMsg.Text = "Please select Location no From DropDown for Radius search";
return;
}
else
{
if (txtRadius.Text == "")
{
lblMsg.Text = "Please enter radius value";
return;
}
double radius = Convert.ToDouble(txtRadius.Text);
searchData = txtLocNo.Text;
str = "Select latitude,longitude from details where locno='" + searchData + "'";
con.Open();
cmd = new OleDbCommand(str, con);
dr = cmd.ExecuteReader();
if (!dr.HasRows)
{
lblMsg.Text = "No Records Found";
dataGridView1.Visible = false;
con.Close();
return;
}
else
{
dr.Read();
double lat1 = dr.GetDouble(0);
double lng1 = dr.GetDouble(1);
double lat2, lng2,dist;
String loc="";
lblMsg.Text = lat1 + " " + lng1;
dr.Dispose();
str = "Select locno,latitude,longitude from details";
cmd = new OleDbCommand(str, con);
dr = cmd.ExecuteReader();
while (dr.Read())
{
loc=dr.GetString(0);
lat2 = dr.GetDouble(1);
lng2 = dr.GetDouble(2);
dist=calculateDistance(lat1,lng1,lat2,lng2);
str = "Update details set distance=" + dist + " where locno='"+loc+"'";
cmd = new OleDbCommand(str, con);
cmd.ExecuteNonQuery();
}
str = "select * from details where distance<=" + radius;
con.Close();
lblResult.Text = "Radius Search Results";
fillGrid();
}
}
}
private double calculateDistance(double lat1,double lng1,double lat2,double lng2)
{
double x= 69.1 * (lat2 - lat1);
double y = 69.1 * (lng2 - lng1) * Math.Cos(lat1 / 57.3);
double dist = Math.Sqrt(x * x + y * y);
dist = Math.Round(dist, 2);
return dist;
}
private double calculateDistance1(double lat1, double lng1, double lat2, double lng2)
{
double theta = lng1 - lng2;
double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) +
Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) *
Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
dist = Math.Round(dist, 2);
return dist;
}
private double deg2rad(double deg)
{
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad)
{
return (rad / Math.PI * 180.0);
}
private void txtRadius_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar != '0' && e.KeyChar != '1' && e.KeyChar != '2' && e.KeyChar != '3' &&
e.KeyChar != '4' && e.KeyChar != '5' && e.KeyChar != '6' && e.KeyChar != '7' &&
e.KeyChar != '8' && e.KeyChar != '9' && e.KeyChar != '.' && e.KeyChar!= Convert.ToChar(8))
{
e.Handled = true;
}
答案 0 :(得分:3)
您可以使用System.Device.Location.GeoCoordinate
类
var loc = new GeoCoordinate(0, 0);
var dist = loc.GetDistanceTo(new GeoCoordinate(1, 1));
修改强>
数据集有1300行
1300行数据集太小。您可以使用任何方法,无需优化(您甚至不需要数据库。您可以将所有数据加载到内存中)
double radius = ....
List<GeoCoordinate> locations = .....;
var result = locations.Where(l=>l.GetDistanceTo(loc)<radius);
答案 1 :(得分:1)
这一切都取决于你的算法有多快以及你有多少位置。
你可以通过遍历所有位置来实现,只保留半径范围内的位置,但如果你有很多位置,这将会很慢。
另一种方法是将您的位置放入链接列表,并且在每个节点上都有到下一个节点的距离列表,这可以加快搜索速度。您还可以将这些节点放在区域中,以便快速找到要开始搜索的节点。
然后,如果你的问题只是计算两个地点之间的距离,请参阅@ I4V的回答
答案 2 :(得分:0)
之前我有过这样的任务但是我使用SQL函数解决了它,这可能不是你的场景,而是对任何感兴趣的人:
-- =============================================
-- Description: Return list of myTable within provided radius and location
-- =============================================
ALTER PROCEDURE [dbo].[proc_]
@lattitude DECIMAL(9, 6) = 0 ,
@longitude DECIMAL(9, 6) = 0 ,
@radius DECIMAL(18, 3) = 0
AS
BEGIN
DECLARE @point GEOGRAPHY = GEOGRAPHY::Point(@lattitude, @longitude, 4326)
SELECT *
FROM myTable a
WHERE @point.STDistance(GEOGRAPHY::Point(a.Lattitude, a.Longitude, 4326)) <= @radius *2
END
myTable
列包含:
Lattitude decimal
Longitude decimal
注意:SQL版本是2008或更高版本。
希望这个帮助