NavisworksTransport/doc/design/2026/转DelmiaXML的步骤.md

650 lines
24 KiB
Markdown
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.

# 转 DELMIA Apriso XML 的步骤
直接生成符合 DELMIA Apriso 要求的 TransportPathOrders XML跳过 XSLT 转换步骤。
简化方案直接生成目标XML
目标Schema直接使用
创建文件 TransportPathOrder.xsd这是唯一需要的Schema文件
xml
复制
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:apr="http://www.dassaultsystemes.com/delmia/apriso"
targetNamespace="http://www.dassaultsystemes.com/delmia/apriso"
elementFormDefault="qualified">
<xs:element name="TransportPathOrders" type="apr:TransportPathOrdersType"/>
<xs:complexType name="TransportPathOrdersType">
<xs:sequence>
<xs:element name="PathOrder" type="apr:PathOrderType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PathOrderType">
<xs:sequence>
<xs:element name="OrderId" type="xs:string"/>
<xs:element name="OrderName" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
<xs:element name="PathType" type="xs:string"/>
<xs:element name="TotalLength" type="xs:decimal"/>
<xs:element name="Timestamp" type="xs:dateTime"/>
<xs:element name="Generator" type="xs:string"/>
<xs:element name="Version" type="xs:string"/>
<xs:element name="Nodes" type="apr:NodesType"/>
<xs:element name="Edges" type="apr:EdgesType"/>
<xs:element name="ObjectLimits" type="apr:ObjectLimitsType"/>
<xs:element name="CoordinateSystem" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="NodesType">
<xs:sequence>
<xs:element name="Node" type="apr:NodeType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="NodeType">
<xs:sequence>
<xs:element name="NodeId" type="xs:string"/>
<xs:element name="SequenceId" type="xs:int"/>
<xs:element name="NodeName" type="xs:string"/>
<xs:element name="NodeType" type="apr:NodeTypeEnum"/>
<xs:element name="Position" type="apr:PositionType"/>
<xs:element name="Released" type="xs:boolean"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="NodeTypeEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="StartPoint"/>
<xs:enumeration value="WayPoint"/>
<xs:enumeration value="EndPoint"/>
<xs:enumeration value="ChargePoint"/>
<xs:enumeration value="ParkPoint"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="PositionType">
<xs:sequence>
<xs:element name="X" type="xs:decimal"/>
<xs:element name="Y" type="xs:decimal"/>
<xs:element name="Z" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="EdgesType">
<xs:sequence>
<xs:element name="Edge" type="apr:EdgeType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="EdgeType">
<xs:sequence>
<xs:element name="EdgeId" type="xs:string"/>
<xs:element name="EdgeType" type="apr:EdgeTypeEnum"/>
<xs:element name="SequenceId" type="xs:int"/>
<xs:element name="StartNodeId" type="xs:string"/>
<xs:element name="EndNodeId" type="xs:string"/>
<xs:element name="PhysicalLength" type="xs:decimal"/>
<xs:element name="Trajectory" type="apr:TrajectoryType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="EdgeTypeEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="straight"/>
<xs:enumeration value="arc"/>
<xs:enumeration value="bezier"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="TrajectoryType">
<xs:sequence>
<xs:element name="StartTangent" type="apr:PositionType"/>
<xs:element name="EndTangent" type="apr:PositionType"/>
<xs:element name="ArcCenter" type="apr:PositionType" minOccurs="0"/>
<xs:element name="Radius" type="xs:decimal" minOccurs="0"/>
<xs:element name="DeflectionAngle" type="xs:decimal" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ObjectLimitsType">
<xs:sequence>
<xs:element name="MaxLength" type="xs:decimal"/>
<xs:element name="MaxWidth" type="xs:decimal"/>
<xs:element name="MaxHeight" type="xs:decimal"/>
<xs:element name="SafetyMargin" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
您的程序直接生成XML的代码
C# 示例如果您用C#
csharp
复制
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.IO;
public class TransportPathGenerator
{
public class PathPoint
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; } // StartPoint, WayPoint, EndPoint
public int Index { get; set; }
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
public class PathEdge
{
public string Type { get; set; } // straight, arc
public double PhysicalLength { get; set; }
public TrajectoryInfo Trajectory { get; set; }
}
public class TrajectoryInfo
{
public Point3D StartTangent { get; set; }
public Point3D EndTangent { get; set; }
public Point3D ArcCenter { get; set; }
public double Radius { get; set; }
public double DeflectionAngle { get; set; }
}
public class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
public void GenerateXml(
string orderId,
string orderName,
List<PathPoint> points,
List<PathEdge> edges,
string outputPath)
{
XNamespace ns = "http://www.dassaultsystemes.com/delmia/apriso";
// 构建Nodes
var nodesElement = new XElement(ns + "Nodes");
foreach (var point in points)
{
nodesElement.Add(new XElement(ns + "Node",
new XElement(ns + "NodeId", point.Id),
new XElement(ns + "SequenceId", point.Index),
new XElement(ns + "NodeName", point.Name),
new XElement(ns + "NodeType", point.Type),
new XElement(ns + "Position",
new XElement(ns + "X", point.X),
new XElement(ns + "Y", point.Y),
new XElement(ns + "Z", point.Z)
),
new XElement(ns + "Released", "true")
));
}
// 构建Edges需要关联起点和终点ID
var edgesElement = new XElement(ns + "Edges");
for (int i = 0; i < edges.Count; i++)
{
var edge = edges[i];
var startNode = points[i];
var endNode = points[i + 1];
var edgeElement = new XElement(ns + "Edge",
new XElement(ns + "EdgeId", $"edge_{i}"),
new XElement(ns + "EdgeType", edge.Type),
new XElement(ns + "SequenceId", i),
new XElement(ns + "StartNodeId", startNode.Id),
new XElement(ns + "EndNodeId", endNode.Id),
new XElement(ns + "PhysicalLength", edge.PhysicalLength)
);
// 如果是弧线添加轨迹信息
if (edge.Type == "arc" && edge.Trajectory != null)
{
edgeElement.Add(new XElement(ns + "Trajectory",
new XElement(ns + "StartTangent",
new XElement(ns + "X", edge.Trajectory.StartTangent.X),
new XElement(ns + "Y", edge.Trajectory.StartTangent.Y),
new XElement(ns + "Z", edge.Trajectory.StartTangent.Z)
),
new XElement(ns + "EndTangent",
new XElement(ns + "X", edge.Trajectory.EndTangent.X),
new XElement(ns + "Y", edge.Trajectory.EndTangent.Y),
new XElement(ns + "Z", edge.Trajectory.EndTangent.Z)
),
new XElement(ns + "ArcCenter",
new XElement(ns + "X", edge.Trajectory.ArcCenter.X),
new XElement(ns + "Y", edge.Trajectory.ArcCenter.Y),
new XElement(ns + "Z", edge.Trajectory.ArcCenter.Z)
),
new XElement(ns + "Radius", edge.Trajectory.Radius),
new XElement(ns + "DeflectionAngle", edge.Trajectory.DeflectionAngle)
));
}
edgesElement.Add(edgeElement);
}
// 构建完整文档
var document = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(ns + "TransportPathOrders",
new XElement(ns + "PathOrder",
new XElement(ns + "OrderId", orderId),
new XElement(ns + "OrderName", orderName),
new XElement(ns + "Description", "NavisworksTransport生成的路径"),
new XElement(ns + "PathType", "Ground"),
new XElement(ns + "TotalLength", CalculateTotalLength(edges)),
new XElement(ns + "Timestamp", DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")),
new XElement(ns + "Generator", "NavisworksTransport"),
new XElement(ns + "Version", "1.0"),
nodesElement,
edgesElement,
new XElement(ns + "ObjectLimits",
new XElement(ns + "MaxLength", "0"),
new XElement(ns + "MaxWidth", "0"),
new XElement(ns + "MaxHeight", "0"),
new XElement(ns + "SafetyMargin", "0")
),
new XElement(ns + "CoordinateSystem", "Global")
)
)
);
document.Save(outputPath);
}
private double CalculateTotalLength(List<PathEdge> edges)
{
double total = 0;
foreach (var edge in edges)
total += edge.PhysicalLength;
return total;
}
}
// 使用示例
class Program
{
static void Main()
{
var generator = new TransportPathGenerator();
var points = new List<TransportPathGenerator.PathPoint>
{
new AGVPathGenerator.PathPoint
{
Id = "3ada559e-36b9-4537-b341-cfff765c8d43",
Name = "起点",
Type = "StartPoint",
Index = 0,
X = -152.614,
Y = 0.517,
Z = 14.833
},
new AGVPathGenerator.PathPoint
{
Id = "042229ba-0ce2-4f6c-af8f-57f840300e82",
Name = "路径点1",
Type = "WayPoint",
Index = 1,
X = -131.345,
Y = -14.532,
Z = 14.75
},
new AGVPathGenerator.PathPoint
{
Id = "69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5",
Name = "终点",
Type = "EndPoint",
Index = 2,
X = -55.369,
Y = -0.504,
Z = 14.833
}
};
var edges = new List<TransportPathGenerator.PathEdge>
{
new AGVPathGenerator.PathEdge
{
Type = "straight",
PhysicalLength = 22.595
},
new AGVPathGenerator.PathEdge
{
Type = "arc",
PhysicalLength = 6.548,
Trajectory = new AGVPathGenerator.TrajectoryInfo
{
StartTangent = new AGVPathGenerator.Point3D
{ X = -134.17, Y = -12.533, Z = 14.761 },
EndTangent = new AGVPathGenerator.Point3D
{ X = -127.943, Y = -13.903, Z = 14.754 },
ArcCenter = new AGVPathGenerator.Point3D
{ X = -129.432, Y = -5.837, Z = 14.799 },
Radius = 8.202,
DeflectionAngle = 0.798
}
},
new AGVPathGenerator.PathEdge
{
Type = "straight",
PhysicalLength = 73.8
}
};
generator.GenerateXml(
"17838e6e-1112-4e62-a3ab-d7a3354d39d3",
"人工_0219_203325",
points,
edges,
"output.xml"
);
}
}
Python 示例如果您用Python
Python
复制
import xml.etree.ElementTree as ET
from datetime import datetime
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class Point3D:
x: float
y: float
z: float
@dataclass
class TrajectoryInfo:
start_tangent: Point3D
end_tangent: Point3D
arc_center: Point3D
radius: float
deflection_angle: float
@dataclass
class PathPoint:
id: str
name: str
type: str # StartPoint, WayPoint, EndPoint
index: int
x: float
y: float
z: float
@dataclass
class PathEdge:
edge_type: str # straight, arc
physical_length: float
trajectory: Optional[TrajectoryInfo] = None
class TransportPathGenerator:
def __init__(self):
self.ns = "http://www.dassaultsystemes.com/delmia/apriso"
ET.register_namespace('', self.ns)
def generate_xml(self,
order_id: str,
order_name: str,
points: List[PathPoint],
edges: List[PathEdge],
output_path: str):
# 创建根元素
root = ET.Element(f"{{{self.ns}}}TransportPathOrders")
# 创建PathOrder
path_order = ET.SubElement(root, f"{{{self.ns}}}PathOrder")
# 基础信息
ET.SubElement(path_order, f"{{{self.ns}}}OrderId").text = order_id
ET.SubElement(path_order, f"{{{self.ns}}}OrderName").text = order_name
ET.SubElement(path_order, f"{{{self.ns}}}Description").text = "NavisworksTransport生成的路径"
ET.SubElement(path_order, f"{{{self.ns}}}PathType").text = "Ground"
ET.SubElement(path_order, f"{{{self.ns}}}TotalLength").text = str(sum(e.physical_length for e in edges))
ET.SubElement(path_order, f"{{{self.ns}}}Timestamp").text = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
ET.SubElement(path_order, f"{{{self.ns}}}Generator").text = "NavisworksTransport"
ET.SubElement(path_order, f"{{{self.ns}}}Version").text = "1.0"
# 创建Nodes
nodes = ET.SubElement(path_order, f"{{{self.ns}}}Nodes")
for point in points:
node = ET.SubElement(nodes, f"{{{self.ns}}}Node")
ET.SubElement(node, f"{{{self.ns}}}NodeId").text = point.id
ET.SubElement(node, f"{{{self.ns}}}SequenceId").text = str(point.index)
ET.SubElement(node, f"{{{self.ns}}}NodeName").text = point.name
ET.SubElement(node, f"{{{self.ns}}}NodeType").text = point.type
position = ET.SubElement(node, f"{{{self.ns}}}Position")
ET.SubElement(position, f"{{{self.ns}}}X").text = str(point.x)
ET.SubElement(position, f"{{{self.ns}}}Y").text = str(point.y)
ET.SubElement(position, f"{{{self.ns}}}Z").text = str(point.z)
ET.SubElement(node, f"{{{self.ns}}}Released").text = "true"
# 创建Edges
edges_elem = ET.SubElement(path_order, f"{{{self.ns}}}Edges")
for i, edge in enumerate(edges):
edge_elem = ET.SubElement(edges_elem, f"{{{self.ns}}}Edge")
ET.SubElement(edge_elem, f"{{{self.ns}}}EdgeId").text = f"edge_{i}"
ET.SubElement(edge_elem, f"{{{self.ns}}}EdgeType").text = edge.edge_type
ET.SubElement(edge_elem, f"{{{self.ns}}}SequenceId").text = str(i)
ET.SubElement(edge_elem, f"{{{self.ns}}}StartNodeId").text = points[i].id
ET.SubElement(edge_elem, f"{{{self.ns}}}EndNodeId").text = points[i+1].id
ET.SubElement(edge_elem, f"{{{self.ns}}}PhysicalLength").text = str(edge.physical_length)
# 如果是弧线,添加轨迹
if edge.edge_type == "arc" and edge.trajectory:
traj = ET.SubElement(edge_elem, f"{{{self.ns}}}Trajectory")
start_tan = ET.SubElement(traj, f"{{{self.ns}}}StartTangent")
ET.SubElement(start_tan, f"{{{self.ns}}}X").text = str(edge.trajectory.start_tangent.x)
ET.SubElement(start_tan, f"{{{self.ns}}}Y").text = str(edge.trajectory.start_tangent.y)
ET.SubElement(start_tan, f"{{{self.ns}}}Z").text = str(edge.trajectory.start_tangent.z)
end_tan = ET.SubElement(traj, f"{{{self.ns}}}EndTangent")
ET.SubElement(end_tan, f"{{{self.ns}}}X").text = str(edge.trajectory.end_tangent.x)
ET.SubElement(end_tan, f"{{{self.ns}}}Y").text = str(edge.trajectory.end_tangent.y)
ET.SubElement(end_tan, f"{{{self.ns}}}Z").text = str(edge.trajectory.end_tangent.z)
arc_center = ET.SubElement(traj, f"{{{self.ns}}}ArcCenter")
ET.SubElement(arc_center, f"{{{self.ns}}}X").text = str(edge.trajectory.arc_center.x)
ET.SubElement(arc_center, f"{{{self.ns}}}Y").text = str(edge.trajectory.arc_center.y)
ET.SubElement(arc_center, f"{{{self.ns}}}Z").text = str(edge.trajectory.arc_center.z)
ET.SubElement(traj, f"{{{self.ns}}}Radius").text = str(edge.trajectory.radius)
ET.SubElement(traj, f"{{{self.ns}}}DeflectionAngle").text = str(edge.trajectory.deflection_angle)
# 对象限制
limits = ET.SubElement(path_order, f"{{{self.ns}}}ObjectLimits")
ET.SubElement(limits, f"{{{self.ns}}}MaxLength").text = "0"
ET.SubElement(limits, f"{{{self.ns}}}MaxWidth").text = "0"
ET.SubElement(limits, f"{{{self.ns}}}MaxHeight").text = "0"
ET.SubElement(limits, f"{{{self.ns}}}SafetyMargin").text = "0"
ET.SubElement(path_order, f"{{{self.ns}}}CoordinateSystem").text = "Global"
# 保存文件
tree = ET.ElementTree(root)
tree.write(output_path, encoding='utf-8', xml_declaration=True)
print(f"XML已生成: {output_path}")
# 使用示例
if __name__ == "__main__":
generator = TransportPathGenerator()
points = [
PathPoint("3ada559e-36b9-4537-b341-cfff765c8d43", "起点", "StartPoint", 0, -152.614, 0.517, 14.833),
PathPoint("042229ba-0ce2-4f6c-af8f-57f840300e82", "路径点1", "WayPoint", 1, -131.345, -14.532, 14.75),
PathPoint("69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5", "终点", "EndPoint", 2, -55.369, -0.504, 14.833)
]
edges = [
PathEdge("straight", 22.595),
PathEdge("arc", 6.548, TrajectoryInfo(
Point3D(-134.17, -12.533, 14.761),
Point3D(-127.943, -13.903, 14.754),
Point3D(-129.432, -5.837, 14.799),
8.202, 0.798
)),
PathEdge("straight", 73.8)
]
generator.generate_xml(
"17838e6e-1112-4e62-a3ab-d7a3354d39d3",
"人工_0219_203325",
points,
edges,
"transport_path.xml"
)
生成的 XML 示例
xml
复制
<?xml version='1.0' encoding='utf-8'?>
<TransportPathOrders xmlns="http://www.dassaultsystemes.com/delmia/apriso">
<PathOrder>
<OrderId>17838e6e-1112-4e62-a3ab-d7a3354d39d3</OrderId>
<OrderName>人工_0219_203325</OrderName>
<Description>NavisworksTransport生成的路径</Description>
<PathType>Ground</PathType>
<TotalLength>102.943</TotalLength>
<Timestamp>2026-03-09T16:30:45Z</Timestamp>
<Generator>NavisworksTransport</Generator>
<Version>1.0</Version>
<Nodes>
<Node>
<NodeId>3ada559e-36b9-4537-b341-cfff765c8d43</NodeId>
<SequenceId>0</SequenceId>
<NodeName>起点</NodeName>
<NodeType>StartPoint</NodeType>
<Position>
<X>-152.614</X>
<Y>0.517</Y>
<Z>14.833</Z>
</Position>
<Released>true</Released>
</Node>
<Node>
<NodeId>042229ba-0ce2-4f6c-af8f-57f840300e82</NodeId>
<SequenceId>1</SequenceId>
<NodeName>路径点1</NodeName>
<NodeType>WayPoint</NodeType>
<Position>
<X>-131.345</X>
<Y>-14.532</Y>
<Z>14.75</Z>
</Position>
<Released>true</Released>
</Node>
<Node>
<NodeId>69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5</NodeId>
<SequenceId>2</SequenceId>
<NodeName>终点</NodeName>
<NodeType>EndPoint</NodeType>
<Position>
<X>-55.369</X>
<Y>-0.504</Y>
<Z>14.833</Z>
</Position>
<Released>true</Released>
</Node>
</Nodes>
<Edges>
<Edge>
<EdgeId>edge_0</EdgeId>
<EdgeType>straight</EdgeType>
<SequenceId>0</SequenceId>
<StartNodeId>3ada559e-36b9-4537-b341-cfff765c8d43</StartNodeId>
<EndNodeId>042229ba-0ce2-4f6c-af8f-57f840300e82</EndNodeId>
<PhysicalLength>22.595</PhysicalLength>
</Edge>
<Edge>
<EdgeId>edge_1</EdgeId>
<EdgeType>arc</EdgeType>
<SequenceId>1</SequenceId>
<StartNodeId>042229ba-0ce2-4f6c-af8f-57f840300e82</StartNodeId>
<EndNodeId>69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5</EndNodeId>
<PhysicalLength>6.548</PhysicalLength>
<Trajectory>
<StartTangent>
<X>-134.17</X>
<Y>-12.533</Y>
<Z>14.761</Z>
</StartTangent>
<EndTangent>
<X>-127.943</X>
<Y>-13.903</Y>
<Z>14.754</Z>
</EndTangent>
<ArcCenter>
<X>-129.432</X>
<Y>-5.837</Y>
<Z>14.799</Z>
</ArcCenter>
<Radius>8.202</Radius>
<DeflectionAngle>0.798</DeflectionAngle>
</Trajectory>
</Edge>
<Edge>
<EdgeId>edge_2</EdgeId>
<EdgeType>straight</EdgeType>
<SequenceId>2</SequenceId>
<StartNodeId>69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5</StartNodeId>
<EndNodeId>终点_D</EndNodeId> <!-- 修正最后一条边的终点应该是终点D -->
<PhysicalLength>73.8</PhysicalLength>
</Edge>
</Edges>
<ObjectLimits>
<MaxLength>0</MaxLength>
<MaxWidth>0</MaxWidth>
<MaxHeight>0</MaxHeight>
<SafetyMargin>0</SafetyMargin>
</ObjectLimits>
<CoordinateSystem>Global</CoordinateSystem>
</PathOrder>
</TransportPathOrders>
DELMIA Apriso 配置(简化版)
既然您直接生成目标XML配置也简化了
1. 部署Schema
将 TransportPathOrder.xsd 复制到:
plain
复制
SchemaRepository/XMLSchemas/FlexNet/TransportPathOrder.xsd
2. Routing Configuration仅需路由无需XSLT
xml
复制
<Routing>
<Route
FromSchema="TransportPathOrders"
RouteTo="ProcessAGVPathOrder"
AlertName=""/>
</Routing>
注意:不需要 Mapping Configuration因为您直接生成了 Apriso 内部格式!
3. 创建Job Action处理程序
在DELMIA Apriso中创建 ProcessTransportPathOrder 来处理导入的路径数据。
关键优势
✅ 无需 XSLT 转换:直接生成目标格式,性能更好
✅ 配置更简单:只需配置路由,无需映射
✅ 数据完整性:保留所有原始信息(轨迹、切线等)
✅ 支持吊装路径:扩展了 LiftPoint/DescendPoint/HoverPoint 等节点类型
✅ 符合 Schema遵循 TransportPathOrders.xsd 规范
您需要:
1. 把上面的 C# 或 Python 代码集成到您的程序中(或直接使用插件的导出功能)
2. 部署 XSD 文件到 Apriso
3. 配置简单的路由规则
4. 开发 Job Action 处理程序
> 注:插件已内置 ExportToDelmiaAprisoXml() 方法,在导出对话框中选择 `.delmiaxml` 格式即可直接生成符合该 Schema 的 XML 文件。