lots of rails gpx stuff
authorSteve Coast <steve@asklater.com>
Fri, 1 Dec 2006 20:38:29 +0000 (20:38 +0000)
committerSteve Coast <steve@asklater.com>
Fri, 1 Dec 2006 20:38:29 +0000 (20:38 +0000)
app/controllers/trace_controller.rb
app/models/tracepoint.rb
app/views/trace/_trace.rhtml
app/views/trace/view.rhtml [new file with mode: 0644]
config/routes.rb
lib/daemons/gpx_import.rb
lib/osm.rb

index c8b33060134f319224ac2c0cec6267752d7bfacc..06db32248229e3b139927f7a3b966ed5f7ecd02d 100644 (file)
@@ -10,6 +10,11 @@ class TraceController < ApplicationController
     @traces = Trace.find(:all, :conditions => ['user_id = ?', @user.id])
   end
 
+  def view
+    @trace = Trace.find(params[:id])
+    render :nothing, :status => 401 if @trace.user.id != @user.id
+  end
+
   def create
     filename = "/tmp/#{rand}"
 
@@ -28,4 +33,15 @@ class TraceController < ApplicationController
 
     redirect_to :action => 'mine'
   end
+
+  def picture
+    trace = Trace.find(params[:id])
+    send_data(trace.large_picture, :filename => "#{trace.id}.gif", :type => 'image/png', :disposition => 'inline') if trace.public
+  end
+
+  def icon
+    trace = Trace.find(params[:id])
+    send_data(trace.icon_picture, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline') if trace.public
+  end
+
 end
index 9de8dc548a04ece9a2b5642cbe8feb685fab2bab..dd75ce0e95f104f96d831ca5880e55cf66d96640 100644 (file)
@@ -1,8 +1,8 @@
 class Tracepoint < ActiveRecord::Base
   set_table_name 'gps_points'
 
-  validates_numericality_of :latitude
-  validates_numericality_of :longitude
+#  validates_numericality_of :latitude
+#  validates_numericality_of :longitude
 
   belongs_to :user
   belongs_to :trace, :foreign_key => 'gpx_id'
index 73fb5080ccc1f9b803a7c03abad456a7282543a9..f7ea77219d3544392be03417c3748fc6a3eb4848 100644 (file)
@@ -1,6 +1,12 @@
 <tr>
   <% cl = cycle('table0', 'table1') %>
-  <td class="<%= cl %>">image here</td>
+  <td class="<%= cl %>">
+    <% if trace.inserted %>
+    <a href="<%= url_for :controller => 'trace', :action => 'view', :id => trace.id, :user_login => trace.user.display_name %>">
+      <img src="<%= url_for :controller => 'trace', :action => 'icon', :id => trace.id, :user_login => trace.user.display_name %>" border="0">
+    </a>
+    <% end %>
+  </td>
   <td class="<%= cl %>"><%= link_to trace.name, {:controller => 'trace', :action => 'onetrace', :id => trace.id} %>
     <span class="gpxsummary" title="<%= trace.timestamp %>"> ... 
       <% if trace.inserted %> 
diff --git a/app/views/trace/view.rhtml b/app/views/trace/view.rhtml
new file mode 100644 (file)
index 0000000..28ef095
--- /dev/null
@@ -0,0 +1,15 @@
+trace <%= @trace.name %>
+<br>
+icon <img src="<%= url_for :controller => 'trace', :action => 'icon', :id => @trace.id, :user_login => @trace.user.display_name %>" border="0">
+<br>
+
+picture <img src="<%= url_for :controller => 'trace', :action => 'picture', :id => @trace.id, :user_login => @trace.user.display_name %>" border="0">
+
+<br>
+time <%= @trace.timestamp %>
+<br>
+dec <%= @trace.description %>
+
+
+
+
index c36984c11c437bf83cde1b347050e228290825f7..bb6da37851f4df938167b894d6b41ebc06fc6dfc 100644 (file)
@@ -28,10 +28,14 @@ ActionController::Routing::Routes.draw do |map|
   map.connect '/logout.html', :controller => 'user', :action => 'logout'
   map.connect '/create-account.html', :controller => 'user', :action => 'new'
   map.connect '/forgot-password.html', :controller => 'user', :action => 'lost_password'
-  
+
+  # traces  
   map.connect '/traces', :controller => 'trace', :action => 'list'
   map.connect '/traces/mine', :controller => 'trace', :action => 'mine'
-  map.connect '/traces/user/:user/:id', :controller => 'trace', :action => 'list', :id => nil
+  map.connect '/traces/user/:user_login/:id', :controller => 'trace', :action => 'view', :id => nil
+  map.connect '/traces/user/:user_login/:id/picture', :controller => 'trace', :action => 'picture', :id => nil
+  map.connect '/traces/user/:user_login/:id/icon', :controller => 'trace', :action => 'icon', :id => nil
 
+  # fall through
   map.connect ':controller/:action/:id'
 end
index 1fc60858a3cebb423fa0aca1f2dc5ebd7e7576f4..70764dd38c8a3f9b23979f6e1ba77aec0a30573a 100755 (executable)
@@ -36,19 +36,34 @@ while($running) do
         gpx.points do |point|
           tp = Tracepoint.new
           tp.latitude = point['latitude']
-          tp.latitude = point['longitude']
+          tp.longitude = point['longitude']
           tp.altitude = point['altitude']
           tp.user_id = trace.user.id
           tp.gpx_id = trace.id
           tp.trackid = point['segment']
-        end 
-        trace.size = gpx.actual_points
-        trace.inserted = true
-        trace.save
-        Notifier::deliver_gpx_success(trace, gpx.possible_points)
+          tp.save!
+        end
+
+        if gpx.actual_points > 0
+          max_lat = Tracepoint.maximum('latitude', :conditions => ['gpx_id = ?', trace.id])
+          min_lat = Tracepoint.minimum('latitude', :conditions => ['gpx_id = ?', trace.id])
+          max_lon = Tracepoint.maximum('longitude', :conditions => ['gpx_id = ?', trace.id])
+          min_lon = Tracepoint.minimum('longitude', :conditions => ['gpx_id = ?', trace.id])
+          #logger.info("bbox: #{min_lat} #{max_lat} #{min_lon} #{max_lon}")
+          trace.large_picture = gpx.get_picture(min_lat, min_lon, max_lat, max_lon, gpx.actual_points)
+          trace.icon_picture = gpx.get_icon(min_lat, min_lon, max_lat, max_lon)
+          trace.size = gpx.actual_points
+          trace.inserted = true
+          trace.save
+          Notifier::deliver_gpx_success(trace, gpx.possible_points)
+        else
+          #trace.destroy
+          Notifier::deliver_gpx_failure(trace, '0 points parsed ok. Do they all have lat,lng,alt,timestamp?')
+        end
+
       rescue Exception => ex
-        trace.destroy
-        Notifier::deliver_gpx_failure(trace, ex.to_s)
+        #trace.destroy
+        Notifier::deliver_gpx_failure(trace, ex.to_s + ex.backtrace.join("\n") )
       end
     end
   end
index af9608132e8f293aa971dbbb8317cbfa93aef99a..f9f77d1b53afc9d3afee19115148a4ff5c2b8f71 100644 (file)
@@ -7,10 +7,58 @@ module OSM
   #
   # gpx = OSM:GPXImporter.new('somefile.gpx')
   # gpx.points {|p| puts p['latitude']}
-  
+
   require 'time'
   require 'rexml/parsers/sax2parser'
   require 'rexml/text'
+  require 'RMagick'
+
+  class Mercator
+    include Math
+
+    def initialize(lat, lon, degrees_per_pixel, width, height)
+      #init me with your centre lat/lon, the number of degrees per pixel and the size of your image
+      @clat = lat
+      @clon = lon
+      @degrees_per_pixel = degrees_per_pixel
+      @width = width
+      @height = height
+      @dlon = width / 2 * degrees_per_pixel
+      @dlat = height / 2 * degrees_per_pixel  * cos(@clat * PI / 180)
+
+      @tx = xsheet(@clon - @dlon)
+      @ty = ysheet(@clat - @dlat)
+
+      @bx = xsheet(@clon + @dlon)
+      @by = ysheet(@clat + @dlat)
+
+    end
+
+    #the following two functions will give you the x/y on the entire sheet
+
+    def kilometerinpixels
+      return 40008.0  / 360.0 * @degrees_per_pixel
+    end
+
+    def ysheet(lat)
+      log(tan(PI / 4 +  (lat  * PI / 180 / 2)))
+    end
+
+    def xsheet(lon)
+      lon
+    end
+
+    #and these two will give you the right points on your image. all the constants can be reduced to speed things up. FIXME
+
+    def y(lat)
+      return @height - ((ysheet(lat) - @ty) / (@by - @ty) * @height)
+    end
+
+    def x(lon)
+      return  ((xsheet(lon) - @tx) / (@bx - @tx) * @width)
+    end
+  end
+
 
   class GPXImporter
     attr_reader :possible_points
@@ -73,5 +121,114 @@ module OSM
       end
       parser.parse
     end
+
+    def get_picture(min_lat, min_lon, max_lat, max_lon, num_points)
+      frames = 10
+      width = 250
+      height = 250
+      rat= Math.cos( ((max_lat + min_lat)/2.0) /  180.0 * 3.141592)
+      proj = OSM::Mercator.new((min_lat + max_lat) / 2, (max_lon + min_lon) / 2, (max_lat - min_lat) / width / rat, width, height)
+
+      images = []
+
+      frames.times do
+        gc =  Magick::Draw.new
+        gc.stroke_linejoin('miter')
+        gc.stroke('#FFFFFF')
+        gc.fill('#FFFFFF')
+        gc.rectangle(0,0,width,height)
+        gc.stroke_width(1)
+        images << gc
+      end
+
+      oldpx = 0.0
+      oldpy = 0.0
+
+      first = true
+
+      m = 0
+      mm = 0
+      points do |p|
+        px = proj.x(p['longitude'])
+        py = proj.y(p['latitude'])
+        frames.times do |n|
+          images[n].stroke_width(1)
+          images[n].stroke('#BBBBBB')
+          images[n].fill('#BBBBBB')
+          images[n].line(px, py, oldpx, oldpy ) unless first
+        end
+        images[mm].stroke_width(3)
+        images[mm].stroke('#000000')
+        images[mm].fill('#000000')
+        images[mm].line(px, py, oldpx, oldpy ) unless first
+
+        m +=1
+        if m > num_points.to_f / frames.to_f * (mm+1)
+          mm += 1
+        end
+        first = false
+        oldpy = py
+        oldpx = px
+      end
+
+      il = Magick::ImageList.new
+
+      frames.times do |n|
+        canvas = Magick::Image.new(width, height) {
+          self.background_color = 'white'
+        }
+        begin
+          images[n].draw(canvas)
+        rescue ArgumentError
+        end
+        canvas.format = 'GIF'
+        il << canvas
+      end
+
+      il.delay = 50
+      il.format = 'GIF'
+      return il.to_blob
+    end
+
+    def get_icon(min_lat, min_lon, max_lat, max_lon)
+      width = 50
+      height = 50
+      rat= Math.cos( ((max_lat + min_lat)/2.0) /  180.0 * 3.141592)
+      proj = OSM::Mercator.new((min_lat + max_lat) / 2, (max_lon + min_lon) / 2, (max_lat - min_lat) / width / rat, width, height)
+
+      images = []
+
+      gc =  Magick::Draw.new
+      gc.stroke_linejoin('miter')
+
+      oldpx = 0.0
+      oldpy = 0.0
+
+      first = true
+
+      gc.stroke_width(1)
+      gc.stroke('#000000')
+      gc.fill('#000000')
+
+      points do |p|
+        px = proj.x(p['longitude'])
+        py = proj.y(p['latitude'])
+        gc.line(px, py, oldpx, oldpy ) unless first
+        first = false
+        oldpy = py
+        oldpx = px
+      end
+
+      canvas = Magick::Image.new(width, height) {
+        self.background_color = 'white'
+      }
+      begin
+        gc.draw(canvas)
+      rescue ArgumentError
+      end
+      canvas.format = 'GIF'
+      return canvas.to_blob
+    end
+
   end
 end