How to convert GPS coordinates to decimal in Lua? - lua

I need to convert GPS coordinates from WGS84 to decimal using Lua.
I am sure it's been done before, so I am looking for a hint to a code snippet.
corrected question: Code to convert DMS (Degress Minutes Seconds) to DEG ((decimal) Degrees) in Lua?
examples:
Vienna: dms: 48°12'30" N 16°22'28" E
or
Zurich: dms: 47°21'7" N 8°30'37" E
The difficulty I find is to get the numbers out of these strings.
Especially how to handle the signs for degree (°) minutes (') and seconds (").
So that I would have for example a table coord{} per coordinate to deal with.
coord {1} [48]
coord {2} [12]
coord {3} [30]
coord {4} [N]
coord {5} [16]
coord {6} [22]
coord {7} [28]
coord {8} [E]
Suggestions are appreciated, thanks.

Parse the string latlon = '48°12'30" N 16°22'28" E' into DMS+heading components:
This is your string (note the escaped single-quote):
latlon = '48°12\'30" N 16°22\'28" E'
Break it down into two steps: the lat/lon, then components of each. You need captures "()", ignore spaces around the heading (N and E) with "%s*":
lat, ns, lon, ew = string.match(latlon, '(.*)%s*(%a)%s*(.*)%s*(%a)')
The lat is now 48°12'30", ns is 'N', lon is 16°22'28", ew is 'E'. For components of lat, step by step:
-- string.match(lat, '48°12'30"') -- oops the ' needs escaping or us
-- string.match(lat, '48°12\'30"')
-- ready for the captures:
-- string.match(lat, '(48)°(12)\'(30)"') -- ready for generic numbers
d1, m1, s1 = string.match(lat, '(%d+)°(%d+)\'(%d+)"')
d2, m2, s2 = string.match(lon, '(%d+)°(%d+)\'(%d+)"')
Now that you know (d1, m1, s1, ns) and (d2, m2, s2, ew), you have:
sign = 1
if ns=='S' then sign = -1 end
decDeg1 = sign*(d1 + m1/60 + s1/3600)
sign = 1
if ew=='W' then sign = -1 end
decDeg2 = sign*(d2 + m2/60 + s2/3600)
For your values of lat, you get decDeg1 = 48.208333 which is the correct value according to online calculators (like http://www.satsig.net/degrees-minutes-seconds-calculator.htm).

Related

How to get each individual digit of a given number in Basic?

I have one program downloaded from internet and need to get each digit printed out from a three digit number. For example:
Input: 123
Expected Output:
1
2
3
I have 598
Need to Get:
5
9
8
I try using this formula but the problem is when number is with decimal function failed:
FIRST_DIGIT = (number mod 1000) / 100
SECOND_DIGIT = (number mod 100) / 10
THIRD_DIGIT = (number mod 10)
Where number is the above example so here is calulation:
FIRST_DIGIT = (598 mod 1000) / 100 = 5,98 <== FAILED...i need to get 5 but my program shows 0 because i have decimal point
SECOND_DIGIT = (598 mod 100) / 10 = 9,8 <== FAILED...i need to get 9 but my program shows 0 because i have decimal point
THIRD_DIGIT = (598 mod 10) = 8 <== CORRECT...i get from program output number 8 and this digit is correct.
So my question is is there sample or more efficient code that get each digit from number without decimal point? I don't want to use round to round nearest number because sometime it fill failed if number is larger that .5.
Thanks
The simplest solution is to use integer division (\) instead of floating point division (/).
If you replace each one of your examples with the backslash (\) instead of forward slash (/) they will return integer values.
FIRST_DIGIT = (598 mod 1000) \ 100 = 5
SECOND_DIGIT = (598 mod 100) \ 10 = 9
THIRD_DIGIT = (598 mod 10) = 8
You don't have to do any fancy integer calculations as long as you pull it apart from a string:
INPUT X
X$ = STR$(X)
FOR Z = 1 TO LEN(X$)
PRINT MID$(X$, Z, 1)
NEXT
Then, for example, you could act upon each string element:
INPUT X
X$ = STR$(X)
FOR Z = 1 TO LEN(X$)
Q = VAL(MID$(X$, Z, 1))
N = N + 1
PRINT "Digit"; N; " equals"; Q
NEXT
Additionally, you could tear apart the string character by character:
INPUT X
X$ = STR$(X)
FOR Z = 1 TO LEN(X$)
SELECT CASE MID$(X$, Z, 1)
CASE " ", ".", "+", "-", "E", "D"
' special char
CASE ELSE
Q = VAL(MID$(X$, Z, 1))
N = N + 1
PRINT "Digit"; N; " equals"; Q
END SELECT
NEXT
I'm no expert in Basic but looks like you have to convert floating point number to Integer. A quick google search told me that you have to use Int(floating_point_number) to convert float to integer.
So
Int((number mod 100)/ 10)
should probably the one you are looking for.
And, finally, all string elements could be parsed:
INPUT X
X$ = STR$(X)
PRINT X$
FOR Z = 1 TO LEN(X$)
SELECT CASE MID$(X$, Z, 1)
CASE " "
' nul
CASE "E", "D"
Exponent = -1
CASE "."
Decimal = -1
CASE "+"
UnaryPlus = -1
CASE "-"
UnaryNegative = -1
CASE ELSE
Q = VAL(MID$(X$, Z, 1))
N = N + 1
PRINT "Digit"; N; " equals"; Q
END SELECT
NEXT
IF Exponent THEN PRINT "There was an exponent."
IF Decimal THEN PRINT "There was a decimal."
IF UnaryPlus THEN PRINT "There was a plus sign."
IF UnaryNegative THEN PRINT "There was a negative sign."

st_buffer multipoint with different distance

I have a sfc_multipoint object and want to use st_buffer but with different distances for every single point in the multipoint object.
Is that possible?
The multipoint object are coordinates.
table = data
Every coordinate point (in the table in "lon" and "lat") should have a buffer with a different size. This buffer size is containt in the table in row "dist".
The table is called data.
This is my code:
library(sf)
coords <- matrix(c(data$lon,data$lat), ncol = 2)
tt <- st_multipoint(coords)
sfc <- st_sfc(tt, crs = 4326)
dt <- st_sf(data.frame(geom = sfc))
web <- st_transform(dt, crs = 3857)
geom <- st_geometry(web)
buf <- st_buffer(geom, dist = data$dist)
But it uses just the first dist of (0.100).
This is the result. Just really small buffers.
small buffer
For visualization see this picture. It´s just an example to show that the buffer should get bigger. example result
I think that he problem here is in how you are "creating" the points dataset.
Replicating your code with dummy data, doing this:
library(sf)
data <- data.frame(lat = c(0,1,2,3), lon = c(0,1,2,3), dist = c(0.1,0.2,0.3, 0.4))
coords <- matrix(c(data$lon,data$lat), ncol = 2)
tt <- st_multipoint(coords)
does not give you multiple points, but a single MULTIPOINT feature:
tt
#> MULTIPOINT (0 0, 1 1, 2 2, 3 3)
Therefore, only a single buffer distance can be "passed" to it and you get:
plot(sf::st_buffer(tt, data$dist))
To solve the problem, you need probably to build the point dataset differently. For example, using:
tt <- st_as_sf(data, coords = c("lon", "lat"))
gives you:
tt
#> Simple feature collection with 4 features and 1 field
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: 0 ymin: 0 xmax: 3 ymax: 3
#> epsg (SRID): NA
#> proj4string: NA
#> dist geometry
#> 1 0.1 POINT (0 0)
#> 2 0.2 POINT (1 1)
#> 3 0.3 POINT (2 2)
#> 4 0.4 POINT (3 3)
You see that tt is now a simple feature collection made of 4 points, on which buffering with multiple distances will indeed work:
plot(sf::st_buffer(tt, data$dist))
HTH!

Parsing an input file which contains polynomials

Hello experienced pythoners.
The goal is simply to read in my own files which have the following format, and to then apply mathematical operations to these values and polynomials. The files have the following format:
m1:=10:
m2:=30:
Z1:=1:
Z2:=-1:
...
Some very similar variables, next come the laguerre polynomials
...
F:= (12.58295)*L(0,x)*L(1,y)*L(6,z) + (30.19372)*L(0,x)*L(2,y)*L(2,z) - ...:
Where L stands for a laguerre polynomial and takes two arguments.
I have written a procedure in Python which splits apart each line into a left and right hand side split using the "=" character as a divider. The format of these files is always the same, but the number of laguerre polynomials in F can vary.
import re
linestring = open("file.txt", "r").read()
linestring = re.sub("\n\n","\n",str(linestring))
linestring = re.sub(",\n",",",linestring)
linestring = re.sub("\\+\n","+",linestring)
linestring = re.sub(":=\n",":=",linestring)
linestring = re.sub(":\n","\n",linestring)
linestring = re.sub(":","",linestring)
LINES = linestring.split("\n")
for LINE in LINES:
LINE = re.sub(" ","",LINE)
print "LINE=", LINE
if len(LINE) <=0:
next
PAIR = LINE.split("=")
print "PAIR=", PAIR
LHS = PAIR[0]
RHS = PAIR[1]
print "LHS=", LHS
print "RHS=", RHS
The first re.sub block just deals with formatting the file and discarding characters that python will not be able to process; then a loop is performed to print 4 things, LINE, PAIR, LHS and RHS, and it does this nicely. using the example file from above the procedure will print the following:
LINE= m1=1
PAIR= ['m1', '1']
LHS= m1
RHS= 1
LINE= m2=1
PAIR= ['m2', '1']
LHS= m2
RHS= 1
LINE= Z1=-1
PAIR= ['Z1', '-1']
LHS= Z1
RHS= -1
LINE= Z2=-1
PAIR= ['Z2', '-1']
LHS= Z2
RHS= -1
LINE= F= 12.5*L(0,x)L(1,y) + 30*L(0,x)L(2,y)L(2,z)
PAIR=['F', '12.5*L(0,x)L(1,y) + 30*L(0,x)L(2,y)L(2,z)']
LHS= F
RHS= 12.5*L(0,x)L(1,y) + 30*L(0,x)L(2,y)L(2,z)
My question is what is the next best step to process this output and use it in a mathematical script, especially assigning the L to mean a laguerre polynomial? I tried putting the LHS and RHS into a dictionary, but found it troublesome to put F in it due to the laguerre polynomials.
Any ideas are welcome. Perhaps I am overcomplicating this and there is a much simpler way to parse this file.
Many thanks in advance
Your parsing algorithm doesn't seem to work correctly, as the RHS of your variables dont produce the expected result.
Also the first re.sub block where you want to format the file seems overly complicated. Assuming every statement in your input file is terminated by a colon, you could get rid of all whitespace and newlines and seperate the statements using the following code:
linestring = open('file.txt','r').read()
strippedstring = linestring.replace('\n','').replace(' ','')
statements = re.split(':(?!=)',strippedstring)[:-1]
Then you iterate over the statements and split each one in LHS and RHS:
for st in statements:
lhs,rhs = re.split(':=',st)
print 'lhs=',lhs
print 'rhs=',rhs
In the next step, try to distinguish normal float variables and polynomials:
#evaluate rhs
try:
#interpret as numeric constant
f = float(rhs)
print " ",f
except ValueError:
#interpret as laguerre-polynomial
summands = re.split('\+', re.sub('-','+-',rhs))
for s in summands:
m = re.match("^(?P<factor>-?[0-9]*(\.[0-9]*)?)(?P<poly>(\*?L\([0-9]+,[a-z]\))*)", s)
if not m:
print ' polynomial misformatted'
continue
f = m.group('factor')
print ' factor: ',f
p = m.group('poly')
for l in re.finditer("L\((?P<a>[0-9]+),(?P<b>[a-z])\)",p):
print ' poly: L(%s,%s)' % (l.group("a"),l.group("b"))
This should work for your given example file.

Lua 3 point crossover help to start

I want to implement a 3 point crossover for genetic programming but I don't know how to do it and where to start.
My input is:
a = {(first pair), (second pair), ... etc.}
For example a = {(12345,67890), (09876,54321)} (those are numbers, not strings)
Output: Something like this:
Example: a_1 = {(12895), (67340)} also numbers.
Thanks for reply and sorry for my bad English.
Here is my quick implementation of k-point crossover for integers using mostly integer arithmetic. Starting with this, you can extend it to crossover your chromosomes of many pairs of integers using a loop.
math.randomseed(111)
-- math.randomseed(os.time())
a = 12345
b = 67890
len = 5 -- number of digits
function split(mum, dad, len, base)
local split = math.pow(base, math.random(len))
local son = math.floor(dad / split) * split + mum % split
local daughter = math.floor(mum / split) * split + dad % split
return son, daughter
end
function kpoint(mum, dad, len, base, k)
for i=1, k do
mum, dad = split(mum, dad, len, base)
end
return mum, dad
end
s, d = kpoint(a, b, len, 10, 3) -- 3 point crossover in base 10
print(s) -- 67395
print(d) -- 12840
-- binary, (crossover binary representation)
s, d = kpoint(tonumber("10001", 2), tonumber("10110", 2), 5, 2, 3)
print(s) -- 23 which is (10111) in base 2
print(d) -- 16 which is (10000) in base 2
-- binary, (crossover base 10, but interpret as binary)
s, d = kpoint(1101, 1010, 4, 10, 3)
print(s) -- 1001
print(d) -- 1110

F# Floating point ranges are experimental and may be deprecated

I'm trying to make a little function to interpolate between two values with a given increment.
[ 1.0 .. 0.5 .. 20.0 ]
The compiler tells me that this is deprecated, and suggests using ints then casting to float. But this seems a bit long-winded if I have a fractional increment - do I have to divide my start and end values by my increment, then multiple again afterwards? (yeuch!).
I saw something somewhere once about using sequence comprehensions to do this, but I can't remember how.
Help, please.
TL;DR: F# PowerPack's BigRational type is the way to go.
What's Wrong with Floating-point Loops
As many have pointed out, float values are not suitable for looping:
They do have Round Off Error, just like with 1/3 in decimal, we inevitably lose all digits starting at a certain exponent;
They do experience Catastrophic Cancellation (when subtracting two almost equal numbers, the result is rounded to zero);
They always have non-zero Machine epsilon, so the error is increased with every math operation (unless we are adding different numbers many times so that errors mutually cancel out -- but this is not the case for the loops);
They do have different accuracy across the range: the number of unique values in a range [0.0000001 .. 0.0000002] is equivalent to the number of unique values in [1000000 .. 2000000];
Solution
What can instantly solve the above problems, is switching back to integer logic.
With F# PowerPack, you may use BigRational type:
open Microsoft.FSharp.Math
// [1 .. 1/3 .. 20]
[1N .. 1N/3N .. 20N]
|> List.map float
|> List.iter (printf "%f; ")
Note, I took my liberty to set the step to 1/3 because 0.5 from your question actually has an exact binary representation 0.1b and is represented as +1.00000000000000000000000 * 2-1; hence it does not produce any cumulative summation error.
Outputs:
1.000000; 1.333333; 1.666667; 2.000000; 2.333333; 2.666667; 3.000000; (skipped) 18.000000; 18.333333; 18.666667; 19.000000; 19.333333; 19.666667; 20.000000;
// [0.2 .. 0.1 .. 3]
[1N/5N .. 1N/10N .. 3N]
|> List.map float
|> List.iter (printf "%f; ")
Outputs:
0.200000; 0.300000; 0.400000; 0.500000; (skipped) 2.800000; 2.900000; 3.000000;
Conclusion
BigRational uses integer computations, which are not slower than for floating-points;
The round-off occurs only once for each value (upon conversion to a float, but not within the loop);
BigRational acts as if the machine epsilon were zero;
There is an obvious limitation: you can't use irrational numbers like pi or sqrt(2) as they have no exact representation as a fraction. It does not seem to be a very big problem because usually, we are not looping over both rational and irrational numbers, e.g. [1 .. pi/2 .. 42]. If we do (like for geometry computations), there's usually a way to reduce the irrational part, e.g. switching from radians to degrees.
Further reading:
What Every Computer Scientist Should Know About Floating-Point Arithmetic
Numeric types in PowerPack
Interestingly, float ranges don't appear to be deprecated anymore. And I remember seeing a question recently (sorry, couldn't track it down) talking about the inherent issues which manifest with float ranges, e.g.
> let xl = [0.2 .. 0.1 .. 3.0];;
val xl : float list =
[0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6;
1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9]
I just wanted to point out that you can use ranges on decimal types with a lot less of these kind of rounding issues, e.g.
> [0.2m .. 0.1m .. 3.0m];;
val it : decimal list =
[0.2M; 0.3M; 0.4M; 0.5M; 0.6M; 0.7M; 0.8M; 0.9M; 1.0M; 1.1M; 1.2M; 1.3M;
1.4M; 1.5M; 1.6M; 1.7M; 1.8M; 1.9M; 2.0M; 2.1M; 2.2M; 2.3M; 2.4M; 2.5M;
2.6M; 2.7M; 2.8M; 2.9M; 3.0M]
And if you really do need floats in the end, then you can do something like
> {0.2m .. 0.1m .. 3.0m} |> Seq.map float |> Seq.toList;;
val it : float list =
[0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6;
1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9; 3.0]
As Jon and others pointed out, floating point range expressions are not numerically robust. For example [0.0 .. 0.1 .. 0.3] equals [0.0 .. 0.1 .. 0.2]. Using Decimal or Int Types in the range expression is probably better.
For floats I use this function, it first increases the total range 3 times by the smallest float step. I am not sure if this algorithm is very robust now. But it is good enough for me to insure that the stop value is included in the Seq:
let floatrange start step stop =
if step = 0.0 then failwith "stepsize cannot be zero"
let range = stop - start
|> BitConverter.DoubleToInt64Bits
|> (+) 3L
|> BitConverter.Int64BitsToDouble
let steps = range/step
if steps < 0.0 then failwith "stop value cannot be reached"
let rec frange (start, i, steps) =
seq { if i <= steps then
yield start + i*step
yield! frange (start, (i + 1.0), steps) }
frange (start, 0.0, steps)
Try the following sequence expression
seq { 2 .. 40 } |> Seq.map (fun x -> (float x) / 2.0)
You can also write a relatively simple function to generate the range:
let rec frange(from:float, by:float, tof:float) =
seq { if (from < tof) then
yield from
yield! frange(from + by, tof) }
Using this you can just write:
frange(1.0, 0.5, 20.0)
Updated version of Tomas Petricek's answer, which compiles, and works for decreasing ranges (and works with units of measure):
(but it doesn't look as pretty)
let rec frange(from:float<'a>, by:float<'a>, tof:float<'a>) =
// (extra ' here for formatting)
seq {
yield from
if (float by > 0.) then
if (from + by <= tof) then yield! frange(from + by, by, tof)
else
if (from + by >= tof) then yield! frange(from + by, by, tof)
}
#r "FSharp.Powerpack"
open Math.SI
frange(1.0<m>, -0.5<m>, -2.1<m>)
UPDATE I don't know if this is new, or if it was always possible, but I just discovered (here), that this - simpler - syntax is also possible:
let dl = 9.5 / 11.
let min = 21.5 + dl
let max = 40.5 - dl
let a = [ for z in min .. dl .. max -> z ]
let b = a.Length
(Watch out, there's a gotcha in this particular example :)

Resources