actually my complete need is to click on somewhere on the map. draw an ellipse on that location(centered) and as i move the mouse back and forth the radius of the ellipse gets enlarged/shortend until i again click the mouse and the ellipse is persisted in its last shape. the radius of the ellipse is the length between the first click and the second click. i must not that i cannot use the Ellipse because i need the radius to be in kilometers so that it changes with zoom changing.
7 Answers, 1 is accepted
As you said in your ticket the EllipseData refer to its top left corner. If you want the top left corner to be the center of the ellipse you can manually calculate it using the code below:
EllipseData ellipse =
new
EllipseData();
ellipse.Width = 0.5;
ellipse.Height = 0.5;
var latitude = topLeftCornerLocation.Latitude + (ellipse.Height / 2);
var longitude = topLeftCornerLocation.Longitude - (ellipse.Width / 2);
ellipse.Location =
new
Location(latitude, longitude);
As for your approach, you can subscribe to the MapMouseClick event of the RadMap. In the event arguments you can get the current click location on the map and the code mentioned above you can calculate the mouse click location to be the center of the ellipse.
private Location originPosition;
private
void
radMap_MapMouseClick(
object
sender, Telerik.Windows.Controls.Map.MapMouseRoutedEventArgs eventArgs)
{
EllipseData ellipse =
new
EllipseData();
ellipse.Width = 0.5;
ellipse.Height = 0.5;
var latitude = eventArgs.Location.Latitude + (ellipse.Height / 2);
var longitude = eventArgs.Location.Longitude - (ellipse.Width / 2);
ellipse.Location =
new
Location(latitude, longitude);
this
.visualizationLayer.Items.Add(ellipse);
this.originPosition = eventArgs.Location;
}
private
void
radMap_MouseMove(
object
sender, MouseEventArgs e)
{
var mousePosition = e.GetPosition(
this
.radMap);
var location = Location.GetCoordinates(
this
.radMap, mousePosition);
var distance = GetDistance(location,
this
.originPosition);
}
private
static
double
GetDistance(Location point1, Location point2)
{
double
a = (
double
)(point2.Latitude - point1.Latitude);
double
b = (
double
)(point2.Longitude - point1.Longitude);
return
Math.Sqrt(a * a + b * b);
}
Hope this information is helpful.
Regards,
Dinko
Telerik by Progress
hi dear dinko and thank you for your valuable time and your VERY complete answer
i had 3 problem/questions
1- if your GetDistance() Method doesn't give a degree number what does it give? and how can i convert it to degree
2- for calculating distance i'm using a formula called the "haversine" formula and i think it gives the right answer so i put it here so you can confirm it for me and others can use it if confirmed:
private
double
calculatedegreedestination(Location l1, Location l2)
{
var la1 = DegToRadian(l1.Latitude);
var la2 = DegToRadian(l2.Latitude);
var deltalat = DegToRadian(Math.Abs(l2.Latitude - l1.Latitude));
var deltalong = DegToRadian(Math.Abs(l2.Longitude - l1.Longitude));
var a = Math.Sin(deltalat / 2) * Math.Sin(deltalat / 2) +
Math.Cos(la1) * Math.Cos(la2) * Math.Sin(deltalong / 2) * Math.Sin(deltalong / 2);
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return
RadianTodegree(c);
}
and this is where i got the idea:
http://www.movable-type.co.uk/scripts/latlong.html
3- now my problem is after i calculate the radius with this formula and i draw an ellipsedata with the same width and height it draws an ellipse but not CIRCLE it is egg shaped! with smaller width and bigger height (although when i trace the width and height of the ellipse are numerically equal). why is that?and how can i stop it from happening? i want a circle shaped ellipsedata with the width of like 1 kilometer it should be equal in height and width
4- now that it came to this. in another use case i want to draw another ellipsedata which its width is like 2 kilometers. how can i convert that to degree
again thank you very much for your valuable time
I am looking into this right now and will let you know once I have more information.
Regards,
Dinko
Telerik by Progress
Let me get straight to your question.
We are happy to hear that you have found a method that works for you. Hope it works in all cases. About the GetDistance() method, indeed, it doesn't return a correct degree number. This was just a suggestion and in your case, you will need to implement custom logic that gets into account the distortion in the distance caused by the ellipse form of the world - the different distance will have different pixels size on the different meridians.
About your third question, the described behavior is expected. The EllipseData objects are measured in spatial units and as you may notice their size depends on the zoom level and their location. Basically, the distance is represented differently on the different coordinates in the Mercator projection. The Mercator projection distorts the size of objects as the latitude increases from the Equator to the poles. For example, let's have a shape which covers 10 km on the map. On the equator, this shape will have 100px width while on the North pole the width will be 30px. That is why the map shape is distorted when moving to another location.
For your last question, you can check the following StackOverflow article which could be a good starting point for implementing a method to convert kilometers to degrees.
Regards,
Dinko
Telerik by Progress
Hi,
I also ran into the problem with the "third question". Is there a way to inverse this Mercator projection or is there another workaround so that I can draw a circle that actually is 1 km i diameter on the map?.
/Ola
The RadMap control does not provide a way to inverse the Mercator projection. I am afraid that I can't suggest you a workaround for the described behavior.
Regards,
Dinko
Progress Telerik
I generated my own circle with the code below and added a binding to MapPolygonView.Points. Works ok for now.
private
IEnumerable<Location> GenerateCircle(Location center,
double
distance)
{
return
Enumerable.Range(0, 360).Select(i => CalculateLocation(center, distance, Math.PI * i / 180));
}
private
Location CalculateLocation(Location location,
double
distance,
double
bearing)
{
var lat1 = location.Latitude * Math.PI / 180;
var lon1 = location.Longitude * Math.PI / 180;
var d = distance / Radius;
var lat2 = Math.Asin(Math.Sin(lat1) * Math.Cos(d) + Math.Cos(lat1) * Math.Sin(d) * Math.Cos(bearing));
var lon2 = lon1 + Math.Atan2(Math.Sin(bearing) * Math.Sin(d) * Math.Cos(lat1),
Math.Cos(d) - Math.Sin(lat1) * Math.Sin(lat2));
return
new
Location(lat2 * 180 / Math.PI, lon2 * 180 / Math.PI);
}