Arcengine开发效率优化建议
1.修改要素效率对比
需要对图层的某个字段统一赋值
方法1:IFeature赋值
var dataset = layer as IDataset;
var workspaceEdit = dataset.Workspace as IWorkspaceEdit;
workspaceEdit.StartEditing(true);
workspaceEdit.StartEditOperation();
IQueryFilter filter = new QueryFilterClass();
filter.WhereClause = $"{GuidField} is null or {GuidField} = ' '";
var index = layer.FeatureClass.Fields.FindField(GuidField);
var cursor = layer.Search(filter, false);
IFeature feature = null;
while ((feature = cursor.NextFeature()) != null)
{
feature.Value[index] = Guid.NewGuid().ToString();
feature.Store();
}
Marshal.ReleaseComObject(cursor);
workspaceEdit.StartEditOperation();
workspaceEdit.StopEditing(true);
Marshal.ReleaseComObject(workspaceEdit);
该方法也是常用的一种方法,耗时112132ms
方法2 IRow赋值
var dataset = layer as IDataset;
var workspaceEdit = dataset.Workspace as IWorkspaceEdit;
workspaceEdit.StartEditing(true);
workspaceEdit.StartEditOperation();
IQueryFilter filter = new QueryFilterClass();
filter.WhereClause = $"{GuidField} is null or {GuidField} = ' '";
var index = layer.FeatureClass.Fields.FindField(GuidField);
ITable table = layer as ITable;
var cursor = table.Update(filter, false);
IRow row;
while((row = cursor.NextRow()) != null)
{
row.set_Value(index,Guid.NewGuid().ToString());
cursor.UpdateRow(row);
}
Marshal.ReleaseComObject(cursor);
workspaceEdit.StartEditOperation();
workspaceEdit.StopEditing(true);
Marshal.ReleaseComObject(workspaceEdit);
结论
方法 | 时间 |
---|---|
IFeature | ≤112132ms |
IRow | ≤40808ms |
方法1无疑是我们最常用的一种属性编辑方法,然而耗时大概是方法2的3倍。
2.新增要素效率对比(待补充)
3.删除要素效率对比(待补充)
4.遍历要素效率对比
4.1. 需多次遍历要素时
var layer = pLayer as IFeatureLayer;
var cursor = layer.Search(null, false);
IFeature feature;
List<IFeature> features = new List<IFeature>();
while ((feature = cursor.NextFeature()) != null)
{
features.Add(feature);
}
//1.Cursor遍历
cursor = layer.Search(null, false);
while ((feature = cursor.NextFeature()) != null)
{
}
//2.list遍历
foreach(var f in features)
{
}
Marshal.ReleaseComObject(cursor);
在日常开发中有时需要对要素进行自身的一些对比,比如拓扑检查的时候,
方法 | 时间 |
---|---|
Cursor遍历 | ≤17ms |
List遍历 | ≤1ms |
实验表明,Cursor的遍历效率远远低于list
4.2.只需读取要素OID时
4.2.1.遍历IDS
IFeatureSelection selection = layer as IFeatureSelection;
selection.SelectFeatures(filter, esriSelectionResultEnum.esriSelectionResultNew, false);
var ids = selection.SelectionSet.IDs;
int id = -1;
while ((id = ids.Next()) != -1)
{
result.Add(new ExecuteResult()
{
DataId = id.ToString(),
DataSource = layerPathInfo.Path,
DataType = type,
ErrorInfo = $"{target}字段值为空!源要素:{layer.Name}(OID={id})"
});
}
Marshal.ReleaseComObject(ids);
selection.Clear();
4.2.2.遍历Ifeature
var cursor = layer.Search(filter, false);
IFeature feature = null;
while ((feature = cursor.NextFeature()) != null)
{
result.Add(new ExecuteResult()
{
DataId = feature.OID.ToString(),
DataSource = layerPathInfo.Path,
DataType = type,
ErrorInfo = $"{target}字段值为空!源要素:{layer.Name}(OID={feature.OID})"
});
Marshal.ReleaseComObject(feature);
}
Marshal.ReleaseComObject(cursor);
4.2.3.遍历IRow
ITable table = layer as ITable;
var cursor = table.Search(filter, false);
IRow row = null;
while ((row = cursor.NextRow()) != null)
{
result.Add(new ExecuteResult()
{
DataId = row.OID.ToString(),
DataSource = layerPathInfo.Path,
DataType = type,
ErrorInfo = $"{target}字段值为空!源要素:{layer.Name}(OID={row.OID})"
});
Marshal.ReleaseComObject(row);
}
Marshal.ReleaseComObject(cursor);
方法 | 时间 |
---|---|
IDS | ≤13886ms |
IFeature | ≤36424ms |
IRow | ≤36491ms |
实验表明,遍历Ids的效率是较高的
5. 计算点到目标几何的最短距离是否在容差范围内
5.1 esri方法
/// <summary>
/// 求指定距离
/// </summary>
/// <param name="pGeometryA">目标几何</param>
/// <param name="pGeometryB">点</param>
/// <param name="torrance">容差</param>
/// <returns></returns>
private bool GetTwoGeometryDistance(IGeometry pGeometryA, IPoint pGeometryB,double torrance)
{
IProximityOperator pProOperator = pGeometryA as IProximityOperator;
if (pGeometryA != null || pGeometryB != null)
{
double distance = pProOperator.ReturnDistance(pGeometryB);
Marshal.ReleaseComObject(pProOperator);
return distance<torrance;
}
else
{
return false;
}
}
5.2.数学方法
/// <summary>
/// 数学方法计算点到几何的最短距离
/// </summary>
/// <param name="point">点</param>
/// <param name="geo">目标几何</param>
/// <param name="torrance">容差</param>
/// <returns></returns>
private bool GetTwoGeometryDistanceByMath(IPoint point, IGeometry geo,double torrance)
{
var segments = geo as ISegmentCollection;
torrance = torrance * torrance;
for(int i = 0; i < segments.SegmentCount; i++)
{
var line = segments.Segment[i];
var dis = GetPointLineDis(line.FromPoint, line.ToPoint, point);
if (dis < torrance)
return true;
}
return false;
}
/// <summary>
/// 求点p到线段ab的最短距离的平方,避免过多开方运算
/// </summary>
/// <param name="pa"></param>
/// <param name="pb"></param>
/// <param name="p"></param>
/// <returns></returns>
private double GetPointLineDis(IPoint a,IPoint b,IPoint p)
{
double dis = 0;
//向量AB·向量Ap
var abCrossAp = (b.X - a.X) * (p.X - a.X) + (b.Y - a.Y) * (p.Y - a.Y);
//∠PAB为钝角,最短距离为PA
if (abCrossAp <= 0)
dis = (p.X - a.X) * (p.X - a.X) + (p.Y - a.Y) * (p.Y - a.Y);
else
{
var ab2 = (b.X - a.X) * (b.X - a.X) + (b.Y - a.Y) * (b.Y - a.Y);
//p的垂线相交于AB向量的延长线上,最短距离为PB
if (abCrossAp >= ab2)
dis = (p.X - b.X) * (p.X - b.X) + (p.Y - b.Y) * (p.Y - b.Y);
//p的垂线相交于AB向量上(交点为D),最短距离为垂线的值
else
{
var r = abCrossAp / ab2;
var Dx = a.X + (b.X - a.X) * r;
var Dy = a.Y + (b.Y - a.Y) * r;
dis = (p.X - Dx) * (p.X - Dx) + (p.Y - Dy) * (p.Y - Dy);
}
}
return dis;
}
结论
方法 | 时间 |
---|---|
Esri | ≤12ms |
数学方法 | ≤3ms |
实验表明,使用数学方法计算效率大概是直接用esri方法的4倍