EKL - Automation of Pipe creation

Introduction

In the many Industry, some customers need to route a very large number of parts in the Pipe/Tube/HVAC Duct/Raceway Tray discipline, the route point coordinates and other part characteristics coming from an input file (csv, Excel or xml files for instance).

Dedicated new EKL functions/methods to support automatic routing are now available from 2017x FD09.

In this demonstration, we use :

  • an xml file containing the definition of 3 HVAC ducts and 1 pipe, definition in terms of nodes position, size (width, height, wall thickness), section shape, and orientation for the HVAC duct, and just size (outside diameter & wall thickness) for the pipe.
     
  • an Expert Rule containing an EKL script to read the xml file and translate the information contained in the file into a structured data supplied to the different EKL methods to generate the duct and pipe parts.
     
  • a product containing a HVAC Spool and a Piping Spool in which the duct and pipe parts will be automatically created.
     

The choice of Expert Rule to generate the ducts and pipes is motivated by the fact that it could be run in batch mode (KnowledgeExpertReport batch), allowing to process files containing the definition of hundreds of pipes, ducts or raceway trays.

Video 1:

 

Video2:

In the second video, we just modify a few things in the file and we generate the parts again, just to show the difference.

 

Dataset

 

EKL commands for pipe from DS doc

https://dsdoc.dsone.3ds.com/3DEXPERIENCER2021x/en/English/DSDocDSExa.htm?show=EKLRefMap/eklpip-r-PipeTube_PhysicalFunctions.htm

 

EKL CODE

 

/* inputName: ProdToGenerateRoutes                  inputType: VPMReference*/

if ProdToGenerateRoutes.V_Name->Search( "ProductToGenerateRoutes" ) == -1
{
                exit
}


/* Prepare variables containing spools */
let instProductForHvac (VPMInstance)
instProductForHvac = ProdToGenerateRoutes.Children.GetItem(1)

let refProductForHvac (VPMReference)
refProductForHvac = instProductForHvac.Reference

let instHvacSpool (HVAC_Spool_Inst)
instHvacSpool = refProductForHvac.Children.GetItem(1)

let refHvacSpool (HVAC_Spool)
set refHvacSpool = instHvacSpool.Reference

let instProductForPipe (VPMInstance)
instProductForPipe = ProdToGenerateRoutes.Children.GetItem(2)

let refProductForPipe (VPMReference)
refProductForPipe = instProductForPipe.Reference

let instPipingSpool (VPMInstance)
instPipingSpool = refProductForPipe.Children.GetItem(1)

let refPipingSpool (Piping_Spool)
set refPipingSpool = instPipingSpool.Reference


/* Read the xml file containing routes data */
let xmlDocRoutes (XMLDocument)
xmlDocRoutes = CreateXMLDocument( "E:\Work\Customers\Astrium\V6Introduction\WaveGuide\2017x\Tests\AutomaticRouting\Routes.xml" )

// Access the root node
let xmlRoot (XMLNode)
xmlRoot = xmlDocRoutes.Root

// Access the xmlElement named Routes
let xmlRoutes (XMLElement)
xmlRoutes = xmlRoot.Access( "Routes", "XMLElement" )


// Process all the routes found in the file
let n (Integer)
let lXmlRoutes (List)
lXmlRoutes = xmlRoutes.Children.Filter( "XMLElement", "" )
n = lXmlRoutes.Size()


let xmlPart (XMLElement)
let xmlSize (XMLElement)
let xmlWidth, xmlHeight, xmlCornerRadius, xmlThickness, xmlOuterDiameter (XMLElement)
let xmlWidthValue, xmlHeightValue, xmlCornerRadiusValue, xmlThicknessValue, xmlOuterDiameterValue (XMLText)
let xmlShape (XMLElement)
let xmlShapeValue (XMLText)
let xmlOrientation (XMLElement)
let xmlOrientationValue (XMLText)
let sPartName (String)
let sType (String)
let sWidth, sHeight, sCornerRadius, sWallThickness, sOuterDiameter (String)
let Width, Height, CornerRadius, WallThickness, OuterDiameter (LENGTH)
let hvOrientation (HvacOrientation)
let hvCurOrientation (HvacOrientation)
let hvShape (V_Shape_Enum)

let xmlPoints (XMLElement)
let lXmlPoints (List)
let xmlBendRadius (XMLElement)
let xmlBendRadiusValue (XMLText)
let BendRadius (LENGTH)
let xmlCoordinates (XMLElement)
let xmlCoordinatesValue (XMLText)
let sCoordinates (String)
let lCoordinates (List)
let X, Y, Z (LENGTH)
let p (Integer)
let xmlPoint (XMLElement)
let sPointName (String)
let i (Integer)

let refNewHvacPart (HVAC_Rigid_Duct)
let instNewHvacPart (HVAC_Rigid_Duct_Inst)
let refNewPipingPart (Piping_Rigid_Pipe)
let instNewPipingPart (Piping_Rigid_Pipe_Inst)

let lPoints (List)
let lBendRadii (List)
let P (Point)
let gsmP (GSMPoint)
let gsmPcoord (GSMPointCoord)
let obPoints (OpenBodyFeature)
let lRouteNodes (List)
let nPoints (Integer)

let retCode (Integer)

i = 1
for i while i <= n
{
                // Get info on the first level node
                xmlPart = lXmlRoutes[i]
               
                // Read part name and type (HVAC or Pipe)
                sPartName = xmlPart.GetAttributeString( "id" )
                sType = xmlPart.GetAttributeString( "type" )
               
                Trace( 1, "Processing # which is a #", sPartName, sType )
               
                // Get the size node
                xmlSize = xmlPart.Access( "Size", "XMLElement" )
               
               
                if sType == "HVAC"
                {
                                // If HVAC, read Width, Height, CornerRadius, Shape and Orientation information from the xml node
                                xmlWidth = xmlSize.Access( "Width", "XMLElement" )
                                set xmlWidthValue = xmlWidth.Find( "XMLText", "x.Text <> \"\"", true )
                                sWidth = xmlWidthValue.Text
                                Width = sWidth.ToDimension( "Length" )
                               
                                xmlHeight = xmlSize.Access( "Height", "XMLElement" )
                                set xmlHeightValue = xmlHeight.Find( "XMLText", "x.Text <> \"\"", true )
                                sHeight = xmlHeightValue.Text
                                Height = sHeight.ToDimension( "Length" )
                                Trace( 2, "Size read: # x #", Width, Height )
                               
                                xmlShape = xmlPart.Access( "Shape", "XMLElement" )
                                set xmlShapeValue = xmlShape.Find( "XMLText", "x.Text <> \"\"", true )
                                hvShape = xmlShapeValue.Text
                                Trace( 2, "Shape = #", hvShape )
                               
                                if hvShape == "Rectangle"
                                {
                                                xmlCornerRadius = xmlSize.Access( "CornerRadius", "XMLElement" )
                                                if xmlCornerRadius <> NULL
                                                {
                                                                set xmlCornerRadiusValue = xmlCornerRadius.Find( "XMLText", "x.Text <> \"\"", true )
                                                                sCornerRadius = xmlCornerRadiusValue.Text
                                                                CornerRadius = sCornerRadius.ToDimension( "Length" )
                                                }
                                                else
                                                {
                                                                // Set a default value to the corner radius in case the tag is not present in the file.
                                                                CornerRadius = 0.1mm
                                                                Trace( 3, "The tag  was not found for the shape Rectangle as specified, a default value of 0.1mm is used." )
                                                }
                                }
                                                               
                                xmlOrientation = xmlPart.Access( "Orientation", "XMLElement" )
                                set xmlOrientationValue = xmlOrientation.Find( "XMLText", "x.Text <> \"\"", true )
                                if xmlOrientationValue.Text == "Default"
                                {
                                                hvOrientation = "CATHvaDuctVerticalUp"
                                }
                                else
                                {
                                                hvOrientation = "CATHvaDuctHorizontalLeft"
                                }
                                Trace( 2, "Orientation = #", hvOrientation )
                }
                else
                {
                                // If Pipe, read outer diameter from the xml node
                                xmlOuterDiameter = xmlSize.Access( "OutsideDiameter", "XMLElement" )
                                set xmlOuterDiameterValue = xmlOuterDiameter.Find( "XMLText", "x.Text <> \"\"", true )
                                sOuterDiameter = xmlOuterDiameterValue.Text
                                OuterDiameter = sOuterDiameter.ToDimension( "Length" )
                                Trace( 2, "Diameter read: #", OuterDiameter )
                }
               
                xmlThickness = xmlSize.Access( "Thickness", "XMLElement" )
                set xmlThicknessValue = xmlThickness.Find( "XMLText", "x.Text <> \"\"", true )
                sWallThickness = xmlThicknessValue.Text
                WallThickness = sWallThickness.ToDimension( "Length" )
                Trace( 2, "WallThickness = #", WallThickness )
               
               
                /* ========== Read the Points =========== */
                // Access the Points xml node
                xmlPoints = xmlPart.Access( "Points", "XMLElement" )
               
                // Get all the points info (coordinates, bend radius)
                lXmlPoints = xmlPoints.Children.Filter( "XMLElement", "" )
               
                p = 1
                for p while p <= lXmlPoints.Size()
                {
                                // Accessing xml element related to one point
                                xmlPoint = lXmlPoints[p]
                               
                                // Get its name
                                sPointName = xmlPoint.GetAttributeString( "id" )
                               
                                // Read Bend Radius
                                xmlBendRadius = xmlPoint.Access( "BendRadius", "XMLElement" )
                                set xmlBendRadiusValue = xmlBendRadius.Find( "XMLText", "x.Text <> \"\"", true )
                                BendRadius = xmlBendRadiusValue.Text->ToDimension( "Length" )
                               
                                // Read coordinates
                                xmlCoordinates = xmlPoint.Access( "Coordinates", "XMLElement" )
                                set xmlCoordinatesValue = xmlCoordinates.Find( "XMLText", "x.Text <> \"\"", true )
                                sCoordinates = xmlCoordinatesValue.Text
                                lCoordinates = SplitString( sCoordinates, ", " )
                                X = ( lCoordinates[1] ) ->ToDimension( "Length" )
                                Y = ( lCoordinates[2] ) ->ToDimension( "Length" )
                                Z = ( lCoordinates[3] ) ->ToDimension( "Length" )
                               
                                Trace( 3, "# (Bend radius = #, X=#, Y=#, Z=#)", sPointName, BendRadius, X, Y, Z )
                               
                                lPoints.Append( List( sPointName, X, Y, Z ) )
                                lBendRadii.Append( BendRadius )
                }
               
                // Create the part
                if sType == "HVAC"
                {
                                // Create the new duct reference
                                refNewHvacPart = new( "HVAC_Rigid_Duct", sPartName, NULL )
                               
                                // Instantiate it under the HVAC spool
                                instNewHvacPart = new( "HVAC_Rigid_Duct_Inst", "", refHvacSpool, refNewHvacPart )
                               
                                // Create it as a "New Reference"
                                instNewHvacPart.SetNewReference( NULL )
                               
                                // Set its shape
                                refNewHvacPart.SetShape( hvShape )
                               
                                // Set its dimensions
                                refNewHvacPart.V_Width = Width
                                refNewHvacPart.V_Height = Height
                                if hvShape == "Rectangle"
                                {
                                                refNewHvacPart.V_CornerRadius = CornerRadius
                                }
                                refNewHvacPart.V_WallThickness = WallThickness
                               
                                // Create the points in the duct inside the first geometrical set
                                set obPoints = refNewHvacPart.Find( "OpenBodyFeature", "", true )
                                if obPoints == NULL
                                {
                                                Trace( 3, "Warning!! No geometrical set was created upon the creation of the part. Please check your Preferences > Infrastructure > 3DShape Infrastructure > 3DShape" )
                                                Trace( 3, "We can not generate this duct, skipping to the next one." )
                                                continue
                                }
                               
                                p = 1
                                nPoints = lPoints.Size()
                                for p while p <= nPoints
                                {
                                                // First get information on the point to create (name and coordinates)
                                                sPointName = lPoints[p][1]
                                                X = lPoints[p][2]
                                                Y = lPoints[p][3]
                                                Z = lPoints[p][4]
                                               
                                                // Create a new point
                                                P = new( "Point", sPointName, obPoints )
                                                set gsmP = P
                                                if gsmP <> NULL
                                                {
                                                                // Make this point a "Point with coordinates" type
                                                                gsmP.PointType = "Coordinates"
                                                                set gsmPcoord = gsmP
                                                }
                                                if gsmPcoord <> NULL
                                                {
                                                                // Define the coordinates to the point, and its name
                                                                gsmPcoord.X = X
                                                                gsmPcoord.Y = Y
                                                                gsmPcoord.Z = Z
                                                                gsmPcoord.Name = sPointName
                                                                gsmPcoord.Update()
                                                                gsmPcoord.Show = false
                                                               
                                                                // Populate the list of nodes to be used to route the duct
                                                                lRouteNodes.Append( P )
                                                }                              
                                }
                               
                                // Route the duct through the points
                                retCode = refNewHvacPart.Add3DPoint( lRouteNodes, 0 )
                                Trace( 2, "Adding the points resulted in the return code: #", retCode )
                               
                                // Remove the two initial points that are automatically created upon the creation of the new duct.
                                retCode = refNewHvacPart.RemoveNode( List( nPoints+1, nPoints+2 ) )
                                Trace( 2, "Removing the two inial points resulted in the return code: #", retCode )
                               
                                // Assign the right bend radius on each node
                                p = 1
                                for p while p <= lBendRadii.Size()
                                {
                                                BendRadius = lBendRadii[p]
                                                retCode = refNewHvacPart.SetNodeBendRadius( p, BendRadius )
                                                Trace( 3, "Assign the radius # to node # resulted in the return code: #", BendRadius, p, retCode )
                                }

                                // Set its orientation
                                refNewHvacPart.SetSectionOrientation( hvOrientation )                              
                                                               
                                // Propagate the geometry
                                retCode = instNewHvacPart->PropagateReferenceToGeometry()
                                Trace( 2, "Propagating the geometry resulted in the return code: #", retCode )
                }
                else
                {
                                // Create the new pipe reference
                                refNewPipingPart = new( "Piping_Rigid_Pipe", sPartName, NULL )
                               
                                // Instantiate it under the Piping spool
                                instNewPipingPart = new( "Piping_Rigid_Pipe_Inst", "", refPipingSpool, refNewPipingPart )
                               
                                // Create it as a "New Reference"
                                instNewPipingPart.SetNewReference( NULL )
                               
                                // Set its dimensions
                                refNewPipingPart.V_OutsideDiameter = OuterDiameter
                                refNewPipingPart.V_WallThickness = WallThickness
                               
                                // Create the points in the pipe inside the first geometrical set
                                set obPoints = refNewPipingPart.Find( "OpenBodyFeature", "", true )
                                if obPoints == NULL
                                {
                                                Trace( 3, "Warning!! No geometrical set was created upon the creation of the part. Please check your Preferences > Infrastructure > 3DShape Infrastructure > 3DShape" )
                                                Trace( 3, "We can not generate this pipe, skipping to the next one." )
                                                continue
                                }
                               
                                p = 1
                                nPoints = lPoints.Size()
                                forwhile p <= nPoints
                                {
                                                // First get information on the point to create (name and coordinates)
                                                sPointName = lPoints[p][1]
                                                X = lPoints[p][2]
                                                Y = lPoints[p][3]
                                                Z = lPoints[p][4]
                                               
                                                // Create a new point
                                                P = new( "Point", sPointName, obPoints )
                                                set gsmP = P
                                                if gsmP <> NULL
                                                {
                                                                // Make this point a "Point with coordinates" type
                                                                gsmP.PointType = "Coordinates"
                                                                set gsmPcoord = gsmP
                                                }
                                                if gsmPcoord <> NULL
                                                {
                                                                // Define the coordinates to the point, and its name
                                                                gsmPcoord.X = X
                                                                gsmPcoord.Y = Y
                                                                gsmPcoord.Z = Z
                                                                gsmPcoord.Name = sPointName
                                                                gsmPcoord.Update()
                                                                gsmPcoord.Show = false
                                                               
                                                                // Populate the list of nodes to be used to route the duct
                                                                lRouteNodes.Append( P )
                                                }                              
                                }
                               
                                // Route the duct through the points
                                retCode = refNewPipingPart.Add3DPoint( lRouteNodes, 0 )
                                Trace( 2, "Adding the points resulted in the return code: #", retCode )
                               
                                // Remove the two initial points that are automatically created upon the creation of the new duct.
                                retCode = refNewPipingPart.RemoveNode( List( nPoints+1, nPoints+2 ) )
                                Trace( 2, "Removing the two initial points resulted in the return code: #", retCode )

                                // Set a default radius, otherwise the assignment of different bend radius doesn't work ...
                                retCode = refNewPipingPart.SetDefaultBendRadius( 10mm )
                                Trace( 2, "Setting a default radius of 10mm resulted in the return code: #", retCode )
                               
                                // Assign the right bend radius on each node
                                p = 1
                                forwhile p <= lBendRadii.Size()
                                {
                                                BendRadius = lBendRadii[p]
                                                retCode = refNewPipingPart.SetNodeBendRadius( p, BendRadius )
                                                Trace( 3, "Assign the radius # to node # resulted in the return code: #", BendRadius, p, retCode )
                                }
                               
                               
                                // Propagate the geometry
                                retCode = instNewPipingPart->PropagateReferenceToGeometry()
                                Trace( 2, "Propagating the geometry resulted in the return code: #", retCode )
                }
               
                lRouteNodes.RemoveAll()
                lPoints.RemoveAll()
                lBendRadii.RemoveAll()

}

ReframeOn( ProdToGenerateRoutes )