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

24 KiB
Raw Blame History

转 DELMIA Apriso XML 的步骤

直接生成符合 DELMIA Apriso 要求的 TransportPathOrders XML跳过 XSLT 转换步骤。 简化方案直接生成目标XML 目标Schema直接使用 创建文件 TransportPathOrder.xsd这是唯一需要的Schema文件 xml 复制

<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 复制

17838e6e-1112-4e62-a3ab-d7a3354d39d3 人工_0219_203325 NavisworksTransport生成的路径 Ground 102.943 2026-03-09T16:30:45Z NavisworksTransport 1.0 3ada559e-36b9-4537-b341-cfff765c8d43 0 起点 StartPoint -152.614 0.517 14.833 true 042229ba-0ce2-4f6c-af8f-57f840300e82 1 路径点1 WayPoint -131.345 -14.532 14.75 true 69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5 2 终点 EndPoint -55.369 -0.504 14.833 true edge_0 straight 0 3ada559e-36b9-4537-b341-cfff765c8d43 042229ba-0ce2-4f6c-af8f-57f840300e82 22.595 edge_1 arc 1 042229ba-0ce2-4f6c-af8f-57f840300e82 69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5 6.548 -134.17 -12.533 14.761 -127.943 -13.903 14.754 -129.432 -5.837 14.799 8.202 0.798 edge_2 straight 2 69fa7321-3dc5-4ec5-9c1f-74e2a6d787a5 终点_D 73.8 0 0 0 0 Global DELMIA Apriso 配置(简化版) 既然您直接生成目标XML配置也简化了 1. 部署Schema 将 TransportPathOrder.xsd 复制到: plain 复制 SchemaRepository/XMLSchemas/FlexNet/TransportPathOrder.xsd 2. Routing Configuration仅需路由无需XSLT xml 复制 注意:不需要 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 文件。