From: ······@gmail.com
Subject: Elisp Tutorial: Make Google Earth
Date: 
Message-ID: <1166046616.138321.213250@l12g2000cwl.googlegroups.com>
Elisp Tutorial: Make Google Earth

Xah Lee, 2006-12

This page shows a example of writing a emacs lisp function that creates
a Google Earth file, and creates a link to the file, as well a link to
Google Map. If you don't know elisp, first take a gander at Elisp
Basics.

I often write travelogs on my website. If i traveled to Las Vegas, then
my Las Vegas travelog page will have a link to Google Map location of
Las Vegas. Like this:

<p>
<a
href="http://maps.google.com/maps?z=15&amp;q=36.1027,-115.1730&amp;t=k"
title="Las Vegas">Google Map↗</a>
</p>

The above would display in browser like this:
Google Map↗

It is tedious to type all these characters to create a link, if i need
to do it for many different cities. It would be nice, if all i have to
do is to press a button and have the entire link inserted for me, then
all i have to do is to edit the latitude and longitude part, and the
title part. This is easily done in emacs!

The following elisp function will insert the Google Map link:

(defun insert-google-map-link ()
"Inserts html link markup for Google Map location."
(interactive)
(insert "<p>
<a href=\"http://maps.google.com/maps?z=11&q=ttt&t=k\" title=\"ttt\">
Google Map↗</a>
</p>")
(re-search-backward "ttt" nil t)
)

Now, on my web site i also want to have a Google Earth file of the
location. For example, in the HTML file i would have the following
code:

<p>
<img src="http://xahlee.org/Icons_dir/google_earth.png" alt="">
<a href="las_vegas.kml" title="Las Vegas">Google Earth file</a>
</p>

The above would display in browser like this:
Google Earth file

Then, i create the file las_vegas.kml, having this content:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Placemark>
  <name>Las Vegas</name>
  <description>Good for a visit!</description>
  <Point>
   <coordinates>-115.1730,36.1027,1000</coordinates>
  </Point>
 </Placemark>
</kml>

It easy to write a elisp function “insert-google-earth-link” that
will insert the link for me.

It is also easy to write a function “insert-kml-template” that
inserts the Google Earth KML template.

So, now the procedure to create a Google Map and Google Earth of Las
Vegas is:

   1. Use “insert-google-map-link”, then go edit the coordinates
and title.
   2. Use “insert-google-earth-link”, then go edit the coordinates,
title, and file name.
   3. Create a file.
   4. Use “insert-kml-template” to insert the XML template.
   5. Edit the coordinate and the title in the template.
   6. Save the file.

As you can see, this is becoming tedious. If you are writing a travelog
on your website and needs to place many Google Maps and Google Earth
for various locations, going through the above process is no fun.

As we can see, coordinates and names are manually entered repeatedly.
It would be nice, if we can type out the city's name, the coordinates,
and file name, and press a button, and have emacs create the Google Map
link, Google Earth link, as well as the Google Earth KML file. For
example, for the city Las Vegas, will have this block of text:

Las Vegas
36.1027,-115.1730
Las_Vegas.kml

Then, move the cursor somewhere in that block. Execute the function
google-earth, and emacs will insert the Google Map link, Google Earth
link, and create the Google Earth file as well.

We proceed to write this function.

First, we write a documentation for the function so that we know
precisely what we want.

(defun google-earth ()
"Create a Google Earth file and link.\n
The cursor must be on 3 lines separated by empty lines.
The lines are:

Name
Coordinate
file path (relative to the current file)

For Example:

Las Vegas
36.1027,-115.1730
Las_Vegas.kml

google-earth will create the KML file and with proper html link
to it in the current file."
(interactive)
)

The first step in implementing this function, is to have a code that
grab the 3 lines and store them as values in variables.

After coding this for a while, i realized that its probably better to
write a stand-along function to do this, since turning lines into
values stored in variables can be useful for other programs. Here's our
code:

(defun grab-lines (n)
"Delete the next n lines and return a list
where each element is a line."
(interactive)
(move-beginning-of-line 1)
(let (t1 t2 cl (lns '()))
  (dotimes (x n)
    (progn
      (setq t1 (point))
      (move-end-of-line nil)
      (setq t2 (point))
      (setq cl (buffer-substring-no-properties t1 t2))
      (delete-region t1 t2)
      (delete-char 1)
      (push cl lns)
      )
    )
  (setq lns (reverse lns))
;  (prin1 lns (current-buffer)) ; print result for testing purposes
))

In the above code, variables t1 and t2 are temp vars used to store
positions for the beginning of line and ending of line. cl is a temp
variable that stores the current line. “lns” is a temp var that
stores the final list. The whole code is a simple loop and is easy to
understand.

For example, you can test this code on the following lines

(grab-lines 4)
line1
line2
line3

Now, we write the insert-google-earth-link.

(defun insert-google-earth-link
  (&optional title file-path)
  "Inserts HTML markup for Google Earth."
(interactive)
(if title
  (progn (setq title2 title) (setq file-path2 file-path))
  (progn (setq title2 "ttt") (setq file-path2 "ttt"))
)
(insert "<div style=\"display:table;background-color:cornsilk\">
<img src=\"../../Icons_dir/google_earth.png\" alt=\"\">
<a href=\"" file-path2 "\" title=\"" title2 "\">Google Earth file</a>
</div>")
)

Note the optional argument “title” and “file-path”. So that, if
called by a program and these are given, then a complete link with
title and file path will be inserted. If called interactively, dummy
text “ttt” is used for places the user need to fill in.

(We could write it so that it prompts user for input, but i find such
interactive program less convenient to use.)

Now, we write a function to insert the Google Earth KML template. Like
before, we use several optional parameters.

(defun insert-kml (&optional title latti longi)
"Inserts a dummy Google Earth KML markup."
(interactive)
(let (title2 latti2 longi2)
  (if title ; if optional args not given, set them to dummy text
      (progn
        (setq title2 title)
        (setq latti2 latti)
        (setq longi2 longi)
      )
    (progn
      (setq title2 "ttt")
      (setq latti2 "ttt")
      (setq longi2 "ttt")
    )
  )
(insert "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<kml xmlns=\"http://earth.google.com/kml/2.1\">
<Placemark>
  <name>" title2 "</name>
  <description>Good for a visit.</description>
  <Point>
   <coordinates>" longi2 "," latti2 "</coordinates>
  </Point>
 </Placemark>
</kml>")
)
)

Finally, we have all our auxiliary components we need, we can go head
and define our google-earth.

(defun google-earth ()
"Create a Google Earth file and link.\n
The cursor must be on 3 lines separated by empty lines.
The lines are:

Name
Coordinate
file path (relative to the current file)

For Example:

Altamount Pass Wind Farm
37.7497,-121.6832
livermore/Altamount_Pass_Wind_Farm.kml

google-earth will create the kml file and with proper html link
to it in the current file."
(interactive)
(search-backward "\n\n")
(search-forward "\n\n")
(let (title latlon file-path sl vl latti longi)

  (setq sl '(title latlon file-path))
  (setq vl (grab-lines 3))
  (while sl (set (pop sl) (pop vl) ) )

  (setq sl '(latti longi))
  (setq vl (split-string latlon ","))
  (while sl (set (pop sl) (pop vl) ) )

  (insert-google-map-link title latlon)
  (insert-google-earth-link title file-path)
  (find-file file-path)
  (insert-kml title latti longi)
  (html-mode)
  (save-buffer)
  )
)

In this code, first we call “(search-backward "\n\n") (search-forward
"\n\n")”. What these do is to move the cursor to the beginning of a
text block, which is right after two blank lines.

Then, we define our temp vars. Here's what they mean:

“title” is the title of the Google Map/Earth. e.g. Las Vegas.

“latlon” is the lattitude and longitude string, string. e.g.
37.7497,-121.6832.

“file-path” is the file path to the Google Earth KML file.

“sl” and “vl” are temp vars. “sl” stands for symbols list,
and “vl” stands for value list. They are used to assign a list of
values to variables.

“latti” and “longi” and lattitudes and longitudes.

Now, in this block of code:

  (setq sl '(title latlon file-path))
  (setq vl (grab-lines 3))
  (while sl (set (pop sl) (pop vl) ) )

We set sl to be a list of variable symbols. Then, we use grab-lines to
get a list of values. The while function assigns the variables.

Then, we do the same by splitting the latitude and longitude string
into separate variables and store them in latti and longi.

The rest of the code is trivial. We call insert-google-map-link to
insert the Google Map link with proper fillers. We call
insert-google-earth-link too. These will insert the Google Map link and
the Google Earth link. We then call find-file to generate a new file,
insert-kml to insert the KML template with proper fillers, then we make
the buffer html-mode and save it.

If we want, we can close the buffer. But we want to leave it open so
that the user might want to add descriptions for the KML file.

So now, we have a elisp function, that we can assign to a keystroke.
Upon a press of button, it saves us a few hundreds of tedious
error-prone keystrokes and file managing process.

Emacs is Beautiful.

----
This post is archived at
http://xahlee.org/emacs/google-earth.html

  Xah
  ···@xahlee.org
∑ http://xahlee.org/
From: Harlan Messinger
Subject: Re: Elisp Tutorial: Make Google Earth
Date: 
Message-ID: <4ubb1oF171egqU1@mid.individual.net>
This is off-topic in c.i.w.a.h.