Scenario
I am trying to generate 500 to 1000 random coordinates (lat,long) that lies within a circle with 1 kilometer radius where center point located at (5.418680, 100.327829). I am trying to code this in php but failed to do so as i have no idea what value should i provide for $radius.
$radius = ?;
$origin_x = 5.420525;
$origin_y = 100.319500;
$angle = deg2rad(mt_rand(0, 359));
$pointRadius = mt_rand(0, $radius);
$point[] = array(
'x' => $origin_x + ($pointRadius * cos($angle)),
'y' => $origin_y + ($pointRadius * sin($angle))
);
There is another approach came across my mind. Instead of generating point within a circle, i would like to generate point inside a boundary of square and then apply Haversine great circle distance formula to determine is the random generated point lies within the circle with 1KM radius.
Note: The generated point is fine to overlap each other.
Please advise, I need general idea of what approach should I take. Thanks in advance.
Create random points inside the bounds of the circle:
var bounds = circle.getBounds();
map.fitBounds(bounds);
var sw = bounds.getSouthWest();
var ne = bounds.getNorthEast();
for (var i = 0; i < 100; i++) {
// create a random point inside the bounds
var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat();
var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
var point = new google.maps.LatLng(ptLat,ptLng);
If they are within the circle itself keep them (add them to the map in this case), otherwise discard them:
if (google.maps.geometry.spherical.computeDistanceBetween(point,circle.getCenter()) < circle.getRadius()) {
createMarker(map, point,"marker "+i);
// break; if only need one point
} // else nothing.
Example using the Google Maps Javascript API v3:
var circle;
var infowindow = new google.maps.InfoWindow({});
function initialize() {
var map = new google.maps.Map(document.getElementById("map"), {
zoom: 4,
center: new google.maps.LatLng(22.7964, 79.8456),
mapTypeId: google.maps.MapTypeId.HYBRID
});
circle = new google.maps.Circle({
center: map.getCenter(),
radius: 1000, // meters
strokeColor: "#0000FF",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#0000FF",
fillOpacity: 0.26
});
circle.setMap(map);
var bounds = circle.getBounds();
map.fitBounds(bounds);
var sw = bounds.getSouthWest();
var ne = bounds.getNorthEast();
for (var i = 0; i < 100; i++) {
var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat();
var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
var point = new google.maps.LatLng(ptLat, ptLng);
if (google.maps.geometry.spherical.computeDistanceBetween(point, circle.getCenter()) < circle.getRadius()) {
createMarker(map, point, "marker " + i);
// break;
}
}
}
function createMarker(map, point, content) {
var marker = new google.maps.Marker({
position: point,
map: map
});
google.maps.event.addListener(marker, "click", function(evt) {
infowindow.setContent(content + "<br>" + marker.getPosition().toUrlValue(6));
infowindow.open(map, marker);
});
return marker;
}
google.maps.event.addDomListener(window, 'load', initialize);
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map" style="width: 530px; height: 500px">
</div>
fiddle
I'd do it like this:
Choose two independent x and y coordinate, uniformly from the interval [0,1].
If x² + y² > 1 your point lies outside the circle. Discard that sample and try again. Not transforming the square to the circle ensures equidistribution.
Turn coordinates in the circle to lat/lon on the sphere. If you want to preserve equidistribution, you'd use an area-preserving map projection here. But as the radius is way smaller than the radius of the earth, this doesn't matter much, so you might use some simpler projection instead unless you have to provide strong guarantees for equidistribution.
I guess there might be ways to avoid the discarding in step 2, but that would probably make things way more complicated, so for practical applications I'd stick with this.
Related
This is for a game that I am considering.
I have a point that is noted as moving inside a (2D) circle from an arbitrary point, at an arbitrary direction and at a particular time. The point will bounce off the interior wall of the circle when it intersects.
For this example let's say the circle has a diameter of 100 kilometers with it's center at (0,0) and 10 hours ago the point was at location (20,30) with a heading of 40 degrees at a speed of 50kph .
What is the best way to determine where that point currently is and at what direction it's traveling?
I will be implementing this in PHP with the point and circle data stored in MySQL. Since it is a web page there will be no constantly running host process to keep things up to date and the data will need to be refreshed upon a page load.
I'm certainly not looking for anyone to write the code for me but am hoping someone can help me with a somewhat efficient way to approach this.
Your point-object will travel along what is called chords in geometry.
As the object hits the circle boundary, it will reflect from the circle's tangent at that point, and go along a next chord that has the same length. The next hit will be at the same angle (with the tangent at that hit point) as the previous hit, and so it will continue. At a constant speed, the time between hits will be a constant time.
Given the start time and the current time, one can calculate the number of chords that have been completed, and how much of the current chord has been completed. Calculating the position from that is easy when you know the previous and next hit positions. As these hit positions are at equal distances along the circle boundary, that is a matter of converting polar coordinates (an angle, and a distance of 1 radian) to Cartesian coordinates.
I will demonstrate this with JavaScript code. It will not be a great effort to wrap this in PHP:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var radius = canvas.height / 2 - 5;
var pixel = 1/radius;
// transform the canvas so that 0,0 is in the center of the canvas,
// and a unit circle would cover most of the height of the canvas:
context.setTransform(radius, 0, 0, radius, radius+2, radius+2);
// draw unit circle
context.beginPath();
context.arc(0, 0, 1, 0, 2 * Math.PI, false);
context.lineWidth = pixel;
context.strokeStyle = 'black';
context.stroke();
function drawPoint(point) {
// use a different color every 30 seconds:
context.fillStyle = Date.now() % 60000 > 30000 ? 'red' : 'blue';
context.fillRect(point.x-2*pixel, point.y-2*pixel, 4*pixel, 4*pixel);
}
function polarToCartesian(rad, dist) {
return {
x: Math.cos(rad) * dist,
y: Math.sin(rad) * dist
}
}
function pointBetween(a, b, fractionTravelled) {
return {
x: a.x + (b.x-a.x)*fractionTravelled,
y: a.y + (b.y-a.y)*fractionTravelled
}
}
// 4 parameters are needed:
var startRadians = 0; // distance along circle boundary from (0,1)
var hitAngle = Math.PI/2.931; // PI/2 would be head-on impact along diagonal
var speed = 0.4; // radians per second
var startTime = Date.now()/1000; // seconds
//
// Calculate some derived values which remain constant:
// - theta as used on https://en.wikipedia.org/wiki/Chord_%28geometry%29
// - chordSize formula comes from that wiki article.
var theta = 2 * hitAngle;
var chordSize = 2 * Math.sin(theta/2); // in radians
function drawCurrentPosition() {
// Note that this calculation does not look at the previous result,
// but uses the original parameters and time passed to calculate
// the objects current position.
var elapsedTime = Date.now()/1000 - startTime; // in secs
var distanceTravelled = speed * elapsedTime; // in radians
var chordsTravelled = distanceTravelled / chordSize; // in number of chords
var chordsTravelledComplete = Math.floor(chordsTravelled);
var fractionOnChord = chordsTravelled - chordsTravelledComplete; // 0<=f<1
var lastHitRadians = startRadians + chordsTravelledComplete * theta; // rad
var nextHitRadians = lastHitRadians + theta;
var lastHitPos = polarToCartesian(lastHitRadians, 1); // (x,y)
var nextHitPos = polarToCartesian(nextHitRadians, 1);
var currentPos = pointBetween(lastHitPos, nextHitPos, fractionOnChord);
drawPoint(currentPos);
}
// Demo: keep drawing the object's position every 0.1 second:
setInterval(drawCurrentPosition, 100);
<canvas id="myCanvas" width="200" height="200"></canvas>
Addendum: PHP code
Here is some code that could be useful for use in PHP. It uses the same calculations as the above JavaScript code, but does not keep running. Instead it first checks if there is a started game in the session scope, if not, it starts the "clock". At every request (reload of the page), the new position is calculated and printed on the page as an X,Y pair.
The coordinates are normalised, based on a unit circle (radius 1). The game parameters are hard-coded, but you could easily let them be passed via POST/GET parameters:
session_start(); // needed to persist game data for this user session
function getNewGame($startRadians, $hitAngle, $speed) {
$game = array();
$game["startTime"] = microtime(true);
$game["startRadians"] = $startRadians;
$game["theta"] = 2 * $hitAngle;
$game["chordSize"] = 2 * sin($hitAngle);
$game["speed"] = $speed;
return (object) $game;
}
function polarToCartesian($rad, $dist) {
return (object) array(
"x" => cos($rad) * $dist,
"y" => sin($rad) * $dist
);
}
function pointBetween($a, $b, $fractionTravelled) {
return (object) array(
"x" => $a->x + ($b->x-$a->x)*$fractionTravelled,
"y" => $a->y + ($b->y-$a->y)*$fractionTravelled
);
}
function getCurrentPosition($game) {
// Note that this calculation does not look at the previous result,
// but uses the original parameters and time passed to calculate
// the objects current position.
$elapsedTime = microtime(true) - $game->startTime; // in secs
$distanceTravelled = $game->speed * $elapsedTime; // in radians
$chordsTravelled = $distanceTravelled / $game->chordSize; //number of chords
$chordsTravelledComplete = floor($chordsTravelled);
$fractionOnChord = $chordsTravelled - $chordsTravelledComplete; // 0<=f<1
$lastHitRadians = $game->startRadians
+ $chordsTravelledComplete * $game->theta; // in radians on circle
$nextHitRadians = $lastHitRadians + $game->theta;
$lastHitPos = polarToCartesian($lastHitRadians, 1); // (x,y)
$nextHitPos = polarToCartesian($nextHitRadians, 1);
$currentPos = pointBetween($lastHitPos, $nextHitPos, $fractionOnChord);
return $currentPos;
}
// check if this is the first time the user loads this page:
if (!isset($_SESSION["game"])) {
// start game with some game parameters:
$_SESSION["game"] = getNewGame(0, pi()/2.931, 0.4);
}
// calculate the position based on game info and current time:
$pos = getCurrentPosition($_SESSION["game"]);
// print the result:
echo "Current position: {$pos->x}, {$pos->y}<br>";
I have seen examples of enabling certain dates, disabling certain dates, changing background colors...etc, but I was looking for suggestions on how to place a Red / or \ on a date based on a mysql return.
I have a 2 story house I rent out. Upper and Lower Level. If Upper is rented for a specific date I am looking for a red / to be placed on the date. If Lower Level is rented place a red \ on the date. If both are rented on the same date the end result would be a red X on the date.
unavailableDates would be where both upper and lower are rented out
upperavailableDates would be where only upper is rented out
loweravailableDates would be where only lower is rented out
suggestions would be greatly appreciated.
<input id="picker1">
var unavailableDates = ["27-11-2013", "28-11-2013", "29-11-2013"];
var upperavailableDates = ["01-12-2013", "02-12-2013", "03-12-2013"];
var loweravailableDates = ["24-12-2013", "25-12-2013", "26-12-2013"];
function unavailable(date) {
dmy = date.getDate() + "-" + (date.getMonth() + 1) + "-" + date.getFullYear();
if ($.inArray(dmy, unavailableDates) == -1) {
return [true, ""];
} else {
return [false, "", "Unavailable"];
}
}
$(function() {
$("#picker1").datepicker({
dateFormat: 'dd MM yy',
beforeShowDay: unavailable
});
});
I'm looking for a elegant solution that calculates the center between several latitude-longitude coordinates (for example, to simply center a map to the center of a google-maps polygon).
Table: locations:
id | city | latitude | longitude
-----------------------------------------------
1 | Berlin | 52.524268 | 13.406290
-----------------------------------------------
2 | London | 51.508129 | -0.1280050
-----------------------------------------------
3 | Hamburg | 53.551084 | 9.9936817
-----------------------------------------------
4 | Amsterdam | 52.370215 | 4.8951678
-----------------------------------------------
The current calculation:
function calculateCenter($array_locations) {
$minlat = false;
$minlng = false;
$maxlat = false;
$maxlng = false;
foreach ($array_locations as $geolocation) {
if ($minlat === false) { $minlat = $geolocation['lat']; } else { $minlat = ($geolocation['lat'] < $minlat) ? $geolocation['lat'] : $minlat; }
if ($maxlat === false) { $maxlat = $geolocation['lat']; } else { $maxlat = ($geolocation['lat'] > $maxlat) ? $geolocation['lat'] : $maxlat; }
if ($minlng === false) { $minlng = $geolocation['lon']; } else { $minlng = ($geolocation['lon'] < $minlng) ? $geolocation['lon'] : $minlng; }
if ($maxlng === false) { $maxlng = $geolocation['lon']; } else { $maxlng = ($geolocation['lon'] > $maxlng) ? $geolocation['lon'] : $maxlng; }
}
// Calculate the center
$lat = $maxlat - (($maxlat - $minlat) / 2);
$lon = $maxlng - (($maxlng - $minlng) / 2);
return array($lat, $lon);
}
As you are using Google Maps you can use getBounds() method and getCenter() method.
I have rearranged your coordinates to form a Convex Polygon (All the vertices point 'outwards', away from the center).The polygon is closed by having the first coordinate as the first and last value in polygonCoords array.
See jsfiddle
var map;
var polygon;
var bounds = new google.maps.LatLngBounds();
var i;
var myLatLng = new google.maps.LatLng(52.5,6.6);
var myOptions = {
zoom: 5,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
var polygonCoords = [
new google.maps.LatLng(52.524268,13.406290),
new google.maps.LatLng(53.551084,9.9936817),
new google.maps.LatLng(51.508129,-0.1280050),
new google.maps.LatLng(52.370215,4.8951678),
new google.maps.LatLng(52.524268,13.406290)//Start & end point
];
polygon = new google.maps.Polygon({
paths: polygonCoords,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 3,
fillColor: "#FF0000",
fillOpacity: 0.05
});
polygon.setMap(map);
for (i = 0; i < polygonCoords.length; i++) {
bounds.extend(polygonCoords[i]);
}
// The Center of the polygon
var latlng = bounds.getCenter();
var marker = new google.maps.Marker({
position: latlng,
map: map,
title:latlng.toString()
});
Averaging your latitudes and longitudes works in many cases, but have problems in a number of cases. Example, you have 2 cites, Tokyo (long = 140) and Seattle (long -122), your average longitude is 18, somewhere in Europe. You would expect something closer to the international date line, 180 degrees away.
The most direct, no problem method, is to average the vectors as if each originated from the earth's center.
Pseudo code, (assumes radians)
for each lat,long
// assume 1 radii from the earth's center.
// covert lat, long, and radii into x,y,z (spherical to cartesian coordinates)
r=1, theta=pi/2 - lat, phi=long
x = r*sin(theta)*cos(phi)
y = r*sin(theta)*sin(phi)
z = r*cos(theta)
N++;
// accumulate x,y,z
sum_x += x, etc.
// average x,y,z
avg_x = sum_x/N, etc.
// convert x,y,z back to spherical co-ordinates to get the lat/long center.
rho = sqrt(avg_x*avg_x + avg_y*avg_y + avg_z*avg_z)
lat = pi/2 - acos(avg_z/rho) // acos() results are 0 to pi
long = atan2(avg_y, avg_x) // 4 quadrant arctangent
[Edit Corrected spherical co-ordinates to cartesian]
Google uses a Mercator projection, treating the earth as an elongated cylinder. Thus the problem to to find the center of that projection.
For each lat/long pair, convert to map scaled x,y co-ordinates (using radians):
x = long
y = ln(tan(pi/4 + lat/2)) // Mercator projection
Then, for x & y, find the average of the minimum and maximum to get your center. Convert back to lat/long as follows
Pseudo code
center_long = average(minimum_x, maximum_x)
center_lat = (atan(exp(average(minimum_y, maximum_y))) - pi/4)*2
The calculation of the center longitude works fine were it not for the circular nature of the cylindric Earth projection. If the longitudes are in both the Eastern and Western hemispheres (some negative, some positive), than additional work may be needed.
Pseudo code
sort the longitudes into ascending order
for each longitude
difference = longitude(i-1) - longitude(i)
// for first, use longitude(0) - longitude(last)
if (difference < 0) add 2*pi (360 degrees)
Keep track of index of minimal difference
The pair with the minimal difference represents the pair that most tightly contains all longitudes.
Average this pair for the center longitude.
If this pair was index 0 & last, add pi (180 degrees)
OP 4 city result: (52.4 N, 7.0 E)
This is my second answer, for the first does not get the the crux of OP's post. Since it has some value it remains.
I am having some problems with the way PHP and javascript round numbers. I am using PHP's round function and this javascript function:
function roundNumber(number, decimals) {
var newnumber = new Number(number+'').toFixed(parseInt(decimals));
var value = parseFloat(newnumber);
return value;
}
The number i am trying to round is 43.65 * 2.5 + 40% which when done using a calculator = 152.775 or when rounded in PHP = 152.78.
In javascript when i do a console.log the number is 152.774999999998 and when rounded with the above function gives me 152.77
Any help to reslove this issue is greatly appreciated
This isn't anything to do with rounding per se, but is to do with how decimal numbers are represented in binary-based hardware.
Check out the floating point guide for lots more information on this, as well as solutions/alternatives.
Please have a look at How to deal with floating point number precision in JavaScript?
Here is an example
function roundNumber(number, decimals) {
decimals = parseInt(decimals,10);
var dec = Math.pow(10,decimals)
console.log(dec,parseFloat(number)*dec);
number=""+Math.round(parseFloat(number)*dec+.0000000000001); // fixed the .X99999999999
return parseFloat(number.slice(0,-1*decimals) + "." + number.slice(-1*decimals))
}
var val = 43.65 * 2.5;
val+= val*0.40
console.log(val+' ~= 152.78? --> '+roundNumber(val,2).toFixed(2));
console.log('15.803 ~= 15.80? --> '+roundNumber(15.803,2).toFixed(2));
console.log('15.805 ~= 15.81? --> '+roundNumber(15.805,2).toFixed(2));
console.log('14.803 ~= 14.80? --> '+roundNumber(14.803,2).toFixed(2));
console.log('0.575 ~= 0.58? --> '+roundNumber(0.575,2).toFixed(2));
I was thinking a bit on this, and wanted to share my solution, let it not go to waste:
function roundNumber(number, decimals) {
var d = parseInt(decimals,10),
dx = Math.pow(10,d),
n = parseFloat(number),
f = Math.round(Math.round(n * dx * 10) / 10) / dx;
return f.toFixed(d);
}
This does not use string functions, or any forced up or down rounding.
Test it here: http://jsfiddle.net/inti/hMrsp/4/
Edit: corrected, was cutting down zeros at the end
php rounds to 152.78, because it sees 152.77499 which is 152.775 and in the end 152.178. can't you use rounded value from php?
It is because the different precisions used in JS (by the browser) and PHP or actually how many bits are used to store the numbers.
you can make your JS rounding function do this to round to the 2nd digit
Math.round(floatNumber*100)/100
Find below javascript function for number format
<script type="text/javascript">
function format_number(pnumber,decimals){
if (isNaN(pnumber)) { return 0};
if (pnumber=='') { return 0};
var snum = new String(pnumber);
var sec = snum.split('.');
var whole = parseFloat(sec[0]);
var result = '';
if(sec.length > 1){
var dec = new String(sec[1]);
dec = String(parseFloat(sec[1])/Math.pow(10,(dec.length - decimals)));
dec = String(whole + Math.round(parseFloat(dec))/Math.pow(10,decimals));
var dot = dec.indexOf('.');
if(dot == -1){
dec += '.';
dot = dec.indexOf('.');
}
while(dec.length <= dot + decimals) { dec += '0'; }
result = dec;
} else{
var dot;
var dec = new String(whole);
dec += '.';
dot = dec.indexOf('.');
while(dec.length <= dot + decimals) { dec += '0'; }
result = dec;
}
return result;
}
var value = format_number(newnumber,2);
</script>
I have the Lat/Long value of New York City, NY; 40.7560540,-73.9869510 and a flat image of the earth, 1000px × 446px.
I would like to be able to convert, using Javascript, the Lat/Long to an X,Y coordinate where the point would reflect the location.
So the X,Y coordinate form the Top-Left corner of the image would be; 289, 111
Things to note:
don't worry about issues of what projection to use, make your own
assumption or go with what you know
might work
X,Y can be form any corner of the image
Bonus points for
the same solution in PHP (but I
really need the JS)
The projection you use is going to change everything, but this will work assuming a Mercator projection:
<html>
<head>
<script language="Javascript">
var dot_size = 3;
var longitude_shift = 55; // number of pixels your map's prime meridian is off-center.
var x_pos = 54;
var y_pos = 19;
var map_width = 430;
var map_height = 332;
var half_dot = Math.floor(dot_size / 2);
function draw_point(x, y) {
dot = '<div style="position:absolute;width:' + dot_size + 'px;height:' + dot_size + 'px;top:' + y + 'px;left:' + x + 'px;background:#00ff00"></div>';
document.body.innerHTML += dot;
}
function plot_point(lat, lng) {
// Mercator projection
// longitude: just scale and shift
x = (map_width * (180 + lng) / 360) % map_width + longitude_shift;
// latitude: using the Mercator projection
lat = lat * Math.PI / 180; // convert from degrees to radians
y = Math.log(Math.tan((lat/2) + (Math.PI/4))); // do the Mercator projection (w/ equator of 2pi units)
y = (map_height / 2) - (map_width * y / (2 * Math.PI)) + y_pos; // fit it to our map
x -= x_pos;
y -= y_pos;
draw_point(x - half_dot, y - half_dot);
}
</script>
</head>
<body onload="plot_point(40.756, -73.986)">
<!-- image found at http://www.math.ubc.ca/~israel/m103/mercator.png -->
<img src="mercator.png" style="position:absolute;top:0px;left:0px">
</body>
</html>
A basic conversion function in js would be:
MAP_WIDTH = 1000;
MAP_HEIGHT = 446;
function convert(lat, lon){
var y = ((-1 * lat) + 90) * (MAP_HEIGHT / 180);
var x = (lon + 180) * (MAP_WIDTH / 360);
return {x:x,y:y};
}
This will return the number of pixels from upper left.
This function assumes the following:
That your image is properly aligned
with the upper left corner (0,0)
aligning with 90* North by 180*
West.
That your coords are signed with N being -, S being +, W being - and E being +
If you have a picture of the whole earth, the projection does always matter. But maybe I just don't understand your question.