Merge rails_port as of r4613 & fix tests.
authorGabriel Ebner <gabriel@svn.openstreetmap.org>
Thu, 20 Sep 2007 14:37:29 +0000 (14:37 +0000)
committerGabriel Ebner <gabriel@svn.openstreetmap.org>
Thu, 20 Sep 2007 14:37:29 +0000 (14:37 +0000)
52 files changed:
app/controllers/amf_controller.rb
app/controllers/api_controller.rb
app/controllers/diary_entry_controller.rb
app/controllers/message_controller.rb
app/controllers/node_controller.rb
app/controllers/relation_controller.rb
app/controllers/swf_controller.rb
app/controllers/way_controller.rb
app/helpers/geocoder_helper.rb
app/models/diary_entry.rb
app/models/message.rb
app/models/node.rb
app/models/notifier.rb
app/models/relation.rb
app/models/trace.rb
app/models/tracepoint.rb
app/models/way.rb
app/views/diary_entry/_diary_entry.rhtml
app/views/diary_entry/list.rhtml
app/views/diary_entry/new.rhtml
app/views/message/_message_summary.rhtml
app/views/message/read.rhtml
app/views/notifier/message_notification.rhtml [new file with mode: 0644]
app/views/site/_search.rhtml
app/views/site/edit.rhtml
app/views/site/index.rhtml
app/views/trace/_trace.rhtml
app/views/trace/view.rhtml
config/environment.rb
db/README
db/functions/Makefile [new file with mode: 0644]
db/functions/quadtile.c [new file with mode: 0644]
db/migrate/005_tile_tracepoints.rb [new file with mode: 0644]
db/migrate/006_add_relations.rb [moved from db/migrate/005_add_relations.rb with 100% similarity]
db/migrate/007_remove_segments.rb [moved from db/migrate/006_remove_segments.rb with 96% similarity]
db/migrate/007_remove_segments_helper.cc [moved from db/migrate/006_remove_segments_helper.cc with 97% similarity]
lib/migrate.rb
lib/osm.rb
lib/quad_tile.rb [new file with mode: 0644]
lib/quad_tile/extconf.rb [new file with mode: 0644]
lib/quad_tile/quad_tile.c [new file with mode: 0644]
lib/quad_tile/quad_tile.h [new file with mode: 0644]
public/potlatch/potlatch.swf
public/potlatch/ymap.swf
test/fixtures/current_relation_members.yml
test/fixtures/current_relation_tags.yml
test/fixtures/current_relations.yml
test/fixtures/relation_members.yml
test/fixtures/relation_tags.yml
test/fixtures/relations.yml
test/functional/relation_controller_test.rb
test/unit/node_test.rb

index d30043e..99c2a48 100644 (file)
@@ -43,6 +43,8 @@ class AmfController < ApplicationController
                  when 'putway';                results[index]=putdata(index,putway(args))
                  when 'deleteway';             results[index]=putdata(index,deleteway(args))
                  when 'makeway';               results[index]=putdata(index,makeway(args))
+                 when 'putpoi';                results[index]=putdata(index,putpoi(args))
+                 when 'getpoi';                results[index]=putdata(index,getpoi(args))
       end
     end
 
@@ -71,8 +73,8 @@ class AmfController < ApplicationController
 
   def getpresets
     presets={}
-    presetmenus={}; presetmenus['point']=[]; presetmenus['way']=[]
-    presetnames={}; presetnames['point']={}; presetnames['way']={}
+    presetmenus={}; presetmenus['point']=[]; presetmenus['way']=[]; presetmenus['POI']=[]
+    presetnames={}; presetnames['point']={}; presetnames['way']={}; presetnames['POI']={}
     presettype=''
     presetcategory=''
 
@@ -97,8 +99,8 @@ unclassified road: highway=unclassified,name=(type road name)
 
 way/footway
 footpath: highway=footway,foot=yes
-bridleway: highway=bridleway,foot=yes,horse=yes,bicycle=yes
-byway: highway=byway,foot=yes,horse=yes,bicycle=yes,motorcar=yes
+bridleway: highway=bridleway,foot=yes
+byway: highway=unsurfaced,foot=yes
 permissive path: highway=footway,foot=permissive
 
 way/cycleway
@@ -124,13 +126,8 @@ disused railway tracks: railway=disused
 course of old railway: railway=abandoned
 
 way/natural
-forest: natural=wood,landuse=forest
-woodland: natural=wood,landuse=
-reservoir: natural=water,landuse=reservoir
-lake: natural=water,landuse=
-marsh: natural=marsh
-beach: natural=beach
-coastline: natural=coastline
+lake: landuse=water
+forest: landuse=forest
 
 point/road
 mini roundabout: highway=mini_roundabout
@@ -158,7 +155,33 @@ viaduct: railway=viaduct
 level crossing: railway=crossing
 
 point/natural
-peak: natural=peak
+peak: point=peak
+
+POI/road
+car park: amenity=parking
+petrol station: amenity=fuel
+
+POI/cycleway
+bike park: amenity=bicycle_parking
+
+POI/place
+city: place=city,name=(type name here),is_in=(type region or county)
+town: place=town,name=(type name here),is_in=(type region or county)
+suburb: place=suburb,name=(type name here),is_in=(type region or county)
+village: place=village,name=(type name here),is_in=(type region or county)
+hamlet: place=hamlet,name=(type name here),is_in=(type region or county)
+
+POI/tourism
+attraction: tourism=attraction,amenity=,religion=,denomination=
+church: tourism=,amenity=place_of_worship,name=(type name here),religion=christian,denomination=(type denomination here)
+hotel: tourism=hotel,amenity=,religion=,denomination=
+other religious: tourism=,amenity=place_of_worship,name=(type name here),religion=(type religion),denomination=
+post box: amenity=post_box,tourism=,name=,religion=,denomination=
+post office: amenity=post_office,tourism=,name=,religion=,denomination=
+pub: tourism=,amenity=pub,name=(type name here),religion=,denomination=
+
+POI/natural
+peak: point=peak
 EOF
 
     StringIO.open(txt) do |file|
@@ -192,6 +215,9 @@ EOF
     ymin = args[1].to_f-0.01
     xmax = args[2].to_f+0.01
     ymax = args[3].to_f+0.01
+       baselong    = args[4]
+       basey       = args[5]
+       masterscale = args[6]
 
     RAILS_DEFAULT_LOGGER.info("  Message: whichways, bbox=#{xmin},#{ymin},#{xmax},#{ymax}")
 
@@ -207,7 +233,7 @@ EOF
 
        ways = waylist.collect {|a| a.wayid.to_i } # get an array of way id's
 
-       pointlist =ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,current_nodes.tags "+
+       pointlist =ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,latitude,longitude,current_nodes.tags "+
        "  FROM current_nodes "+
        "  LEFT OUTER JOIN current_segments cs1 ON cs1.node_a=current_nodes.id "+
        "  LEFT OUTER JOIN current_segments cs2 ON cs2.node_b=current_nodes.id "+
@@ -216,7 +242,7 @@ EOF
        "   AND cs1.id IS NULL AND cs2.id IS NULL "+
        "   AND current_nodes.visible=1")
 
-           points = pointlist.collect {|a| [a['id'],tag2array(a['tags'])]      } # get a list of node ids and their tags
+           points = pointlist.collect {|a| [a['id'],long2coord(a['longitude'].to_f,baselong,masterscale),lat2coord(a['latitude'].to_f,basey,masterscale),tag2array(a['tags'])] } # get a list of node ids and their tags
 
     return [ways,points]
   end
@@ -443,6 +469,49 @@ EOF
     [originalway,way,renumberednodes,numberedsegments,xmin,xmax,ymin,ymax]
   end
 
+  # -----      putpoi (user token, id, x,y,tag array,visible,baselong,basey,masterscale)
+  #                    returns current id, new id
+  #                    if new: add new row to current_nodes and nodes
+  #                    if old: add new row to nodes, update current_nodes
+
+  def putpoi(args)
+       usertoken,id,x,y,tags,visible,baselong,basey,masterscale=args
+       uid=getuserid(usertoken)
+       return if !uid
+    db_now='@now'+uid.to_s+id.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars
+    ActiveRecord::Base.connection.execute("SET #{db_now}=NOW()")
+
+       id=id.to_i
+       visible=visible.to_i
+       x=coord2long(x.to_f,masterscale,baselong)
+       y=coord2lat(y.to_f,masterscale,basey)
+       tagsql="'"+sqlescape(array2tag(tags))+"'"
+       
+       if (id>0) then
+               ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{id},#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
+               ActiveRecord::Base.connection.update("UPDATE current_nodes SET latitude=#{y},longitude=#{x},timestamp=#{db_now},user_id=#{uid},visible=#{visible},tags=#{tagsql} WHERE id=#{id}");
+               newid=id
+       else
+               newid=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
+                         ActiveRecord::Base.connection.update("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{newid},#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
+       end
+       [id,newid]
+  end
+
+  # -----      getpoi (id,baselong,basey,masterscale)
+  #                    returns id,x,y,tag array
+  
+  def getpoi(args)
+       id,baselong,basey,masterscale=args; id=id.to_i
+       poi=ActiveRecord::Base.connection.select_one("SELECT latitude,longitude,tags "+
+               "FROM current_nodes WHERE visible=1 AND id=#{id}")
+       if poi.nil? then return [nil,nil,nil,''] end
+       [id,
+        long2coord(poi['longitude'].to_f,baselong,masterscale),
+        lat2coord(poi['latitude'].to_f,basey,masterscale),
+        tag2array(poi['tags'])]
+  end
+
   # -----      deleteway (user token, way)
   #                    returns way ID only
 
@@ -691,18 +760,33 @@ end
 def createuniquenodes(uqs_name,uqn_name)
        # Finds nodes which appear in uniquesegments but no other segments
        sql=<<-EOF
-               CREATE TEMPORARY TABLE #{uqn_name}
-                          SELECT DISTINCT node_id
-                             FROM (SELECT cn.id AS node_id
-                                                 FROM current_nodes AS cn,
-                                                      current_segments AS cs,
-                                                      #{uqs_name} AS us
-                                                WHERE cs.id=us.segment_id
-                                                  AND (cn.id=cs.node_a OR cn.id=cs.node_b)) AS n
-                                        LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
-                                        LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
-                                            WHERE cs2.node_a IS NULL
-                                              AND cs3.node_b IS NULL
+       CREATE TEMPORARY TABLE #{uqn_name}
+          SELECT DISTINCT node_id
+          FROM (SELECT cn.id AS node_id
+                FROM current_nodes AS cn,
+                     current_segments AS cs,
+                     #{uqs_name} AS us
+                WHERE cs.id=us.segment_id
+                  AND cn.id=cs.node_a) AS n
+          LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
+          LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
+          WHERE cs2.node_a IS NULL
+            AND cs3.node_b IS NULL
+       EOF
+       ActiveRecord::Base.connection.execute(sql)
+       sql=<<-EOF
+       INSERT INTO #{uqn_name}
+          SELECT DISTINCT node_id
+          FROM (SELECT cn.id AS node_id
+                FROM current_nodes AS cn,
+                     current_segments AS cs,
+                     #{uqs_name} AS us
+                WHERE cs.id=us.segment_id
+                  AND cn.id=cs.node_b) AS n
+          LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
+          LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
+          WHERE cs2.node_a IS NULL
+            AND cs3.node_b IS NULL
        EOF
        ActiveRecord::Base.connection.execute(sql)
 end
index 44ae652..6e8e77c 100644 (file)
@@ -63,13 +63,8 @@ class ApiController < ApplicationController
       return
     end
 
-    # integerise
-    min_lat = min_lat * 1000000
-    max_lat = max_lat * 1000000
-    min_lon = min_lon * 1000000
-    max_lon = max_lon * 1000000
     # get all the points
-    points = Tracepoint.find(:all, :conditions => ['latitude BETWEEN ? AND ? AND longitude BETWEEN ? AND ?', min_lat.to_i, max_lat.to_i, min_lon.to_i, max_lon.to_i], :select => "DISTINCT *", :offset => offset, :limit => TRACEPOINTS_PER_PAGE, :order => "timestamp DESC" )
+    points = Tracepoint.find_by_area(min_lat, min_lon, max_lat, max_lon, :offset => offset, :limit => TRACEPOINTS_PER_PAGE, :order => "timestamp DESC" )
 
     doc = XML::Document.new
     doc.encoding = 'UTF-8'
@@ -142,8 +137,7 @@ class ApiController < ApplicationController
     end
 
     # get all the nodes
-    nodes = Node.find(:all, :conditions => 
-        ['latitude > ? AND longitude > ? AND latitude < ? AND longitude < ? AND visible = 1', min_lat, min_lon, max_lat, max_lon])
+    nodes = Node.find(:all, :conditions => ['latitude BETWEEN ? AND ? AND longitude BETWEEN ? AND ? AND visible = 1', min_lat, max_lat, min_lon, max_lon])
 
     node_ids = nodes.collect {|node| node.id }
 
index 92f5413..e763dfd 100644 (file)
@@ -7,9 +7,9 @@ class DiaryEntryController < ApplicationController
   def new
     @title = 'new diary entry'
     if params[:diary_entry]     
-      @entry = DiaryEntry.new(params[:diary_entry])
-      @entry.user = @user
-      if @entry.save 
+      @diary_entry = DiaryEntry.new(params[:diary_entry])
+      @diary_entry.user = @user
+      if @diary_entry.save 
         redirect_to :controller => 'diary_entry', :action => 'list', :display_name => @user.display_name 
       end
     end
@@ -41,10 +41,7 @@ class DiaryEntryController < ApplicationController
     end
 
     @entries.each do |entry|
-      # add geodata here
-      latitude = nil
-      longitude = nil
-      rss.add(latitude, longitude, entry.title, entry.user.display_name, url_for({:controller => 'diary_entry', :action => 'list', :id => entry.id, :display_name => entry.user.display_name}), entry.body, entry.created_at)
+      rss.add(entry.latitude, entry.longitude, entry.title, entry.user.display_name, url_for({:controller => 'diary_entry', :action => 'list', :id => entry.id, :display_name => entry.user.display_name}), entry.body, entry.created_at)
     end
 
     render :text => rss.to_s, :content_type => "application/rss+xml"
index f52274c..52f38e9 100644 (file)
@@ -7,23 +7,16 @@ class MessageController < ApplicationController
   def new
     @title = 'send message'
     if params[:message]
-      to_user = User.find(params[:user_id])
-      body = params[:message][:body]
-      title = params[:message][:title]
-      message = Message.new
-      message.body = body
-      message.title = title
-      message.to_user_id = params[:user_id]
-      message.from_user_id = @user.id
-      message.sent_on = Time.now
+      @message = Message.new(params[:message])
+      @message.to_user_id = params[:user_id]
+      @message.from_user_id = @user.id
+      @message.sent_on = Time.now
    
-      if message.save
+      if @message.save
         flash[:notice] = 'Message sent'
+        Notifier::deliver_message_notification(@message)
         redirect_to :controller => 'message', :action => 'inbox', :display_name => @user.display_name
-      else
-        @message.errors.add("Sending message failed")
       end
-
     end
   end
 
index de81f18..7c7e3e6 100644 (file)
@@ -13,12 +13,9 @@ class NodeController < ApplicationController
       if node
         node.user_id = @user.id
         node.visible = true
+        node.save_with_history!
 
-        if node.save_with_history
-          render :text => node.id.to_s, :content_type => "text/plain"
-        else
-          render :nothing => true, :status => :internal_server_error
-        end
+        render :text => node.id.to_s, :content_type => "text/plain"
       else
         render :nothing => true, :status => :bad_request
       end
@@ -38,8 +35,6 @@ class NodeController < ApplicationController
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
   end
 
@@ -55,12 +50,9 @@ class NodeController < ApplicationController
           node.latitude = new_node.latitude 
           node.longitude = new_node.longitude
           node.tags = new_node.tags
+          node.save_with_history!
 
-          if node.save_with_history
-            render :nothing => true
-          else
-            render :nothing => true, :status => :internal_server_error
-          end
+          render :nothing => true
         else
           render :nothing => true, :status => :bad_request
         end
@@ -69,8 +61,6 @@ class NodeController < ApplicationController
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
   end
 
@@ -86,7 +76,8 @@ class NodeController < ApplicationController
         else
           node.user_id = @user.id
           node.visible = 0
-          node.save_with_history
+          node.save_with_history!
+
           render :nothing => true
         end
       else
@@ -94,8 +85,6 @@ class NodeController < ApplicationController
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
   end
 
index efd5bf9..d00e9e0 100644 (file)
@@ -15,12 +15,9 @@ class RelationController < ApplicationController
           render :nothing => true, :status => :precondition_failed
         else
           relation.user_id = @user.id
+          relation.save_with_history!
 
-          if relation.save_with_history
-            render :text => relation.id.to_s, :content_type => "text/plain"
-          else
-            render :text => "save error", :status => :internal_server_error
-          end
+         render :text => relation.id.to_s, :content_type => "text/plain"
         end
       else
         render :nothing => true, :status => :bad_request
@@ -61,12 +58,9 @@ class RelationController < ApplicationController
             relation.tags = new_relation.tags
             relation.members = new_relation.members
             relation.visible = true
+            relation.save_with_history!
 
-            if relation.save_with_history
-              render :nothing => true
-            else
-              render :nothing => true, :status => :internal_server_error
-            end
+            render :nothing => true
           end
         else
           render :nothing => true, :status => :bad_request
@@ -94,12 +88,9 @@ class RelationController < ApplicationController
           relation.tags = []
           relation.members = []
           relation.visible = false
+          relation.save_with_history!
 
-          if relation.save_with_history
-            render :nothing => true
-          else
-            render :nothing => true, :status => :internal_server_error
-          end
+          render :nothing => true
         end
       else
         render :nothing => true, :status => :gone
index 33e2ee4..6b29d15 100644 (file)
@@ -20,10 +20,10 @@ class SwfController < ApplicationController
                basey           =params['basey'].to_f
                masterscale     =params['masterscale'].to_f
        
-               xmin=params['xmin'].to_f; xminr=xmin/0.000001
-               xmax=params['xmax'].to_f; xmaxr=xmax/0.000001
-               ymin=params['ymin'].to_f; yminr=ymin/0.000001
-               ymax=params['ymax'].to_f; ymaxr=ymax/0.000001
+               xmin=params['xmin'].to_f;
+               xmax=params['xmax'].to_f;
+               ymin=params['ymin'].to_f;
+               ymax=params['ymax'].to_f;
        
                # -     Begin movie
        
@@ -47,20 +47,18 @@ class SwfController < ApplicationController
        
                if params['token']
                         user=User.authenticate(:token => params[:token])
-                       sql="SELECT gps_points.latitude*0.000001 AS lat,gps_points.longitude*0.000001 AS lon,gpx_files.id AS fileid,UNIX_TIMESTAMP(gps_points.timestamp) AS ts "+
+                       sql="SELECT gps_points.latitude*0.0000001 AS lat,gps_points.longitude*0.0000001 AS lon,gpx_files.id AS fileid,UNIX_TIMESTAMP(gps_points.timestamp) AS ts "+
                                 " FROM gpx_files,gps_points "+
                                 "WHERE gpx_files.id=gpx_id "+
                                 "  AND gpx_files.user_id=#{user.id} "+
-                                "  AND (gps_points.longitude BETWEEN #{xminr} AND #{xmaxr}) "+
-                                "  AND (gps_points.latitude BETWEEN #{yminr} AND #{ymaxr}) "+
+                                "  AND "+OSM.sql_for_area(ymin,xmin,ymax,xmax,"gps_points.")+
                                 "  AND (gps_points.timestamp IS NOT NULL) "+
                                 "ORDER BY fileid DESC,ts "+
                                 "LIMIT 10000"
                else
-                       sql="SELECT latitude*0.000001 AS lat,longitude*0.000001 AS lon,gpx_id AS fileid,UNIX_TIMESTAMP(timestamp) AS ts "+
+                       sql="SELECT latitude*0.0000001 AS lat,longitude*0.0000001 AS lon,gpx_id AS fileid,UNIX_TIMESTAMP(timestamp) AS ts "+
                                 " FROM gps_points "+
-                                "WHERE (longitude BETWEEN #{xminr} AND #{xmaxr}) "+
-                                "  AND (latitude  BETWEEN #{yminr} AND #{ymaxr}) "+
+                                "WHERE "+OSM.sql_for_area(ymin,xmin,ymax,xmax,"gps_points.")+
                                 "  AND (gps_points.timestamp IS NOT NULL) "+
                                 "ORDER BY fileid DESC,ts "+
                                 "LIMIT 10000"
index 2ef960c..2e0623d 100644 (file)
@@ -15,12 +15,9 @@ class WayController < ApplicationController
           render :nothing => true, :status => :precondition_failed
         else
           way.user_id = @user.id
+          way.save_with_history!
 
-          if way.save_with_history
-            render :text => way.id.to_s, :content_type => "text/plain"
-          else
-            render :nothing => true, :status => :internal_server_error
-          end
+          render :text => way.id.to_s, :content_type => "text/plain"
         end
       else
         render :nothing => true, :status => :bad_request
@@ -41,8 +38,6 @@ class WayController < ApplicationController
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
   end
 
@@ -61,12 +56,9 @@ class WayController < ApplicationController
             way.tags = new_way.tags
             way.nds = new_way.nds
             way.visible = true
+            way.save_with_history!
 
-            if way.save_with_history
-              render :nothing => true
-            else
-              render :nothing => true, :status => :internal_server_error
-            end
+            render :nothing => true
           end
         else
           render :nothing => true, :status => :bad_request
@@ -76,8 +68,6 @@ class WayController < ApplicationController
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
   end
 
@@ -93,20 +83,17 @@ class WayController < ApplicationController
           way.tags = []
           way.nds = []
           way.visible = false
+         way.save_with_history!
 
-          if way.save_with_history
-            render :nothing => true
-          else
-            render :nothing => true, :status => :internal_server_error
-          end
+         render :nothing => true
         end
       else
         render :nothing => true, :status => :gone
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
+    rescue => ex
+      puts ex
     end
   end
 
@@ -131,8 +118,6 @@ class WayController < ApplicationController
       end
     rescue ActiveRecord::RecordNotFound
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
   end
 
index c337b5e..f1b4e01 100644 (file)
@@ -2,7 +2,7 @@ module GeocoderHelper
   def result_to_html(result)
     html_options = {}
     #html_options[:title] = strip_tags(result[:description]) if result[:description]
-    html_options[:href] = "?lat=#{result[:lat]}&lon=#{result[:lon]}&zoom=#{result[:zoom]}"
+    html_options[:href] = "?mlat=#{result[:lat]}&mlon=#{result[:lon]}&zoom=#{result[:zoom]}"
     html = ""
     html << result[:prefix] if result[:prefix]
     html << link_to_function(result[:name],"setPosition(#{result[:lat]}, #{result[:lon]}, #{result[:zoom]})", html_options)  if result[:name]
index ad33415..8894f44 100644 (file)
@@ -1,3 +1,8 @@
 class DiaryEntry < ActiveRecord::Base
   belongs_to :user
+
+  validates_presence_of :title, :body
+  validates_numericality_of :latitude, :allow_nil => true
+  validates_numericality_of :longitude, :allow_nil => true
+  validates_associated :user
 end
index 039c8d3..97e4111 100644 (file)
@@ -1,4 +1,8 @@
 class Message < ActiveRecord::Base
   belongs_to :sender, :class_name => "User", :foreign_key => :from_user_id
   belongs_to :recipient, :class_name => "User", :foreign_key => :to_user_id
+
+  validates_presence_of :title, :body, :sent_on
+  validates_inclusion_of :message_read, :in => [ true, false ]
+  validates_associated :sender, :recipient
 end
index 230c838..7e78aaf 100644 (file)
@@ -68,18 +68,12 @@ class Node < ActiveRecord::Base
     return node
   end
 
-  def save_with_history
-    begin
-      Node.transaction do
-        self.timestamp = Time.now
-        self.save!
-        old_node = OldNode.from_node(self)
-        old_node.save!
-      end
-
-      return true
-    rescue
-      return nil
+  def save_with_history!
+    Node.transaction do
+      self.timestamp = Time.now
+      self.save!
+      old_node = OldNode.from_node(self)
+      old_node.save!
     end
   end
 
index aaad67d..9eff2fb 100644 (file)
@@ -37,4 +37,16 @@ class Notifier < ActionMailer::Base
     @body['trace_name'] = trace.name
     @body['error'] = error
   end
+  
+  def message_notification(message)
+    @recipients = message.recipient.email
+    @from = 'abuse@openstreetmap.org'
+    @subject = "[OpenStreetMap] #{message.sender.display_name} sent you a new message"
+    @body['to_user'] = message.recipient.display_name
+    @body['from_user'] = message.sender.display_name
+    @body['body'] = message.body
+    @body['subject'] = message.title
+    @body['readurl'] = "http://#{SERVER_URL}/message/read/#{message.id}"
+    @body['replyurl'] = "http://#{SERVER_URL}/message/new/#{message.from_user_id}"
+  end
 end
index f74a149..a5d463f 100644 (file)
@@ -141,46 +141,40 @@ class Relation < ActiveRecord::Base
     @tags[k] = v
   end
 
-  def save_with_history
-    begin
-      Relation.transaction do
-        t = Time.now
-        self.timestamp = t
-        self.save!
-
-        tags = self.tags
-
-        RelationTag.delete_all(['id = ?', self.id])
-
-        tags.each do |k,v|
-          tag = RelationTag.new
-          tag.k = k
-          tag.v = v
-          tag.id = self.id
-          tag.save!
-        end
-
-        members = self.members
+  def save_with_history!
+    Relation.transaction do
+      t = Time.now
+      self.timestamp = t
+      self.save!
+
+      tags = self.tags
+
+      RelationTag.delete_all(['id = ?', self.id])
+
+      tags.each do |k,v|
+       tag = RelationTag.new
+       tag.k = k
+       tag.v = v
+       tag.id = self.id
+       tag.save!
+      end
 
-        RelationMember.delete_all(['id = ?', self.id])
+      members = self.members
 
-        members.each do |n|
-          mem = RelationMember.new
-          mem.id = self.id
-          mem.member_type = n[0];
-          mem.member_id = n[1];
-          mem.member_role = n[2];
-          mem.save!
-        end
+      RelationMember.delete_all(['id = ?', self.id])
 
-        old_relation = OldRelation.from_relation(self)
-        old_relation.timestamp = t
-        old_relation.save_with_dependencies!
+      members.each do |n|
+       mem = RelationMember.new
+       mem.id = self.id
+       mem.member_type = n[0];
+       mem.member_id = n[1];
+       mem.member_role = n[2];
+       mem.save!
       end
 
-      return true
-    rescue Exception => ex
-      return nil
+      old_relation = OldRelation.from_relation(self)
+      old_relation.timestamp = t
+      old_relation.save_with_dependencies!
     end
   end
 
index c189c03..4cac233 100644 (file)
@@ -175,7 +175,12 @@ class Trace < ActiveRecord::Base
       f_lon = 0
       first = true
 
-      Tracepoint.delete_all(['gpx_id = ?', self.id])
+      # If there are any existing points for this trace then delete
+      # them - we check for existing points first to avoid locking
+      # the table in the common case where there aren't any.
+      if Tracepoint.exists?(['gpx_id = ?', self.id])
+        Tracepoint.delete_all(['gpx_id = ?', self.id])
+      end
 
       gpx.points do |point|
         if first
@@ -199,10 +204,10 @@ class Trace < ActiveRecord::Base
         max_lon = Tracepoint.maximum('longitude', :conditions => ['gpx_id = ?', id])
         min_lon = Tracepoint.minimum('longitude', :conditions => ['gpx_id = ?', id])
 
-        max_lat = max_lat.to_f / 1000000
-        min_lat = min_lat.to_f / 1000000
-        max_lon = max_lon.to_f / 1000000
-        min_lon = min_lon.to_f / 1000000
+        max_lat = max_lat.to_f / 10000000
+        min_lat = min_lat.to_f / 10000000
+        max_lon = max_lon.to_f / 10000000
+        min_lon = min_lon.to_f / 10000000
 
         self.latitude = f_lat
         self.longitude = f_lon
index 70d0f99..e0fcfbd 100644 (file)
@@ -1,26 +1,40 @@
 class Tracepoint < ActiveRecord::Base
-set_table_name 'gps_points'
+  set_table_name 'gps_points'
 
-#  validates_numericality_of :latitude
-#  validates_numericality_of :longitude
+  validates_numericality_of :trackid, :only_integer => true
+  validates_numericality_of :latitude, :only_integer => true
+  validates_numericality_of :longitude, :only_integer => true
+  validates_associated :trace
+  validates_presence_of :timestamp
 
-  belongs_to :user
   belongs_to :trace, :foreign_key => 'gpx_id'
+  before_save :update_tile
+
+  def self.find_by_area(minlat, minlon, maxlat, maxlon, options)
+    self.with_scope(:find => {:conditions => OSM.sql_for_area(minlat, minlon, maxlat, maxlon)}) do
+      return self.find(:all, options)
+    end
+  end
+
+  def update_tile
+    self.tile = QuadTile.tile_for_point(lat, lon)
+  end
 
   def lat=(l)
-    self.latitude = l * 1000000
+    self.latitude = (l * 10000000).round
   end
 
   def lng=(l)
-    self.longitude = l * 1000000
+    self.longitude = (l * 10000000).round
   end
 
   def lat
-    return self.latitude.to_f / 1000000
+    return self.latitude.to_f / 10000000
   end
 
   def lon
-    return self.longitude.to_f / 1000000
+    return self.longitude.to_f / 10000000
   end
 
   def to_xml_node
@@ -29,5 +43,4 @@ set_table_name 'gps_points'
     el1['lon'] = self.lon.to_s
     return el1
   end
-
 end
index b564a33..e0a4450 100644 (file)
@@ -142,49 +142,47 @@ class Way < ActiveRecord::Base
     @tags[k] = v
   end
 
-  def save_with_history
-    begin
-      Way.transaction do
-        t = Time.now
-        self.timestamp = t
-        self.save!
+  def save_with_history!
+    t = Time.now
 
-        tags = self.tags
+    Way.transaction do
+      self.timestamp = t
+      self.save!
+    end
 
-        WayTag.delete_all(['id = ?', self.id])
+    WayTag.transaction do
+      tags = self.tags
 
-        tags.each do |k,v|
-          tag = WayTag.new
-          tag.k = k
-          tag.v = v
-          tag.id = self.id
-          tag.save!
-        end
+      WayTag.delete_all(['id = ?', self.id])
 
-        nds = self.nds
+      tags.each do |k,v|
+        tag = WayTag.new
+        tag.k = k
+        tag.v = v
+        tag.id = self.id
+        tag.save!
+      end
+    end
 
-        WayNode.delete_all(['id = ?', self.id])
+    WayNode.transaction do
+      nds = self.nds
 
-        i = 1
-        nds.each do |n|
-          nd = WayNode.new
-          nd.id = self.id
-          nd.node_id = n
-          nd.sequence_id = i
-          nd.save!
-          i += 1
-        end
+      WayNode.delete_all(['id = ?', self.id])
 
-        old_way = OldWay.from_way(self)
-        old_way.timestamp = t
-        old_way.save_with_dependencies!
+      i = 1
+      nds.each do |n|
+        nd = WayNode.new
+        nd.id = self.id
+        nd.node_id = n
+        nd.sequence_id = i
+        nd.save!
+        i += 1
       end
-
-      return true
-    rescue => ex
-      puts ex
-      return nil
     end
+
+    old_way = OldWay.from_way(self)
+    old_way.timestamp = t
+    old_way.save_with_dependencies!
   end
 
   def preconditions_ok?
index 168bb83..366a67f 100644 (file)
@@ -1,5 +1,8 @@
 <b><%= diary_entry.title %></b><br />
 <%= simple_format(diary_entry.body) %>
-Posted by user <b><%= link_to diary_entry.user.display_name, :controller => 'user', :action => 'view', :display_name => diary_entry.user.display_name %></b> at <%= diary_entry.created_at %><br />
+<% if diary_entry.latitude and diary_entry.longitude %>
+Coordinates: <div class="geo" style="display: inline"><span class="latitude"><%= diary_entry.latitude %></span>; <span class="longitude"><%= diary_entry.longitude %></span></div> (<%=link_to 'map', :controller => 'site', :action => 'index', :lat => diary_entry.latitude, :lon => diary_entry.longitude, :zoom => 14 %> / <%=link_to 'edit', :controller => 'site', :action => 'edit', :lat => diary_entry.latitude, :lon => diary_entry.longitude, :zoom => 14 %>)<br/>
+<% end %>
+Posted by <b><%= link_to diary_entry.user.display_name, :controller => 'user', :action => 'view', :display_name => diary_entry.user.display_name %></b> at <%= diary_entry.created_at %><br />
 <br />
 <hr />
index 8a60c18..a7aa84c 100644 (file)
@@ -1,7 +1,11 @@
 <% if @this_user %>
   <h2><%= @this_user.display_name %>'s diary</h2>
-
-  <% if @user and @this_user.id == @user.id %>
+  <% if @user == @this_user %>
+    <%= link_to 'New diary post', :controller => 'diary_entry', :action => 'new', :display_name => @user.display_name %>
+  <% end %>
+<% else %>
+  <h2>Users' diaries</h2>
+  <% if @user %>
     <%= link_to 'New diary post', :controller => 'diary_entry', :action => 'new', :display_name => @user.display_name %>
   <% end %>
 <% end %>
index 16974fa..69995d0 100644 (file)
       <th>Body</th>
       <td><%= f.text_area :body, :cols => 80 %></td>
     </tr>
+    <tr valign="top">
+           <th>Location</th>
+           <td><a name="map"></a><div id="map" style="border: 1px solid black; position: relative; width : 90%; height : 300px; display: none;"></div>
+                 <span class="location">Latitude: <%= f.text_field :latitude, :size => 20, :id => "latitude" %> Longitude: <%= f.text_field :longitude, :size => 20, :id => "longitude" %></span> <a href="#map" id="usemap" onclick="document.getElementById('map').style.display = 'block'; document.getElementById('usemap').style.display = 'none';">use map</a> </td>
+         </tr>
     <tr>
       <th></th>
       <td><%= submit_tag 'Save' %></td>
     </tr>
   </table>
 <% end %>
+
+<% if @user.home_lat.nil? or @user.home_lon.nil? %>
+  <% lon =  params['lon'] || '-0.1' %>
+  <% lat =  params['lat'] || '51.5' %>
+  <% zoom =  params['zoom'] || '4' %> 
+<% else %>
+  <% lon =  @user.home_lon %>
+  <% lat =  @user.home_lat %>
+  <% zoom =  '12' %>
+<% end %>
+
+<script type="text/javascript" src="/openlayers/OpenLayers.js"></script>
+<%= javascript_include_tag 'map.js' %>
+
+<script type="text/javascript">
+  <!--
+  var marker;
+
+  function init(){
+    var centre = lonLatToMercator(new OpenLayers.LonLat(<%= lon %>, <%= lat %>));
+    var zoom = <%= zoom %>;
+
+    var map = createMap("map");
+
+    map.setCenter(centre, zoom);
+
+    map.events.register("click", map, setLocation);
+  }        
+
+  function setLocation( e ) { 
+    closeMapPopup();
+
+    var merc = map.getLonLatFromViewPortPx(e.xy);
+    var lonlat = mercatorToLonLat(merc);
+
+    document.getElementById('latitude').value = lonlat.lat;
+    document.getElementById('longitude').value = lonlat.lon;
+
+    if (marker) {
+      removeMarkerFromMap(marker);
+    }
+
+    marker = addMarkerToMap(merc, null, "Diary entry location");
+  }
+
+  window.onload = init;
+// -->
+</script>
\ No newline at end of file
index 56f6bb1..0297272 100644 (file)
@@ -1,7 +1,9 @@
+<% this_colour = cycle('lightgrey', 'white') # can only call once for some dumb reason %>
+
 <tr class="inbox-row<%= "-unread" if not message_summary.message_read? %>">
-  <td class="inbox-sender"><%= link_to message_summary.sender.display_name , :controller => 'user', :action => message_summary.sender.display_name %></td>
-  <td class="inbox-subject"><%= link_to  message_summary.title , :controller => 'message', :action => 'read', :message_id => message_summary.id  %></td>
-  <td class="inbox-sent"><%= message_summary.sent_on %></td>
+  <td class="inbox-sender" bgcolor='<%= this_colour %>'><%= link_to message_summary.sender.display_name , :controller => 'user', :action => message_summary.sender.display_name %></td>
+  <td class="inbox-subject" bgcolor='<%= this_colour %>'><%= link_to  message_summary.title , :controller => 'message', :action => 'read', :message_id => message_summary.id  %></td>
+  <td class="inbox-sent" bgcolor='<%= this_colour %>'><%= message_summary.sent_on %></td>
   <% if message_summary.message_read? %>
     <td><%= button_to 'Mark as unread', :controller => 'message', :action => 'mark', :message_id => message_summary.id, :mark => 'unread' %></td>
   <% else %>
index b84fea4..7a0d2bb 100644 (file)
@@ -2,19 +2,19 @@
 
 <table>
   <tr>
-    <th>From</th>
+    <th align="right">From</th>
     <td><%= link_to @message.sender.display_name, :controller => 'user', :action => 'view', :display_name => @message.sender.display_name %></td>
   </tr>
   <tr>
-    <th>Subject</th>
+    <th align="right">Subject</th>
     <td><%= @message.title %></td>
   </tr>
   <tr>
-    <th>Date</th>
+    <th align="right">Date</th>
     <td><%= @message.sent_on %></td>
   </tr>
   <tr>
-    <th>Message</th>
+    <th></th>
     <td><%= @message.body %></td>
   </tr>
 </table>
diff --git a/app/views/notifier/message_notification.rhtml b/app/views/notifier/message_notification.rhtml
new file mode 100644 (file)
index 0000000..892ac11
--- /dev/null
@@ -0,0 +1,10 @@
+Hi <%= @to_user %>,
+
+<%= @from_user %> has sent you a message through OpenStreetMap with the subject "<%= @subject %>":
+
+==
+<%= @body %>
+==
+
+You can also read the message at <%= @readurl %>
+and you can reply at <%= @replyurl %>
index 14f8fa5..84f44f0 100644 (file)
@@ -66,7 +66,7 @@
     <p class="search_help">
       examples: 'Alkmaar', 'Regent Street, Cambridge', 'CB2 5AQ',
       or 'post offices near L√ľnen'
-      <a href="http://wiki.openstreetmap.org/index.php/Search_Help">more examples...</a>
+      <a href="http://wiki.openstreetmap.org/index.php/Search">more examples...</a>
     </p>
   </div>
 <% end %>
index a41a801..b1c5555 100644 (file)
   var fo = new SWFObject("/potlatch/potlatch.swf?d="+Math.round(Math.random()*1000), "potlatch", "700", "600", "6", "#FFFFFF");
 
   function doSWF(lat,lon,sc) {
+    if (sc < 11) sc = 11;
     fo.addVariable('lat',lat);
     fo.addVariable('long',lon);
     fo.addVariable('scale',sc);
     fo.addVariable('token','<%= session[:token] %>');
+<% if params['gpx'] %>    fo.addVariable('gpx','<%= params['gpx']+"/data" %>'); <% end %>
     fo.write("map");
   }
 
index 41b2b86..bbd1a8a 100644 (file)
     map.setCenter(centre, zoom);
     <% end %>
 
-    <% if marker %>
-    marker = addMarkerToMap(lonLatToMercator(new OpenLayers.LonLat(<%= mlon %>, <%= mlat %>)));
-    <% end %>
-
     <% if layers %>
     setMapLayers("<%= layers %>");
     <% end %>
 
+    <% if marker %>
+    marker = addMarkerToMap(lonLatToMercator(new OpenLayers.LonLat(<%= mlon %>, <%= mlat %>)));
+    <% end %>
+
     map.events.register("moveend", map, updateLocation);
     updateLocation();
 
index eb85585..9186244 100644 (file)
@@ -15,7 +15,7 @@
       ... <%= time_ago_in_words( trace.timestamp ) %>  ago</span>
       <%= link_to 'more', {:controller => 'trace', :action => 'view', :display_name => trace.user.display_name, :id => trace.id}, {:title => 'View Trace Details'} %> /
       <%= link_to_if trace.inserted?, 'map', {:controller => 'site', :action => 'index', :lat => trace.latitude, :lon => trace.longitude, :zoom => 14}, {:title => 'View Map'} %> /
-      <%= link_to_if trace.inserted?, 'edit', {:controller => 'site', :action => 'edit', :lat => trace.latitude, :lon => trace.longitude, :zoom => 14}, {:title => 'Edit Map'} %>
+      <%= link_to_if trace.inserted?, 'edit', {:controller => 'site', :action => 'edit', :lat => trace.latitude, :lon => trace.longitude, :zoom => 14, :gpx => trace.id }, {:title => 'Edit Map'} %>
       <br />
       <%= escape_once(trace.description) %>
     <br />
index 1ad5637..60f71b7 100644 (file)
@@ -17,7 +17,7 @@
     <td><%= @trace.size.to_s.gsub(/(\d)(?=(\d{3})+$)/,'\1,') %></td></tr>
   <tr>
     <td>Start coordinate:</td>
-    <td><%= @trace.latitude %>, <%= @trace.longitude %> (<%=link_to 'map', :controller => 'site', :action => 'index', :lat => @trace.latitude, :lon => @trace.longitude, :zoom => 14 %> / <%=link_to 'edit', :controller => 'site', :action => 'edit', :lat => @trace.latitude, :lon => @trace.longitude, :zoom => 14 %>)</td>
+    <td><div class="geo" style="display: inline"><span class="latitude"><%= @trace.latitude %></span>; <span class="longitude"><%= @trace.longitude %></span></div> (<%=link_to 'map', :controller => 'site', :action => 'index', :lat => @trace.latitude, :lon => @trace.longitude, :zoom => 14 %> / <%=link_to 'edit', :controller => 'site', :action => 'edit', :lat => @trace.latitude, :lon => @trace.longitude, :gpx=> @trace.id, :zoom => 14 %>)</td>
   </tr>
   <% end %>
   <tr>
index 570cb04..3820ed2 100644 (file)
@@ -1,5 +1,8 @@
 # Be sure to restart your web server when you modify this file.
 
+# Limit each rails process to a 512Mb resident set size
+Process.setrlimit Process::RLIMIT_AS, 640*1024*1024, Process::RLIM_INFINITY
+
 # Uncomment below to force Rails into production mode when 
 # you don't control web/app server and can't set it the proper way
 ENV['RAILS_ENV'] ||= 'production'
index e3e210a..f4530f0 100644 (file)
--- a/db/README
+++ b/db/README
@@ -22,10 +22,33 @@ $ mysql -u <uid> -p
 > flush privileges;
 > exit
 
+Creating functions
+====================
+
+Run this command in the db/functions directory:
+
+$ make
+
+Make sure the db/functions directory is on the MySQL server's library
+path and restart the MySQL server. On linux the easiest way to do this
+is to create /etc/ld.so.conf.d/osm.conf and place the path to the
+db/functions directory in it and then run the following command as root:
+
+$ ldconfig
+
+Now create the functions as follows:
+
+$ mysql -u <uid> -p openstreetmap
+
+(change <uid> with appropriate username of administrative user eg. root )
+
+> create function tile_for_point returns integer soname 'libquadtile.so';
+> exit
+
 Creating database skeleton tables
 ===================================
 
-Run this command from the root of your rails direcotry:
+Run this command from the root of your rails directory:
 
 $ rake db:migrate
 
diff --git a/db/functions/Makefile b/db/functions/Makefile
new file mode 100644 (file)
index 0000000..6544db1
--- /dev/null
@@ -0,0 +1,4 @@
+QTDIR=../../lib/quad_tile
+
+libquadtile.so: quadtile.c ${QTDIR}/quad_tile.h
+       cc `mysql_config --include` -I${QTDIR} -fPIC -O3 -shared -o libquadtile.so quadtile.c
diff --git a/db/functions/quadtile.c b/db/functions/quadtile.c
new file mode 100644 (file)
index 0000000..d601892
--- /dev/null
@@ -0,0 +1,31 @@
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <mysql.h>
+#include <quad_tile.h>
+
+my_bool tile_for_point_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+   if ( args->arg_count != 2 ||
+        args->arg_type[0] != INT_RESULT ||
+        args->arg_type[1] != INT_RESULT )
+   {
+      strcpy( message, "Your tile_for_point arguments are bogus!" );
+      return 1;
+   }
+
+   return 0;
+}
+
+void tile_for_point_deinit(UDF_INIT *initid)
+{
+   return;
+}
+
+long long tile_for_point(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
+{
+   long long lat = *(long long *)args->args[0];
+   long long lon = *(long long *)args->args[1];
+
+   return xy2tile(lon2x(lon / 10000000.0), lat2y(lat / 10000000.0));
+}
diff --git a/db/migrate/005_tile_tracepoints.rb b/db/migrate/005_tile_tracepoints.rb
new file mode 100644 (file)
index 0000000..c0e6d8a
--- /dev/null
@@ -0,0 +1,15 @@
+class TileTracepoints < ActiveRecord::Migration
+  def self.up
+    add_column "gps_points", "tile", :integer, :null => false, :unsigned => true
+    add_index "gps_points", ["tile"], :name => "points_tile_idx"
+    remove_index "gps_points", :name => "points_idx"
+
+    Tracepoint.update_all("latitude = latitude * 10, longitude = longitude * 10, tile = tile_for_point(latitude * 10, longitude * 10)")
+  end
+
+  def self.down
+    add_index "gps_points", ["latitude", "longitude"], :name => "points_idx"
+    remove_index "gps_points", :name => "points_tile_idx"
+    remove_column "gps_points", "tile"
+  end
+end
similarity index 96%
rename from db/migrate/006_remove_segments.rb
rename to db/migrate/007_remove_segments.rb
index de9557c..492beda 100644 (file)
@@ -5,9 +5,9 @@ class RemoveSegments < ActiveRecord::Migration
     have_segs = select_value("SELECT count(*) FROM current_segments").to_i != 0
 
     if have_segs
-      prefix = File.join Dir.tmpdir, "006_remove_segments.#{$$}."
+      prefix = File.join Dir.tmpdir, "007_remove_segments.#{$$}."
 
-      cmd = "db/migrate/006_remove_segments_helper"
+      cmd = "db/migrate/007_remove_segments_helper"
       src = "#{cmd}.cc"
       if not File.exists? cmd or File.mtime(cmd) < File.mtime(src) then 
        system 'c++ -O3 -Wall `mysql_config --cflags --libs` ' +
similarity index 97%
rename from db/migrate/006_remove_segments_helper.cc
rename to db/migrate/007_remove_segments_helper.cc
index dd2176a..2234a3b 100644 (file)
@@ -32,9 +32,9 @@ static T parse(const char *str) {
 static void exit_mysql_err(MYSQL *mysql) {
   const char *err = mysql_error(mysql);
   if (err) {
-    fprintf(stderr, "005_remove_segments_helper: MySQL error: %s\n", err);
+    fprintf(stderr, "007_remove_segments_helper: MySQL error: %s\n", err);
   } else {
-    fprintf(stderr, "005_remove_segments_helper: MySQL error\n");
+    fprintf(stderr, "007_remove_segments_helper: MySQL error\n");
   }
   abort();
   exit(EXIT_FAILURE);
@@ -43,9 +43,9 @@ static void exit_mysql_err(MYSQL *mysql) {
 static void exit_stmt_err(MYSQL_STMT *stmt) {
   const char *err = mysql_stmt_error(stmt);
   if (err) {
-    fprintf(stderr, "005_remove_segments_helper: MySQL stmt error: %s\n", err);
+    fprintf(stderr, "007_remove_segments_helper: MySQL stmt error: %s\n", err);
   } else {
-    fprintf(stderr, "005_remove_segments_helper: MySQL stmt error\n");
+    fprintf(stderr, "007_remove_segments_helper: MySQL stmt error\n");
   }
   abort();
   exit(EXIT_FAILURE);
@@ -536,7 +536,7 @@ int main(int argc, char **argv) {
   char *tempfn;
 
   if (argc != 8) {
-    printf("Usage: 006_remove_segments_helper host user passwd database port socket prefix\n");
+    printf("Usage: 007_remove_segments_helper host user passwd database port socket prefix\n");
     exit(EXIT_FAILURE);
   }
 
index c31e315..1d32d17 100644 (file)
@@ -17,6 +17,14 @@ module ActiveRecord
         return false if options[:options] =~ /AUTO_INCREMENT/i
         return old_options_include_default?(options)
       end
+
+      alias_method :old_add_column_options!, :add_column_options!
+
+      def add_column_options!(sql, options)
+        sql << " UNSIGNED" if options[:unsigned]
+        old_add_column_options!(sql, options)
+        sql << " #{options[:options]}"
+      end
     end
 
     class MysqlAdapter
@@ -40,7 +48,6 @@ module ActiveRecord
 
         change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
         add_column_options!(change_column_sql, options)
-        change_column_sql << " #{options[:options]}"
         execute(change_column_sql) 
       end
 
index aab3e13..45c506e 100644 (file)
@@ -410,4 +410,15 @@ module OSM
     return Digest::MD5.hexdigest(password) if salt.nil?
     return Digest::MD5.hexdigest(salt + password)
   end
+
+  # Return an SQL fragment to select a given area of the globe
+  def self.sql_for_area(minlat, minlon, maxlat, maxlon, prefix = nil)
+    tilesql = QuadTile.sql_for_area(minlat, minlon, maxlat, maxlon, prefix)
+    minlat = (minlat * 10000000).round
+    minlon = (minlon * 10000000).round
+    maxlat = (maxlat * 10000000).round
+    maxlon = (maxlon * 10000000).round
+
+    return "#{tilesql} AND #{prefix}latitude BETWEEN #{minlat} AND #{maxlat} AND #{prefix}longitude BETWEEN #{minlon} AND #{maxlon}"
+  end
 end
diff --git a/lib/quad_tile.rb b/lib/quad_tile.rb
new file mode 100644 (file)
index 0000000..6e4fb6d
--- /dev/null
@@ -0,0 +1,81 @@
+module QuadTile
+  begin
+    require "quad_tile/quad_tile_so"
+  rescue MissingSourceFile
+    def self.tile_for_point(lat, lon)
+      x = ((lon + 180) * 65535 / 360).round
+      y = ((lat + 90) * 65535 / 180).round
+
+      return tile_for_xy(x, y)
+    end
+
+    def self.tiles_for_area(minlat, minlon, maxlat, maxlon)
+      minx = ((minlon + 180) * 65535 / 360).round
+      maxx = ((maxlon + 180) * 65535 / 360).round
+      miny = ((minlat + 90) * 65535 / 180).round
+      maxy = ((maxlat + 90) * 65535 / 180).round
+      tiles = []
+
+      minx.upto(maxx) do |x|
+        miny.upto(maxy) do |y|
+          tiles << tile_for_xy(x, y)
+        end
+      end
+
+      return tiles
+    end
+
+    def self.tile_for_xy(x, y)
+      t = 0
+
+      16.times do
+        t = t << 1
+        t = t | 1 unless (x & 0x8000).zero?
+        x <<= 1
+        t = t << 1
+        t = t | 1 unless (y & 0x8000).zero?
+        y <<= 1
+      end
+
+      return t
+    end
+  end
+
+  def self.sql_for_area(minlat, minlon, maxlat, maxlon, prefix)
+    sql = Array.new
+    single = Array.new
+
+    iterate_tiles_for_area(minlat, minlon, maxlat, maxlon) do |first,last|
+      if first == last
+        single.push(first)
+      else
+        sql.push("#{prefix}tile BETWEEN #{first} AND #{last}")
+      end
+    end
+
+    sql.push("#{prefix}tile IN (#{single.join(',')})") if single.size > 0
+
+    return "( " + sql.join(" OR ") + " )"
+  end
+
+  def self.iterate_tiles_for_area(minlat, minlon, maxlat, maxlon)
+    tiles = tiles_for_area(minlat, minlon, maxlat, maxlon)
+    first = last = nil
+
+    tiles.sort.each do |tile|
+      if last.nil?
+        first = last = tile
+      elsif tile == last + 1
+        last = tile
+      else
+        yield first, last
+
+        first = last = tile
+      end
+    end
+
+    yield first, last unless last.nil?
+  end
+
+  private_class_method :tile_for_xy, :iterate_tiles_for_area
+end
diff --git a/lib/quad_tile/extconf.rb b/lib/quad_tile/extconf.rb
new file mode 100644 (file)
index 0000000..c7fc1b8
--- /dev/null
@@ -0,0 +1,3 @@
+require "mkmf"
+
+create_makefile("quad_tile_so")
diff --git a/lib/quad_tile/quad_tile.c b/lib/quad_tile/quad_tile.c
new file mode 100644 (file)
index 0000000..137963b
--- /dev/null
@@ -0,0 +1,47 @@
+#include "ruby.h"
+#include "quad_tile.h"
+
+static VALUE tile_for_point(VALUE self, VALUE lat, VALUE lon)
+{
+   unsigned int x = lon2x(NUM2DBL(lon));
+   unsigned int y = lat2y(NUM2DBL(lat));
+
+   return UINT2NUM(xy2tile(x, y));
+}
+
+static VALUE tiles_for_area(VALUE self, VALUE minlat, VALUE minlon, VALUE maxlat, VALUE maxlon)
+{
+   unsigned int minx = lon2x(NUM2DBL(minlon));
+   unsigned int maxx = lon2x(NUM2DBL(maxlon));
+   unsigned int miny = lat2y(NUM2DBL(minlat));
+   unsigned int maxy = lat2y(NUM2DBL(maxlat));
+   VALUE        tiles = rb_ary_new();
+   unsigned int x;
+   unsigned int y;
+
+   for (x = minx; x <= maxx; x++)
+   {
+      for (y = miny; y <= maxy; y++)
+      {
+         rb_ary_push(tiles, UINT2NUM(xy2tile(x, y)));
+      }
+   }
+
+   return tiles;
+}
+
+static VALUE tile_for_xy(VALUE self, VALUE x, VALUE y)
+{
+   return UINT2NUM(xy2tile(NUM2UINT(x), NUM2UINT(y)));
+}
+
+void Init_quad_tile_so(void)
+{
+   VALUE m = rb_define_module("QuadTile");
+
+   rb_define_module_function(m, "tile_for_point", tile_for_point, 2);
+   rb_define_module_function(m, "tiles_for_area", tiles_for_area, 4);
+   rb_define_module_function(m, "tile_for_xy", tile_for_xy, 2);
+
+   return;
+}
diff --git a/lib/quad_tile/quad_tile.h b/lib/quad_tile/quad_tile.h
new file mode 100644 (file)
index 0000000..f868ff5
--- /dev/null
@@ -0,0 +1,25 @@
+#include <math.h>
+
+inline unsigned int xy2tile(unsigned int x, unsigned int y)
+{
+   unsigned int tile = 0;
+   int          i;
+
+   for (i = 15; i >= 0; i--)
+   {
+      tile = (tile << 1) | ((x >> i) & 1);
+      tile = (tile << 1) | ((y >> i) & 1);
+   }
+
+   return tile;
+}
+
+inline unsigned int lon2x(double lon)
+{
+   return round((lon + 180.0) * 65535.0 / 360.0);
+}
+
+inline unsigned int lat2y(double lat)
+{
+   return round((lat + 90.0) * 65535.0 / 180.0);
+}
index 28db77c..ce4cd00 100755 (executable)
Binary files a/public/potlatch/potlatch.swf and b/public/potlatch/potlatch.swf differ
index 10242b7..873fc3e 100755 (executable)
Binary files a/public/potlatch/ymap.swf and b/public/potlatch/ymap.swf differ
index 7921ac1..bddc8a0 100644 (file)
@@ -1,5 +1,23 @@
 t1:
+  id: 1
+  member_role: "some"
+  member_type: "way"
+  member_id: 3
+
+t2:
   id: 1
   member_role: "some"
   member_type: "node"
+  member_id: 5
+
+t3:
+  id: 1
+  member_role: "some"
+  member_type: "relation"
   member_id: 3
+
+t4:
+  id: 3
+  member_role: "some"
+  member_type: "node"
+  member_id: 5
index ba795b6..aaf06a3 100644 (file)
@@ -7,3 +7,8 @@ t2:
   id: 2
   k: test
   v: yes
+
+t2:
+  id: 3
+  k: test
+  v: yes
index 67c8ddb..c1f77d4 100644 (file)
@@ -9,3 +9,9 @@ invisible_relation:
   user_id: 1
   timestamp: 2007-01-01 00:00:00
   visible: 0
+
+used_relation:
+  id: 3
+  user_id: 1
+  timestamp: 2007-01-01 00:00:00
+  visible: 1
index f424e6a..27e8b53 100644 (file)
@@ -1,6 +1,24 @@
 t1:
+  id: 1
+  member_role: "some"
+  member_type: "way"
+  member_id: 3
+  version: 1
+t2:
   id: 1
   member_role: "some"
   member_type: "node"
+  member_id: 5
+  version: 1
+t3:
+  id: 1
+  member_role: "some"
+  member_type: "relation"
   member_id: 3
   version: 1
+t4:
+  id: 3
+  member_role: "some"
+  member_type: "node"
+  member_id: 5
+  version: 1
index d1c69a6..39f4bd5 100644 (file)
@@ -9,3 +9,9 @@ t2:
   k: test
   v: yes
   version: 1
+
+t3:
+  id: 3
+  k: test
+  v: yes
+  version: 1
index f1e4026..cf1d1ff 100644 (file)
@@ -11,3 +11,10 @@ invisible_relation:
   timestamp: 2007-01-01 00:00:00
   visible: 0
   version: 1
+
+used_relation:
+  id: 3
+  user_id: 1
+  timestamp: 2007-01-01 00:00:00
+  visible: 1
+  version: 1
index 2893ba9..8f8b727 100644 (file)
@@ -42,7 +42,7 @@ class RelationControllerTest < Test::Unit::TestCase
     assert_response :not_found
 
     # check the "relations for node" mode
-    get :relations_for_node, :id => current_nodes(:used_node_1).id
+    get :relations_for_node, :id => current_nodes(:node_used_by_relationship).id
     assert_response :success
     # FIXME check whether this contains the stuff we want!
     if $VERBOSE
@@ -59,7 +59,7 @@ class RelationControllerTest < Test::Unit::TestCase
 
 
     # check the "relations for relation" mode
-    get :relations_for_node, :id => current_relations(:used_relation).id
+    get :relations_for_relation, :id => current_relations(:used_relation).id
     assert_response :success
     # FIXME check whether this contains the stuff we want!
     if $VERBOSE
@@ -67,7 +67,7 @@ class RelationControllerTest < Test::Unit::TestCase
     end
 
     # check the "full" mode
-    get :full, :id => current_relations(:relation_using_all).id
+    get :full, :id => current_relations(:visible_relation).id
     assert_response :success
     # FIXME check whether this contains the stuff we want!
     if $VERBOSE
index b3e8343..95321b5 100644 (file)
@@ -11,7 +11,7 @@ class NodeTest < Test::Unit::TestCase
                              :user_id => users(:normal_user).id,
                              :visible => 1,
                              :tags => "")
-    assert node_template.save_with_history
+    assert node_template.save_with_history!
 
     node = Node.find(node_template.id)
     assert_not_nil node
@@ -44,7 +44,7 @@ class NodeTest < Test::Unit::TestCase
     node_template.latitude = 12.3456
     node_template.longitude = 65.4321
     node_template.tags = "updated=yes"
-    assert node_template.save_with_history
+    assert node_template.save_with_history!
 
     node = Node.find(node_template.id)
     assert_not_nil node
@@ -76,7 +76,7 @@ class NodeTest < Test::Unit::TestCase
     assert_not_nil old_node_template
 
     node_template.visible = 0
-    assert node_template.save_with_history
+    assert node_template.save_with_history!
 
     node = Node.find(node_template.id)
     assert_not_nil node