source: subversion/sites/rails_port/app/controllers/api_controller.rb @ 2863

Revision 2863, 7.6 KB checked in by steve, 7 years ago (diff)

bring checks back

Line 
1class ApiController < ApplicationController
2
3  before_filter :authorize
4  after_filter :compress_output
5
6  helper :user
7  model :user
8
9  #COUNT is the number of map requests to allow before exiting and starting a new process
10  @@count = COUNT
11
12  def authorize_web
13    @current_user = User.find_by_token(session[:token])
14  end
15
16  # The maximum area you're allowed to request, in square degrees
17  MAX_REQUEST_AREA = 0.25
18
19
20  # Number of GPS trace/trackpoints returned per-page
21  TRACEPOINTS_PER_PAGE = 5000
22 
23  def trackpoints
24    @@count+=1
25    response.headers["Content-Type"] = 'text/xml'
26    #retrieve the page number
27    page = params['page'].to_i
28    unless page
29        page = 0;
30    end
31
32    unless page >= 0
33        report_error("Page number must be greater than or equal to 0")
34        return
35    end
36
37    offset = page * TRACEPOINTS_PER_PAGE
38
39    # Figure out the bbox
40    bbox = params['bbox']
41    unless bbox and bbox.count(',') == 3
42      report_error("The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat")
43      return
44    end
45
46    bbox = bbox.split(',')
47
48    min_lon = bbox[0].to_f
49    min_lat = bbox[1].to_f
50    max_lon = bbox[2].to_f
51    max_lat = bbox[3].to_f
52
53    # check the bbox is sane
54    unless min_lon <= max_lon
55      report_error("The minimum longitude must be less than the maximum longitude, but it wasn't")
56      return
57    end
58    unless min_lat <= max_lat
59      report_error("The minimum latitude must be less than the maximum latitude, but it wasn't")
60      return
61    end
62    unless min_lon >= -180 && min_lat >= -90 && max_lon <= 180 && max_lat <= 90
63      report_error("The latitudes must be between -90 and 90, and longitudes between -180 and 180")
64      return
65    end
66
67    # check the bbox isn't too large
68    requested_area = (max_lat-min_lat)*(max_lon-min_lon)
69    if requested_area > MAX_REQUEST_AREA
70      report_error("The maximum bbox size is " + MAX_REQUEST_AREA.to_s + ", and your request was too large. Either request a smaller area, or use planet.osm")
71      return
72    end
73
74    # integerise
75    min_lat = min_lat * 1000000
76    max_lat = max_lat * 1000000
77    min_lon = min_lon * 1000000
78    max_lon = max_lon * 1000000
79    # get all the points
80    points = Tracepoint.find(:all, :conditions => ['gps_points.latitude > ? AND gps_points.longitude > ? AND gps_points.latitude < ? AND gps_points.longitude < ? AND ( public = 1 OR gpx_files.user_id = ? ) AND visible = 1', min_lat.to_i, min_lon.to_i, max_lat.to_i, max_lon.to_i, @user.id ], :select => "gps_points.*", :joins => "INNER JOIN gpx_files ON gpx_files.id = gpx_id", :offset => offset, :limit => TRACEPOINTS_PER_PAGE, :order => "timestamp DESC" )
81
82    doc = XML::Document.new
83    doc.encoding = 'UTF-8'
84    root = XML::Node.new 'gpx'
85    root['version'] = '1.0'
86    root['creator'] = 'OpenStreetMap.org'
87    root['xmlns'] = "http://www.topografix.com/GPX/1/0/"
88   
89    doc.root = root
90
91    track = XML::Node.new 'trk'
92    doc.root << track
93
94    trkseg = XML::Node.new 'trkseg'
95    track << trkseg
96
97    points.each do |point|
98      trkseg << point.to_xml_node()
99    end
100
101    #exit when we have too many requests
102    if @@count > MAX_COUNT
103      render :text => doc.to_s
104      @@count = COUNT
105      exit!
106    end
107
108    render :text => doc.to_s
109
110  end
111
112  def map
113    GC.start
114    @@count+=1
115
116    response.headers["Content-Type"] = 'text/xml'
117    # Figure out the bbox
118    bbox = params['bbox']
119    unless bbox and bbox.count(',') == 3
120      report_error("The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat")
121      return
122    end
123
124    bbox = bbox.split(',')
125
126    min_lon = bbox[0].to_f
127    min_lat = bbox[1].to_f
128    max_lon = bbox[2].to_f
129    max_lat = bbox[3].to_f
130
131    # check the bbox is sane
132    unless min_lon <= max_lon
133      report_error("The minimum longitude must be less than the maximum longitude, but it wasn't")
134      return
135    end
136    unless min_lat <= max_lat
137      report_error("The minimum latitude must be less than the maximum latitude, but it wasn't")
138      return
139    end
140    unless min_lon >= -180 && min_lat >= -90 && max_lon <= 180 && max_lat <= 90
141      report_error("The latitudes must be between -90 and 90, and longitudes between -180 and 180")
142      return
143    end
144
145    # check the bbox isn't too large
146    requested_area = (max_lat-min_lat)*(max_lon-min_lon)
147    if requested_area > MAX_REQUEST_AREA
148      report_error("The maximum bbox size is " + MAX_REQUEST_AREA.to_s + ", and your request was too large. Either request a smaller area, or use planet.osm")
149      return
150    end
151
152    # get all the nodes
153    nodes = Node.find(:all, :conditions => ['latitude > ? AND longitude > ? AND latitude < ? AND longitude < ? AND visible = 1', min_lat, min_lon, max_lat, max_lon])
154
155    node_ids = nodes.collect {|node| node.id }
156
157    if node_ids.length > 50_000
158      report_error("You requested too many nodes (limit is 50,000). Either request a smaller area, or use planet.osm")
159    end
160
161    if node_ids.length == 0
162      render :text => '<osm></osm>'
163      return
164    end
165
166    # grab the segments
167    segments = Array.new
168    if node_ids.length > 0
169      node_ids_sql = "(#{node_ids.join(',')})"
170      # get the referenced segments
171      segments = Segment.find_by_sql "select * from current_segments where visible = 1 and (node_a in #{node_ids_sql} or node_b in #{node_ids_sql})"
172    end
173    # see if we have any missing nodes
174    segments_nodes = segments.collect {|segment| segment.node_a }
175    segments_nodes += segments.collect {|segment| segment.node_b }
176
177    segments_nodes.uniq!
178
179    missing_nodes = segments_nodes - node_ids
180
181    # get missing nodes if there are any
182    nodes += Node.find(missing_nodes) if missing_nodes.length > 0
183
184    doc = OSM::API.new.get_xml_doc
185
186    # get ways
187    # find which ways are needed
188    segment_ids = segments.collect {|segment| segment.id }
189    ways = Array.new
190    if segment_ids.length > 0
191      way_segments = WaySegment.find_all_by_segment_id(segment_ids)
192      way_ids = way_segments.collect {|way_segment| way_segment.id }
193      ways = Way.find(way_ids) # NB: doesn't pick up segments, tags from db until accessed via way.way_segments etc.
194
195      # seg_ids = way_segments.collect {|way_segment| way_segment.segment_id }
196
197      list_of_way_segs = ways.collect {|way| way.way_segments}
198      list_of_way_segs.flatten!
199
200      list_of_way_segments = list_of_way_segs.collect { |way_seg| way_seg.segment_id }
201
202    end
203
204    segments_to_fetch = list_of_way_segments.uniq - segment_ids
205
206    if segments_to_fetch.length > 0
207      segments += Segment.find(segments_to_fetch)
208    end
209
210    # get more nodes
211    #
212
213    segments_nodes = segments.collect {|segment| segment.node_a }
214    segments_nodes += segments.collect {|segment| segment.node_b }
215
216    node_ids_a = nodes.collect {|node| node.id }
217
218    nodes_to_get = segments_nodes - node_ids_a
219    nodes += Node.find(nodes_to_get) if nodes_to_get.length > 0
220
221    visible_nodes = {}
222    user_display_name_cache = {}
223
224    nodes.each do |node|
225      if node.visible?
226        doc.root << node.to_xml_node(user_display_name_cache)
227        visible_nodes[node.id] = node
228      end
229    end
230
231    visible_segments = {}
232
233    segments.each do |segment|
234      if visible_nodes[segment.node_a] and visible_nodes[segment.node_b] and segment.visible?
235        doc.root << segment.to_xml_node(user_display_name_cache) 
236        visible_segments[segment.id] = segment
237      end
238    end
239
240    ways.each do |way|
241      doc.root << way.to_xml_node(visible_segments, user_display_name_cache) if way.visible?
242    end 
243
244    render :text => doc.to_s
245   
246    #exit when we have too many requests
247    if @@count > MAX_COUNT
248      @@count = COUNT
249      exit!
250    end
251
252  end
253end
Note: See TracBrowser for help on using the repository browser.