public
Description: PutsGIS. PostGIS, for Rails (featuring acts_as_line: treat start/end date columns as a single spatial object.)
Homepage: http://tempestattack.com
Clone URL: git://github.com/broughcut/acts_as_line.git
acts_as_line / README
100644 131 lines (82 sloc) 3.335 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
being rewritten.
 
see lib/act_as_line.rb for options.
 
ActsAsLine
==========
 
Need to add tests as a priority, and must clean things up.
 
In order to maintain consistency with postgis methods, intersects
is now simply intersects, the 'touching' alias has been removed.
 
added:
 
a.intersects?(b)
a.covers?(b)
a.covered_by?(b)
 
Foo.within(b,:days,3,options={}) #also :secs, :hours
Foo.covers(b,options={})
Foo.covered_by(b,options={})
 
covers: 'Geom A covers Geom B if no points of B lie in the exterior of A'
 
 
Early days.
 
Things are progressing (and probably breaking in places).
Some big changes, and some very undry source....
 
acts_as_line.rb has been rewritten to include instance methods.
 
I am basically adding functions as I need them.
 
> b = Foo.find(:first)
 
Length of line in seconds:
 
> b.duration
 
also
 
> b.duration(:days)
> b.duration(:weeks)
 
Query against a part line, in this case the first half:
 
> Foo.touching_segment(b,[0,0.5])
 
­- where 0.5 is the midpoint of b's geom. A new line is created using the
   start/end points specified in the array.
 
 Find records that do not intersect the latter two thirds of the line (and
 have a bar_id of 5):
 
> Foo.not_touching_segment(b,[0.3,1], :bar_id => 5)
 
This needs to be able to support actual days/hours, rather than a proportion
of a line -- which is not very robost if you are using it for bookings and
such like.
 
'asunder' method is now not_touching.
 
> b = Booking.find(:first)
 
> Booking.not_touching(b)
 
Foo.asunder is now an alias for the class method, not_in_intersects
which uses joins to speed up queries against a large dataset.
 
class Property < ActiveRecord::Base
  has_many :bookings
  acts_as_line
end
 
class Booking < ActiveRecord::Base
  belongs_to :property
  acts_as_line
end
 
class Bookable < ActiveRecord::Base
  acts_as_line
end
 
> week = Bookable.find(38)
 
Find all *unbooked* properties for the booking period 'week'
without selecting each property:
 
> Property.asunder(Booking,week)
 
SQL:
 
  SELECT (id) FROM properties WHERE properties.id
  NOT IN (SELECT DISTINCT on (properties.id) properties.id FROM bookings
  INNER JOIN properties ON properties.id=bookings.property_id
  WHERE (ST_Intersects(bookings.geom,(SELECT geom FROM bookables
  WHERE id = 38)) = true))
 
  [SQL (0.000791) -- small dataset as yet, but seems reasonable]
 
  SELECT (id) FROM properties WHERE properties.id
  NOT IN (SELECT DISTINCT on (properties.id) properties.id FROM bookings
  INNER JOIN properties ON properties.id=bookings.property_id
  WHERE (ST_Intersects(bookings.geom,(SELECT geom FROM bookables
  WHERE id = 38)) = true))
 
 
 
Example
=======
 
table must already have a start_date and end_date column of type date or datetime.
 
script/generate datesgeom_migration table_name
 
 runs the following on target table:
   execute("ALTER TABLE table_name ADD COLUMN geom geometry;")
   execute("CREATE INDEX idx_table_name_dates_geom ON table_name USING GIST (geom);")
 
 
object = Foo.find(:first)
 
results = Foo.touching(object) | results = Foo.intersects(object,true)
results = Foo.not_touching(object) | results = Foo.intersects(object,false)
results = Foo.touching(object,{:id => 123})
results = Foo.touching(object,{:id => '>123'})
results = Foo.touching(object,{:id => '<>123'}) etc
results = Foo.touching(object,{:id => 123, :title => 'bar'})