How Can I Use (Ruby) RGeo to Transform (Unproject) Coordinates - ruby

I started with How can I transform the coordinates of a Shapefile? .
The response there started me on [what I think is] the right track, but I still haven't been able to solve my problem.
One issue is that I haven't found the correct projection yet: https://gis.stackexchange.com/questions/13330/how-can-i-correctly-transform-unproject-from-lcc
EDIT: That question on the gis site has been answered, and I was able to reproduce a correct transformation using the PROJ command line tool cs2cs. It looks like this:
larry$ cs2cs -f "%.8f" +proj=lcc +lat_1=37.06666666666667 +lat_2=38.43333333333333 +lat_0=36.5 +lon_0=-120.5 +x_0=2000000 +y_0=500000.0000000002 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs +to +proj=lonlat +datum=WGS84 +ellps=WGS84
6011287.4999795845 2100857.2499904726
-122.40375492 37.74919006 0.00000000
Now, that I had the correct transformation, I was able to try the same thing in a simple form using RGeo:
ruby-1.9.2-p180 :001 > projection_str = ' +proj=lcc +lat_1=37.06666666666667 +lat_2=38.43333333333333 +lat_0=36.5 +lon_0=-120.5 +x_0=2000000 +y_0=500000.0000000002 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs'
=> " +proj=lcc +lat_1=37.06666666666667 +lat_2=38.43333333333333 +lat_0=36.5 +lon_0=-120.5 +x_0=2000000 +y_0=500000.0000000002 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs"
ruby-1.9.2-p180 :002 > projection = RGeo::CoordSys::Proj4.new(projection_str)
=> #<RGeo::CoordSys::Proj4:0x805cba18 " +proj=lcc +lat_1=37.06666666666667 +lat_2=38.43333333333333 +lat_0=36.5 +lon_0=-120.5 +x_0=2000000 +y_0=500000.0000000002 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs +towgs84=0,0,0">
ruby-1.9.2-p180 :003 > desired_str = '+proj=lonlat +datum=WGS84 +ellps=WGS84'
=> "+proj=lonlat +datum=WGS84 +ellps=WGS84"
ruby-1.9.2-p180 :004 > desired = RGeo::CoordSys::Proj4.new(desired_str)
=> #<RGeo::CoordSys::Proj4:0x805271ac " +proj=lonlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0">
ruby-1.9.2-p180 :005 > RGeo::CoordSys::Proj4::transform_coords(projection, desired, 6011287.4999795845, 2100857.2499904726 )
=> [-140.92282523143973, 30.16981659183029]
Why are the results different between RGeo and cs2cs?
Once I can make RGeo perform the correct translation, is there a way I can create the proper factory to transform a complete Geometry instead of a point?
Is there a command-line tool I can use as a workaround to transform all of the points in my shapefile so that I can move on with my life?
In general: Would someone please instruct me on how to properly use this library?
Thank you so much for looking.

As a wild stab in the dark, because I don't know RGeo or even Ruby, try substituting your coordinates in feet with their metres equivalent: 1832244.0944819663048746863094224, 640342.57048223700783128534419392 (you probably won't need that number of decimal places though...) Another possibility is to swap the coordinates around - maybe RGeo makes some unconventional assumptions.
If you are able to call executables from Ruby, you could simply use ogr2ogr to convert your shapefiles.

Related

Uuencode vs Base64 encode: why do pack('m') and pack('u') in Ruby return strings of different lengths?

According to the specs they should be same length, and a string of length 36 should translate to a string of length 48, for example:
bin = "123456789012345678901234567890123456"
[49] pry(main)> [bin].pack("m").length
=> 49
[50] pry(main)> [bin].pack("u").length
=> 50
[54] pry(main)> [bin].pack("m")
=> "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2\n"
[55] pry(main)> [bin].pack("u")
=> "D,3(S-#4V-S#Y,\#$R,S0U-C<X.3`Q,C,T-38W.#DP,3(S-#4V\n"
Compensating for the "funny newline" we get the proper length in the base64 encoding (the pack('m') variant), but I don't know how to get the line length right in the uuencoding (the pack('u') variant).
I really need that uuencoded string to be 48 chars long :) what's the issue here?
Update
I did my own uuencode implementation, created a method that generates bitmap and then split the bitmap etc to make a uuencode implementation, as the provider of the specification helpfully explained in the spec
def to_bitmap bytes
bytes.scan(/./).map{|b| b.ord.to_s(2).rjust(8, "0")}.join
end
[5] pry(main)> to_bitmap(str).scan(/.{6}/).map{|b| (from_bitmap("00"+b).ord+0x20).chr }.join
=> ",3(S-#4V-S#Y,\#$R,S0U-C<X.3 Q,C,T-38W.#DP,3(S-#4V"
[6] pry(main)> to_bitmap(str).scan(/.{6}/).map{|b| (from_bitmap("00"+b).ord+0x20).chr }.join.length
=> 48
and I assume this is the good thing, it's kind of like uuencode, but differs in a couple of places:
,3(S-#4V-S#Y,\#$R,S0U-C<X.3 Q,C,T-38W.#DP,3(S-#4V
D,3(S-#4V-S#Y,\#$R,S0U-C<X.3`Q,C,T-38W.#DP,3(S-#4V\n
Wierd, I guess it's the specification I'm implementing is using a "uuencode" and not quite uuencode though they claim that generic software libraries support this format, am I missing something or does this seem like bullshit and workaround for somebodies half-assed implementation of uuencode?

Missing countries from natural earth topojson map?

I am missing South Sudan (and Western Sahara) from my natural earth map (ne_10m_admin_0_countries):
Here is how I am creating my map:
? ogr2ogr -f GeoJSON -where "ADM0_A3 IN ('DJI', 'DZA', 'EGY', 'LBY', 'MAR', 'TUN', 'AGO', 'BDI', 'BEN', 'BFA', 'BWA', 'CAF', 'CIV', 'CMR', 'COD', 'COG', 'COM', 'CPV', 'ERI', 'ETH', 'GAB', 'GHA', 'GIN', 'GMB', 'GNB', 'GNQ', 'KEN', 'LBR', 'LSO', 'MDG', 'MLI', 'MOZ', 'MRT', 'MUS', 'MWI', 'NAM', 'NER', 'NGA', 'RWA', 'SDN', 'SEN', 'SLE', 'SOM', 'SSD', 'STP', 'SWZ', 'SYC', 'TCD', 'TGO', 'TZA', 'UGA', 'ZAF', 'ZMB', 'ZWE', 'ESH')" areas.json ne_110m_admin_0_countries/ne_110m_admin_0_countries.shp
? topojson -o mymmap.json --id-property iso_a3 areas.json
I have 'SSD' (South Sudan) and 'ESH' (Western Sahara) in my list of areas to include.
I've tried the following maps:
ne_110m_admin_0_countries
ne_110m_admin_0_map_units
ne_110m_admin_0_sovereignty
...but I still get these missing shapes. On searching mymap.json, I cannot find either 'SSD' or 'ESH'?
Basically, I don't want two white holes in my map, if I can avoid it.
Thanks.
SSD and ESH don't exist as ADM0_A3 classification in that file. Maybe try ISO_A3 instead?

Amazon API and hardcover versus paperback

When searching Amazon using their API is there a way to separate out hardcover, paperback, kindle and preorderable books?
I'm using Ruby and Amazon Product gem and have been searching through their documentation looking for info on this and haven't managed to find anything yet.
update:
I have come across some starting points that I am working through. There seems to a way to get this information via RrelatedItems ResponseGroup as described here. The KindleStore hierarchy seems relevant.
update II:
Binding is possibly the field I need to somehow look at and amazon's API provides an way of getting to AlternateVersions of an ASIN using the AlternativeVersion ResponseGroup type for books.
I will assume you know how to set up the Amazon Product gem request object correctly. from there, you can do...
search = req.search( 'Ender\'s Game' )
search.each('Item') do |item|
asin = item["ASIN"]
title = item['ItemAttributes']['Title']
hash = {
:response_group => ['ItemAttributes']
}
items = req.find( asin, hash )
items.each('Item') do |ia|
puts "[#{asin}]: #{title} => [#{ia['ItemAttributes']['Binding']}]"
end
end
which produces output like
[0812550706]: Ender's Game (Ender, Book 1) => [Mass Market Paperback]
[0765362430]: The Ender Quartet Box Set: Ender's Game, Speaker for the Dead, Xenocide, Children of the Mind => [Mass Market Paperback]
[0812550757]: Speaker for the Dead (Ender, Book 2) => [Mass Market Paperback]
[0765342405]: Ender's Shadow (Ender, Book 5) => [Paperback]
[B003G4W49C]: Ender's Game => [Kindle Edition]
[0785135820]: Ender's Game: Command School => [Hardcover]
[0785135804]: Ender's Game: Battle School (Ender's Game Gn) => [Hardcover]
[0765362449]: The Ender's Shadow Series Box Set: Ender's Shadow, Shadow of the Hegemon, Shadow Puppets, Shadow of the Giant => [Paperback]
[0785136096]: Ender's Game: Formic Wars: Burning Earth => [Hardcover]
[0812565959]: Shadow of the Hegemon (Ender, Book 6) => [Mass Market Paperback]
You could try looking at the BrowseNodes. For example if you see the kindle store BrowseNode you know it's a kindle book.

Round up to the nearest tenth?

I need to round up to the nearest tenth. What I need is ceil but with precision to the first decimal place.
Examples:
10.38 would be 10.4
10.31 would be 10.4
10.4 would be 10.4
So if it is any amount past a full tenth, it should be rounded up.
I'm running Ruby 1.8.7.
This works in general:
ceil(number*10)/10
So in Ruby it should be like:
(number*10).ceil/10.0
Ruby's round method can consume precisions:
10.38.round(1) # => 10.4
In this case 1 gets you rounding to the nearest tenth.
If you have ActiveSupport available, it adds a round method:
3.14.round(1) # => 3.1
3.14159.round(3) # => 3.142
The source is as follows:
def round_with_precision(precision = nil)
precision.nil? ? round_without_precision : (self * (10 ** precision)).round / (10 ** precision).to_f
end
To round up to the nearest tenth in Ruby you could do
(number/10.0).ceil*10
(12345/10.0).ceil*10 # => 12350
(10.33 + 0.05).round(1) # => 10.4
This always rounds up like ceil, is concise, supports precision, and without the goofy /10 *10.0 thing.
Eg. round up to nearest hundredth:
(10.333 + 0.005).round(2) # => 10.34
To nearest thousandth:
(10.3333 + 0.0005).round(3) # => 10.334
etc.

How to get today's day of previous month in ruby?

Is there a built-in function to get the day in last month, same as today? Examples:
2010/05/02 -> 2010/04/02
2010/05/15 -> 2010/04/15
2010/05/31 -> 2010/04/30
Thanks!
You can subtract entire months with <<.
>> d = Date.parse('2010-05-31')
=> #<Date: 4910695/2,0,2299161>
>> d.to_s
=> "2010-05-31"
>> (d<<1).to_s
=> "2010-04-30"
More info
You could do this:
(Date.today - 1.month).strftime("%Y/%m/%d")
You can try using
Time.parse('2010/05/31').months_since(-1).
You could for instance make a time object
old_time = Time.now
Then create a new time object based on that
new_time = Time.local(old_time.year, (old_time.month - 1), old_time.day, old_time.hour, old_time.min, old_time.sec)
However, as deceze pointed out, what is the criterion for 5/31 becoming 4/30?
In irb, 4/31 'overflows' to 5/01.
Ruby's date class allows you to add, subtract days from a particular date.

Resources