How can I bring the closest stores from the database according to the given latitude and longitude with .Net Core? [duplicate] - c#

I have latitude and longitude and I want to pull the record from the database, which has nearest latitude and longitude by the distance, if that distance gets longer than specified one, then don't retrieve it.
Table structure:
id
latitude
longitude
place name
city
country
state
zip
sealevel

SELECT latitude, longitude, SQRT(
POW(69.1 * (latitude - [startlat]), 2) +
POW(69.1 * ([startlng] - longitude) * COS(latitude / 57.3), 2)) AS distance
FROM TableName HAVING distance < 25 ORDER BY distance;
where [starlat] and [startlng] is the position where to start measuring the distance.

Google's solution:
Creating the Table
When you create the MySQL table, you want to pay particular attention to the lat and lng attributes. With the current zoom capabilities of Google Maps, you should only need 6 digits of precision after the decimal. To keep the storage space required for your table at a minimum, you can specify that the lat and lng attributes are floats of size (10,6). That will let the fields store 6 digits after the decimal, plus up to 4 digits before the decimal, e.g. -123.456789 degrees. Your table should also have an id attribute to serve as the primary key.
CREATE TABLE `markers` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 60 ) NOT NULL ,
`address` VARCHAR( 80 ) NOT NULL ,
`lat` FLOAT( 10, 6 ) NOT NULL ,
`lng` FLOAT( 10, 6 ) NOT NULL
) ENGINE = MYISAM ;
Populating the Table
After creating the table, it's time to populate it with data. The sample data provided below is for about 180 pizzarias scattered across the United States. In phpMyAdmin, you can use the IMPORT tab to import various file formats, including CSV (comma-separated values). Microsoft Excel and Google Spreadsheets both export to CSV format, so you can easily transfer data from spreadsheets to MySQL tables through exporting/importing CSV files.
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Frankie Johnnie & Luigo Too','939 W El Camino Real, Mountain View, CA','37.386339','-122.085823');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Amici\'s East Coast Pizzeria','790 Castro St, Mountain View, CA','37.38714','-122.083235');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Kapp\'s Pizza Bar & Grill','191 Castro St, Mountain View, CA','37.393885','-122.078916');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Round Table Pizza: Mountain View','570 N Shoreline Blvd, Mountain View, CA','37.402653','-122.079354');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Tony & Alba\'s Pizza & Pasta','619 Escuela Ave, Mountain View, CA','37.394011','-122.095528');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Oregano\'s Wood-Fired Pizza','4546 El Camino Real, Los Altos, CA','37.401724','-122.114646');
Finding Locations with MySQL
To find locations in your markers table that are within a certain radius distance of a given latitude/longitude, you can use a SELECT statement based on the Haversine formula. The Haversine formula is used generally for computing great-circle distances between two pairs of coordinates on a sphere. An in-depth mathemetical explanation is given by Wikipedia and a good discussion of the formula as it relates to programming is on Movable Type's site.
Here's the SQL statement that will find the closest 20 locations that are within a radius of 25 miles to the 37, -122 coordinate. It calculates the distance based on the latitude/longitude of that row and the target latitude/longitude, and then asks for only rows where the distance value is less than 25, orders the whole query by distance, and limits it to 20 results. To search by kilometers instead of miles, replace 3959 with 6371.
SELECT
id,
(
3959 *
acos(cos(radians(37)) *
cos(radians(lat)) *
cos(radians(lng) -
radians(-122)) +
sin(radians(37)) *
sin(radians(lat )))
) AS distance
FROM markers
HAVING distance < 28
ORDER BY distance LIMIT 0, 20;
This one is to find latitudes and longitudes in a distance less than 28 miles.
Another one is to find them in a distance between 28 and 29 miles:
SELECT
id,
(
3959 *
acos(cos(radians(37)) *
cos(radians(lat)) *
cos(radians(lng) -
radians(-122)) +
sin(radians(37)) *
sin(radians(lat )))
) AS distance
FROM markers
HAVING distance < 29 and distance > 28
ORDER BY distance LIMIT 0, 20;
https://developers.google.com/maps/articles/phpsqlsearch_v3#creating-the-map

The original answers to the question are good, but newer versions of mysql (MySQL 5.7.6 on) support geo queries, so you can now use built in functionality rather than doing complex queries.
You can now do something like:
select *, ST_Distance_Sphere( point ('input_longitude', 'input_latitude'),
point(longitude, latitude)) * .000621371192
as `distance_in_miles`
from `TableName`
having `distance_in_miles` <= 'input_max_distance'
order by `distance_in_miles` asc
The results are returned in meters. So if you want in KM simply use .001 instead of .000621371192 (which is for miles).
MySql docs are here

Here is my full solution implemented in PHP.
This solution uses the Haversine formula as presented in http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL.
It should be noted that the Haversine formula experiences weaknesses around the poles. This answer shows how to implement the vincenty Great Circle Distance formula to get around this, however I chose to just use Haversine because it's good enough for my purposes.
I'm storing latitude as DECIMAL(10,8) and longitude as DECIMAL(11,8). Hopefully this helps!
showClosest.php
<?PHP
/**
* Use the Haversine Formula to display the 100 closest matches to $origLat, $origLon
* Only search the MySQL table $tableName for matches within a 10 mile ($dist) radius.
*/
include("./assets/db/db.php"); // Include database connection function
$db = new database(); // Initiate a new MySQL connection
$tableName = "db.table";
$origLat = 42.1365;
$origLon = -71.7559;
$dist = 10; // This is the maximum distance (in miles) away from $origLat, $origLon in which to search
$query = "SELECT name, latitude, longitude, 3956 * 2 *
ASIN(SQRT( POWER(SIN(($origLat - latitude)*pi()/180/2),2)
+COS($origLat*pi()/180 )*COS(latitude*pi()/180)
*POWER(SIN(($origLon-longitude)*pi()/180/2),2)))
as distance FROM $tableName WHERE
longitude between ($origLon-$dist/cos(radians($origLat))*69)
and ($origLon+$dist/cos(radians($origLat))*69)
and latitude between ($origLat-($dist/69))
and ($origLat+($dist/69))
having distance < $dist ORDER BY distance limit 100";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
echo $row['name']." > ".$row['distance']."<BR>";
}
mysql_close($db);
?>
./assets/db/db.php
<?PHP
/**
* Class to initiate a new MySQL connection based on $dbInfo settings found in dbSettings.php
*
* #example $db = new database(); // Initiate a new database connection
* #example mysql_close($db); // close the connection
*/
class database{
protected $databaseLink;
function __construct(){
include "dbSettings.php";
$this->database = $dbInfo['host'];
$this->mysql_user = $dbInfo['user'];
$this->mysql_pass = $dbInfo['pass'];
$this->openConnection();
return $this->get_link();
}
function openConnection(){
$this->databaseLink = mysql_connect($this->database, $this->mysql_user, $this->mysql_pass);
}
function get_link(){
return $this->databaseLink;
}
}
?>
./assets/db/dbSettings.php
<?php
$dbInfo = array(
'host' => "localhost",
'user' => "root",
'pass' => "password"
);
?>
It may be possible to increase performance by using a MySQL stored procedure as suggested by the "Geo-Distance-Search-with-MySQL" article posted above.
I have a database of ~17,000 places and the query execution time is 0.054 seconds.

Just in case you are lazy like me, here's a solution amalgamated from this and other answers on SO.
set #orig_lat=37.46;
set #orig_long=-122.25;
set #bounding_distance=1;
SELECT
*
,((ACOS(SIN(#orig_lat * PI() / 180) * SIN(`lat` * PI() / 180) + COS(#orig_lat * PI() / 180) * COS(`lat` * PI() / 180) * COS((#orig_long - `long`) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance`
FROM `cities`
WHERE
(
`lat` BETWEEN (#orig_lat - #bounding_distance) AND (#orig_lat + #bounding_distance)
AND `long` BETWEEN (#orig_long - #bounding_distance) AND (#orig_long + #bounding_distance)
)
ORDER BY `distance` ASC
limit 25;

Easy one ;)
SELECT * FROM `WAYPOINTS` W ORDER BY
ABS(ABS(W.`LATITUDE`-53.63) +
ABS(W.`LONGITUDE`-9.9)) ASC LIMIT 30;
Just replace the coordinates with your required ones. The values have to be stored as double. This ist a working MySQL 5.x example.
Cheers

Try this, it show the nearest points to provided coordinates (within 50 km). It works perfectly:
SELECT m.name,
m.lat, m.lon,
p.distance_unit
* DEGREES(ACOS(COS(RADIANS(p.latpoint))
* COS(RADIANS(m.lat))
* COS(RADIANS(p.longpoint) - RADIANS(m.lon))
+ SIN(RADIANS(p.latpoint))
* SIN(RADIANS(m.lat)))) AS distance_in_km
FROM <table_name> AS m
JOIN (
SELECT <userLat> AS latpoint, <userLon> AS longpoint,
50.0 AS radius, 111.045 AS distance_unit
) AS p ON 1=1
WHERE m.lat
BETWEEN p.latpoint - (p.radius / p.distance_unit)
AND p.latpoint + (p.radius / p.distance_unit)
AND m.lon BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
ORDER BY distance_in_km
Just change <table_name>. <userLat> and <userLon>
You can read more about this solution here: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

You're looking for things like the haversine formula. See here as well.
There's other ones but this is the most commonly cited.
If you're looking for something even more robust, you might want to look at your databases GIS capabilities. They're capable of some cool things like telling you whether a point (City) appears within a given polygon (Region, Country, Continent).

Check this code based on the article Geo-Distance-Search-with-MySQL:
Example: find the 10 nearest hotels to my current location in a 10 miles radius:
#Please notice that (lat,lng) values mustn't be negatives to perform all calculations
set #my_lat=34.6087674878572;
set #my_lng=58.3783670308302;
set #dist=10; #10 miles radius
SELECT dest.id, dest.lat, dest.lng, 3956 * 2 * ASIN(SQRT(POWER(SIN((#my_lat -abs(dest.lat)) * pi()/180 / 2),2) + COS(#my_lat * pi()/180 ) * COS(abs(dest.lat) * pi()/180) * POWER(SIN((#my_lng - abs(dest.lng)) * pi()/180 / 2), 2))
) as distance
FROM hotel as dest
having distance < #dist
ORDER BY distance limit 10;
#Also notice that distance are expressed in terms of radius.

Find nearest Users to my:
Distance in meters
Based in Vincenty's formula
i have User table:
+----+-----------------------+---------+--------------+---------------+
| id | email | name | location_lat | location_long |
+----+-----------------------+---------+--------------+---------------+
| 13 | xxxxxx#xxxxxxxxxx.com | Isaac | 17.2675625 | -97.6802361 |
| 14 | xxxx#xxxxxxx.com.mx | Monse | 19.392702 | -99.172596 |
+----+-----------------------+---------+--------------+---------------+
sql:
-- my location: lat 19.391124 -99.165660
SELECT
(ATAN(
SQRT(
POW(COS(RADIANS(users.location_lat)) * SIN(RADIANS(users.location_long) - RADIANS(-99.165660)), 2) +
POW(COS(RADIANS(19.391124)) * SIN(RADIANS(users.location_lat)) -
SIN(RADIANS(19.391124)) * cos(RADIANS(users.location_lat)) * cos(RADIANS(users.location_long) - RADIANS(-99.165660)), 2)
)
,
SIN(RADIANS(19.391124)) *
SIN(RADIANS(users.location_lat)) +
COS(RADIANS(19.391124)) *
COS(RADIANS(users.location_lat)) *
COS(RADIANS(users.location_long) - RADIANS(-99.165660))
) * 6371000) as distance,
users.id
FROM users
ORDER BY distance ASC
radius of the earth : 6371000 ( in meters)

simpledb.execSQL("CREATE TABLE IF NOT EXISTS " + tablename + "(id INTEGER PRIMARY KEY AUTOINCREMENT,lat double,lng double,address varchar)");
simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2891001','70.780154','craftbox');");
simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2901396','70.7782428','kotecha');");//22.2904718 //70.7783906
simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2863155','70.772108','kkv Hall');");
simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.275993','70.778076','nana mava');");
simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2667148','70.7609386','Govani boys hostal');");
double curentlat=22.2667258; //22.2677258
double curentlong=70.76096826;//70.76096826
double curentlat1=curentlat+0.0010000;
double curentlat2=curentlat-0.0010000;
double curentlong1=curentlong+0.0010000;
double curentlong2=curentlong-0.0010000;
try{
Cursor c=simpledb.rawQuery("select * from '"+tablename+"' where (lat BETWEEN '"+curentlat2+"' and '"+curentlat1+"') or (lng BETWEEN '"+curentlong2+"' and '"+curentlong1+"')",null);
Log.d("SQL ", c.toString());
if(c.getCount()>0)
{
while (c.moveToNext())
{
double d=c.getDouble(1);
double d1=c.getDouble(2);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}

It sounds like you want to do a nearest neighbour search with some bound on the distance. SQL does not support anything like this as far as I am aware and you would need to use an alternative data structure such as an R-tree or kd-tree.

MS SQL Edition here:
DECLARE #SLAT AS FLOAT
DECLARE #SLON AS FLOAT
SET #SLAT = 38.150785
SET #SLON = 27.360249
SELECT TOP 10 [LATITUDE], [LONGITUDE], SQRT(
POWER(69.1 * ([LATITUDE] - #SLAT), 2) +
POWER(69.1 * (#SLON - [LONGITUDE]) * COS([LATITUDE] / 57.3), 2)) AS distance
FROM [TABLE] ORDER BY 3

Sounds like you should just use PostGIS, SpatialLite, SQLServer2008, or Oracle Spatial. They can all answer this question for you with spatial SQL.

+----+-----------------------+---------+--------------+---------------+
| id | email | name | location_lat | location_long |
+----+-----------------------+---------+--------------+---------------+
| 7 | test#gmail.com | rembo | 23.0249256 | 72.5269697 |
| 25 | test1#gmail.com. | Rajnis | 23.0233221 | 72.5342112 |
+----+-----------------------+---------+--------------+---------------+
$lat = 23.02350629;
$long = 72.53230239;
DB::
SELECT
("
SELECT
*
FROM
(
SELECT
,
(
( ( acos( sin(( ". $ lat ." * pi() / 180)) * sin(( lat * pi() / 180)) + cos(( ". $ lat ." pi() / 180 )) * cos(( lat * pi() / 180)) * cos((( ". $ long ." - LONG) * pi() / 180))) ) * 180 / pi() ) * 60 * 1.1515 * 1.609344
)
as distance
FROM
users
)
users
WHERE
distance <= 2");

In extreme cases this approach fails, but for performance, I've skipped the trigonometry and simply calculated the diagonal squared.

Mysql query for search coordinates with distance limit and where condition
SELECT id, ( 3959 * acos( cos( radians('28.5850154') ) * cos( radians(latitude) ) * cos( radians( longitude ) - radians('77.07207489999999') ) + sin( radians('28.5850154') ) * sin( radians( latitude ) ) ) ) AS distance FROM `vendors` HAVING distance < 5;

This problem is not very hard at all, but it gets more complicated if you need to optimize it.
What I mean is, do you have 100 locations in your database or 100 million? It makes a big difference.
If the number of locations is small, get them out of SQL and into code by just doing ->
Select * from Location
Once you get them into code, calculate the distance between each lat/lon and your original with the Haversine formula and sort it.

Related

Find closest location using longitude and latitude by linq from database

I need to get nearby location using (longitude, latitude )
I have a table where the locations are saved in database with longitude and latitude fields,
I want to retrieve the nearest locations, and I have Sql code and want to convert it to linq, where I'm using ASP.Net MVC5
Here is my code:
SELECT Name, ( 3959 * acos( cos( radians(24.743055) ) * cos( radians(
latitude ) ) *
cos( radians( longitude ) - radians(46.669702) ) + sin( radians(24.743055)
)*
sin( radians( latitude ) ) ) ) AS distance
FROM Event
ORDER BY distance
I wrote it in linq like this:
double startlat = Convert.ToDouble(db.Users.Where(u => u.Id == 2).Select(u
=> u.latitude).Single());
double startlng = Convert.ToDouble(db.Users.Where(u => u.Id == 2).Select(u
=> u.longitude).Single());
var c = (from ev in db.Event
where (3959 * Math.Acos(Math.Cos((Math.PI * startlat / 180.0)) *
Math.Cos(Math.PI * (Convert.ToDouble(ev.latitude)) / 180.0) *
Math.Cos((Math.PI * (Convert.ToDouble(ev.longitude)) / 180.0) - (Math.PI *
(startlng) / 180.0)) + Math.Sin(Math.PI * (startlat) / 180.0)) *
Math.Sin(Math.PI * (Convert.ToDouble(ev.latitude) ) / 180.0) ) < 2500
select ev.Name).ToList();
but I get this error:
LINQ to Entities does not recognize the method 'Double Acos(Double)'
method, and this method cannot be translated into a store expression.
I tried to use "public static double ToRadians" and pass the value, but it didn't work because it's a static
Any Ideas ?
Firstly, you should get your user's location data in one hit:
var startCoords = db.Users.Where(u => u.Id == 2).Select(u
=> new { u.latitude, u.longitude }).Single();
To get the closest location, could this be simplified to sum the X delta and Y delta and take the smallest total delta?
var closestEvent = db.Event.Select(x => new { x.EventId, delta = Math.Abs(x.latitude - startCoords.latitude) + Math.Abs(x.longitude - startCoords.longitude)})
.OrderBy(x => x.delta)
.FirstOrDefault();
This might be an over-simplification, but given X,Y coordinates, comparing the sum of an absolute difference would give you a rough ranking as the crow flies. If a more detailed formula is needed, or you want to feed those into something like Google Earth for a road check or other pathfinding, the rough check could return the top 10 or so events and coordinates to memory, where a more detailed check can be run against these without worrying about transformation to SQL issues.

Find Nearest Latitude and Longitude

my question is , i have hotel info alone with their latitude and longitude in my database.now i want to find the nearest hotel from the given latitude and longitude .
for example :suppose latitude is 196.98575 and longitude is = 24.985644,
now based on this lat long i want to find the nearest hotel in 15 km, which i have available in my database .
please suggest me any idea or if you have any stored procedure please tell me so that i can avoid manually task.
i am using sql server.
As was alluded to in a comment above, SQL Server has had native geospatial capabilities since SQL 2008. Here's my stab at a solution:
create table dbo.Hotels (
HotelID int identity not null,
constraint [PK_Hotels] primary key clustered (HotelID),
Longitude decimal(15, 12) not null,
Latitude decimal(14, 12) not null,
geo as geography::Point(Latitude, Longitude, 4326)
)
insert into dbo.Hotels
(Longitude, Latitude)
values
(-122.4167, 37.7833);
go
create procedure dbo.findHotels (#point geography, #distanceKM int = 15)
as
begin
--SRID 4326 measures disances in meters, so use that measure
declare #distanceM int = #distanceKM * 1000;
select HotelID, #point.STDistance(geo) as [DistanceInM]
from dbo.Hotels
where #point.STDistance(geo) <= #distanceM
order by #point.STDistance(geo);
end
go
declare #longitude decimal(15, 12) = -122.4168,
#latitude decimal(14, 12) = 37.7832;
declare #p geography = geography::Point(#latitude, #longitude, 4326);
exec dbo.findHotels #p, 15;
Take a look at here.there It find places within a distance d=1000 km from M=(lat, lon)=(1.3963, -0.6981) in a database
*Lat and Lon that hold the coordinates in radians
here is the simple query according to this source
SELECT * FROM Places WHERE
(Lat => 1.2393 AND Lat <= 1.5532) AND (Lon >= -1.8184 AND Lon <= 0.4221)
AND
acos(sin(1.3963) * sin(Lat) + cos(1.3963) * cos(Lat) * cos(Lon - (-0.6981))) <= 0.1570;

get match percentages between two objects by parameters

I want to create a program that will automate a process that i am doing manually today.
I apologize if the solution seems to be easy i just don't want to think about new algorithm specially for my problem because i am sure that someone already thought about it.
My Scenario is this:
I have candidates list that are looking for jobs and I have jobs list.
For each candidate I know the following requirements of the job that he is searching for. like:
Salary
Location of the Job
Company Size (Big / Small)
In the manual process what i do is to match between those candidate's requirements parameters to the job's requirements parameter and "return" the jobs that seems to fit to the candidate (it doesn't have to be a completely match).
Of course i am considering candidate's requirement is "nice to have" or "must have".
I am searching for an algorithm that returns a fit percentage between each candidate to each job.
Can someone please point me to a any name of matching algorithm like this.
Thanks
My advice is to convert every object to a vector in a 3-D space and then find the Euclidean distance between the two vectors (objects).
First, assign salary, location and size to x, y and z axis, respectively.
Then map the properties to [0, 1] interval of the axis.
For example, if your min salary is 1'000, and max salary is 10'000, then you would map:
$ 1'000 -> 0 on the x axis,
$ 10'000 -> to 1 on the x axis.
Mapping locations is hard, but let's say you have a map grid, and you assign a value to each patch of the grid according to geo position - closer ones have similar values. For example, US states provide us with a good example:
New York -> 1.0 on the y axis,
New Jersey -> 0.99 on the y axis,
...
California -> 0.1 on the y axis.
Map company sizes something like:
start-up -> 0.2 on the z axis,
...
multinational -> 1.0 on the z axis.
So, to give an example: John wants a salary of 9.000, wants a job in New York, and wants to work in a start-up company. His vector in 3D space would be [0.82, 1.00, 0.1].
Peter wants a salary of 5.500, wants a job in New Jersey, and wants to work in a really big company - [0.5, 0.99, 0.8]. And at last, Mike wants a salary of 8.000, a job in California, and a start-up too - [0.73, 0.1, 0.1].
According to formula for Euclidean distance in 3D space:
d(a, b) = sqrt((a1-b1)^2 + (a2-b2)^2 + (a3 - b3)^2)
Distance between John and Peter is: d(J, P) = 0.77
Distance between John and Mike is: d(J, M) = 0.90
So the conclusion would be that John and Peter are closer than John and Mike.
One more thing you could do is to bring in some constants to each axis to emphasize the importance of it (location is more important than company size, for example) so in the formula you could do something like:
d(a, b) = sqrt((a1-b1)^2 + (C*a2 - C*b2)^2 + (a3 - b3)^2), where C = 10
similiarity(A,B) = 1 / (1 + (distance(A,B) / unit))
Case where distance is 0:
similarity(A,A)
= 1 / (1 + (distance(A,A) / unit))
= 1 / (1 + (0 / unit))
= 1 / (1 + 0)
= 1.0
~ 100 %
Case where distance is infinite:
similarity(A,Z)
= 1 / (1 + (distance(A,Z) / unit))
= 1 / (1 + (infinity / unit))
= 1 / infinity
= 0.0
~ 0 %
Code:
JobComparison* compare (Job a, Job b)
{
// define units based on measurement
double unit1 = 1000.0;
double unit2 = 100.0;
double unit3 = 10.0;
// calculate distance
double d1 = abs(a.salary - b.salary);
double d2 = distance(a.location, b.location);
double d3 = abs(a.companySize - b.companySize);
// calculate similiarity
double p1 = 1 / (1 + (d1 / unit1));
double p2 = 1 / (1 + (d2 / unit2));
double p3 = 1 / (1 + (d3 / unit3));
return new JobCompare(p1, p2, p3);
}
public class JobCompare
{
public:
double salarySimiliarity;
double locationSimiliarity;
double companySimiliarity;
}
public class Job
{
public:
double salary;
Location location;
double companySize;
}

SELECT top 35 Lat Lan records with reference to a particular Lat Lan from MS SQL Table

I am working with a 'NearBy Properties' Module in C#,Asp.net,.net ver 2.0 and MSSQL 2005.My requirement is like ,
I pass a specific Lat and Lan value to DB,It should fetch me 35 nearest properties by comparing the passed Lat Lan with the Lat Lan values already saved in DB.Can this be done in the SQL part itself ?
I can do this in Asp.net part by
looping through all the rows in a DataTable,then
Creating an extra field called 'Miles' in DataTable and inserting Km values in to
it,like this
public decimal calcDistance(decimal latA, decimal longA, decimal latB, decimal longB)
{
double theDistance = (Math.Sin(DegreesToRadians(latA)) *
Math.Sin(DegreesToRadians(latB)) +
Math.Cos(DegreesToRadians(latA)) *
Math.Cos(DegreesToRadians(latB)) *
Math.Cos(DegreesToRadians(longA - longB)));
return Convert.ToDecimal((RadiansToDegrees(Math.Acos(theDistance)))) * 69.09M * 1.6093M;
}
Then Sorting the DataTable with 'Miles' field,and fetching top 35 rows from DataTable.
The Problem is,
I have to fetch all the DB rows in to asp part and then do a for loop and then do a sort,this takes up lot of time and resources,Is there any way I can execute this in the SQL part itself ?
SOLUTION
I tweaked #Bacon Bits answer below as
SELECT PM.Id AS PropertyId,PM.Address,PM.PropertyImage, ROUND((DEGREES(ACOS(SIN(RADIANS('9.98')) * SIN(RADIANS(PM.Latitude)) + COS(RADIANS('9.98')) * COS(RADIANS(PM.Latitude)) * COS(RADIANS(76.27999999999997 - PM.Longitude)))) * 69.09 * 1.6093),0) AS Miles
FROM Tbl_PropertyMaster PM
INNER JOIN dbo.Tbl_PropertyApproval AS PA
ON PA.PropertyId = PM.Id
WHERE PM.IsDeleted='False' AND PM.Enabled='True' and PA.Action='Approved' AND ROUND((DEGREES(ACOS(SIN(RADIANS('9.98')) * SIN(RADIANS(PM.Latitude)) + COS(RADIANS('9.98')) * COS(RADIANS(PM.Latitude)) * COS(RADIANS(76.27999999999997 - PM.Longitude)))) * 69.09 * 1.6093),0) < 1000
ORDER BY Miles DESC
Try the following user defined function, which is a conversion of the function you supplied to TSQL. This should be as accurate as SQL Server can be. The queries should work on SQL Server 2005 and later. Note that you should probably evaluate the product of the two static values. I'm just lazy.
CREATE FUNCTION dbo.calcDistance (
#latA AS NUMERIC(38, 35),
#longA AS NUMERIC(38, 35),
#latB AS NUMERIC(38, 35),
#longB AS NUMERIC(38, 35)
)
RETURNS NUMERIC(38, 35)
AS
BEGIN
RETURN (DEGREES(ACOS(SIN(RADIANS(#latA)) * SIN(RADIANS(#latB)) + COS(RADIANS(#latA)) * COS(RADIANS(#latB)) * COS(RADIANS(#longA - #longB)))) * 69.09 * 1.6093)
END
SQLFiddle. My example uses the location in your test and the Wikipedia coordinates of Mangalore.
Create a Scalar Function that calculate the distance between given two set of lan-lat parameters (like you did in asp.net side).
Example:
SELECT TOP 35 * FROM Table_1 ORDER BY dbo.calcDistance(field_latitude,field_longitude, param_lat,param_long) DESC;
I dont know how to calculate the distance from given two set of lang,lat. It is up to you write the function implementation. You can use here and here

Find closest city to given location

I am trying to find the closest city to given location. I have stored location of some cities that I want to work with. And I have my location, but I dont know how to find the closest city to my location ?
Cities
New York - Lat 40.714353; Long -74.005973
Washington - Lat 38.895112; Long -77.036366
....more cities
My location
Philadephia - Lat 39.952335; Long -75.163789
So how should I compare the coords to find the closest city ? I am doing program in C# but just knowing the solution of algorythm is enaught for me :)
Thanks for any help
You should use your high school knowledge to solve this problem, your alghorithm is:
closest = sqrt ( (lat2 - lat1) ^2 + (Long2-Long1) ^2 )
now this give you your air distance.
so, when you do this for an array of values, you can use asort function to compare which one is closest to you.
Strictly, you'd want to use the Haversine formula.
However, while you could perhaps be just slightly out in far northern or far southern points, you could probably get by by pretending that Mercator projections are accurate for distance, and ignoring the curvature of the earth. This is especially true if you are going to have lots of cities, as the error is greater, the further points are from the target point. Hence you would just use Pythagoras':
relDist = √((xLat - yLat) × (xLat - yLat) + (xLng - yLng) × (xLng - yLng))
But since you only care about (and only get) a relative ordering, you can skip the square-root bit, which is the heaviest step:
relDist = (xLat - yLat) × (xLat - yLat) + (xLng - yLng) × (xLng - yLng)
As well as being faster in and of itself, it can also be reasonably preformed on integers, should you store your coordinates as multiples of the actual coordinate (e.g. storing New York's (40.664167, -73.938611) as the pair (406642, -739386). This can be a big boost if you want to quickly sort a large number of places in order of proximity to a given point.
If however you really care about precision in the face of the fact that the earth is round, then the following implements Haversine:
private const double radiusE = 6378135; // Equatorial radius
private const double radiusP = 6356750; // Polar radius
private const double radianConv = 180 / Math.PI;
public static double GetDistanceBetweenPoints(double lat1, double long1, double lat2, double long2)
{
double dLat = (lat2 - lat1) / radianConv;
double dLong = (long2 - long1) / radianConv;
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(lat2) * Math.Sin(dLong/2) * Math.Sin(dLong/2);
return Math.Sqrt((Math.Pow(radiusE * radiusP * Math.Cos(lat1 / radianConv), 2)) / (Math.Pow(radiusE * Math.Cos(lat1 / radianConv), 2) + Math.Pow(radiusP * Math.Sin(lat1 / radianConv), 2))) * (2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)));
}
The distance bitween two points (x1, y1) and (x2, y2) is
d = sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
so in c# you we will have:
public City FindNearestCity(double currentLatitude, double currentLogitude, List<City> cities)
{
Dictionary<City, double> distances = new Dictionary<City, double>();
foreach (City city in cities)
{
double distance = Math.Sqrt(Math.Pow(city.latitude - currentLatitude, 2) + Math.Pow(city.Longitude - currentLogitude, 2));
distances.Add(city, distance);
}
double minimumDistance = distances.Min(distance => distance.Value);
return distances.First(distance => distance.Value == minimumDistance).Key;
}
Visit here
you can find two c# function using Brute force and divide-and-conquer algorithms to find the closest two points among a set of given points in two dimensions.
Jon's answer is very inspiring, although there're few missing pieces.
lat1 should be in a
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(lat1/ RadianConv) * Math.Cos(lat2/ RadianConv) * Math.Sin(dLong / 2) * Math.Sin(dLong / 2);
The simulated radius in last statement gave 2000ish sometimes, which should be close to either RadiusE or RadiusP, so I used mean radius instead.
return 6371* (2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)));

Categories