Ik heb de oorspronkelijke code niet meer, dus schreef ik de kern opnieuw als één iLogic-regel. Die volgt dezelfde tags en dezelfde stappen, en is klein genoeg om in één keer te lezen. Draai ze vanuit een lege, opgeslagen hoofdassembly, met het rapport als report.xml in dezelfde map.
Wat de regel verwacht
Het rapport is de XML die je krijgt via Export Report in Tacton Studio. De regel kijkt alleen naar onderdelen met een attribuut IA_type:
| IA_type | Wat de regel doet |
|---|---|
| assembly | Kopieert de bronassembly naar een eigen map, bouwt de kinderen erin op en plaatst ze |
| part | Kopieert het bronpart, vult parameters in, bouwt de features en plaatst het |
| extrude_rectangle | Schetst een rechthoek op een werkvlak en extrudeert die, in het part erboven |
Een Tacton-onderdeel zonder IA-tags is alleen een groepering in de configuratie. De regel loopt erdoor en hangt de kinderen aan de dichtstbijzijnde assembly erboven.
Twee details uit echte rapporten. Attribuutnamen waren niet altijd op dezelfde manier geschreven (IA_Type en IA_type komen allebei voor), dus de regel vergelijkt ze zonder op hoofdletters te letten. En Tacton schrijft getallen met een punt als decimaalteken, wat de Windows-instellingen ook zeggen, dus ze worden gelezen met de invariant culture.
Posities en eenheden
Tacton geeft posities en maten in millimeter. De Inventor API werkt in centimeter, wat de documenteenheden ook zijn. Elke waarde uit het rapport wordt dus door 10 gedeeld voor ze in een matrix of feature gaat. Wie dat vergeet, krijgt een frame dat tien keer te groot is. Dat zie je snel, maar het is makkelijker om het op één plaats te regelen.
Rotatie is rond de Z-as in graden, zoals in de rapporten die ik gebruikte. Parts worden na het plaatsen gefixeerd (grounded). De positie komt uit Tacton; ik voeg geen constraints toe die ze ergens anders naartoe kunnen trekken.
De regel
Zet library op de map met je bronbestanden. Hun namen moeten overeenkomen met IA_source_part, zonder extensie.
AddReference "System.Xml"
Imports System.IO
Imports System.Xml
Imports System.Globalization
Sub Main()
Dim library As String = "C:\Work\Library"
Dim reportPath As String = Path.Combine(ThisDoc.Path, "report.xml")
Dim xml As New XmlDocument()
xml.Load(reportPath)
Dim topAsm As AssemblyDocument = ThisDoc.Document
For Each node As XmlElement In xml.SelectNodes("//report/part")
Walk(node, topAsm, ThisDoc.Path, library)
Next
topAsm.Update()
topAsm.Save()
End Sub
' Build one Tacton part, or pass its children through when it has no IA tags.
Sub Walk(node As XmlElement, parent As AssemblyDocument, folder As String, library As String)
Dim iaType As String = Attr(node, "IA_type").ToLowerInvariant()
If iaType <> "assembly" AndAlso iaType <> "part" Then
For Each child As XmlElement In node.SelectNodes("subparts/part")
Walk(child, parent, folder, library)
Next
Return
End If
If Num(node, "qty", 1) < 1 Then Return
Dim isAssembly As Boolean = (iaType = "assembly")
Dim ext As String = If(isAssembly, ".iam", ".ipt")
Dim name As String = Attr(node, "IA_target_part")
' An assembly gets its own folder, a part is named after its parent.
Dim targetFolder As String = If(isAssembly, Path.Combine(folder, name), folder)
Dim fileName As String = If(isAssembly, name, Path.GetFileNameWithoutExtension(parent.FullFileName) & "_" & name)
Directory.CreateDirectory(targetFolder)
Dim source As String = Path.Combine(library, Attr(node, "IA_source_part") & ext)
Dim target As String = Path.Combine(targetFolder, fileName & ext)
File.Copy(source, target, True)
Dim doc As Document = ThisApplication.Documents.Open(target, False)
If isAssembly Then
For Each child As XmlElement In node.SelectNodes("subparts/part")
Walk(child, doc, targetFolder, library)
Next
Else
ApplyParameters(node, doc)
ApplyFeatures(node, doc)
End If
doc.Update()
doc.Save()
Place(parent, target, node)
End Sub
' Place a file in its parent at the Tacton position (mm) and Z rotation (degrees).
Sub Place(parent As AssemblyDocument, filePath As String, node As XmlElement)
Dim tg As TransientGeometry = ThisApplication.TransientGeometry
Dim m As Matrix = tg.CreateMatrix()
m.SetToRotation(Num(node, "IA_z_rotation") * Math.PI / 180, tg.CreateVector(0, 0, 1), tg.CreatePoint(0, 0, 0))
m.SetTranslation(tg.CreateVector(Num(node, "IA_x_position") / 10, Num(node, "IA_y_position") / 10, Num(node, "IA_z_position") / 10))
Dim occ As ComponentOccurrence = parent.ComponentDefinition.Occurrences.Add(filePath, m)
occ.Grounded = True
End Sub
' Every Tacton attribute with the same name as a part parameter drives that parameter.
Sub ApplyParameters(node As XmlElement, doc As PartDocument)
Dim params As Parameters = doc.ComponentDefinition.Parameters
For Each a As XmlElement In node.SelectNodes("attributes/attribute")
Dim name As String = a.GetAttribute("name")
If name.StartsWith("IA_", StringComparison.OrdinalIgnoreCase) Then Continue For
Dim p As Parameter
Try
p = params.Item(name)
Catch
Continue For
End Try
Dim v As Double
If Not Double.TryParse(a.InnerText, NumberStyles.Float, CultureInfo.InvariantCulture, v) Then Continue For
Dim text As String = v.ToString(CultureInfo.InvariantCulture)
Select Case p.Units
Case "ul" : p.Expression = text
Case "deg" : p.Expression = text & " deg"
Case Else : p.Expression = text & " mm"
End Select
Next
End Sub
Sub ApplyFeatures(node As XmlElement, doc As PartDocument)
For Each f As XmlElement In node.SelectNodes("subparts/part")
If Attr(f, "IA_type").ToLowerInvariant() = "extrude_rectangle" Then ExtrudeRectangle(doc, f)
Next
End Sub
' A rectangle centred on the given point, extruded symmetrically along IA_workplane.
Sub ExtrudeRectangle(doc As PartDocument, f As XmlElement)
Dim def As PartComponentDefinition = doc.ComponentDefinition
Dim tg As TransientGeometry = ThisApplication.TransientGeometry
' Default work planes: 1 = YZ, 2 = XZ, 3 = XY. The axis is the extrusion direction.
Dim plane As WorkPlane
Select Case Attr(f, "IA_workplane")
Case "X_axis" : plane = def.WorkPlanes.Item(1)
Case "Y_axis" : plane = def.WorkPlanes.Item(2)
Case Else : plane = def.WorkPlanes.Item(3)
End Select
Dim sk As PlanarSketch = def.Sketches.Add(plane)
Dim c As Point2d = sk.ModelToSketchSpace(tg.CreatePoint(Num(f, "IA_x_position") / 10, Num(f, "IA_y_position") / 10, Num(f, "IA_z_position") / 10))
Dim hl As Double = Num(f, "IA_length") / 20
Dim hh As Double = Num(f, "IA_height") / 20
sk.SketchLines.AddAsTwoPointRectangle(tg.CreatePoint2d(c.X - hl, c.Y - hh), tg.CreatePoint2d(c.X + hl, c.Y + hh))
Dim op As PartFeatureOperationEnum = PartFeatureOperationEnum.kJoinOperation
If Attr(f, "IA_extrusion_operation").ToLowerInvariant() = "cut" Then op = PartFeatureOperationEnum.kCutOperation
Dim ed As ExtrudeDefinition = def.Features.ExtrudeFeatures.CreateExtrudeDefinition(sk.Profiles.AddForSolid(), op)
ed.SetDistanceExtent(Num(f, "IA_depth") / 10, PartFeatureExtentDirectionEnum.kSymmetricExtentDirection)
def.Features.ExtrudeFeatures.Add(ed)
End Sub
Function Attr(node As XmlElement, name As String) As String
For Each a As XmlElement In node.SelectNodes("attributes/attribute")
If String.Equals(a.GetAttribute("name"), name, StringComparison.OrdinalIgnoreCase) Then Return a.InnerText.Trim()
Next
Return ""
End Function
Function Num(node As XmlElement, name As String, Optional fallback As Double = 0) As Double
Dim v As Double
If Double.TryParse(Attr(node, name), NumberStyles.Float, CultureInfo.InvariantCulture, v) Then Return v
Return fallback
End Function
Wat de regel weglaat
Het is een vertrekpunt, niet de volledige middleware.
De regel overschrijft bestanden in de projectmap, dus draai ze op een lege map of een verse kopie. Ze kent alleen symmetrische extrusies, omdat die de enige waren in mijn rapporten. De eerste feature in een part moet een join zijn; een cut op een leeg part heeft niets om uit te snijden. Parameters worden op exacte naam gekoppeld, dus Length in Tacton en length in Inventor vinden elkaar niet.
De rechthoek wordt gecentreerd op het punt uit het rapport, met IA_length langs de X-as van de schets en IA_height langs de Y-as. Op de standaard werkvlakken legt Inventor die oriëntatie vast, dus controleer één part met de hand voor je een hele structuur vertrouwt.
Waar je verder kan
Dezelfde doorloop werkt voor andere features. Een gat, een afronding of een iFeature uit de bibliotheek is één Case meer in ApplyFeatures en één tag meer in Tacton. Het punt is dat de lijst tags kort en algemeen blijft, zodat het Tacton-model niets over Inventor-bestanden moet weten, en de Inventor-bibliotheek niets over het product.