【.net core】.KMZ文件解压为.KML文件并解析为GEOJSON坐标数据集。附KML处理多线(LineString)闭环问题

news2025/6/7 8:49:13

通过使用ZipFile解压KMZ文件,获取其中的KML文件,并解析KML文件,输出解析后的坐标数据集。

KML文件:地理信息的标准格式

解析后的坐标数据集输出格式(GEOJSON坐标数据集):[[[经度,纬度],[经度,纬度]]]

解析类

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.IO;
using System.Xml;
using System.Linq;


namespace WaterCloud.Code
{
    public static class KMZHelper
    {
        /// <summary>
        /// 解压 KMZ 文件到指定目录。
        /// </summary>
        /// <param name="kmzFilePath">kmz文件地址</param>
        /// <param name="extractDirectory">解压路径</param>
        /// <returns></returns>
        public static PlotCoordinateClass HandleKMZ(string kmzFilePath, string extractDirectory)
        {
            PlotCoordinateClass plotCoordinate = new PlotCoordinateClass();
            try
            {
                if (!File.Exists(kmzFilePath))
                {
                    Console.WriteLine($"错误: 文件 '{kmzFilePath}' 不存在。");
                    LogHelper.WriteWithTime($"错误: 文件 '{kmzFilePath}' 不存在。");
                    plotCoordinate.message = $"错误: 文件 '{kmzFilePath}' 不存在。";
                    plotCoordinate.code = 1;
                    return plotCoordinate;
                }

                if (string.IsNullOrWhiteSpace(extractDirectory))
                {
                    // 使用临时目录
                    extractDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
                    Console.WriteLine($"使用临时目录: {extractDirectory}");
                    LogHelper.WriteWithTime($"使用临时目录: {extractDirectory}");
                }

                // 确保目录存在
                Directory.CreateDirectory(extractDirectory);

                // 解压 KMZ 文件
                ExtractKMZFile(kmzFilePath, extractDirectory);
                Console.WriteLine("KMZ 文件解压完成。");
                LogHelper.WriteWithTime($"KMZ 文件解压完成。");

                // 查找并读取 KML 文件
                string[] kmlFiles = Directory.GetFiles(extractDirectory, "*.kml", SearchOption.AllDirectories);

                if (kmlFiles.Length == 0)
                {
                    Console.WriteLine("警告: 在解压文件中未找到 KML 文件。");
                    LogHelper.WriteWithTime("警告: 在解压文件中未找到 KML 文件。");
                    plotCoordinate.message = ("警告: 在解压文件中未找到 KML 文件。");
                    plotCoordinate.code = 1;
                    return plotCoordinate;
                }

                Console.WriteLine($"找到 {kmlFiles.Length} 个 KML 文件:");
                LogHelper.WriteWithTime($"找到 {kmlFiles.Length} 个 KML 文件:");
                // 处理第一个 KML 文件
                plotCoordinate = KMLHelper.HandleKML(kmlFiles[0]);

                Console.WriteLine("\n处理完成。");
                LogHelper.WriteWithTime("\n处理完成。");
                return plotCoordinate;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
                LogHelper.WriteWithTime($"发生错误: {ex.Message}");
                plotCoordinate.message = $"发生错误: {ex.Message}";
                plotCoordinate.code = 1;
                return plotCoordinate;
            }
        }
        /// <summary>
        /// 解压 KMZ 文件到指定目录。
        /// </summary>
        /// <param name="kmzFilePath">kmz文件地址</param>
        /// <param name="extractDirectory">解压路径</param>
        public static void ExtractKMZFile(string kmzFilePath, string extractDirectory)
        {
            try
            {
                using (ZipArchive archive = ZipFile.OpenRead(kmzFilePath))
                {
                    foreach (ZipArchiveEntry entry in archive.Entries)
                    {
                        string entryPath = Path.Combine(extractDirectory, entry.FullName);
                        string entryDirectory = Path.GetDirectoryName(entryPath);

                        // 确保目录存在
                        if (!Directory.Exists(entryDirectory))
                        {
                            Directory.CreateDirectory(entryDirectory);
                        }

                        // 跳过目录条目
                        if (entry.Length == 0)
                        {
                            continue;
                        }

                        // 提取文件
                        entry.ExtractToFile(entryPath, true);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"解压错误: {ex.Message}");
                throw;
            }
        }
        /// <summary>
        /// 截断字符串,如果长度超过指定最大长度则添加省略号。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxLength"></param>
        /// <returns></returns>
        public static string TruncateString(string value, int maxLength)
        {
            if (string.IsNullOrEmpty(value))
            {
                return value;
            }

            return value.Length <= maxLength
                ? value
                : value.Substring(0, maxLength) + "...";
        }
    }
    public static class KMLHelper
    {
        /// <summary>
        /// 解析 KML 文件并提取坐标信息。
        /// </summary>
        /// <param name="kmlFilePath">kml文件地址</param>
        /// <returns></returns>
        public static PlotCoordinateClass HandleKML(string kmlFilePath)
        {
            PlotCoordinateClass plotCoordinate = new PlotCoordinateClass();
            try
            {

                if (!File.Exists(kmlFilePath))
                {
                    Console.WriteLine($"错误: 文件 '{kmlFilePath}' 不存在。");
                    LogHelper.WriteWithTime($"错误: 文件 '{kmlFilePath}' 不存在。");
                    plotCoordinate.message = ($"错误: 文件 '{kmlFilePath}' 不存在。");
                    plotCoordinate.code = 1;
                    return plotCoordinate;
                }

                // 加载 KML 文件
                XmlDocument kmlDoc = new XmlDocument();
                kmlDoc.Load(kmlFilePath);

                // 创建命名空间管理器,处理 KML 命名空间
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(kmlDoc.NameTable);
                nsmgr.AddNamespace("kml", "http://www.opengis.net/kml/2.2");

                // 解析基本信息
                List<PlotCoordinateClass> plotCoordinates =  ParseKmlDocument(kmlDoc, nsmgr);
                if (plotCoordinates != null && plotCoordinates.Count > 0) {
                    // 取最大的坐标点数作为结果,如果有多个则取最大的一个
                    plotCoordinate = plotCoordinates.OrderByDescending(a => a.PlotCoordinateCount).First();
                }
                Console.WriteLine("\n解析完成。");
                LogHelper.WriteWithTime("\n解析完成。");
                return plotCoordinate;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
                LogHelper.WriteWithTime($"发生错误: {ex.Message}");
                plotCoordinate.message = ($"发生错误: {ex.Message}");
                plotCoordinate.code = 1;
                return plotCoordinate;
            }
        }

        static List<PlotCoordinateClass> ParseKmlDocument(XmlDocument kmlDoc, XmlNamespaceManager nsmgr)
        {
            List<PlotCoordinateClass> plotCoordinates = new List<PlotCoordinateClass>();
            // 获取文档名称
            XmlNode documentNode = kmlDoc.SelectSingleNode("//kml:Document", nsmgr);
            if (documentNode != null)
            {
                XmlNode nameNode = documentNode.SelectSingleNode("kml:name", nsmgr);
                if (nameNode != null)
                {
                    Console.WriteLine($"文档名称: {nameNode.InnerText}");
                }

                // 解析文件夹
                plotCoordinates =ParseFolders(documentNode, nsmgr);

                // 解析地点标记
                //plotCoordinates = ParsePlacemarks(documentNode, nsmgr);
            }
            return plotCoordinates;
        }
        /// <summary>
        /// 解析文件夹及其子节点(地点标记和嵌套的文件夹)
        /// </summary>
        /// <param name="parentNode"></param>
        /// <param name="nsmgr"></param>
        /// <returns></returns>
        static List<PlotCoordinateClass> ParseFolders(XmlNode parentNode, XmlNamespaceManager nsmgr)
        {
            List<PlotCoordinateClass> plotCoordinates = new List<PlotCoordinateClass>();
            XmlNodeList folderNodes = parentNode.SelectNodes("kml:Folder", nsmgr);
            if (folderNodes != null && folderNodes.Count > 0)
            {
                Console.WriteLine("\n发现 {0} 个文件夹:", folderNodes.Count);

                foreach (XmlNode folderNode in folderNodes)
                {
                    XmlNode nameNode = folderNode.SelectSingleNode("kml:name", nsmgr);
                    string folderName = nameNode != null ? nameNode.InnerText : "[未命名文件夹]";
                    Console.WriteLine($"  - 文件夹: {folderName}");

                    // 递归解析文件夹中的地点标记
                    List<PlotCoordinateClass> result =  ParsePlacemarks(folderNode, nsmgr);
                    plotCoordinates.AddRange(result);

                    // 递归解析子文件夹
                    plotCoordinates.AddRange(ParseFolders(folderNode, nsmgr));
                }
            }
            return plotCoordinates;
        }
        /// <summary>
        /// 解析地点标记(点、线、多边形)
        /// </summary>
        /// <param name="parentNode"></param>
        /// <param name="nsmgr"></param>
        /// <returns></returns>
        static List<PlotCoordinateClass> ParsePlacemarks(XmlNode parentNode, XmlNamespaceManager nsmgr)
        {
            List<PlotCoordinateClass> plotCoordinateClasses = new List<PlotCoordinateClass>();
            
            XmlNodeList placemarkNodes = parentNode.SelectNodes("kml:Placemark", nsmgr);
            if (placemarkNodes != null && placemarkNodes.Count > 0)
            {
                Console.WriteLine("\n发现 {0} 个地点标记:", placemarkNodes.Count);

                foreach (XmlNode placemarkNode in placemarkNodes)
                {
                    PlotCoordinateClass plotCoordinate = null;
                    // 获取地点标记名称
                    XmlNode nameNode = placemarkNode.SelectSingleNode("kml:name", nsmgr);
                    string placemarkName = nameNode != null ? nameNode.InnerText : "[未命名地点]";
                    Console.WriteLine($"  - 地点: {placemarkName}");

                    // 解析点
                    XmlNode pointNode = placemarkNode.SelectSingleNode("kml:c", nsmgr);
                    if (pointNode != null)
                    {
                        ParsePoint(pointNode, nsmgr);
                    }



                    // 解析多边形
                    XmlNode MultiGeometryNode = placemarkNode.SelectSingleNode("kml:MultiGeometry", nsmgr);

                    if (MultiGeometryNode != null)
                    {
                        XmlNode polygonNode = MultiGeometryNode.SelectSingleNode("kml:Polygon", nsmgr);
                        if (polygonNode != null)
                        {
                            plotCoordinate =  ParsePolygon(polygonNode, nsmgr);
                            if (plotCoordinate != null) plotCoordinateClasses.Add(plotCoordinate);
                        }
                        // 解析线
                        XmlNodeList lineStringNodes = MultiGeometryNode.SelectNodes("kml:LineString", nsmgr);
                        if (lineStringNodes != null && lineStringNodes.Count > 0)
                        {
                            List< PlotCoordinateClass > tempList = new List<PlotCoordinateClass>();
                            //获取所有线串节点数据
                            foreach (XmlNode node in lineStringNodes) {
                                plotCoordinate = ParseLineString(node, nsmgr);
                                if (plotCoordinate != null) tempList.Add(plotCoordinate);
                            }
                            //闭合多边形区域,将多个线串整合为一个闭合的多边形区域,并添加处理结果到返回集合中。
                            plotCoordinateClasses.Add(ClosePolygon(tempList));
                        }
                    
                    }
                }
            }
            return plotCoordinateClasses;
        }
        /// <summary>
        /// 点处理方法
        /// </summary>
        /// <param name="pointNode"></param>
        /// <param name="nsmgr"></param>
        static void ParsePoint(XmlNode pointNode, XmlNamespaceManager nsmgr)
        {
            XmlNode coordinatesNode = pointNode.SelectSingleNode("kml:coordinates", nsmgr);
            if (coordinatesNode != null && !string.IsNullOrWhiteSpace(coordinatesNode.InnerText))
            {
                string[] coords = coordinatesNode.InnerText.Trim().Split(',');
                if (coords.Length >= 2)
                {
                    double longitude = double.Parse(coords[0]);
                    double latitude = double.Parse(coords[1]);
                    double? altitude = coords.Length > 2 ? (double?)double.Parse(coords[2]) : null;

                    Console.WriteLine($"    点坐标: 经度={longitude}, 纬度={latitude}{(altitude.HasValue ? $", 高度={altitude.Value}" : "")}");
                }
            }
        }
        /// <summary>
        /// 线处理方法
        /// </summary>
        /// <param name="lineStringNode"></param>
        /// <param name="nsmgr"></param>
        /// <returns></returns>
        private static PlotCoordinateClass ParseLineString(XmlNode lineStringNode, XmlNamespaceManager nsmgr)
        {
            PlotCoordinateClass plotCoordinate = null;
            XmlNode coordinatesNode = lineStringNode.SelectSingleNode("kml:coordinates", nsmgr);
            if (coordinatesNode != null && !string.IsNullOrWhiteSpace(coordinatesNode.InnerText))
            {
                plotCoordinate = GetPlotCoordinate(coordinatesNode.InnerText);
                //string[] pointStrings = coordinatesNode.InnerText.Trim().Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
                //Console.WriteLine($"    线串: {pointStrings.Length} 个点");
            }
            return plotCoordinate;
        }
        /// <summary>
        /// 多线闭环处理方法,将多个线串整合为一个闭合的多边形区域
        /// </summary>
        /// <param name="plotCoordinateClasses">多线集合</param>
        /// <returns></returns>
        private static PlotCoordinateClass ClosePolygon(List<PlotCoordinateClass> plotCoordinateClasses)
        {
            PlotCoordinateClass plotCoordinate = new PlotCoordinateClass();
            //plotCoordinateClasses中的PlotCoordinates数据格式为[[[经度,纬度],[经度,纬度]]],需要将这些数据整合载入到一个List中
            List<List<List<double>>> plotCoordinates = new List<List<List<double>>>();
            if (plotCoordinateClasses != null && plotCoordinateClasses.Count > 0) {
                if (plotCoordinateClasses.Count == 1) {
                    //如果只有一个区域,则直接返回第一个区域数据
                    plotCoordinate = plotCoordinateClasses.First();
                }
                else {
                    //处理多区域数据,将多个区域整合为一个区域
                    foreach (PlotCoordinateClass item in plotCoordinateClasses)
                    {
                        List<List<List<double>>> temp = JsonConvert.DeserializeObject<List<List<List<double>>>>(item.PlotCoordinates);
                        if (temp != null && temp.Count > 0) {
                            plotCoordinates.Add(temp.First());
                        }
                    }
                    //调用序列化坐标数据方法获取处理结果
                    List<List<List<double>>> result = SerializePlotCoordinate(plotCoordinates, plotCoordinates.First());
                    if(result != null && result.Count > 0) {
                        //创建新的坐标数据集合并将序列化结果赋值给新的坐标数据
                        List<List<List<double>>> newCoordinates = new List<List<List<double>>>();
                        List<List<double>> newNodes = new  List<List<double>>();
                        foreach (List<List<double>> item in result) {
                            foreach (List<double> node in item) {
                                newNodes.Add(node);
                            }
                        }
                        newCoordinates.Add(newNodes);
                        //将处理后的坐标数据赋值给PlotCoordinate对象
                        plotCoordinate.PlotCoordinates = JsonConvert.SerializeObject(newCoordinates);
                        plotCoordinate.CententCoordinate = JsonConvert.SerializeObject(newCoordinates.First().First());
                        plotCoordinate.PlotCoordinateCount = newCoordinates.First().Count;
                        plotCoordinate.code = 0;
                        plotCoordinate.message = "处理成功";
                    }
                }

            }
            return plotCoordinate;
        }
        /// <summary>
        /// 递归序列化区域坐标数据
        /// </summary>
        /// <param name="plotCoordinates">坐标数据集合,格式为"[[[经度,纬度],[经度,纬度]],[[经度,纬度],[经度,纬度]]]"</param>
        /// <param name="coordinates">初始依据坐标数据集,根据该参数处理后续节点内容</param>
        /// <returns></returns>
        private static List<List<List<double>>> SerializePlotCoordinate(List<List<List<double>>> plotCoordinates, List<List<double>> coordinates) {
            List<List<List<double>>> result = new List<List<List<double>>>();
            //将传入的坐标数据添加到结果中
            result.Add(coordinates);
            
            List<List<double>> nextCoordinates = new List<List<double>>();
            int deleteIndex = -1;//数据集删除索引
            //遍历传入的坐标数据集,判断当前传入坐标数据的后一个数据
            List<double> coordinatesLastNode = coordinates.Last();
            for (int i = 0; i < plotCoordinates.Count; i++) {
                List < List<double> > temp = plotCoordinates[i];
                temp = temp.Distinct().ToList();
                List<double> tempLastNode = temp.Last();
                List<double> tempFirstNode = temp.First();
                if (coordinatesLastNode.First().Equals(tempFirstNode.First())
                    && coordinatesLastNode.Last().Equals(tempFirstNode.Last()))
                {
                    //说明当前遍历数据temp的第一个节点与coordinates的最后一个节点相同,直接将temp的第一个节点删除,并将剩余数据添加到nextCoordinates中
                    temp.RemoveAt(0);
                    nextCoordinates.AddRange(temp);
                    deleteIndex = i;//获取删除索引
                    break;
                }
                else if (coordinatesLastNode.First().Equals(tempLastNode.First())
                    && coordinatesLastNode.Last().Equals(tempLastNode.Last()))
                {
                    //说明当前遍历数据temp的最后一个节点与coordinates的最后一个节点相同,需要将temp翻转后,删除第一个节点,并将剩余数据添加到nextCoordinates中
                    temp.Reverse();
                    temp.RemoveAt(0);
                    nextCoordinates.AddRange(temp);
                    deleteIndex = i;//获取删除索引
                    break;
                }
                else {
                    //未匹配的情况,跳出当前循环,遍历下一个节点
                    continue;
                }
            }
            
            if (deleteIndex != -1) { 
                //如果存在删除索引,则从数据集中删除该节点
                plotCoordinates.RemoveAt(deleteIndex);
                
            }
            
            if (plotCoordinates != null && plotCoordinates.Count > 0)
            {
                //如果数据集不为空,则继续递归调用该方法
                result.AddRange(SerializePlotCoordinate(plotCoordinates, nextCoordinates));
            }
            else {
                //如果数据集为空,则将nextCoordinates添加到结果中
                result.Add(nextCoordinates);
            }

            return result;
        }
        /// <summary>
        /// 区域处理方法
        /// </summary>
        /// <param name="polygonNode"></param>
        /// <param name="nsmgr"></param>
        /// <returns></returns>
        private static PlotCoordinateClass ParsePolygon(XmlNode polygonNode, XmlNamespaceManager nsmgr)
        {
            PlotCoordinateClass plotCoordinate = null;
            XmlNode outerBoundaryNode = polygonNode.SelectSingleNode("kml:outerBoundaryIs", nsmgr);
            if (outerBoundaryNode != null)
            {
                XmlNode linearRingNode = outerBoundaryNode.SelectSingleNode("kml:LinearRing", nsmgr);
                if (linearRingNode != null)
                {
                    XmlNode coordinatesNode = linearRingNode.SelectSingleNode("kml:coordinates", nsmgr);
                    if (coordinatesNode != null && !string.IsNullOrWhiteSpace(coordinatesNode.InnerText))
                    {
                        //string[] pointStrings = coordinatesNode.InnerText.Trim().Split(new[] { '0',' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
                        //获取区域坐标集合
                        plotCoordinate = GetPlotCoordinate(coordinatesNode.InnerText);
                    }
                }
            }

            // 解析内圈(洞)
            XmlNodeList innerBoundaryNodes = polygonNode.SelectNodes("kml:innerBoundaryIs", nsmgr);
            if (innerBoundaryNodes != null && innerBoundaryNodes.Count > 0)
            {
                Console.WriteLine($"    多边形内圈: {innerBoundaryNodes.Count} 个");
                foreach (XmlNode innerBoundaryNode in innerBoundaryNodes)
                {
                    XmlNode linearRingNode = innerBoundaryNode.SelectSingleNode("kml:LinearRing", nsmgr);
                    if (linearRingNode != null)
                    {
                        XmlNode coordinatesNode = linearRingNode.SelectSingleNode("kml:coordinates", nsmgr);
                        if (coordinatesNode != null && !string.IsNullOrWhiteSpace(coordinatesNode.InnerText))
                        {
                            plotCoordinate = GetPlotCoordinate(coordinatesNode.InnerText);
                            string[] pointStrings = coordinatesNode.InnerText.Trim().Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
                            Console.WriteLine($"      内圈: {pointStrings.Length} 个点");
                        }
                    }
                }
            }
            return plotCoordinate;
        }
        /// <summary>
        /// 获取区域坐标
        /// </summary>
        /// <param name="InnerText"></param>
        /// <returns></returns>
        private static PlotCoordinateClass GetPlotCoordinate(string InnerText)
        {
            PlotCoordinateClass plotCoordinate = new PlotCoordinateClass();
            List<string> coordinates = InnerText.Trim().Split(",0").ToList();
            if (coordinates != null && coordinates.Count > 0)
            {
                coordinates = coordinates.Where(a => !string.IsNullOrEmpty(a)).ToList();
                coordinates.ForEach(a =>
                {
                    a = a.Trim();
                });
            }
            plotCoordinate.code = 0;
            List<List<List<double>>> PlotCoordinates = GetCoordinatesList(coordinates);
            if ((PlotCoordinates != null && PlotCoordinates.Count > 0) &&
                (PlotCoordinates[0] != null && PlotCoordinates[0].Count > 0)
                )
            {
                plotCoordinate.PlotCoordinates = JsonConvert.SerializeObject(PlotCoordinates);
                plotCoordinate.CententCoordinate = JsonConvert.SerializeObject(PlotCoordinates[0][0]);
                plotCoordinate.PlotCoordinateCount = PlotCoordinates[0].Count;
                plotCoordinate.code = 0;
                plotCoordinate.message = "数据获取成功";
            }
            else
            {
                plotCoordinate.code = 1;
                plotCoordinate.message = "数据获取失败";
            }

            return plotCoordinate;
        }
        /// <summary>
        /// 获取坐标集合
        /// </summary>
        /// <param name="coordinates"></param>
        /// <returns></returns>
        private static List<List<List<double>>> GetCoordinatesList(List<string> coordinates)
        {
            List<List<List<double>>> result = new List<List<List<double>>>();
            List<List<double>> secondList = new List<List<double>>();
            foreach (string item in coordinates)
            {
                //List<double> ints = item.Split(",").Select(a => Math.Round(a.ToDouble(), 6)).ToList();
                List<double> ints = item.Split(",").Select(a => a.ToDouble()).ToList();
                if (ints != null && ints.Count > 1) {
                    var gcjCoord = WGS84ToGCJ02Helper.Wgs84ToGcj02(ints[0], ints[1]);
                    ints[0] = gcjCoord.lng;
                    ints[1] = gcjCoord.lat;
                    secondList.Add(ints);
                }
            }
            result.Add(secondList);
            return result;
        }
    }
    /// <summary>
    /// 区域坐标类
    /// </summary>
    public class PlotCoordinateClass
    {
        /// <summary>
        /// 地块坐标集合,格式为"[[[经度,纬度],[经度,纬度]]]"
        /// </summary>
        public string PlotCoordinates { get; set; }
        /// <summary>
        /// 地块中心坐标,格式为"[经度,纬度]"
        /// </summary>
        public string CententCoordinate { get; set; }
        /// <summary>
        /// 区域坐标数量
        /// </summary>
        public int PlotCoordinateCount { get; set; }
        /// <summary>
        /// 解析状态码,0为成功,1为失败。默认为0
        /// </summary>
        public int code { get; set; }
        /// <summary>
        /// 解析状态信息,默认为"成功"。失败时为具体错误描述。
        /// </summary>
        public string message { get; set; }
    }


}

调用

PlotCoordinateClass plotCoordinate = null;
//调用解压KMZ文件并解析解压后的KML文件并返回结果
plotCoordinate = KMZHelper.HandleKMZ("/your/kmzFile/path",
   "/your/kmzFile/extractDirectory");
//调用解析KML文件并返回解析结果
plotCoordinate = KMLHelper.HandleKML("/your/kmlFile/path");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Devops系列---python基础篇二

1、列表 1.1 概念 格式&#xff1a; 名称 [ “元素1”,“元素2”,…] #定义一个列表 computer ["主机","键盘","显示器","鼠标"]类型方法用途查index(“元素”)查看元素索引位置count(“元素”)统计元素出现的次数reverse()倒序排…

​​TLV4062-Q1​​、TLV4082-Q1​​迟滞电压比较器应用笔记

文章目录 主要作用应用场景关键优势典型应用示意图TLV4062-Q1 和 TLV4082-Q1 的主要作用及应用场景如下: 主要作用 精密电压监测:是一款双通道、低功耗比较器,用于监测输入电压是否超过预设阈值。 集成高精度基准电压源(阈值精度1%),内置60mV迟滞功能,可避免因噪声导致的…

DHCP介绍

DHCP介绍 1 DHCP简述2 DHCP协议分析2.1 主要流程2.2 DHCP全部报文介绍2.3 IP租用更新报文2.4 DHCP协议抓包分析 3 DHCP应用3.1 DNSmasq参数配置3.2 DNSmasq框架代码3.2.1 创建socket监听67端口3.2.2 监听67端口3.2.3 处理DHCP请求 3.3 DNSmasq模块排障方法 4 常见问题排查4.1 问…

[蓝桥杯]耐摔指数

耐摔指数 题目描述 X 星球的居民脾气不太好&#xff0c;但好在他们生气的时候唯一的异常举动是&#xff1a;摔手机。 各大厂商也就纷纷推出各种耐摔型手机。X 星球的质监局规定了手机必须经过耐摔测试&#xff0c;并且评定出一个耐摔指数来&#xff0c;之后才允许上市流通。…

2024年第十五届蓝桥杯青少Scratch初级组-国赛—画矩形

2024年第十五届蓝桥杯青少Scratch初级组-国赛—画矩形 题目点下方&#xff0c;支持在线编程&#xff0c;在线获取源码和素材&#xff5e; 画矩形_scratch_少儿编程题库学习中心-嗨信奥 程序演示可点下方&#xff0c;支持源码获取&#xff5e; 画矩形-scratch作品-少儿编程题库…

JMM初学

文章目录 1,线程间的同步和通信1.1, 共享内存并发模型 (Shared Memory Model)线程通信机制线程同步机制特点 1.2, 消息传递并发模型 (Message Passing Model)线程通信机制线程同步机制特点 适用场景对比 2,Java内存模型JMM2.0,Java内存模型的基础&#xff08;1&#xff09;内存…

构建云原生安全治理体系:挑战、策略与实践路径

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;从传统安全走向“云原生安全” 随着企业 IT 架构从传统单体系统向容器化、微服务和云原生平台转型&#xf…

vcs仿真产生fsdb波形的两种方式

目录 方法一&#xff1a; 使用verilog自带的系统函数 方法二&#xff1a; 使用UCLI command 2.1 需要了解什么是vcs的ucli&#xff0c;怎么使用ucli&#xff1f; 2.2 使用ucli dump波形的方法 使用vcs仿真产生fsdb波形有两种方式&#xff0c;本文参考《vcs user guide 20…

Go语言底层(三): sync 锁 与 对象池

1. 背景 在并发编程中&#xff0c;正确地管理共享资源是构建高性能程序的关键。Go 语言标准库中的 sync 包提供了一组基础而强大的并发原语&#xff0c;用于实现安全的协程间同步与资源控制。本文将简要介绍 sync 包中常用的类型和方法: sync 锁 与 对象池&#xff0c;帮助开发…

2025年06月06日Github流行趋势

项目名称&#xff1a;agent-zero 项目地址url&#xff1a;https://github.com/frdel/agent-zero项目语言&#xff1a;Python历史star数&#xff1a;8958今日star数&#xff1a;324项目维护者&#xff1a;frdel, 3clyp50, linuztx, evrardt, Jbollenbacher项目简介&#xff1a;A…

动态规划 熟悉30题 ---上

本来是要写那个二维动态规划嘛&#xff0c;但是我今天在问题时候&#xff0c;一个大佬就把他初一时候教练让他练dp的30题发出来了&#xff08;初一&#xff0c;啊虽然知道计算机这一专业&#xff0c;很多人从小就学了&#xff0c;但是我每次看到一些大佬从小学还是会很羡慕吧或…

Linux系统:ELF文件的定义与加载以及动静态链接

本节重点 ELF文件的概念与结构可执行文件&#xff0c;目标文件ELF格式的区别ELF文件的形成过程ELF文件的加载动态链接与静态链接动态库的编址与方法调用 一、ELF文件的概念与结构 1.1 文件概述 ELF&#xff08;Executable and Linkable Format&#xff09;即“可执行与可链…

【国产化适配】如何选择高效合规的安全数据交换系统?

一、安全数据交换系统的核心价值与国产化需求 在数字化转型浪潮中&#xff0c;企业数据流动的频率与规模呈指数级增长&#xff0c;跨网文件传输已成为日常运营的刚需&#xff0c;所以安全数据交换系统也是企业必备的工具。然而&#xff0c;数据泄露事件频发、行业合规要求趋严…

简化复杂系统的优雅之道:深入解析 Java 外观模式

一、外观模式的本质与核心价值 在软件开发的世界里&#xff0c;我们经常会遇到这样的场景&#xff1a;一个复杂的子系统由多个相互协作的类组成&#xff0c;这些类之间可能存在错综复杂的依赖关系和交互逻辑。当外部客户端需要使用这个子系统时&#xff0c;往往需要了解多个类…

设计模式杂谈-模板设计模式

在进入正题之前&#xff0c;先引入这样一个场景&#xff1a; 程序员A现在接到这样一个需求&#xff1a;这个需求有10个接口&#xff0c;这些接口都需要接收前端的传参&#xff0c;以及给前端返回业务状态信息。出于数据保密的要求&#xff0c;不管是前端传参还是最终参数返回都…

C#入门学习笔记 #6(字段、属性、索引器、常量)

欢迎进入这篇文章&#xff0c;文章内容为学习C#过程中做的笔记&#xff0c;可能有些内容的逻辑衔接不是很连贯&#xff0c;但还是决定分享出来&#xff0c;由衷的希望可以帮助到你。 笔记内容会持续更新~~ 将这四种成语放在一起讲是因为这四种成员都是用来表达数据的。 字段…

广目软件GM DC Monitor

广目&#xff08;北京&#xff09;软件有限公司成立于2024年&#xff0c;技术和研发团队均来自于一家具有近10年监控系统研发的企业。广目的技术团队一共实施了9家政府单位、1家股份制银行、1家芯片制造企业的数据中心监控预警项目。这11家政企单位由2家正部级、1家副部级、6家…

每日八股文6.6

每日八股-6.6 Mysql1.怎么查看一条sql语句是否走了索引&#xff1f;2.能说说 MySQL 事务都有哪些关键特性吗&#xff1f;3.MySQL 是如何保证事务的原子性的&#xff1f;4.MySQL 是如何保证事务的隔离性的&#xff1f;5.能简单介绍一下 MVCC 吗&#xff1f;或者说&#xff0c;你…

PostgreSQL17 编译安装+相关问题解决

更新时间&#xff1a;2025.6.6&#xff0c;当前最新稳定版本17.5&#xff0c;演示的是17.5&#xff0c;最新测试版本18beta1 演示系统&#xff1a;debian12 很多时候&#xff0c;只有编译安装才能用上最新的软件版本或指定的版本。这也是编译安装的意义。 一、编译安装 &…

React 第五十六节 Router 中useSubmit的使用详解及注意事项

前言 useSubmit 是 React Router v6.4 引入的强大钩子&#xff0c;用于以编程方式提交表单数据。 它提供了对表单提交过程的精细控制&#xff0c;特别适合需要自定义提交行为或非标准表单场景的应用。 一、useSubmit 核心用途 编程式表单提交&#xff1a;不依赖 <form>…