NavisworksTransport/PathDataManager.cs

646 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Text;
using System.Linq;
using Autodesk.Navisworks.Api;
namespace NavisworksTransport
{
/// <summary>
/// 路径数据管理器
/// 负责路径数据的导入导出、持久化存储和DELMIA格式兼容
/// </summary>
public class PathDataManager
{
private const string DEFAULT_EXPORT_FOLDER = "PathPlanningExports";
private const string DEFAULT_FILE_EXTENSION = ".xml";
private const string JSON_FILE_EXTENSION = ".json";
// DELMIA兼容格式配置
private readonly string _delmiaNamespace = "http://www.3ds.com/delmia/pathplanning";
private readonly string _delmiaVersion = "1.0";
/// <summary>
/// 导出路径到XML文件DELMIA兼容格式
/// </summary>
/// <param name="routes">路径集合</param>
/// <param name="filePath">文件路径</param>
/// <param name="exportSettings">导出设置</param>
/// <returns>是否成功</returns>
public bool ExportToXml(List<PathRoute> routes, string filePath, ExportSettings exportSettings = null)
{
if (routes == null || routes.Count == 0)
{
throw new ArgumentException("路径集合不能为空");
}
try
{
// 确保导出目录存在
var directory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 创建XML文档
var xmlDoc = new XmlDocument();
var declaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
xmlDoc.AppendChild(declaration);
// 创建根元素
var rootElement = xmlDoc.CreateElement("PathPlanningData", _delmiaNamespace);
rootElement.SetAttribute("version", _delmiaVersion);
rootElement.SetAttribute("generator", "NavisworksTransport");
rootElement.SetAttribute("timestamp", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss"));
xmlDoc.AppendChild(rootElement);
// 添加项目信息
var projectInfo = CreateProjectInfoElement(xmlDoc, exportSettings);
rootElement.AppendChild(projectInfo);
// 添加路径数据
var routesElement = xmlDoc.CreateElement("Routes", _delmiaNamespace);
rootElement.AppendChild(routesElement);
foreach (var route in routes)
{
if (route.IsValid())
{
var routeElement = CreateRouteElement(xmlDoc, route, exportSettings);
routesElement.AppendChild(routeElement);
}
}
// 保存文件
using (var writer = new XmlTextWriter(filePath, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.Indentation = 2;
xmlDoc.WriteTo(writer);
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"导出XML文件失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 从XML文件导入路径
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>路径集合</returns>
public List<PathRoute> ImportFromXml(string filePath)
{
var routes = new List<PathRoute>();
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"文件不存在: {filePath}");
}
try
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(filePath);
// 验证根元素
var rootElement = xmlDoc.DocumentElement;
if (rootElement?.Name != "PathPlanningData")
{
throw new InvalidOperationException("无效的路径规划数据文件格式");
}
// 读取路径数据
var routesElement = rootElement.SelectSingleNode("*[local-name()='Routes']");
if (routesElement != null)
{
foreach (XmlNode routeNode in routesElement.ChildNodes)
{
if (routeNode.NodeType == XmlNodeType.Element)
{
var route = ParseRouteElement(routeNode);
if (route != null && route.IsValid())
{
routes.Add(route);
}
}
}
}
return routes;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"导入XML文件失败: {ex.Message}");
throw;
}
}
/// <summary>
/// 导出路径到JSON文件简化实现
/// </summary>
/// <param name="routes">路径集合</param>
/// <param name="filePath">文件路径</param>
/// <param name="exportSettings">导出设置</param>
/// <returns>是否成功</returns>
public bool ExportToJson(List<PathRoute> routes, string filePath, ExportSettings exportSettings = null)
{
// JSON功能暂未实现建议使用XML格式
return ExportToXml(routes, filePath.Replace(".json", ".xml"), exportSettings);
}
/// <summary>
/// 从JSON文件导入路径简化实现
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>路径集合</returns>
public List<PathRoute> ImportFromJson(string filePath)
{
// JSON功能暂未实现建议使用XML格式
return ImportFromXml(filePath.Replace(".json", ".xml"));
}
/// <summary>
/// 保存路径到Navisworks文件
/// </summary>
/// <param name="routes">路径集合</param>
/// <param name="filePath">文件路径</param>
/// <returns>是否成功</returns>
public bool SaveToNavisworksFile(List<PathRoute> routes, string filePath)
{
try
{
// 创建临时属性来存储路径数据
var document = Application.ActiveDocument;
if (document == null)
{
throw new InvalidOperationException("没有活动的Navisworks文档");
}
// 简化实现:跳过路径数据序列化
// 这里可以将路径数据保存为自定义属性
// 由于Navisworks API的限制这里是简化实现
// 实际应用中可能需要使用COM API来添加自定义属性
// 保存当前文档
if (Path.GetExtension(filePath).ToLower() == ".nwd")
{
document.PublishFile(filePath, new PublishProperties());
}
else
{
document.SaveFile(filePath);
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"保存到Navisworks文件失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 从Navisworks文件加载路径
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>路径集合</returns>
public List<PathRoute> LoadFromNavisworksFile(string filePath)
{
var routes = new List<PathRoute>();
try
{
// 这里应该从Navisworks文件的自定义属性中读取路径数据
// 由于API限制这里是简化实现
// 实际应用中需要使用COM API来读取自定义属性
return routes;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"从Navisworks文件加载失败: {ex.Message}");
return routes;
}
}
/// <summary>
/// 导出DELMIA兼容格式
/// </summary>
/// <param name="routes">路径集合</param>
/// <param name="filePath">文件路径</param>
/// <param name="exportSettings">导出设置</param>
/// <returns>是否成功</returns>
public bool ExportDelmiaFormat(List<PathRoute> routes, string filePath, ExportSettings exportSettings = null)
{
try
{
// 确保导出目录存在
var directory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
var xmlDoc = new XmlDocument();
var declaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
xmlDoc.AppendChild(declaration);
// 创建DELMIA格式的根元素
var rootElement = xmlDoc.CreateElement("DELMIA_PathPlanning", _delmiaNamespace);
rootElement.SetAttribute("version", _delmiaVersion);
rootElement.SetAttribute("units", exportSettings?.Units ?? "meters");
xmlDoc.AppendChild(rootElement);
// 添加任务信息
var taskInfo = xmlDoc.CreateElement("TaskInfo", _delmiaNamespace);
taskInfo.SetAttribute("name", exportSettings?.ProjectName ?? "物流路径规划");
taskInfo.SetAttribute("description", exportSettings?.Description ?? "从Navisworks导出的路径规划任务");
taskInfo.SetAttribute("created", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss"));
rootElement.AppendChild(taskInfo);
// 添加路径集合
var pathsElement = xmlDoc.CreateElement("Paths", _delmiaNamespace);
rootElement.AppendChild(pathsElement);
foreach (var route in routes.Where(r => r.IsValid()))
{
var pathElement = CreateDelmiaPathElement(xmlDoc, route, exportSettings);
pathsElement.AppendChild(pathElement);
}
// 保存文件
using (var writer = new XmlTextWriter(filePath, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.Indentation = 2;
xmlDoc.WriteTo(writer);
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"导出DELMIA格式失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 获取默认导出路径
/// </summary>
/// <param name="fileName">文件名</param>
/// <param name="format">格式</param>
/// <returns>完整路径</returns>
public string GetDefaultExportPath(string fileName, ExportFormat format)
{
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var exportPath = Path.Combine(documentsPath, DEFAULT_EXPORT_FOLDER);
if (!Directory.Exists(exportPath))
{
Directory.CreateDirectory(exportPath);
}
var extension = format == ExportFormat.Json ? JSON_FILE_EXTENSION : DEFAULT_FILE_EXTENSION;
return Path.Combine(exportPath, fileName + extension);
}
/// <summary>
/// 验证导出文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="format">格式</param>
/// <returns>验证结果</returns>
public ValidationResult ValidateExportFile(string filePath, ExportFormat format)
{
var result = new ValidationResult();
try
{
if (!File.Exists(filePath))
{
result.IsValid = false;
result.Errors.Add("文件不存在");
return result;
}
if (format == ExportFormat.Xml)
{
// 验证XML格式
var xmlDoc = new XmlDocument();
xmlDoc.Load(filePath);
if (xmlDoc.DocumentElement?.Name != "PathPlanningData" &&
xmlDoc.DocumentElement?.Name != "DELMIA_PathPlanning")
{
result.Warnings.Add("XML根元素格式可能不正确");
}
}
else if (format == ExportFormat.Json)
{
// JSON验证暂未实现
result.Warnings.Add("JSON格式验证暂未实现建议使用XML格式");
}
result.IsValid = true;
}
catch (Exception ex)
{
result.IsValid = false;
result.Errors.Add($"文件验证失败: {ex.Message}");
}
return result;
}
#region
/// <summary>
/// 创建项目信息元素
/// </summary>
private XmlElement CreateProjectInfoElement(XmlDocument xmlDoc, ExportSettings settings)
{
var projectInfo = xmlDoc.CreateElement("ProjectInfo", _delmiaNamespace);
projectInfo.SetAttribute("name", settings?.ProjectName ?? "NavisworksTransport路径规划");
projectInfo.SetAttribute("description", settings?.Description ?? "物流路径规划数据");
projectInfo.SetAttribute("units", settings?.Units ?? "meters");
projectInfo.SetAttribute("coordinateSystem", settings?.CoordinateSystem ?? "Global");
return projectInfo;
}
/// <summary>
/// 创建路径元素
/// </summary>
private XmlElement CreateRouteElement(XmlDocument xmlDoc, PathRoute route, ExportSettings settings)
{
var routeElement = xmlDoc.CreateElement("Route", _delmiaNamespace);
routeElement.SetAttribute("id", route.Id);
routeElement.SetAttribute("name", route.Name);
routeElement.SetAttribute("description", route.Description ?? "");
routeElement.SetAttribute("totalLength", route.TotalLength.ToString("F3"));
routeElement.SetAttribute("created", route.CreatedTime.ToString("yyyy-MM-ddTHH:mm:ss"));
// 添加路径点
var pointsElement = xmlDoc.CreateElement("Points", _delmiaNamespace);
routeElement.AppendChild(pointsElement);
var sortedPoints = route.GetSortedPoints();
foreach (var point in sortedPoints)
{
var pointElement = xmlDoc.CreateElement("Point", _delmiaNamespace);
pointElement.SetAttribute("id", point.Id);
pointElement.SetAttribute("name", point.Name);
pointElement.SetAttribute("type", point.Type.ToString());
pointElement.SetAttribute("index", point.Index.ToString());
pointElement.SetAttribute("x", point.Position.X.ToString("F6"));
pointElement.SetAttribute("y", point.Position.Y.ToString("F6"));
pointElement.SetAttribute("z", point.Position.Z.ToString("F6"));
pointElement.SetAttribute("created", point.CreatedTime.ToString("yyyy-MM-ddTHH:mm:ss"));
pointsElement.AppendChild(pointElement);
}
return routeElement;
}
/// <summary>
/// 解析路径元素
/// </summary>
private PathRoute ParseRouteElement(XmlNode routeNode)
{
try
{
var route = new PathRoute
{
Id = routeNode.Attributes?["id"]?.Value ?? Guid.NewGuid().ToString(),
Name = routeNode.Attributes?["name"]?.Value ?? "导入路径",
Description = routeNode.Attributes?["description"]?.Value ?? ""
};
// 解析创建时间
if (DateTime.TryParse(routeNode.Attributes?["created"]?.Value, out DateTime createdTime))
{
route.CreatedTime = createdTime;
}
// 解析路径点
var pointsNode = routeNode.SelectSingleNode("*[local-name()='Points']");
if (pointsNode != null)
{
foreach (XmlNode pointNode in pointsNode.ChildNodes)
{
if (pointNode.NodeType == XmlNodeType.Element)
{
var point = ParsePointElement(pointNode);
if (point != null)
{
route.AddPoint(point);
}
}
}
}
return route;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"解析路径元素失败: {ex.Message}");
return null;
}
}
/// <summary>
/// 解析路径点元素
/// </summary>
private PathPoint ParsePointElement(XmlNode pointNode)
{
try
{
var point = new PathPoint
{
Id = pointNode.Attributes?["id"]?.Value ?? Guid.NewGuid().ToString(),
Name = pointNode.Attributes?["name"]?.Value ?? ""
};
// 解析位置
if (double.TryParse(pointNode.Attributes?["x"]?.Value, out double x) &&
double.TryParse(pointNode.Attributes?["y"]?.Value, out double y) &&
double.TryParse(pointNode.Attributes?["z"]?.Value, out double z))
{
point.Position = new Point3D(x, y, z);
}
// 解析索引
if (int.TryParse(pointNode.Attributes?["index"]?.Value, out int index))
{
point.Index = index;
}
// 解析类型
if (Enum.TryParse<PathPointType>(pointNode.Attributes?["type"]?.Value, out PathPointType type))
{
point.Type = type;
}
// 解析创建时间
if (DateTime.TryParse(pointNode.Attributes?["created"]?.Value, out DateTime createdTime))
{
point.CreatedTime = createdTime;
}
return point;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"解析路径点元素失败: {ex.Message}");
return null;
}
}
/// <summary>
/// 创建DELMIA路径元素
/// </summary>
private XmlElement CreateDelmiaPathElement(XmlDocument xmlDoc, PathRoute route, ExportSettings settings)
{
var pathElement = xmlDoc.CreateElement("Path", _delmiaNamespace);
pathElement.SetAttribute("id", route.Id);
pathElement.SetAttribute("name", route.Name);
pathElement.SetAttribute("type", "Transportation");
pathElement.SetAttribute("length", route.TotalLength.ToString("F3"));
// 添加路径段
var segmentsElement = xmlDoc.CreateElement("Segments", _delmiaNamespace);
pathElement.AppendChild(segmentsElement);
var sortedPoints = route.GetSortedPoints();
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var segmentElement = xmlDoc.CreateElement("Segment", _delmiaNamespace);
segmentElement.SetAttribute("index", i.ToString());
// 起点
var startElement = xmlDoc.CreateElement("Start", _delmiaNamespace);
AddDelmiaPointData(xmlDoc, startElement, sortedPoints[i]);
segmentElement.AppendChild(startElement);
// 终点
var endElement = xmlDoc.CreateElement("End", _delmiaNamespace);
AddDelmiaPointData(xmlDoc, endElement, sortedPoints[i + 1]);
segmentElement.AppendChild(endElement);
segmentsElement.AppendChild(segmentElement);
}
return pathElement;
}
/// <summary>
/// 添加DELMIA点数据
/// </summary>
private void AddDelmiaPointData(XmlDocument xmlDoc, XmlElement element, PathPoint point)
{
element.SetAttribute("x", point.Position.X.ToString("F6"));
element.SetAttribute("y", point.Position.Y.ToString("F6"));
element.SetAttribute("z", point.Position.Z.ToString("F6"));
element.SetAttribute("name", point.Name);
element.SetAttribute("type", point.Type.ToString());
}
#endregion
}
/// <summary>
/// 导出格式枚举
/// </summary>
public enum ExportFormat
{
Xml,
Json,
Delmia,
Navisworks
}
/// <summary>
/// 导出设置
/// </summary>
public class ExportSettings
{
/// <summary>
/// 项目名称
/// </summary>
public string ProjectName { get; set; } = "NavisworksTransport路径规划";
/// <summary>
/// 项目描述
/// </summary>
public string Description { get; set; } = "物流路径规划数据";
/// <summary>
/// 单位
/// </summary>
public string Units { get; set; } = "meters";
/// <summary>
/// 坐标系
/// </summary>
public string CoordinateSystem { get; set; } = "Global";
/// <summary>
/// 是否包含时间戳
/// </summary>
public bool IncludeTimestamps { get; set; } = true;
/// <summary>
/// 是否包含元数据
/// </summary>
public bool IncludeMetadata { get; set; } = true;
/// <summary>
/// 精度(小数位数)
/// </summary>
public int Precision { get; set; } = 6;
}
/// <summary>
/// 验证结果
/// </summary>
public class ValidationResult
{
/// <summary>
/// 是否有效
/// </summary>
public bool IsValid { get; set; } = true;
/// <summary>
/// 错误信息
/// </summary>
public List<string> Errors { get; set; } = new List<string>();
/// <summary>
/// 警告信息
/// </summary>
public List<string> Warnings { get; set; } = new List<string>();
/// <summary>
/// 获取所有消息
/// </summary>
/// <returns>消息集合</returns>
public IEnumerable<string> GetAllMessages()
{
return Errors.Concat(Warnings);
}
}
}