LinkToolAddin/client/tool/ArcGisProSymbology.cs

250 lines
10 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 ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using LinkToolAddin.server;
using ModelContextProtocol.Server;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace LinkToolAddin.client.tool
{
public class ArcGisProSymbology
{
/// <summary>
/// 将 System.Drawing.Color 转换为 CIMColor支持 RGB 和透明度)
/// </summary>
private static CIMColor ColorToCIMColor(int r, int g, int b, double alpha =0)
{
return ColorFactory.Instance.CreateRGBColor(r, g, b);
}
/// <summary>
/// 构造点符号引用(封装 SymbolFactory 调用)
/// </summary>
private static CIMSymbolReference GetPointSymbolRef(int r, int g, int b, float size)
{
CIMColor color = ColorToCIMColor(r, g, b);
CIMPointSymbol symbol = SymbolFactory.Instance.ConstructPointSymbol(color, size);
return symbol.MakeSymbolReference();
}
/// <summary>
/// 构造线符号引用
/// </summary>
private static CIMSymbolReference GetLineSymbolRef(int r, int g, int b, float width)
{
CIMColor color = ColorToCIMColor(r, g, b);
// 手动创建线符号图层
CIMSolidStroke stroke = new CIMSolidStroke
{
Color = color,
Width = width,
CapStyle = LineCapStyle.Round, // 端点样式:圆头
JoinStyle = LineJoinStyle.Round, // 连接处样式:圆角
Enable = true // 必须启用!
};
// 创建线符号并设置图层
CIMLineSymbol symbol = new CIMLineSymbol
{
SymbolLayers = new CIMSymbolLayer[] { stroke }
};
return symbol.MakeSymbolReference();
}
/// <summary>
/// 构造面符号引用(填充 + 轮廓)
/// </summary>
private static CIMSymbolReference GetPolygonSymbolRef(
int fillR, int fillG, int fillB,
int outlineR, int outlineG, int outlineB,
float outlineWidth)
{
// 填充图层
CIMSolidFill fillLayer = new CIMSolidFill
{
Color = ColorToCIMColor(fillR, fillG, fillB)
};
// 轮廓图层
CIMSolidStroke outlineLayer = new CIMSolidStroke
{
Color = ColorToCIMColor(outlineR, outlineG, outlineB),
Width = outlineWidth,
JoinStyle = LineJoinStyle.Round//圆角
};
CIMPolygonSymbol polygonSymbol = new CIMPolygonSymbol
{
SymbolLayers = new CIMSymbolLayer[] { fillLayer, outlineLayer }
};
return polygonSymbol.MakeSymbolReference();
}
// ==================== 工具方法 ====================
[McpServerTool, Description("可以通过调用 ArcGIS Pro 的符号系统,设置点图层的符号颜色和大小。" +
"此工具将分析要素数据特征与当前地图布局,智能生成符合视觉美学原则的点状符号。" +
"传入参数必须包括红(R)、绿(G)、蓝(B)三种颜色分量0-255、符号尺寸单位以及目标图层名称。" +
"系统在设置过程中综合考虑颜色对比度、符号可辨性、形状匹配度及整体地图协调性等因素," +
"动态调整或创建新的符号配置,避免视觉拥挤或信息弱化问题。" +
"最终输出一个优化后的点符号系统配置,可直接应用于指定的点要素图层,显著提升地图的视觉层次感与信息传达效率。" +
"适用于城市位置、监测站点、兴趣点POI等点状地理要素的可视化表达场景。")]
public static async Task<JsonRpcResultEntity> SetPointColor(string r, string g, string b, string layerName, string size)
{
return await SetSymbolAsync(layerName, esriGeometryType.esriGeometryPoint, () =>
{
return GetPointSymbolRef(int.Parse(r), int.Parse(g), int.Parse(b), float.Parse(size));
}, "点符号");
}
[McpServerTool, Description("可以通过调用 ArcGIS Pro 的符号系统,设置线图层的符号颜色和宽度。" +
"此工具将分析要素数据和当前地图布局,智能选择或生成符合视觉美学原则的线符号。" +
"传入参数必须包括 RGB 三种颜色分量、线符号宽度以及目标图层名称。" +
"系统会综合考虑颜色对比度、线型协调性、地图整体可读性等因素,动态调整或创建新的符号配置。" +
"最终输出一个优化后的线符号系统,可直接应用于指定的线要素图层,显著提升地图的视觉表达效果与信息传达清晰度。" +
"适用于道路、河流、边界等线状要素的符号化场景。")]
public static async Task<JsonRpcResultEntity> SetLineColor(string r, string g, string b, string layerName, string width)
{
return await SetSymbolAsync(layerName, esriGeometryType.esriGeometryPolyline, () =>
{
return GetLineSymbolRef(int.Parse(r), int.Parse(g), int.Parse(b), float.Parse(width));
}, "线符号");
}
[McpServerTool, Description("设置面图层的填充颜色、轮廓颜色和轮廓宽度。" +
"此工具将调用 ArcGIS Pro 符号系统,智能生成符合视觉美学的面符号。" +
"传入参数包括填充颜色的RGB值、轮廓颜色的RGB值、轮廓宽度、图层名称。" +
"最终将优化后的符号应用于指定的面要素图层,提升地图可视化效果。")]
public static async Task<JsonRpcResultEntity> SetPolygonColor(string fillR, string fillG, string fillB,
string outlineR, string outlineG, string outlineB, string outlineWidth, string layerName)
{
return await SetSymbolAsync(layerName, esriGeometryType.esriGeometryPolygon, () =>
{
return GetPolygonSymbolRef(int.Parse(fillR), int.Parse(fillG), int.Parse(fillB), int.Parse(outlineR), int.Parse(outlineG), int.Parse(outlineB), float.Parse(outlineWidth));
}, "面符号");
}
/// <summary>
/// 通用符号设置逻辑(封装重复代码)
/// </summary>
private async static Task<JsonRpcResultEntity> SetSymbolAsync(
string layerName,
esriGeometryType expectedType,
Func<CIMSymbolReference> symbolFactory,
string symbolTypeName)
{
try
{
Map map = MapView.Active?.Map;
if (map == null)
{
return new JsonRpcErrorEntity
{
Error = new Error
{
Code = "404",
Message = "当前没有激活的地图"
}
};
}
FeatureLayer featureLayer = map.GetLayersAsFlattenedList()
.OfType<FeatureLayer>()
.FirstOrDefault(l => l.Name == layerName);
if (featureLayer == null)
{
return(new JsonRpcErrorEntity
{
Error = new Error
{
Code = "404",
Message = $"找不到名为 '{layerName}' 的图层"
}
});
}
if (featureLayer.ShapeType != expectedType)
{
return(new JsonRpcErrorEntity
{
Error = new Error
{
Code = "400",
Message = $"指定图层 '{layerName}' 不是{symbolTypeName}图层"
}
});
}
CIMRenderer renderer = null;
await QueuedTask.Run(async () =>
{
renderer = featureLayer.GetRenderer();
});
CIMSimpleRenderer simpleRenderer = renderer as CIMSimpleRenderer;
if (simpleRenderer == null)
{
return(new JsonRpcErrorEntity
{
Error = new Error
{
Code = "400",
Message = $"图层 '{layerName}' 的渲染器不是简单渲染器,无法设置"
}
});
}
await QueuedTask.Run(async () =>
{
CIMSymbolReference symbolRef = symbolFactory();
simpleRenderer.Symbol = symbolRef;
featureLayer.SetRenderer(renderer);
});
return (new JsonRpcSuccessEntity
{
Result = $"{symbolTypeName}设置成功",
Id = GetIdForType(expectedType)
});
}
catch (Exception ex)
{
// 捕获 QueuedTask 外层异常(如线程中断等)
return new JsonRpcErrorEntity
{
Error = new Error
{
Code = "500",
Message = $"任务执行失败: {ex.Message}"
}
};
}
}
/// <summary>
/// 根据几何类型返回对应的 ID用于兼容原逻辑
/// </summary>
private static int GetIdForType(esriGeometryType type)
{
return type switch
{
esriGeometryType.esriGeometryPoint => 1,
esriGeometryType.esriGeometryPolyline => 2,
esriGeometryType.esriGeometryPolygon => 3,
_ => 0
};
}
}
}