From 30ac98deefac506932b546d7711df79effdc55c7 Mon Sep 17 00:00:00 2001 From: Richard Fairhurst Date: Sat, 21 Jul 2007 21:07:40 +0000 Subject: [PATCH] experimental 'make ways out of unwayed segments' feature --- app/controllers/amf_controller.rb | 148 +++++++++++++++++++++++++++--- public/potlatch/potlatch.swf | Bin 55949 -> 56470 bytes 2 files changed, 135 insertions(+), 13 deletions(-) diff --git a/app/controllers/amf_controller.rb b/app/controllers/amf_controller.rb index 18a1c6346..b318e3eef 100644 --- a/app/controllers/amf_controller.rb +++ b/app/controllers/amf_controller.rb @@ -39,6 +39,7 @@ class AmfController < ApplicationController when 'getway'; results[index]=putdata(index,getway(args)) when 'putway'; results[index]=putdata(index,putway(args)) when 'deleteway'; results[index]=putdata(index,deleteway(args)) + when 'makeway'; results[index]=putdata(index,makeway(args)) end end @@ -62,8 +63,8 @@ class AmfController < ApplicationController # ==================================================================== # Remote calls - # ----- getpresets - # return presets,presetmenus and presetnames arrays + # ----- getpresets + # return presets,presetmenus and presetnames arrays def getpresets presets={} @@ -166,10 +167,10 @@ EOF return [presets,presetmenus,presetnames] end - # ----- whichways(left,bottom,right,top) - # return array of ways in current bounding box - # at present, instead of using correct (=more complex) SQL to find - # corner-crossing ways, it simply enlarges the bounding box by +/- 0.01 + # ----- whichways(left,bottom,right,top) + # return array of ways in current bounding box + # at present, instead of using correct (=more complex) SQL to find + # corner-crossing ways, it simply enlarges the bounding box by +/- 0.01 def whichways(args) xmin = args[0].to_f-0.01 @@ -205,9 +206,9 @@ EOF return [ways,points] end - # ----- getway (objectname, way, baselong, basey, masterscale) - # returns objectname, array of co-ordinates, attributes, - # xmin,xmax,ymin,ymax + # ----- getway (objectname, way, baselong, basey, masterscale) + # returns objectname, array of co-ordinates, attributes, + # xmin,xmax,ymin,ymax def getway(args) objname,wayid,baselong,basey,masterscale=args @@ -322,17 +323,22 @@ EOF from =points[i ][2].to_i to =points[i+1][2].to_i if seg.has_key?(segid) + # if segment exists, check it still refers to the same nodes if seg[segid]=="#{from}-#{to}" then if (seglist!='') then seglist+=',' end; seglist+=segid.to_s next end + elsif segid>0 + # not in previous version of way, but supplied, so assume + # that it's come from makeway (i.e. unwayed segments) + if (seglist!='') then seglist+=',' end; seglist+=segid.to_s + next end segid=ActiveRecord::Base.connection.insert("INSERT INTO current_segments ( node_a,node_b,timestamp,user_id,visible,tags) VALUES ( #{from},#{to},#{db_now},#{uid},1,'')") ActiveRecord::Base.connection.insert("INSERT INTO segments (id,node_a,node_b,timestamp,user_id,visible,tags) VALUES (#{segid},#{from},#{to},#{db_now},#{uid},1,'')") points[i+1][5]=segid numberedsegments[(i+1).to_s]=segid.to_s end - # numberedsegments.each{|a,b| RAILS_DEFAULT_LOGGER.error("Sending back: seg no. #{a} -> id #{b}") } # -- 6.ii insert new way segments @@ -484,6 +490,122 @@ EOF way end +# ----- makeway(x,y,baselong,basey,masterscale) +# returns way made from unwayed segments + +def makeway(args) + x,y,baselong,basey,masterscale=args + points=[] + nodesused={} # so we don't go over the same node twice + + # - find start point near x + + xc=coord2long(x,masterscale,baselong) + yc=coord2lat(y,masterscale,basey) + xs1=xc-0.001; xs2=xc+0.001 + ys1=yc-0.001; ys2=yc+0.001 + + sql=<<-EOF + SELECT cn1.latitude AS lat1,cn1.longitude AS lon1,cn1.id AS id1, + cn2.latitude AS lat2,cn2.longitude AS lon2,cn2.id AS id2, cs.id AS segid + FROM current_nodes AS cn1, + current_nodes AS cn2, + current_segments AS cs + LEFT OUTER JOIN current_way_segments ON segment_id=cs.id + WHERE (cn1.longitude BETWEEN #{xs1} AND #{xs2}) + AND (cn1.latitude BETWEEN #{ys1} AND #{ys2}) + AND segment_id IS NULL + AND cn1.id=node_a AND cn1.visible=1 + AND cn2.id=node_b AND cn2.visible=1 + ORDER BY SQRT(POW(cn1.longitude-#{xc},2)+ + POW(cn1.latitude -#{yc},2)) + LIMIT 1 + EOF + row=ActiveRecord::Base.connection.select_one sql + if row.nil? then return [0,0,0,0,0] end + xs1=long2coord(row['lon1'].to_f,baselong,masterscale); ys1=lat2coord(row['lat1'].to_f,basey,masterscale) + xs2=long2coord(row['lon2'].to_f,baselong,masterscale); ys2=lat2coord(row['lat2'].to_f,basey,masterscale) + xmin=[xs1,xs2].min; xmax=[xs1,xs2].max + ymin=[ys1,ys2].min; ymax=[ys1,ys2].max + nodesused[row['id1'].to_i]=true + nodesused[row['id2'].to_i]=true + points<<[xs1,ys1,row['id1'].to_i,1,{},0] + points<<[xs2,ys2,row['id2'].to_i,1,{},row['segid'].to_i] + + # - extend at start, then end + while (a,point,nodesused=findconnect(points[0][2],nodesused,'b',baselong,basey,masterscale))[0] + points[0][5]=point[5]; point[5]=0 # segment leads to next node + points.unshift(point) + xmin=[point[0],xmin].min; xmax=[point[0],xmax].max + ymin=[point[1],ymin].min; ymax=[point[1],ymax].max + end + while (a,point,nodesused=findconnect(points[-1][2],nodesused,'a',baselong,basey,masterscale))[0] + points.push(point) + xmin=[point[0],xmin].min; xmax=[point[0],xmax].max + ymin=[point[1],ymin].min; ymax=[point[1],ymax].max + end + points[0][3]=0 # start with a move + + [points,xmin,xmax,ymin,ymax] +end + +def findconnect(id,nodesused,lookfor,baselong,basey,masterscale) + # get all segments with 'id' as a point + # (to look for both node_a and node_b, UNION is faster than node_a=id OR node_b=id)! + sql=<<-EOF + SELECT cn1.latitude AS lat1,cn1.longitude AS lon1,cn1.id AS id1, + cn2.latitude AS lat2,cn2.longitude AS lon2,cn2.id AS id2, cs.id AS segid + FROM current_nodes AS cn1, + current_nodes AS cn2, + current_segments AS cs + LEFT OUTER JOIN current_way_segments ON segment_id=cs.id + WHERE segment_id IS NULL + AND cn1.id=node_a AND cn1.visible=1 + AND cn2.id=node_b AND cn2.visible=1 + AND node_a=#{id} + UNION + SELECT cn1.latitude AS lat1,cn1.longitude AS lon1,cn1.id AS id1, + cn2.latitude AS lat2,cn2.longitude AS lon2,cn2.id AS id2, cs.id AS segid + FROM current_nodes AS cn1, + current_nodes AS cn2, + current_segments AS cs + LEFT OUTER JOIN current_way_segments ON segment_id=cs.id + WHERE segment_id IS NULL + AND cn1.id=node_a AND cn1.visible=1 + AND cn2.id=node_b AND cn2.visible=1 + AND node_b=#{id} + EOF + connectlist=ActiveRecord::Base.connection.select_all sql + + if lookfor=='b' then tocol='id1'; tolat='lat1'; tolon='lon1'; fromcol='id2' + else tocol='id2'; tolat='lat2'; tolon='lon2'; fromcol='id1' + end + + # eliminate those already in the hash + connex=0 + point=nil + connectlist.each { |row| + tonode=row[tocol].to_i + fromnode=row[fromcol].to_i + if id==tonode and !nodesused.has_key?(fromnode) + connex+=1 + nodesused[fromnode]=true + elsif id==fromnode and !nodesused.has_key?(tonode) + connex+=1 + point=[long2coord(row[tolon].to_f,baselong,masterscale),lat2coord(row[tolat].to_f,basey,masterscale),tonode,1,{},row['segid'].to_i] + nodesused[tonode]=true + end + } + + # if only one left, then add it; otherwise return false + if connex!=1 or point.nil? then + return [false,[],nodesused] + else + return [true,point,nodesused] + end +end + + # ==================================================================== # Support functions for remote calls @@ -631,9 +753,9 @@ def getvalue(s) when 5; return nil # null when 6; return nil # undefined when 8; s.read(4) # mixedArray - return getobject(s) # | - when 10;return getarray(s) # array - else; return nil # error + return getobject(s) # | + when 10; return getarray(s) # array + else; return nil # error end end diff --git a/public/potlatch/potlatch.swf b/public/potlatch/potlatch.swf index 9b44586b481e03de8e97b71b0b9d00b47b10c638..f936f7321fe86ab8d1312f3adb98e5c2a22b9870 100755 GIT binary patch delta 13950 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 A?f?J) -- 2.43.2