作者:翔翔
背景
在电力行业中,由设计院或者数据生产商提供成果数据。成果数据有的是GIM、有的是模型+姿态矩阵、有的是模型+模型对应的绕轴旋转值、轴缩放值和平移值。但是并不是所有的成果数据就绝对正确或一层不变。当杆塔所在位置地形变了,此时杆塔模型便会根据实际的地形来微调,比如旋转、缩放、平移等。微调杆塔时也需要将绝缘子串的状态实时改变。微调后还能将当前模型的矩阵导出以便做成新的成果数据提交。如何在SuperMap iObjects .Net产品中实现该流程?这就是本文要讲的主题。
主题
首先可能大家会问什么是实例化?如果大家对实例化不熟悉的话可以参考博客中的简单说明:
模型数据处理之实例化处理
数据准备
- 杆塔点位数据集
- 杆塔和绝缘子串S3MB模型文件
- 绝缘子串相对杆塔的矩阵信息
联动更新模型位置信息
通过编辑二维地图中的点位信息,将更改后的点位信息传入到对应的模型上,实现杆塔及其绝缘子串的位置更新。
关键代码如下::
/// <summary>
/// 更新模型位置信息,
/// </summary>
/// <param name="smid">杆塔smid</param>
/// <param name="position">更新位置</param>
public void UpdatePosition(int smid, Point3D position)
{
///获取smid的对象
List<LinkSource> queryLink = m_linkSource.FindAll(o => o.SmID == smid);
m_towerInstance.States.ForEach(item =>
{
if (queryLink.Find(o => o.Guid == item.ID) != null)
{
item.Longitude = position.X;
item.Latitude = position.Y;
item.Altitude = position.Z;
}
});
}
示意gif如下
更新模型旋转
通过设置模型绕XYZ任意轴旋转角度,计算出杆塔和绝缘子串的旋转矩阵。绝缘子串旋转矩阵更新主要流程:
- 获取串的偏移值
- 根据旋转值计算串的新偏移
- 将串原始矩阵的偏移值归零,得到新的原始矩阵
- 通过新的旋转值构建矩阵,然后乘新的原始矩阵
- 将步骤2中的偏移值设置给步骤4得到的矩阵。最后将矩阵赋给对象
关键代码如下:
/// <summary>
/// 更新模型旋转
/// </summary>
/// <param name="smid">杆塔smid</param>
/// <param name="rx">X轴旋转角度</param>
/// <param name="ry">Y轴旋转角度</param>
/// <param name="rz">Z轴旋转角度</param>
public void UpdateRotation(int smid, double rx, double ry, double rz)
{
///获取smid的对象
List<LinkSource> queryLink = m_linkSource.FindAll(o => o.SmID == smid);
///计算杆塔矩阵
m_towerInstance.States.ForEach(item =>
{
if (queryLink.Find(o => o.Guid == item.ID) != null)
{
item.LocalMatrix = item.LocalMatrix.Multipy(Matrix.RotateXYZ(rx, ry, rz));
}
});
///计算绝缘子串矩阵信息
m_stringInstanceS35.States.ForEach(item =>
{
if (queryLink.Find(o => o.Guid == item.ID) != null)
{
Matrix matrix = item.LocalMatrix;
///获取矩阵偏移值
Point3D p1 = new Point3D(matrix.ArrayValue[12], matrix.ArrayValue[13], matrix.ArrayValue[14]);
///串旋转后的挂点
Point3D p2 = CDUtil.Matrix.Matrix.removeP(p1, new Dictionary<int, double>() { { 1, rx }, { 2, ry }, { 3, rz } }, new Point3D(), new Point3D(1, 1, 1));
///先将原始矩阵偏移归零
double[] temp = matrix.ArrayValue;
temp[12] = 0;
temp[13] = 0;
temp[14] = 0;
matrix.ArrayValue = temp;
///旋转矩阵乘归零矩阵
matrix = Matrix.RotateXYZ(rx, ry, rz).Multipy(matrix);
///重新设置矩阵的偏移值,值为串旋转后的挂点
double[] ma = matrix.ArrayValue;
ma[12] = p2.X;
ma[13] = p2.Y;
ma[14] = p2.Z;
matrix.ArrayValue = ma;
//item.Altitude += 0.0001;
item.LocalMatrix = matrix;
}
});
}
示意gif
更新模型缩放
通过设置模型绕XYZ任意轴缩放比例,计算出杆塔和绝缘子串的旋转矩阵。绝缘子串缩放矩阵更新主要流程:
- 先将缩放矩阵乘原始矩阵得到新矩阵
- 获取步骤1中的偏移值
- 计算偏移值缩放后的新偏移值
- 将步骤3中获取的值设置给步骤1中的偏移值
关键代码如下:
/// <summary>
/// 更新模型缩放
/// </summary>
/// <param name="smid">杆塔smid</param>
/// <param name="sx">X缩方比例</param>
/// <param name="sy">Y缩方比例</param>
/// <param name="sz">Z缩方比例</param>
public void UpdateScale(int smid, double sx, double sy, double sz)
{
///获取smid的对象
List<LinkSource> queryLink = m_linkSource.FindAll(o => o.SmID == smid);
///计算杆塔矩阵
m_towerInstance.States.ForEach(item =>
{
if (queryLink.Find(o => o.Guid == item.ID) != null)
{
item.LocalMatrix = Matrix.Scale(sx, sy, sz).Multipy(item.LocalMatrix);
}
});
///计算绝缘子串矩阵信息
m_stringInstanceS35.States.ForEach(item =>
{
if (queryLink.Find(o => o.Guid == item.ID) != null)
{
///用缩放矩阵乘原始矩阵
Matrix matrix = Matrix.Scale(sx, sy, sz).Multipy(item.LocalMatrix);
///获取矩阵偏移值
Point3D p1 = new Point3D(matrix.ArrayValue[12], matrix.ArrayValue[13], matrix.ArrayValue[14]);
Point3D Spoint = new Point3D(sx, sy, sz);
///计算偏移值缩放后的新偏移值
Point3D p2 = CDUtil.Matrix.Matrix.removeP(p1, new Dictionary<int, double>(), new Point3D(), Spoint);
///设置矩阵偏移值
double[] ma = matrix.ArrayValue;
ma[12] = p2.X;
ma[13] = p2.Y;
ma[14] = p2.Z;
matrix.ArrayValue = ma;
item.LocalMatrix = matrix;
}
});
}
示意gif
模型查询
将模型的唯一ID和对应的数据集SMID对应起来,同时也可存储其他的一些信息。当点击杆塔时,可以获取到该对象的唯一ID。在存储的属性中查询到唯一ID即可获取到该对象的信息。如果还有外挂了一些信息,可通过SMID去查询对应的信息并展示出来。
关键代码如下:
/// <summary>
/// 添加对象到实例化图层
/// </summary>
/// <param name="smid"></param>
/// <param name="position"></param>
/// <param name="description"></param>
public void AddGeometry(int smid, Point3D position, string description)
{
InstanceObjectState tower = new InstanceObjectState();
///设置唯一guid,值的范围1-2^24之间
int guid = GetGuid();
LinkSource linkSource = m_linkSource.Find(o => o.Guid == guid);
while (linkSource != null)
{
guid = GetGuid();
linkSource = m_linkSource.Find(o => o.Guid == guid);
}
tower.ID = guid;
tower.Longitude = position.X;
tower.Latitude = position.Y;
tower.Altitude = position.Z;
m_towerInstance.States.Add(tower);
m_linkSource.Add(new LinkSource()
{
Guid = guid,
SmID = smid,
Description = description,
IsTower = true
});
}
示意gif
注意事项
- 上文主要讲的是绝缘字串的矩阵是相对于杆塔的,如果绝缘子串是独立的矩阵,那么新矩阵的算法可能会有改变。
- 需要demo和超图组件包的请给一个邮箱