Conceptually I understand what I need to do. But mathmatically I'm stumped.
I would like to create two functions preferably in SAS but PHP or JavaScript would work too. The first to convert a latitude/longitude into the Maidenhead Grid Square, the second finds the latitude and longitude for the center of the Maidenhead Grid Square given the grid square name (i.e. EM29qe78pq). I would like both to work with all 10 characters but still be flexable enough to only need 6 and 8 of them.
I've read and re-read the Wikipedia article https://en.wikipedia.org/wiki/Maidenhead_Locator_System but always come up with the wrong values. I've Googled quite literally more than 100 times looking for help, none I found does. I've come to the realization I just am not understanding the math part of this problem. And its simple math..I'm told.
This is the SAS macro I have converting grid square to lat/lon, but while close, its not correct. Would someone care to investigate this for me and perhaps give me the answer.
%macro grid2latlong(grid);
field = 'ABCDEFGHIJKLMNOPQRSTUVWX';
array sparts $ 1 var1-var10;
do i = 1 to length(&grid);
sparts{i} = substr(&grid,i,1);
lon1 = (find(field,var1)-1) * 20 - 180;
lat1 = (find(field,var2)-1) * 10 - 90;
lon2 = var3 * 2;
lat2 = var4 * 1;
lon3 = (find(field,var5)-1) * 5/60;
lat3 = (find(field,var6)-1) * 2.5/60;
lon4 = var7 * 0.0083333;
lat4 = var8 * 0.0041666;
lon5 = var9;
lat5 = var10;
lonx = sum(lon1,lon2,lon3,lon4);
latx = sum(lat1,lat2,lat3,lat4);
end;
drop i var1-var8 lon4 lat4 lon1-lon3 lat1-lat3;
%mend;
You're not calculating the centroid, you're calculating the lower left boundary of the square, as I understand it. To calculate the centroid, it looks like the standard Perl routine Wikipedia references appends "..55LL55LL" as needed (the first two obviously have to be present, but after that 55 or LL will be roughly the central point of the grid tile). I assume 55LL is the "standard" given its presence there; you could calculate it more precisely by taking the average of the left boundary and the right boundary (the next left boundary).
Here's a slightly simplified version of your code above that does this. I write it as a data step to simplify testing but of course making it a macro is trivial. If you have FCMP (9.2+, better 9.4+) you can write it as an actual function in that of course.
data have;
length grid $10;
input grid $;
datalines;
AB12CD34
AB12CD
AB12CD34EF
;;;;
run;
%let grid=grid;
data want;
set have;
*Initialize some variables;
latmult=10; *the amount to multiply latitude values by (starting out);
lonmult=20; *the amount to multiply longitude values by (starting out);
lon=-180; *the zero point for longitude in this system;
lat=-90; *the zero point for latitude in this system;
*append 5's and L's to the string if it is incomplete;
*If you leave this out, this still works, but returns the edge not the center;
initial_String='LL55LL55LL';
substr(initial_String,1,length(&grid.)) = trim(&grid.);
do i = 1 to length(initial_String) by 2;
if mod((i+1)/2,2)=1 then do; *letters;
if I>1 then do; *i=1 it is initialized properly already;
lonmult=lonmult/24;
latmult=latmult/24;
end;
*rank converts "A" to 65 and up through "Z" is 90.;
lon=sum(lon,lonmult*(rank(upcase(char(initial_String,i)))-65));
lat=sum(lat,latmult*(rank(upcase(char(initial_String,i+1)))-65));
end;
else do;
latmult=latmult/10;
lonmult=lonmult/10;
lon=sum(lon,lonmult*input(char(initial_String,i),1.));
lat=sum(lat,latmult*input(char(initial_String,i+1),1.));
end;
end;
run;
Related
I am using Javascripts built in canvas feature to draw a graph showing home loan payments, loan balance, and equity based on user input. I am not able to use any other form of graphing package, as the code is part of an assessment.
My graph is drawn by converting data to X and Y coordinates. When a loan price is input, some home loan payment equations calculate the total amount payed, which is divided by the canvas width to get a spacing variable. This spacing variable is used to convert dollar amounts into pixels on the canvas. A similar setup is used to get the years and months spacing pixels.
The problem I am having is that the Y axis on Javascript's canvas is inverted, with 0 being the top of the canvas and 280, my canvas height, being at the bottom. So far, I have been able to work around this, simply by swapping "+" and "-" operators, however, I am currently creating the code that draws the Loan Balance line on the graph, and the inversion is causing issues that I can't seem to solve. It may be something simple that I'm just not seeing, or it may be a more complex problem that needs to be solved, but either way, I can't figure it out.
X = 0; // same as before, iterators both set back to 0 for the new line.
iterator = 0;
c.beginPath // this next line is for loan balance, it starts at 300000 and goes down with each payment made, then back up with each bit of interest accrued.
// due to the fact that the y axis begins at the top, this means that the pixels for payments is added to the pixel count, and the interest accrued is taken away.
c.moveTo(0, loanLocation) // set starting point to x=0 y= loanLocation
while (X <= 510)// loan balance loop
{
X = X + 0.001; // iterates X by .001 each time, allowing an accurate subpixel resolution loop, see above for why this is needed.
iterator = iterator + 0.001;
if (iterator >= monthSpacing)
{
loanBalance = loanBalance - monthlyPayment + (monthlyInterest * loanBalance);
//alert(loanBalance);
//interestY =
//alert(interestY);
//alert(X + " " + monthSpacing);
loanY = loanY + paymentY - (loanY * monthlyInterest);
//alert(loanY);
//loanY = loanBalance * paySpacing;
c.lineTo(X, loanY);
iterator = 0;
}
}
c.strokeStyle = "black"
c.stroke(); // there is no fill for this line, so it is just left as a stroke.
This is the set of code which draws the line, above it are a few variables which are being used here:
var X = 0;
var iterator = 0;
var monthSpacing = yearSpacing / 12;
//alert(yearSpacing);
//alert(monthSpacing);
var monthlyInterest = interest/1200; // this gives the montly interest rate, the monthly interest pixel amount is below
//alert(monthlyInterest);//debugging, comment out.
var paymentY = monthlyPayment * paySpacing;
var interestY = monthlyInterest * paySpacing; // this is inaccurate, the interestY needs to be gotten by multiplying the remaining loan balance by the
//monthly interest each month.
//var interestY; // will be used further down, must be calculated monthly so cannot be set outside of the line drawing loops.
var totalY = 280;
var equityY = 280;
var loanBalance = loan;
var loanY = loanLocation;
When run I get a strange inversion of the desired outcome, I want the loan balance line to curve down towards zero, but instead, the curve is happening in the opposite direction, I have tried two different ways to get the coordinates, the loanBalance way, which involved working with dollar values and converting that to pixels, and the loanY way, which involved working with pixel values directly.
loanBalance provided a line which was the exact inverse of the desired line, it began at the loan value, and curved upwards in the exact opposite direction to what I want, I am confident that the math I'm using for the loanBalance method is accurate, I simply cannot think of a way to convert that dollar value into pixels due to the inverted nature of the Y axis.
loanY provides a line which is headed "down", but is curving downwards at an increasingly shortened rate, this leads me to believe that while the subtraction (addition due to the inversion) of monthly repayments is accurately being calculated, the addition (subtraction) of monthly interest is being calculated incorrectly. Multiplication cannot be simply replaced with division like addition and subtraction can, so converting this value to pixels is proving difficult. The line drawn by the loanY way is definitely being affected by the inversion, but is not a perfect inverse of the desired line, the math being used for that way is clearly very wrong.
Ideally, I'd like to find a way to use the loanY way, it is consistent with the rest of the program, and can be used when not working with such obvious values as dollars. If I have to though, I will use the loanBalance way.
If you aren't entirely certain what I'm asking, or what the code being used is, I can post the program in it's entirety if that would help. I've not done that yet as I don't want to clutter the question more than I already have.
You can change to a Cartesian coordinate system like this:
// get a reference to your canvas element (eg it might have id='myCanvas')
var canvas=document.getElementById('myCanvas');
// get the context for the canvas
var context=canvas.getContext('2d');
// vertically flip the canvas so its Y origin is at the bottom
context.setTransform(1,0,0,-1,0,canvas.height);
This makes y==0 at the bottom of the canvas and increases upward.
If you're using other transformations, then put this transformation before the others.
I have this image which is completely black except for a white object in the middle (it can be anything but it is always completely white). What I would like to do with nodeJs, is trace the boundary of the object (I would like to find all the white points which are next to black) in the image (performance is key!)
With pngjs I can read an image which gives me an array in which each pixels has 4 values (RGBA). Its a one dimensional array. So, suppose the image is 1000 x 1000 pixels it gives me an array of 1000 x 1000 x 4 = 4000000 entries.
The below expression converts x and y into an array index
var idx = (1000 * y + x) << 2;
data[idx] = 243;
data[idx + 1] = 16;
data[idx + 2] = 16;
Anyway, I could traverse the whole array and register the points where black changes into white, but as I said, performance is very important. I can imagine that some kind of smart iterative search algorithm exists that can follow the boundary somehow :)
Maybe someone knows a library that can help, or an article about how to do this would be great too!!
Check out chain codes like Freeman Code. You need 1 contour point to start with. So just iterate through your lines until you hit your object. Then you walk around your object until you reach your starting point. You will get a code that describes the direction you took for every step. This code can be used to calculate various object features or to just draw the contour of your object.
Btw if your obect is always white and your background is always black you don't have to process 4 channels. Red, green or blue channels contain the same information. Just use either one of them.
Hello fellow programmers.
Again I come here to ask for your help. In my game that I am making I added xp or points as I called it. Every time you get enough points, the points will go to zero and the points needed for level up will get multiplied by five and then divided by 1,5. So, I said: "It would be stupid to have a leveling system without a loading bar!". So I quickly made a loading bar and I needed to get the percentage. Only problem is that I don't know how. So I looked it up a bit on the internet and found this:
pointsPerc = ((Game.points * 100) * Game.maxPoints);
But that didn't work out so I Googled a bit more and found this:
pointsPerc = ((Game.maxPoints / Game.points) / 100);
So how do I actually do this ?
Historic explanatory note:
Javascript (aka "unityscript") has not been available in Unity for some years; Unity is c# only.
As long as David's answer can help you, it doesn't refer directly to your sample. So:
pointsPerc = ((Game.points / Game.maxPoints) * 100);
is what you need.
(Game.points / Game.maxPoints) will give you value between 0..1 and then you just multiply it by 100 to get 0..100 value representing percentage
You need to multiply by 100 not divide.
let floatPercentage = (5 / 10) * 100;
let percentage = Math.floor(floatPercentage);
The second line is to get a nice Int.
I've implemented some code to create some code to treat an image of a relatively small location like plane for converting between locations on the image I have stored and incoming Lat/Long information.
Using the formulas provided at https://msdn.microsoft.com/en-us/library/jj635757(v=vs.85).aspx I wrote these lines of code among others
var vector = math.matrix(
[[x1],
[y1],
[x2],
[y2]]);
var matrix = math.matrix(
[[lat1,long1,1,0]
,[-long1,lat1,0,1]
,[lat2,long2,1,0]
,[-long2,lat2,0,1]]);
var solution = math.multiply(math.inv(matrix),vector);
There is an implicit conversion from the vector returned to solution into conversiondata as I put it into and take it back out of my database.
a = parseFloat(conversiondata['A']);
b = parseFloat(conversiondata['B']);
c = parseFloat(conversiondata['C']);
d = parseFloat(conversiondata['D']);
var long = position.coords.longitude;
var lat = position.coords.latitude;
var x = a * lat + b * long + c;
var y = b * lat - a * long + d;
The values x1, x2, y1, y2 are supplied by getting user click data.
The values lat1, lat2, long1, long2 are supplied by the user in response to two clicks on the map image.
When putting x,y back onto the map its not quite in the right position, the position on the map seems to almost be on the opposite side of the line defined by (x1,y1) and (x2,y2). I'm trying to tell what the reason for the inaccuracy is. (I am however assuming for the time being that the apparent reflection is a coincidence)
If someone could help me narrow down what could be going wrong here are things I've considered (the map doesn't reach even a mile in any direction for reference).
The affine transformation simply doesn't work - But acccording to the link provided it includes scaling so that shouldn't be the cause of the problem
There is a problem with my setting of variables - I've been looking at my code too long to see it if it is.
I am losing too much accuracy moving the var data to MySQL as a float or to PHP as a string
I am not giving accurate enough information from click data / lat/long input. - I zoomed i significantly when clicking on the map and getting the lat/long from google maps though
SVG isn't accuracte enough - Though looking at the xml data it keeps the decimals.
The area that I'm working with is too big to simplify by assuming that the local map is a flat plane
Any help is appreciated, thanks for reading this far.
For further reference I put the lat/long data that JavaScript gave me into google maps and i'm comparing accuracy to that rather than my actual location.
Additional reference: I found "landmarks" on the east and west edges of my image and have calculated the longitude difference to be 0.02695 with the length of the image being at least twice the height.
Sample values of a full run-through of values.
Reference Points
Point 1 (x,y) = (619,564)
Point 1 (lat,long) = (X.099546,-Y.465179)
Point 2 (x,y) = (1181,190)
Point 2 (lat,long) = (X.10365341,-Y.457014)
Geolocation
Predicted coordinate (x,y) = (975,262)
Given coordinate(lat,long) = (X.102851,-Y.459996)
Real Blip (x,y) = (1022.7498707999475,351.02335709985346)
Real blip (approximate lat,long) = (X.101964, -Y.459340)
(Real blip lat long is approximate as it is in a body of water with no good landmarks)
For safety's sake I've taken the digits before the decimal out of the lat/long coordinates but I can confirm that all the X's are equal and all the Y's are equal
Additionally I played with the lat long values in Chrome's developer tools, it seems like the axes are a bit rotated approximately 30 degrees from what it should be
After sufficient poking around I figured out that I had ordered lat and long incorrectly. On my map that has not been rotated from N at the top the following code brings me within just a few feet, more than explainable than the lack of precision resulting from relying on user input and the pixel grid.
var matrix = math.matrix(
[[long1,lat1,1,0]
,[-lat1,long1,0,1]
,[long2,lat2,1,0]
,[-lat2,long2,0,1]]);
And
var x = a * long + b * lat + c;
var y = b * long - a * lat + d;
For anyone else that is interested in pursuing this as a potential solution to simplify the math of their app
The drift that occurred was less than 40 feet over a map with a diagonal of 8000 feet and a difference in reference points of around 3000 feet. This means the drift is little over 1% of the distance of the reference points, this includes the effect of human error.
This error should decrease as you work on smaller maps and increase as you work on bigger maps.
I tested it again on a map with a ~90 degree rotation and the code held up
I'm currently making a Conway's Game of Life reproduction in JavaScript and I've noticed that the function Math.random() is always returning a certain pattern. Here's a sample of a randomized result in a 100x100 grid:
Does anyone knows how to get better randomized numbers?
ApplyRandom: function() {
var $this = Evolution;
var total = $this.Settings.grid_x * $this.Settings.grid_y;
var range = parseInt(total * ($this.Settings.randomPercentage / 100));
for(var i = 0; i < total; i++) {
$this.Infos.grid[i] = false;
}
for(var i = 0; i < range; i++) {
var random = Math.floor((Math.random() * total) + 1);
$this.Infos.grid[random] = true;
}
$this.PrintGrid();
},
[UPDATE]
I've created a jsFiddle here: http://jsfiddle.net/5Xrs7/1/
[UPDATE]
It seems that Math.random() was OK after all (thanks raina77ow). Sorry folks! :(. If you are interested by the result, here's an updated version of the game: http://jsfiddle.net/sAKFQ/
(But I think there's some bugs left...)
This line in your code...
var position = (y * 10) + x;
... is what's causing this 'non-randomness'. It really should be...
var position = (y * $this.Settings.grid_x) + x;
I suppose 10 was the original size of this grid, that's why it's here. But that's clearly wrong: you should choose your position based on the current size of the grid.
As a sidenote, no offence, but I still consider the algorithm given in #JayC answer to be superior to yours. And it's quite easy to implement, just change two loops in ApplyRandom function to a single one:
var bias = $this.Settings.randomPercentage / 100;
for (var i = 0; i < total; i++) {
$this.Infos.grid[i] = Math.random() < bias;
}
With this change, you will no longer suffer from the side effect of reusing the same numbers in var random = Math.floor((Math.random() * total) + 1); line, which lowered the actual cell fillrate in your original code.
Math.random is a pseudo random method, that's why you're getting those results. A by pass i often use is to catch the mouse cursor position in order to add some salt to the Math.random results :
Math.random=(function(rand) {
var salt=0;
document.addEventListener('mousemove',function(event) {
salt=event.pageX*event.pageY;
});
return function() { return (rand()+(1/(1+salt)))%1; };
})(Math.random);
It's not completly random, but a bit more ;)
A better solution is probably not to randomly pick points and paint them black, but to go through each and every point, decide what the odds are that it should be filled, and then fill accordingly. (That is, if you want it on average %20 percent chance of it being filled, generate your random number r and fill when r < 0.2 I've seen a Life simulator in WebGL and that's kinda what it does to initialize...IIRC.
Edit: Here's another reason to consider alternate methods of painting. While randomly selecting pixels might end up in less work and less invocation of your random number generator, which might be a good thing, depending upon what you want. As it is, you seem to have selected a way that, at most some percentage of your pixels will be filled. IF you had kept track of the pixels being filled, and chose to fill another pixel if one was already filled, essentially all your doing is shuffling an exact percentage of black pixels among your white pixels. Do it my way, and the percentage of pixels selected will follow a binomial distribution. Sometimes the percentage filled will be a little more, sometimes a little less. The set of all shufflings is a strict subset of the possibilities generated this kind of picking (which, also strictly speaking, contains all possibilities for painting the board, just with astronomically low odds of getting most of them). Simply put, randomly choosing for every pixel would allow more variance.
Then again, I could modify the shuffle algorithm to pick a percentage of pixels based upon numbers generated from a binomial probability distribution function with a defined expected/mean value instead of the expected/mean value itself, and I honestly don't know that it'd be any different--at least theoretically--than running the odds for every pixel with the expected/mean value itself. There's a lot that could be done.
console.log(window.crypto.getRandomValues(new Uint8Array(32))); //return 32 random bytes
This return a random bytes with crypto-strength: https://developer.mozilla.org/en/docs/Web/API/Crypto/getRandomValues
You can try
JavaScript Crypto Library (BSD license). It is supposed to have a good random number generator. See here an example of usage.
Stanford JavaScript Crypto Library (BSD or GPL license). See documentation for random numbers.
For a discussion of strength of Math.random(), see this question.
The implementation of Math.random probably is based on a linear congruential generator, one weakness of which is that a random number depends on the earlier value, producing predictable patterns like this, depending on the choice of the constants in the algorithm. A famous example of the effect of poor choice of constants can be seen in RANDU.
The Mersenne Twister random number generator does not have this weakness. You can find an implementation of MT in JavaScript for example here: https://gist.github.com/banksean/300494
Update: Seeing your code, you have a problem in the code that renders the grid. This line:
var position = (y * 10) + x;
Should be:
var position = (y * grid_x) + x;
With this fix there is no discernible pattern.
You can using the part of sha256 hash from timestamp including nanoseconds:
console.log(window.performance.now()); //return nanoseconds inside
This can be encoded as string,
then you can get hash, using this: http://geraintluff.github.io/sha256/
salt = parseInt(sha256(previous_salt_string).substring(0, 12), 16);
//48 bits number < 2^53-1
then, using function from #nfroidure,
write gen_salt function before, use sha256 hash there,
and write gen_salt call to eventListener.
You can use sha256(previous_salt) + mouse coordinate, as string to get randomized hash.