作为一名测量工程师,日常扛杆扶尺,做控制、测地形图,经常需要利用工具生成kml文件导入手簿。
刚好最近项目空档期,心血来潮就研究了一下kml文件,发现是xml格式的文档,于是利用C#参照测量软件生成的kml格式写了一段生成kml文件的代码。
计划今年有时间自己写一个测量工具集合的小软件,那就先从这个功能开始吧。
本段代码的生成格式为序号,纬度,经度,经纬度单位为度
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace KmlGenerator
{
//实验发现标签的经纬度和谷歌地图上的经纬度是反的
//文件格式需要为 序号,纬度,经度
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请选择输入方式: 1 - 从TXT文件读取");
var input = Console.ReadLine();
List<Coordinate> coordinates = new List<Coordinate>();
string fileDir = null;//声明时必须有值,因此设置坐标txt所在目录为null
string fileName = null;//声明时必须有值,因此设置声明坐标txt名称为为null
if (input == "1")
{
Console.WriteLine("请输入TXT文件路径:");
string txtFilePath = Console.ReadLine();
coordinates = ReadCoordinatesFromTxt(txtFilePath);
fileDir = Path.GetDirectoryName(txtFilePath);
fileName = Path.GetFileNameWithoutExtension(txtFilePath);
}
else
{
Console.WriteLine("无效的输入选项");
return;
}
//生成kml文件目录
string kmlFilePath = fileDir + "\\"+ fileName + ".kml";
GenerateKmlFile(coordinates, kmlFilePath);
Console.WriteLine($"KML文件已生成: {Path.GetFullPath(kmlFilePath)}");
}
//坐标转换方法
static List<Coordinate> ReadCoordinatesFromTxt(string filePath)
{
if (!File.Exists(filePath))
throw new FileNotFoundException($"文件不存在: {filePath}");
var coordinates = new List<Coordinate>();
foreach (string line in File.ReadAllLines(filePath))
{
if (string.IsNullOrWhiteSpace(line))
continue;
string[] parts = line.Split(',');
if (parts.Length != 3)
throw new FormatException($"无效的坐标格式: {line}");
try
{
coordinates.Add(new Coordinate
{
Latitude = double.Parse(parts[1].Trim()),
Longitude = double.Parse(parts[2].Trim())
});
}
catch (FormatException)
{
throw new FormatException($"无效的坐标值: {line}");
}
}
if (coordinates.Count == 0)
throw new Exception("文件中没有有效的坐标数据");
return coordinates;
}
//生成xml格式的kml文件
static void GenerateKmlFile(List<Coordinate> coordinates, string filePath)
{
if (coordinates == null || coordinates.Count == 0)
throw new ArgumentException("坐标列表不能为空");
// 创建KML文档结构
XNamespace ns = "http://www.opengis.net/kml/2.2";
XNamespace gx = "http://www.google.com/kml/ext/2.2";
XNamespace kml = "http://www.opengis.net/kml/2.2";
XNamespace atom = "http://www.w3.org/2005/Atom";
XDocument kmlDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", "yes"),
new XElement(ns + "kml",
new XAttribute(XNamespace.Xmlns + "gx", gx),
new XAttribute(XNamespace.Xmlns + "kml", kml),
new XAttribute(XNamespace.Xmlns + "atom", atom),
new XAttribute("xmlns", ns),
//new XElement(ns + "Document",
new XElement(ns + "Folder",
new XElement(ns + "name", "txttokml"),
coordinates.Select((coord, index) =>
new XElement(ns + "Placemark",
new XElement(ns + "name", index + 1),
new XElement(ns + "LookAt",
new XElement(ns + "longitude", coord.Longitude),
new XElement(ns + "latitude", coord.Latitude),
new XElement(ns + "altitude", "0"),
new XElement(ns + "heading", "0"),
new XElement(ns + "tilt", "0"),
new XElement(ns + "range", "1000")
),
new XElement(ns + "Point",
new XElement(ns + "coordinates", $"{coord.Latitude},{coord.Longitude},0")
)
)
),
// 连接线(LineString)的Placemark
new XElement(ns + "Placemark",
new XElement(ns + "name", "NONAME"),
new XElement(ns + "LookAt",
new XElement(ns + "longitude", coordinates.Last().Longitude),
new XElement(ns + "latitude", coordinates.Last().Latitude),
new XElement(ns + "altitude", "0"),
new XElement(ns + "heading", "0"),
new XElement(ns + "tilt", "0"),
new XElement(ns + "range", "1000")
),
new XElement(ns + "LineString",
new XElement(ns + "tessellate", "1"),
new XElement(ns + "coordinates",
string.Join(" ", coordinates.Select(c => $"{c.Latitude},{c.Longitude},0"))
)
)
)
)
)
);
kmlDoc.Save(filePath);
}
}
//定义坐标类
public class Coordinate
{
public double Longitude { get; set; }
public double Latitude { get; set; }
}
}