242 lines
9.4 KiB
C#
242 lines
9.4 KiB
C#
using System;
|
||
using System.Drawing.Imaging;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text.RegularExpressions;
|
||
using Autodesk.Navisworks.Api;
|
||
|
||
namespace NavisworksTransport.Utils
|
||
{
|
||
/// <summary>
|
||
/// 路径处理工具类 - 提供文件路径相关的通用方法
|
||
/// </summary>
|
||
public static class PathHelper
|
||
{
|
||
/// <summary>
|
||
/// 获取插件目录路径
|
||
/// </summary>
|
||
public static string GetPluginDirectory()
|
||
{
|
||
return Path.Combine(
|
||
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
|
||
"Autodesk",
|
||
"Navisworks Manage 2026",
|
||
"plugins",
|
||
"TransportPlugin"
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取截图目录路径
|
||
/// </summary>
|
||
public static string GetScreenshotDirectory()
|
||
{
|
||
return Path.Combine(GetPluginDirectory(), "screenshots");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取报告目录路径
|
||
/// </summary>
|
||
public static string GetReportDirectory()
|
||
{
|
||
return Path.Combine(GetPluginDirectory(), "reports");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确保目录存在,不存在则创建
|
||
/// </summary>
|
||
public static void EnsureDirectoryExists(string directory)
|
||
{
|
||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||
{
|
||
Directory.CreateDirectory(directory);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理文件名中的非法字符
|
||
/// </summary>
|
||
/// <param name="fileName">原始文件名</param>
|
||
/// <returns>清理后的文件名</returns>
|
||
public static string SanitizeFileName(string fileName)
|
||
{
|
||
if (string.IsNullOrEmpty(fileName))
|
||
{
|
||
return "unnamed";
|
||
}
|
||
|
||
var invalidChars = Path.GetInvalidFileNameChars();
|
||
var cleanedFileName = new string(fileName.Where(c => !invalidChars.Contains(c)).ToArray());
|
||
|
||
// 如果清理后为空,返回默认名称
|
||
return string.IsNullOrWhiteSpace(cleanedFileName) ? "unnamed" : cleanedFileName;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成带时间戳的文件名
|
||
/// </summary>
|
||
/// <param name="prefix">文件名前缀</param>
|
||
/// <param name="extension">文件扩展名(不含点号)</param>
|
||
/// <returns>带时间戳的文件名</returns>
|
||
public static string GenerateTimestampedFileName(string prefix, string extension)
|
||
{
|
||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||
return $"{prefix}_{timestamp}.{extension}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成碰撞检测报告文件名。
|
||
/// 格式:碰撞检测报告_{路径名}_{时间戳}.{extension}
|
||
/// </summary>
|
||
public static string GenerateCollisionReportFileName(string pathName, string extension, DateTime? now = null)
|
||
{
|
||
string sanitizedName = SanitizeFileName(pathName ?? "未知路径");
|
||
string normalizedExtension = string.IsNullOrWhiteSpace(extension)
|
||
? "html"
|
||
: extension.Trim().TrimStart('.');
|
||
string timestamp = (now ?? DateTime.Now).ToString("yyyyMMdd_HHmmss");
|
||
return $"碰撞检测报告_{sanitizedName}_{timestamp}.{normalizedExtension}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复制路径名称。
|
||
/// 如果原名称以 MMdd_HHmmss 结尾,则重建时间戳;否则仅添加“副本_”前缀。
|
||
/// </summary>
|
||
public static string BuildDuplicatedPathName(string originalName, DateTime? now = null)
|
||
{
|
||
var normalizedName = string.IsNullOrWhiteSpace(originalName) ? "路径" : originalName.Trim();
|
||
var timestampPattern = new Regex(@"^(.*)_\d{4}_\d{6}$");
|
||
var match = timestampPattern.Match(normalizedName);
|
||
|
||
if (!match.Success)
|
||
{
|
||
return $"副本_{normalizedName}";
|
||
}
|
||
|
||
var baseName = match.Groups[1].Value;
|
||
var timestamp = (now ?? DateTime.Now).ToString("MMdd_HHmmss");
|
||
return $"副本_{baseName}_{timestamp}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算从HTML文件到目标文件的相对路径
|
||
/// </summary>
|
||
/// <param name="fromPath">HTML文件路径</param>
|
||
/// <param name="toPath">目标文件路径</param>
|
||
/// <returns>相对路径(使用正斜杠)</returns>
|
||
public static string GetRelativePath(string fromPath, string toPath)
|
||
{
|
||
try
|
||
{
|
||
var fromUri = new Uri(fromPath);
|
||
var toUri = new Uri(toPath);
|
||
var relativeUri = fromUri.MakeRelativeUri(toUri);
|
||
return Uri.UnescapeDataString(relativeUri.ToString()).Replace('\\', '/');
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"计算相对路径失败: {ex.Message}");
|
||
return toPath; // 失败时返回绝对路径
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将ImageFormat转换为文件扩展名
|
||
/// </summary>
|
||
public static string ImageFormatToExtension(ImageFormat format)
|
||
{
|
||
if (format.Equals(ImageFormat.Jpeg))
|
||
return "jpg";
|
||
if (format.Equals(ImageFormat.Png))
|
||
return "png";
|
||
if (format.Equals(ImageFormat.Bmp))
|
||
return "bmp";
|
||
return "png"; // 默认
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将文件扩展名转换为ImageFormat
|
||
/// </summary>
|
||
public static ImageFormat ExtensionToImageFormat(string extension)
|
||
{
|
||
if (string.IsNullOrEmpty(extension))
|
||
return ImageFormat.Png;
|
||
|
||
extension = extension.ToLowerInvariant();
|
||
if (extension == ".jpg" || extension == ".jpeg")
|
||
return ImageFormat.Jpeg;
|
||
if (extension == ".png")
|
||
return ImageFormat.Png;
|
||
if (extension == ".bmp")
|
||
return ImageFormat.Bmp;
|
||
return ImageFormat.Png; // 默认
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成场景截图(通用方法)
|
||
/// </summary>
|
||
/// <param name="sceneName">场景名称</param>
|
||
/// <param name="width">图像宽度</param>
|
||
/// <param name="height">图像高度</param>
|
||
/// <param name="format">图像格式</param>
|
||
/// <param name="prefix">文件名前缀</param>
|
||
/// <returns>截图文件路径,失败返回null</returns>
|
||
public static string GenerateSceneScreenshot(string sceneName, int width, int height, ImageFormat format, string prefix = "scene")
|
||
{
|
||
return GenerateSceneScreenshotInternal(GetScreenshotDirectory(), sceneName, width, height, format, prefix);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成场景截图到指定目录
|
||
/// </summary>
|
||
/// <param name="outputDirectory">输出目录</param>
|
||
/// <param name="sceneName">场景名称</param>
|
||
/// <param name="width">图像宽度</param>
|
||
/// <param name="height">图像高度</param>
|
||
/// <param name="format">图像格式</param>
|
||
/// <param name="prefix">文件名前缀</param>
|
||
/// <returns>截图文件路径,失败返回null</returns>
|
||
public static string GenerateSceneScreenshotToDirectory(string outputDirectory, string sceneName, int width, int height, ImageFormat format, string prefix = "scene")
|
||
{
|
||
return GenerateSceneScreenshotInternal(outputDirectory, sceneName, width, height, format, prefix);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成场景截图内部实现
|
||
/// </summary>
|
||
private static string GenerateSceneScreenshotInternal(string outputDirectory, string sceneName, int width, int height, ImageFormat format, string prefix)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Debug(string.Format("开始生成场景截图: {0}_{1}, 尺寸={2}x{3}, 目录={4}", prefix, sceneName, width, height, outputDirectory));
|
||
|
||
// 生成文件名(SaveNavigationMapImage会确保目录存在)
|
||
string extension = ImageFormatToExtension(format);
|
||
string sanitizedName = SanitizeFileName(sceneName);
|
||
string filename = GenerateTimestampedFileName(string.Format("{0}_{1}", prefix, sanitizedName), extension);
|
||
string screenshotPath = Path.Combine(outputDirectory, filename);
|
||
|
||
// 调用截图生成器(复用 NavigationMapGenerator)
|
||
var generator = new Core.NavigationMapGenerator();
|
||
var bitmap = generator.GenerateNavigationMapImage(
|
||
ImageGenerationStyle.ScenePlusOverlay,
|
||
width,
|
||
height,
|
||
false
|
||
);
|
||
|
||
// 保存截图(SaveNavigationMapImage内部会确保目录存在)
|
||
generator.SaveNavigationMapImage(bitmap, screenshotPath, format);
|
||
|
||
LogManager.Debug(string.Format("场景截图已生成: {0}", screenshotPath));
|
||
return screenshotPath;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error(string.Format("生成场景截图失败: {0}", ex.Message), ex);
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
}
|