4

In a Ruby-on-Rails application, I need the area in square meters (or any other surface measure, be it ares, hectares, square kilometers, but not in pseudo surface measure like square degrees) of a geographic polygon.

The application already uses rgeo and PostGIS (via the activerecord-postgis-adapter) and already requires rgeo's optional libGEOS support. So I'd like to make use of these tools for the area calculation, too.

I can use PostGIS (via the activerecord-postgis-adapter) to compute the area of any rgeo geometry:

def calculate_area(geometry)
  ActiveRecord::Base.connection.execute("
  SELECT
    ST_Area(
      geography(
        ST_Transform(
          ST_GeomFromText('#{geometry.as_json}', #{geometry.srid}),
          4326
        )
      )
    ) AS area;
  ")[0]['area'].to_f
end

(Nesting ST_Area()'s argument in geography() is what causes the result to be in square meters.)

However, having to extract the result from execute()'s return value and having the lengthy SQL code embedded in Ruby is rather ugly.

Also, rgeo already provides an area method on the RGeo::Feature::Surface module, which RGeo::Feature::Polygon includes. Its default implementation just isn't all that useful:

srs_db = RGeo::CoordSys::SRSDatabase::ActiveRecordTable.new
wgs84_factory = RGeo::Geographic.spherical_factory(srid: 4326, srs_database: srs_db)

# 1/8 of the Earth, should be around 6.4e13 sqm
polygon = wgs84_factory.parse_wkt('POLYGON ((0 0, 0 90, 90 0, 0 0))')

polygon.area # RGeo::Error::UnsupportedOperation: Method Surface#area not defined.

I have installed rgeo such that it can use libGEOS, which I can verify like so:

RGeo::GEOS.supported? # true

Thus, I thought that I might be luckier with a GEOS-specific factory:

geos_wgs84_factory = RGeo::Geos.factory(srid: 4326, srs_database: srs_db)
geos_polygon = RGeo::Feature.cast(polygon, geos_wgs84_factory)
geos_polygon.area # 4050.0

Well, that's the area in square degrees (90° ⨉ 90° / 2). How can I get the area in square meters without calculating it myself and without longish SQL?

Must I convert my polygon to an area-preserving projected coordinate reference system? (Those seem to come with a working area method in rgeo.) That'd feel kinda wrong to me, but maybe it's still the right thing to do.

3
  • If you are looking for libraries to do this, see GeographicLib (but none are currently available for Ruby). It gives the correct answer for 1/8th of the Earth's surface area
    – Mike T
    Jul 5, 2015 at 22:10
  • @das-g, Can you show us the final implementation to get the area in metric units ? I am stuck at the same point. Feb 8, 2019 at 14:02
  • Sorry, @KinaanKhanSherwani, I don't have access to my code from back then anymore. IIRC, for production code, we stuck to the PostGIS solution as it turned out to be more precise, for whatever reason. Projecting an RGeo or RGeo::Geos polygon to any equal area projection and calling .area on the result would have worked, too, though, I believe.
    – das-g
    Feb 8, 2019 at 21:28

2 Answers 2

4

Yes, if you want ST_Area() on a bare geometry to return a planar area, you need to use an area-preserving CRS. GEOS is not magic, it just works in whatever units are handed to it, assuming cartesian math, so the expectation in a planar CRS if you want useful areas/lengths etc.

3
  • Can GEOS do spherical or even ellipsoidal math, too? The example polygon in my question would require at least the former, I think.
    – das-g
    Jul 4, 2015 at 20:37
  • 1
    No wait, I guess I'm mistaken: For area calculation it doesn't require spherical math. After all, that's what the 'equal area' in 'equal area projection' is all about.
    – das-g
    Jul 4, 2015 at 20:59
  • Ellipsoidal math is required for "exact" results over large areas. Equal area projections just spread the error as evenly as possible over their area of validity. For most uses a planar projection is perfectly sufficient. Jul 6, 2015 at 14:52
0

Get the geometry from json, convert it to a projected CRS, and then do your calculation on the converted geometry.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.