This project has moved. For the latest updates, please go here.

Multiple Points

Jun 14, 2011 at 7:33 PM

The Getting Started example has a very nice example of how to create a KML file with a single placemark.  I can't seem to find any documentation on how to add multiple placemarks to a single KML file.  I've been poking around in the Documentation.chm but am struggling with the fact that there are no examples.

var points = context.GetPoints().ToList();

KmlFile kml;
//WHAT STRUCTURE TO USE

foreach (MapPosition nl in points)
{
   Point point = new Point();
   point.Coordinate = 
        new Vector(nl.Latitude, nl.Longitude);
   Placemark placemark = new Placemark();
   placemark.Geometry = point;
   placemark.Name = nl.Description;
  //How do I add this to the STRUCTURE???

}

kml = KmlFile.Create(WHATGOESHERE, false);
kml.Save("c:\temp.kml");

Coordinator
Jun 14, 2011 at 8:30 PM

The Documentation is mainly for how the library works and assumes knowledge of the KML structure, sorry about the confusion. Looking at the KML Reference we can see both Document and Folder are containers, so in your case you could do something like:

var points = context.GetPoints().ToList();

Document document = new Document();
foreach (MapPosition nl in points)
{
   Point point = new Point();
   point.Coordinate = 
        new Vector(nl.Latitude, nl.Longitude);
   Placemark placemark = new Placemark();
   placemark.Geometry = point;
   placemark.Name = nl.Description;

   document.AddFeature(placemark);
}

// It's conventional for the root element to be Kml,
// but you could use document instead.
Kml root = new Kml();
root.Feature = document;
KmlFile kml = KmlFile.Create(root, false);
Jun 14, 2011 at 8:42 PM

Thank you SO much!  That works perfectly!

Jun 16, 2011 at 10:10 PM
Edited Jun 16, 2011 at 10:11 PM

ok, next question... well, questions actually...

In the example above, we used the KML Engine to create the Kml file with KmlFile.Create.

In the discussion http://sharpkml.codeplex.com/discussions/260359 it looks like you suggested: 

Serializer serializer = new Serializer();
        serializer.Serialize(root);
        Console.WriteLine(serializer.Xml);

Why is this?  Can this file just be saved like the above and sent to Google Earth?  

The reason I ask is that I too am interested in creating dynamic KML files.

I have a database to which lat/long coords are added on a periodic basis.  I would like to create a NetworkLinked (I think this is how it works) KML file (GoogleEarth.kml) which points to a KML file (MyServer.kml) on my server which is updated by a local program, which I have working perfectly thanks to your comment above.  

Do I have the overall process correct, or does the KML with the NetworkLink have to be hosted on a website?

Sorry for the NEWB questions, I'm still learning.

Coordinator
Jun 16, 2011 at 11:26 PM

There's no difference between using a Serializer (or Parser) and using a KmlFile - in fact, the KmlFile class uses the Serializer class:

// KmlFile.cs : Line 246
public void Save(Stream stream)
{
    Serializer serializer = new Serializer();
    serializer.Serialize(this.Root);

    using (var writer = new StreamWriter(stream))
    {
        writer.Write(serializer.Xml);
    }
}

The KmlFile does provide some methods that you might need though, for example, if you are going to use an Update object to add features (via Create) to a container (such as a Folder or Document), then you might want to use the Process extension method (in the SharpKml.Engine namespace) on the Update element, which expects a KmlFile as the parameter so it can find the id of the Feature to change.

What you're planning to do sounds about right: a local file will contain a NetworkLink that points to your file on your server that contains a NetworkLinkControl element with the update information.

Any problems then don't be afraid to ask, as I've not done anything with remote updates so would love to hear how you get on.

Jun 20, 2011 at 7:21 PM

Well, it took a couple hours learning a few things about KML structure, but I got my project working.

What I've learned, not that you don't know it, but to solicit feedback...

This is a 2 part KML solution, one on the client, one on the server.

Client KML is very simple

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">  
<Folder>
    <name>My Links</name>
    <visibility>0</visibility>
    <open>0</open>
    <description>A folder to put my links in</description>
    <NetworkLink>
      <name>Fancy Places</name>
      <visibility>0</visibility>
      <open>0</open>
      <description>Regional Items for Tanya Fox</description>
      <refreshVisibility>0</refreshVisibility>
      <flyToView>0</flyToView>
      <Link>
        <href>http://SERVER_ADDRESS_HERE/KMLGenerator.aspx?PlaceType=fancy</href>
		<refreshInterval>2</refreshInterval>
        <viewRefreshMode>onExpire</viewRefreshMode>
        <viewRefreshTime>1</viewRefreshTime>
      </Link>
    </NetworkLink>
	<NetworkLink>
      <name>Everything</name>
      <visibility>0</visibility>
      <open>0</open>
      <description>All kinds of places</description>
      <refreshVisibility>0</refreshVisibility>
      <flyToView>0</flyToView>
      <Link>
        <href>http://SERVER_ADDRESS_HERE/KMLGenerator.aspx</href>
		<refreshInterval>2</refreshInterval>
        <viewRefreshMode>onExpire</viewRefreshMode>
        <viewRefreshTime>1</viewRefreshTime>
      </Link>
    </NetworkLink>
  </Folder>
</kml>
The only part of this that I can't seem to figure out is how to actually have the client request a refresh automatically.  I thought that the refreshInterval or viewRefreshTime settings would do that, but it does not appear to.
Because I didn't want to have an actual KML file generated every visit to the page, I chose to have my aspx page generate it on the fly.  In order to accomplish that, the markup of the page needed to contain NO html tags. The EnableTheming removes any issues if you have a themed site.

<%@ Page Title="Map" Language="C#" CodeBehind="KMLGenerator.aspx.cs" Inherits="KMLGenerator" 
EnableTheming="false" StylesheetTheme="" Theme="" %>

The only oddity I found in the code behind is you have to manually build your response.  Fortunately, it's simple.  I combined the two examples from earlier, plus a cool tip I found somewhere and got:
Kml root = new Kml { Feature = document };

Serializer serializer = new Serializer();
serializer.Serialize(root);

Response.ClearHeaders();
Response.ContentType = "application/vnd.google-earth.kml kml;";
Response.Write(serializer.Xml);
Response.Flush();

Now I can use whatever C# logic, database queries, etc. I want on page load (to include query strings) and dynamically generate KML specific to the requester. 
The next step in the process is to generate a form to allow the end users to generate the client KML...  

Coordinator
Jun 20, 2011 at 9:35 PM

Thanks for the update!

The problem with updating might be due to the fact that in the client KML the viewRefreshMode is set to onExpire. Depending on what you're returning from the server, if you use a NetworkLinkControl you can set the expires value to a specific date and time (failing that it will look at the HTTP headers for max-age or Expires). If you want the content to refresh every n seconds then I think you might need to change the client KML to use onInterval and set the refreshInterval property.