= PostgisAdapter

A plugin for ActiveRecord which manages the PostGIS geometric columns
in a transparent way (that is like the other base data type columns).
It also provides a way to manage these columns in migrations.

This fork adds handy methods to make geometrical calculations on postgis.
Based on http://georuby.rubyforge.org Spatial Adapter

Postgis Manual - http://postgis.refractions.net/documentation/manual-svn

*PostGIS and Rails 2+ only*.


== Install

If you are using Spatial Adapter, *remove it first*.


=== Dependencies

- georuby
- postgres 8.3+
- postgis  1.3+


=== As gem:

    sudo gem install postgis-adapter

Rails:

    config.gem "postgis_adapter"

Github version:


    sudo gem install nofxx-postgis_adapter --source http://gems.github.com

Rails:

    config.gem "nofxx-postgis_adapter", :lib => "postgis_adapter", :source => "http://gems.github.com"


=== As plugin:

    script/plugin install git://github.com/nofxx/postgis_adapter.git


== How to Use

Geometric columns in your ActiveRecord models now appear just like
any other column of other basic data types. They can also be dumped
in ruby schema mode and loaded in migrations the same way as columns
of basic types.


=== Model

    class TablePoint < ActiveRecord::Base
    end

That was easy! As you see, there is no need to declare a column as geometric.
The plugin will get this information by itself.

Here is an example of PostGIS row creation and access, using the
model and the table defined above :

        pt = TablePoint.new(:data => "Hello!",:geom => Point.from_x_y(1,2))
        pt.save
        pt = TablePoint.first
        puts pt.geom.x
        => 1


== PostGIS Functions

Here are this fork additions. To use it:


    class Street < ActiveRecord::Base
      acts_as_geom :line
    end

    ...

    @place  =   Poi.new(    :data  =>   **Point**      )
    @park   =   Park.new(   :area  =>  **Polygon**     )
    @street =   Street.new( :line  => **LineString**   )


== Play!

    @place.inside?(@park)
    => true

    @place.in_bounds?(@park, 0.5) # margin
    => false

    @place.outside?(@park)

    @street.crosses?(@park)

    @area.contains?(@place)


=== Polygons:

    @park.area
    => 1345

    @park.contains?(@point)
    => true

    @park.overlaps?(@other_park)
    => false

Supports transform (useful to transform SRID to UTM for area in Km^2)

    @park.area(SRID)
    => Area with new SRID


=== Line Strings:

    @street_east.intersects?(@street_west)
    => false

    @street_central.length
    => 4508.53636

    @street_central.length(:miles)
    => 2.81798593

    @street.length_spheroid
    => 4.40853636


=== Class Methods

    City.close_to(@point)
    => [Array of cities in order by distance...

    Street.close_to(@point)
    => [Array streets in order by distance...

    Country.contain(@point)
    => The Conutry that contains the point

    Areas.contains(@point)
    => [Array of areas contains the point...


=== BBox Support

    @area.strictly_left_of? @point

    @area.overlaps_or_above? @street

    ...

    completely_contained_by?
    completely_contains?
    overlaps_or_above?
    overlaps_or_below?
    overlaps_or_left_of?
    overlaps_or_right_of?
    strictly_above?
    strictly_below?
    strictly_left_of?
    strictly_right_of?
    interacts_with?
    binary_equal?
    same_as?


Or use a (almost) PostGIS like notation:

    @area.bbox "<<", @point

    @area.bbox "|>>", @point

    @area.bbox "@",  @park



=== Warning

*To be fixed:*

This only supports one geom column per model. Still looking for the best way to
implement a multi geom.

http://nofxx.lighthouseapp.com/projects/20712/tickets/3-multiple-geoms-in-model


=== Wiki

Check out the wiki pages (http://github.com/nofxx/postgis_adapter/wikis).
For all functions.


=== Find_by

find_by_*column* has been redefined when column is of a geometric type.
Instead of using the Rails default '=' operator, for which I can't see
a definition for MySql spatial datatypes and which performs a bounding
box equality test in PostGIS, it uses a bounding box intersection:
&& in PostGIS and MBRIntersects in MySQL, which can both make use
of a spatial index if one is present to speed up the queries.
You could use this query, for example, if you need to display data
from the database: You would want only the geometries which are in
the screen rectangle and you could use a bounding box query for that.
Since this is a common case, it is the default. You have 2 ways to use
the find_by_*geom_column*: Either by passing a geometric object directly,
or passing an array with the 2 opposite corners of a bounding box
(with 2 or 3 coordinates depending of the dimension of the data).

        Park.find_by_geom(LineString.from_coordinates([[1.4,5.6],[2.7,8.9],[1.6,5.6]]))

  or

        Park.find_by_geom([[3,5.6],[19.98,5.9]])

In PostGIS, since you can only use operations with geometries with the same SRID, you can add a third element representing the SRID of the bounding box to the array. It is by default set to -1:

        Park.find_by_geom([[3,5.6],[19.98,5.9],123])



== Database Tools

=== Migrations

Here is an example of code for the creation of a table with a
geometric column in PostGIS, along with the addition of a spatial
index on the column :

    ActiveRecord::Schema.define do
          create_table :places do |t|
        t.string :name
        t.point  :geom, :srid => 123, :with_z => true, :null => false

        t.timestamps
      end
          add_index :table_points, :geom, :spatial=>true
    end


=== Fixtures

If you use fixtures for your unit tests, at some point,
you will want to input a geometry. You could transform your
geometries to a form suitable for YAML yourself everytime but
the spatial adapter provides a method to do it for you: +to_yaml+.
It works for both MySQL and PostGIS (although the string returned
is different for each database). You would use it like this, if
the geometric column is a point:

    fixture:
          id: 1
          data: HELLO
          geom: <%= Point.from_x_y(123.5,321.9).to_yaml %>


=== Annotate

If you are using annotate_models, check out this fork which adds geometrical annotations for PostgisAdapter and SpatialAdapter:

http://github.com/nofxx/annotate_models


== Geometric data types

Ruby geometric datatypes are currently made available only through
the GeoRuby library (http://georuby.rubyforge.org): This is where the
*Point.from_x_y* in the example above comes from. It is a goal
of a future release of the Spatial Adapter to support additional
geometric datatype libraries, such as Ruby/GEOS, as long as they
can support reading and writing of EWKB.



=== Warning

- Since ActiveRecord seems to keep only the string values directly
returned from the database, it translates from these to the correct
types everytime an attribute is read, which is probably ok for simple
types, but might be less than efficient for geometries, since the EWKB
string has to be parsed everytime. Also it means you cannot modify the
geometry object returned from an attribute directly :

       place = Place.first
       place.the_geom.y=123456.7

- Since the translation to a geometry is performed everytime the_geom
is read, the change to y will not be saved! You would have to do
something like this :

       place = Place.first
       the_geom = place.the_geom
       the_geom.y=123456.7
       place.the_geom = the_geom


== License

Spatial Adapter for Rails is released under the MIT license.
Postgis Adapter is released under the MIT license.


== Support

Tested using rails 2.2.2/2.3.0 / postgresql 8.3.5 / postgis 1.3.3 / linux / osx

Any questions, enhancement proposals, bug notifications or corrections:


=== PostgisAdapter

Project Tracker http://nofxx.lighthouseapp.com/projects/20712-postgis_adapter


=== SpatialAdapter

http://georuby.rubyforge.org
guilhem.vellut+georuby@gmail.com.