From mboxrd@z Thu Jan 1 00:00:00 1970 From: Sebastian Rose Subject: Advice needed. Use links or blocks? Date: Fri, 03 Sep 2010 02:28:38 +0200 Message-ID: <878w3jzn49.fsf@gmx.de> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from [140.186.70.92] (port=39717 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OrK9D-0005se-MR for emacs-orgmode@gnu.org; Thu, 02 Sep 2010 20:28:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OrK9C-0001Tn-DG for emacs-orgmode@gnu.org; Thu, 02 Sep 2010 20:28:51 -0400 Received: from mailout-de.gmx.net ([213.165.64.22]:40434 helo=mail.gmx.net) by eggs.gnu.org with smtp (Exim 4.69) (envelope-from ) id 1OrK9C-0001TT-1i for emacs-orgmode@gnu.org; Thu, 02 Sep 2010 20:28:50 -0400 List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Emacs-orgmode mailing list --=-=-= Hi experts, the attached file fetches background tiles from openstreetmap.org for me, and produces SVG images of tracks I ran. Unfortunately, I cannot find a good way to use that code in an automated way. What I'd like to do, is to have the coords in my training diary, and produce the images on demand. When I publish the diary to HTML, I want the coords to be replaced with a link to the image. Here is an example of the coords (just two), as I save them in my diary: '((9.707136154065665 52.3705158282501)(9.711406230817374 52.37525815071791)) And this is, how the function to produce the images is used: (osm-draw-track ;; Fantasy-track in Brisbane: '((152.968 -27.533) (152.968 -27.546) (152.974 -27.537)) "Track_in_Brisbane" 8) Should I go for a special link type: [[track:((152.968 -27.533) (152.968 -27.546))][2010-09-03 in Brisbane]] ?? Right now, I produce a lisp file, that produces all those images using `osm-draw-tracks' and add simple links. But this is inconvenient and prone to error (forgotten tracks)... Sebastian --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=osm-maps.el Content-Transfer-Encoding: quoted-printable ;;; ;; osm-maps.el ;; ;; Author and Copyright (c) 2010 Sebastian Rose, Hannover, Germany, sebasti= an_rose@gmx.de ;; ;; Contact: ;; ;; Phone: +49 (0) 173 - 83 93 4 17 ;; Email: sebastian_rose@gmx.de ;; ;; Released under the GNU General Public License version 3 ;; see: http://www.gnu.org/licenses/gpl-3.0.html ;;; (defcustom osm-default-zoom 15 "Default zoom level.") (defcustom osm-default-cache-directory "~/.emacs.d/osm" "Directory for the osm tile tree. Set this to nil, to use online map tiles on demand.") (defcustom osm-margin 5 "Minimum distance of trackpoints from the edge of a map. This will be multiplied with the zoom level. Hence 0 means no margin.") (defconst osmMaxLatitude 85.05112877 "Polar areas with abs(latitude) bigger then 85.05112877 are clipped off.") (defvar osm-hosts (list "a" "b" "c") "List of hosts to get tiles from. We balance the load on OSM servers.") (defvar osm-host 0 "Current offset in osm-hosts.") (defun osm-yx-to-xy-lol (lol) "Some application return lists with the values swapped: ((y1 x1) (y2 x2) ... ). This functions turnes them into proper ((x1 y1) (x2 y2) ... ) lists. All osm functions expect the latter format." (setq lol (mapcar 'reverse lol))) (defun osm-new-tile (x y z) "Return a new tile as used throughout this file. A tile is a list (x y z url path). Either url or path is nil, depending on wether the tile is cached on disk or not." (let ((cfile (osm-cache-file-name x y z))) (if (file-exists-p cfile) (list x y z nil cfile) (list x y z (osm-url-for-tile x y z) nil)))) (defun osm-url-for-tile (x y z) "Build the URL for a tile with coords X Y and Z." (setq osm-host (% (+ 1 osm-host) 3)) (concat "http://" (nth osm-host osm-hosts) ".tile.openstreetmap.org/" (number-to-string z) "/" (number-to-string x) "/" (number-to-string y) ".png")) (defun osm-cache-file-name (x y z) "Build the file name of a tiles cache file." (concat (file-name-as-directory osm-default-cache-directory) (number-to-string z) "/" (number-to-string x) "/" (number-to-string y) ".png")) (defun osm-area-file-name (x y w h &optional zoom) "Build the file name of the background for an area denoted by X, Y, W, H and ZOOM (all integers) sans extension. X and Y denote the upper left corner in OSM tiles, W and H the width and height in tiles respectively." (let ((z (or zoom osm-default-zoom))) (format "%s%d/area-%d-%d-%d-%d" (file-name-as-directory osm-default-cache-directory) z x y w h))) (defun osm-fetch-tile (x y z) "Fetch a tile from an OpenStreetmap server. Return the absolut path to the image file or nil if `osm-default-cache-directory' is nil." (if osm-default-cache-directory (let* ((target-file (osm-cache-file-name x y z)) (target-dir (file-name-directory target-file))) (make-directory target-dir t) (when (not (file-directory-p target-dir)) (error "OSM: Cannot create directory: %s" target-dir)) (unless (file-exists-p target-file) (url-copy-file (osm-url-for-tile x y z) target-file t)) target-file) nil)) (defun osm-fetch-area (min-x min-y max-x max-y &optional zoom) "Fetch tiles for an entire area. MIN-X, MIN-Y, MAX-X, MAX-Y and ZOOM must be positive integer values." (let ((x min-x) ;; FIXME: check for valid input (y min-y) ;; FIXME: check for valid input (z (or zoom osm-default-zoom)) (fetched 0)) (while (<=3D y max-y) (setq x min-x) (while (<=3D x max-x) (osm-fetch-tile x y z) (setq fetched (+ 1 fetched)) (setq x (+ 1 x))) (setq y (+ 1 y))) (message "Successfully fetched %s tiles." fetched))) (defun osm-zoom (val z &optional new-z) "Zoom a value. VAL could be a tile number (x or y) or a Pixel. If NEW-Z is provided, assume VAL is in Z and zoom to NEW-Z. Otherwise zoom by Z levels, where negative Z zooms out. The return value is always an integer." (if new-z (lsh val (- new-z z)) (lsh val z))) (defun osm-compose-area-background (min-x min-y max-x max-y &optional zoom) "Compose a background PNG image (i.e. a map) for an area. MIN-X, MIN-Y, MAX-X, MAX-Y and ZOOM must be positive integer values. They denote the row and column minimum and maximum values of the area to fetch. If FILE is supplied, write the result to file FILE. Returns the path to the resulting image PNG file. Montage needs imageMagick to be installed, so that montage is found in $PATH. Deprecated." (let* ((x min-x) ;; FIXME: check for valid input (y min-y) ;; FIXME: check for valid input (w (+ 1 (- max-x min-x))) ;; FIXME: check for valid input (h (+ 1 (- max-y min-y))) ;; FIXME: check for valid input (z (or zoom osm-default-zoom)) (command (executable-find "montage")) (target (concat (osm-area-file-name x y max-x max-y z) ".png")) ) (unless (and command (file-executable-p command)) (error "%s%s%s" "Trying to execute " command "! Is it installed?")) (osm-fetch-area min-x min-y max-x max-y zoom) (while (<=3D y max-y) (setq x min-x) (while (<=3D x max-x) (setq command (concat command " " (osm-cache-file-name x y z))) (setq x (+ 1 x))) (setq y (+ 1 y))) (message "%s" (format "%s -geometry +0+0 -tile %dx%d %s" command w h target)) (shell-command (format "%s -geometry +0+0 -tile %dx%d %s" command w h target)) target )) (defun osm-longitude-to-x (longitude zoom) "Return the x value in pixels from the date line for a certain latitude." ;; TODO: cache the basic values for each zoom factor. (let* ((z (or zoom osm-default-zoom)) (ntiles (lsh 1 z)) ;; circumference of our pixel world: ;; (circ (lsh 1 (+ z 8))) (circ (lsh ntiles 8)) (greenwich (lsh circ -1)) (pixel (floor (+ greenwich (* (/ circ 360) longitude))))) pixel)) (defun osm-latitude-to-y (latitude zoom) "Return the y value in pixels (offset) from the northpole and the y-number of the tile that pixel is found on as '(pixel tileY)." ;; TODO: cache the basic values for each zoom factor. ;; Polar areas with abs(latitude) bigger then 85.05112877 are clipped off. (when (> (abs latitude) osmMaxLatitude) (if (> latitude 0) (progn (message "Latitude %s out of bounds! Using %s, i.e. the maximum." latitude osmMaxLatitude) (setq latitude osmMaxLatitude)) (message "Latitude %s out of bounds! Using %s, i.e. the minimum." latitude (- osmMaxLatitude)) (setq latitude (- osmMaxLatitude)))) (let* ((equator (lsh 128 z)) ; BEFORE we change the zoom (z (or (- zoom 1) (- osm-default-zoom))) (r (/ equator pi)) (north (> latitude 0)) ; Negative latitudes are on the southern he= misphere! (lat (degrees-to-radians (abs latitude))) ret) (setq ret (* (/ r 2.0) (log (/ (+ 1.0 (sin lat)) (- 1.0 (sin lat)))))) (if north (floor (- equator ret)) (floor (+ equator ret))) )) (defun osm-column-for-x (x zoom) "Return the column index that contains X (a pixel)." (lsh x -8)) (defun osm-row-for-y (y zoom) "Return the column index that contains Y (a pixel)." (lsh y -8)) (defun osm-draw-track (points &optional file-name zoom) "Draw a track. POINTS is a list of `(longitude latitude elevation)' elements. The elevation is optional (and not yet implemented). If FILE-NAME is nil, create a file in `default-directory'. The basename of that file will be made up from the x and y values of the background tiles. If FILE-NAME is a string, use that as file name. If absolute, use the provided path, else create the image relative to the current `default-directory'." (let ((minx 360.0) (maxx 0.0) (miny 90.0) (maxy 0.0) (z (or zoom osm-default-zoom)) (margin (* zoom osm-margin)) (defdir default-directory) tmp target x y w h cmin cmax rmin rmax ) (mapc (lambda (p) (and (< (car p) minx) (setq minx (car p))) (and (> (car p) maxx) (setq maxx (car p))) (and (< (abs (cadr p)) miny) (setq miny (cadr p))) (and (> (abs (cadr p)) maxy) (setq maxy (cadr p)))) points) (message "minx maxx miny maxy: %s %s %s %s" minx maxx miny maxy) ;; Get the map x and y values for GPS-values: (setq minx (osm-longitude-to-x minx z)) (setq maxx (osm-longitude-to-x maxx z)) (setq miny (osm-latitude-to-y miny z)) (setq maxy (osm-latitude-to-y maxy z)) (message "minx maxx miny maxy: %s %s %s %s" minx maxx miny maxy) ;; Swap y values (southern hemisphere yield negative latitudes): (when (< maxy miny) (setq tmp maxy) (setq maxy miny) (setq miny tmp)) ;; Add the margin: (setq minx (- minx (* osm-margin z))) (setq maxx (+ maxx (* osm-margin z))) (setq miny (- miny (* osm-margin z))) (setq maxy (+ maxy (* osm-margin z))) ;; Now get the tiles we need (rows and columns): (setq cmin (osm-column-for-x minx z)) (setq cmax (osm-column-for-x maxx z)) (setq rmin (osm-row-for-y miny z)) (setq rmax (osm-row-for-y maxy z)) (message "cmin cmax rmin rmax: %s %s %s %s" cmin cmax rmin rmax) (setq target (concat (if (stringp file-name) (if (file-name-absolute-p file-name) file-name (concat defdir file-name)) (if osm-default-cache-directory (osm-area-file-name cmin rmin cmax rmax z) (concat defdir (file-name-nondirectory (osm-area-file-name cmin rmin cmax rmax z))))) ".svg")) ;; Ensure we have the tiles: (osm-fetch-area cmin rmin cmax rmax z) ;; Create SVG file and draw the track on it: (setq w (lsh (+ 1 (- cmax cmin)) 8) h (lsh (+ 1 (- rmax rmin)) 8)) (let ((ama auto-mode-alist)) (setq auto-mode-alist nil) (with-temp-buffer (write-file target t) (fundamental-mode) (insert "\n" "\n" "\n" " \n") (setq y rmin) (while (<=3D y rmax) (setq x cmin) (while (<=3D x cmax) (setq tmp (if osm-default-cache-directory (concat "file://" (expand-file-name (osm-fetch-tile x y z))) (osm-url-for-tile x y z))) (insert " \n") (setq x (+ x 1))) (setq y (+ y 1))) ;; Draw the track (insert " \n") (insert " \n" "\n") ;; We copy the file, to circumvent the delay produced by image mode= , if ;; tiles on the server are used. (save-buffer 0) ) ; end with-temp-buffer (setq auto-mode-alist ama)) target )) (defun osm-draw-tracks (track-list &optional zoom) "Draw tracks." (let ((z (or zoom osm-default-zoom)) (image-list nil)) (mapc (lambda (track) (push (osm-draw-track (car track) (cadr track) z) image-list)) track-list) image-list)) (provide 'osm-maps) --=-=-= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Emacs-orgmode mailing list Please use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode --=-=-=--