Potlatch-on-Rails, ready to go (fingers crossed)
authorRichard Fairhurst <richard@systemed.net>
Fri, 18 May 2007 15:20:31 +0000 (15:20 +0000)
committerRichard Fairhurst <richard@systemed.net>
Fri, 18 May 2007 15:20:31 +0000 (15:20 +0000)
app/controllers/amf_controller.rb
app/controllers/swf_controller.rb [new file with mode: 0644]
app/helpers/swf_helper.rb [new file with mode: 0644]
app/views/site/edit.rhtml
config/routes.rb
public/potlatch/potlatch.swf

index 9947a4eaabe81fb771e91d9e82ecd9ede233422f..a9a56203a2ebc8b76c398678cb32f0f834450d5b 100644 (file)
@@ -1,9 +1,9 @@
 class AmfController < ApplicationController
-=begin
+#=begin
   require 'stringio'
 
-# to log:
-# RAILS_DEFAULT_LOGGER.error("Args: #{args[0]}, #{args[1]}, #{args[2]}, #{args[3]}")
+  # to log:
+  # RAILS_DEFAULT_LOGGER.error("Args: #{args[0]}, #{args[1]}, #{args[2]}, #{args[3]}")
 
   # ====================================================================
   # Main AMF handler
@@ -55,6 +55,7 @@ class AmfController < ApplicationController
 
   end
 
+       private
 
        # ====================================================================
        # Remote calls
@@ -107,7 +108,20 @@ class AmfController < ApplicationController
                waylist.each {|a|
                        ways<<a.wayid.to_i
                }
-               ways
+
+               pointlist=ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,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 "+
+                        " WHERE (latitude  BETWEEN "+(args[1].to_f-0.01).to_s+" AND "+(args[3].to_f+0.01).to_s+") "+
+                        "   AND (longitude BETWEEN "+(args[0].to_f-0.01).to_s+" AND "+(args[2].to_f-0.01).to_s+") "+
+                        "   AND cs1.id IS NULL AND cs2.id IS NULL "+
+                        "   AND current_nodes.visible=1")
+               points=[]
+               pointlist.each {|a|
+                       points<<[a['id'],tag2array(a['tags'])]
+               }
+               [ways,points]
        end
 
        # ----- getway (objectname, way, baselong, basey, masterscale)
@@ -417,12 +431,13 @@ class AmfController < ApplicationController
        def createuniquesegments(way,uqs_name)
                sql=<<-EOF
                        CREATE TEMPORARY TABLE #{uqs_name}
-                                                       SELECT a.segment_id,COUNT(a.segment_id) AS ct
-                                                         FROM current_way_segments AS a, current_way_segments AS b
-                                                        WHERE a.segment_id=b.segment_id 
-                                                          AND a.id=#{way} 
-                                                 GROUP BY a.segment_id
-                                                       HAVING ct=1
+                                                       SELECT a.segment_id
+                                                         FROM (SELECT DISTINCT segment_id FROM current_way_segments 
+                                                                       WHERE id = #{way}) a
+                                                LEFT JOIN current_way_segments b 
+                                                               ON b.segment_id = a.segment_id
+                                                          AND b.id != #{way}
+                                                        WHERE b.segment_id IS NULL
                EOF
                ActiveRecord::Base.connection.execute(sql)
        end
@@ -438,6 +453,8 @@ class AmfController < ApplicationController
                        b.gsub!('#%',';;;')
                        b.gsub!('===','#%')
                        k,v=b.split('=')
+                       if k.nil? then k='' end
+                       if v.nil? then v='' end
                        tags[k.gsub('#%','=')]=v.gsub('#%','=')
                end
                tags
@@ -611,5 +628,5 @@ class AmfController < ApplicationController
                180/Math::PI * (2*Math.atan(Math.exp(a*Math::PI/180))-Math::PI/2)
        end
 
-=end
+#=end
 end
diff --git a/app/controllers/swf_controller.rb b/app/controllers/swf_controller.rb
new file mode 100644 (file)
index 0000000..0e5b2e4
--- /dev/null
@@ -0,0 +1,202 @@
+class SwfController < ApplicationController
+
+# to log:
+# RAILS_DEFAULT_LOGGER.error("Args: #{args[0]}, #{args[1]}, #{args[2]}, #{args[3]}")
+# $log.puts Time.new.to_s+','+Time.new.usec.to_s+": started GPS script"
+# http://localhost:3000/api/0.4/swf/trackpoints?xmin=-2.32402605810577&xmax=-2.18386309423859&ymin=52.1546608755772&ymax=52.2272777906895&baselong=-2.25325793066437&basey=61.3948537948532&masterscale=5825.4222222222
+
+       # ====================================================================
+       # Public methods
+       
+       # ---- trackpoints      compile SWF of trackpoints
+
+       def trackpoints 
+       
+               # -     Initialise
+       
+               baselong        =params['baselong'].to_f
+               basey           =params['basey'].to_f
+               masterscale     =params['masterscale'].to_f
+       
+               xmin=params['xmin'].to_f/0.0000001
+               xmax=params['xmax'].to_f/0.0000001
+               ymin=params['ymin'].to_f/0.0000001
+               ymax=params['ymax'].to_f/0.0000001
+       
+               # -     Begin movie
+       
+               bounds_left  =0
+               bounds_right =320*20
+               bounds_bottom=0
+               bounds_top   =240*20
+
+               m =''
+               m+=swfRecord(9,255.chr + 155.chr + 155.chr)                     #ƊBackground
+               absx=0
+               absy=0
+               xl=yb= 9999999
+               xr=yt=-9999999
+       
+               # -     Send SQL and draw line
+       
+               b=''
+               lasttime=0
+               lastfile='-1'
+       
+               if params['token']
+                       token=sqlescape(params['token'])
+                       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,users "+
+                                "WHERE gpx_files.id=gpx_id "+
+                                "  AND gpx_files.user_id=users.id "+
+                                "  AND token='#{token}' "+
+                                "  AND (gps_points.longitude BETWEEN #{xmin} AND #{xmax}) "+
+                                "  AND (gps_points.latitude BETWEEN #{ymin} AND #{ymax}) "+
+                                "ORDER BY fileid DESC,ts "+
+                                "LIMIT 10000"
+               else
+                       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 #{xmin} AND #{xmax}) "+
+                                "  AND (latitude  BETWEEN #{ymin} AND #{ymax}) "+
+                                "ORDER BY fileid DESC,ts "+
+                                "LIMIT 10000"
+               end
+               gpslist=ActiveRecord::Base.connection.select_all sql
+       
+               # - Draw lines
+       
+               r=startShape()
+               gpslist.each do |row|
+                       xs=(long2coord(row['lon'].to_f,baselong,masterscale)*20).floor
+                       ys=(lat2coord(row['lat'].to_f ,basey   ,masterscale)*20).floor
+                       xl=[xs,xl].min; xr=[xs,xr].max
+                       yb=[ys,yb].min; yt=[ys,yt].max
+                       if (row['ts'].to_i-lasttime<180 and row['fileid']==lastfile)
+                               b+=drawTo(absx,absy,xs,ys)
+                       else
+                               b+=startAndMove(xs,ys)
+                       end
+                       absx=xs.floor; absy=ys.floor
+                       lasttime=row['ts'].to_i
+                       lastfile=row['fileid']
+                       while b.length>80 do
+                               r+=[b.slice!(0...80)].pack("B*")
+                       end
+               end
+       
+               # - Write shape
+       
+               b+=endShape()
+               r+=[b].pack("B*")
+               m+=swfRecord(2,packUI16(1) + packRect(xl,xr,yb,yt) + r)
+               m+=swfRecord(4,packUI16(1) + packUI16(1))
+               
+               # -     Create Flash header and write to browser
+       
+               m+=swfRecord(1,'')                                                                      # Show frame
+               m+=swfRecord(0,'')                                                                      # End
+               
+               m=packRect(bounds_left,bounds_right,bounds_bottom,bounds_top) + 0.chr + 12.chr + packUI16(1) + m
+               m='FWS' + 6.chr + packUI32(m.length+8) + m
+       
+               response.headers["Content-Type"]="application/x-shockwave-flash"
+               render :text=>m
+       end
+
+       private
+
+       # =======================================================================
+       # SWF functions
+       
+       # -----------------------------------------------------------------------
+       # Line-drawing
+
+       def startShape
+               s =0.chr                                                                                # No fill styles
+               s+=1.chr                                                                                # One line style
+               s+=packUI16(5) + 0.chr + 255.chr + 255.chr              # Width 5, RGB #00FFFF
+               s+=17.chr                                                                               # 1 fill, 1 line index bit
+               s
+       end
+       
+       def endShape
+               '000000'
+       end
+       
+       def startAndMove(x,y)
+               d='001001'                                                                              # Line style change, moveTo
+               l =[lengthSB(x),lengthSB(y)].max
+               d+=sprintf("%05b%0#{l}b%0#{l}b",l,x,y)
+               d+='1'                                                                                  # Select line style 1
+       end
+       
+       def drawTo(absx,absy,x,y)
+               d='11'                                                                                  # TypeFlag, EdgeFlag
+               dx=x-absx
+               dy=y-absy
+               
+               l =[lengthSB(dx),lengthSB(dy)].max
+               d+=sprintf("%04b",l-2)
+               d+='1'                                                                                  # GeneralLine
+               d+=sprintf("%0#{l}b%0#{l}b",dx,dy)
+       end
+
+       # -----------------------------------------------------------------------
+       # Specific data types
+
+       def swfRecord(id,r)
+               if r.length>62
+                       return packUI16((id<<6)+0x3F) + packUI32(r.length) + r
+               else
+                       return packUI16((id<<6)+r.length) + r
+               end
+       end
+
+       def packRect(a,b,c,d)
+               l=[lengthSB(a),
+                  lengthSB(b),
+                  lengthSB(c),
+                  lengthSB(d)].max
+               n=sprintf("%05b%0#{l}b%0#{l}b%0#{l}b%0#{l}b",l,a,b,c,d)
+               [n].pack("B*")
+       end
+
+       # -----------------------------------------------------------------------
+       # Generic pack functions
+       
+       def packUI16(n)
+               [n.floor].pack("v")
+       end
+       
+       def packUI32(n)
+               [n.floor].pack("V")
+       end
+       
+       # Find number of bits required to store arbitrary-length binary
+       
+       def lengthSB(n)
+               Math.frexp(n+ (n==0?1:0) )[1]+1
+       end
+       
+       # ====================================================================
+       # Co-ordinate conversion
+       # (this is duplicated from amf_controller, should probably share)
+       
+       def lat2coord(a,basey,masterscale)
+               -(lat2y(a)-basey)*masterscale+250
+       end
+       
+       def long2coord(a,baselong,masterscale)
+               (a-baselong)*masterscale+350
+       end
+       
+       def lat2y(a)
+               180/Math::PI * Math.log(Math.tan(Math::PI/4+a*(Math::PI/180)/2))
+       end
+
+       def sqlescape(a)
+               a.gsub("'","''").gsub(92.chr,92.chr+92.chr)
+       end
+
+end
diff --git a/app/helpers/swf_helper.rb b/app/helpers/swf_helper.rb
new file mode 100644 (file)
index 0000000..cf2a311
--- /dev/null
@@ -0,0 +1,2 @@
+module SwfHelper
+end
index 20b049198f912e662db4119f94e149f3d66e6192..e1ef556e07fa59c04af1f3ec0c9198f72ed0ab8b 100644 (file)
@@ -1,7 +1,7 @@
-<p>This editor isn't working yet - currently you can only browse the aerial photos.
+<!-- <p>This editor isn't working yet - currently you can only browse the aerial photos.
 See <a href="http://trac.openstreetmap.org/ticket/402">Trac #402</a> for more details.
 You may also want to look at <a href="http://josm.eigenheimstrasse.de/">JOSM</a> for a
-fully functional desktop client editor for Open Street Map.</p>
+fully functional desktop client editor for OpenStreetMap.</p> -->
 
 <div id="mapcontent">You need a Flash player to use Potlatch, the
     OpenStreetMap Flash editor. You can <a href="http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">download Flash Player from Adobe.com</a>.
@@ -18,8 +18,8 @@ fully functional desktop client editor for Open Street Map.</p>
       fo.addVariable('token','<%= @user.token %>');
       fo.write("mapcontent");
     }
-<% lon =  params['lon'] || '-0.1' %>
-<% lat =  params['lat'] || '51.5' %>
+<% lon =  params['lon'] || @user.home_lon || '-0.1' %>
+<% lat =  params['lat'] || @user.home_lat || '51.5' %>
 
     doSWF(<%= lat %>,<%= lon %>,12);
 
index 941991cdc525854f8cac110231de1e1d14615897..4f887d140c46beb761489da9bbb0708cda6ec20b 100644 (file)
@@ -36,6 +36,7 @@ ActionController::Routing::Routes.draw do |map|
   # Potlatch API
   
   map.connect "api/#{API_VERSION}/amf", :controller =>'amf', :action =>'talk'
+  map.connect "api/#{API_VERSION}/swf/trackpoints", :controller =>'swf', :action =>'trackpoints'
   
   # web site
 
index 77b38014dca491803cb442ca0d8222df1bbcce08..bb0dd646a0699634e28706013ef93b6cf31c0cdc 100755 (executable)
Binary files a/public/potlatch/potlatch.swf and b/public/potlatch/potlatch.swf differ