Inventor iLogic – Special Plate Mass (BUCKLE / CHECKERED / PERFORATED)
Hình ảnh kết quả
Tiếp tục câu chuyện còn chưa xong... có chút thời gian là hoàn thiện tool ngay thôi á mà 😄
Mình thực hiện những điều này dựa theo kinh nghiệm sử dụng thực tế và AI cơ bản.
-
Ghi nhớ thuộc tính của file
→ Chạy lại lệnh sẽ có các giá trị đã được thiết lập trước đó. -
Thêm tùy chọn ghi kết quả
→ Weight vào Custom Properties.
→ Override Physical Mass. -
Giao diện tùy chọn đơn giản
→ Chọn Solid, chọn Plate Type, Apply và Calculate. -
Mở rộng thêm các giá trị khác
→ BUCKLE, CHECKERED, PERFORATED, GRATING...
→ Có thể tự thêm Plate Type mới. -
Có cảnh báo nếu lựa chọn chưa chính xác
→ Kiểm tra Thickness của Solid trước khi Apply. -
Hỗ trợ Multi-Solid Part
→ Mỗi Solid Body có thể sử dụng một loại Plate khác nhau.
Vì bản thân Inventor đã có rất nhiều lệnh rồi 😄
Có bạn nào nhờ AI để viết lại tool hôm rồi mình share chưa nhỉ???
iLogic Rule
Copy Rule bên dưới và chạy trong Inventor Part (*.ipt).
AddReference "System.Windows.Forms"
AddReference "System.Drawing"
AddReference "System.Private.Windows.Core"
Imports System
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Windows.Forms
Imports Inventor
'========================================================
' SPECIAL PLATE MASS - PROFESSIONAL MODELESS FORM
' Inventor 2027 / iLogic | Run only in a Part (.ipt)
'========================================================
Sub Main()
If ThisApplication.ActiveDocument Is Nothing OrElse ThisApplication.ActiveDocument.DocumentType <> DocumentTypeEnum.kPartDocumentObject Then
MessageBox.Show("Open a Part document (.ipt) before running this rule.", "Special Plate Mass")
Return
End If
If SpecialPlateForm.Current IsNot Nothing AndAlso Not SpecialPlateForm.Current.IsDisposed Then
SpecialPlateForm.Current.Activate()
Return
End If
SpecialPlateForm.Current = New SpecialPlateForm(CType(ThisApplication.ActiveDocument, PartDocument), ThisApplication)
SpecialPlateForm.Current.Show() 'Modeless: Inventor remains fully usable.
End Sub
Public Class SpecialPlateForm
Inherits System.Windows.Forms.Form
Public Shared Current As SpecialPlateForm
'Keep the previous simple-rule set name so existing Solid assignments continue to work.
Private Const DataSetName As String = "C4I_SpecialPlate_Simple"
Private ReadOnly doc As PartDocument
Private ReadOnly invApp As Inventor.Application
Private ReadOnly bodies As New List(Of SurfaceBody)
Private ReadOnly types As New List(Of PlateType)
Private changingRows As Boolean = False
Private formReady As Boolean = False
Private ReadOnly bodyView As New System.Windows.Forms.ListView
Private ReadOnly typeBox As New System.Windows.Forms.ComboBox
Private ReadOnly nameBox As New System.Windows.Forms.TextBox
Private ReadOnly thicknessBox As New System.Windows.Forms.TextBox
Private ReadOnly rateBox As New System.Windows.Forms.TextBox
Private ReadOnly preview As New System.Windows.Forms.PictureBox
Private ReadOnly statusLabel As New System.Windows.Forms.Label
Private ReadOnly totalLabel As New System.Windows.Forms.Label
Private ReadOnly detailLabel As New System.Windows.Forms.Label
Private ReadOnly customWeightCheck As New System.Windows.Forms.CheckBox
Private ReadOnly overrideMassCheck As New System.Windows.Forms.CheckBox
Private ReadOnly applyButton As New System.Windows.Forms.Button
Public Sub New(partDoc As PartDocument, app As Inventor.Application)
doc = partDoc : invApp = app
Text = "Special Plate Mass"
'A compact, fixed tool window leaves the largest possible Inventor viewport free.
ClientSize = New System.Drawing.Size(735, 500)
StartPosition = FormStartPosition.Manual
Dim workArea As System.Drawing.Rectangle = Screen.PrimaryScreen.WorkingArea
Location = New System.Drawing.Point(Math.Max(workArea.Left, workArea.Right - 750), Math.Max(workArea.Top, workArea.Top + 80))
FormBorderStyle = FormBorderStyle.FixedDialog
MaximizeBox = False
MinimizeBox = False
HelpButton = True
TopMost = True
ShowInTaskbar = False
BackColor = System.Drawing.Color.WhiteSmoke
Dim title As New System.Windows.Forms.Label With {.Left = 12, .Top = 8, .Width = 700, .Height = 24, .Text = "SPECIAL PLATE MASS", .Font = New System.Drawing.Font("Segoe UI", 12, System.Drawing.FontStyle.Bold), .ForeColor = System.Drawing.Color.FromArgb(31, 78, 121)}
Dim subtitle As New System.Windows.Forms.Label With {.Left = 13, .Top = 31, .Width = 700, .Height = 17, .Text = "Tick bodies, select a type, then apply. The panel stays visible while you work in Inventor.", .ForeColor = System.Drawing.Color.DimGray}
Dim solidGroup As New System.Windows.Forms.GroupBox With {.Left = 12, .Top = 54, .Width = 435, .Height = 275, .Text = "Solid bodies"}
bodyView.Left = 9 : bodyView.Top = 22 : bodyView.Width = 417 : bodyView.Height = 185
bodyView.View = System.Windows.Forms.View.Details : bodyView.CheckBoxes = True : bodyView.FullRowSelect = True : bodyView.GridLines = True : bodyView.MultiSelect = False : bodyView.HideSelection = False
bodyView.Columns.Add("Solid", 58) : bodyView.Columns.Add("Assigned type", 105) : bodyView.Columns.Add("Thk.", 43) : bodyView.Columns.Add("kg/m²", 48) : bodyView.Columns.Add("Mass", 68) : bodyView.Columns.Add("Check", 65)
Dim useSelection As New System.Windows.Forms.Button With {.Left = 9, .Top = 220, .Width = 135, .Height = 26, .Text = "Use selection"}
Dim clearSelection As New System.Windows.Forms.Button With {.Left = 153, .Top = 220, .Width = 90, .Height = 26, .Text = "Clear ticks"}
Dim reloadButton As New System.Windows.Forms.Button With {.Left = 252, .Top = 220, .Width = 105, .Height = 26, .Text = "Refresh"}
solidGroup.Controls.AddRange(New System.Windows.Forms.Control() {bodyView, useSelection, clearSelection, reloadButton})
Dim materialGroup As New System.Windows.Forms.GroupBox With {.Left = 457, .Top = 54, .Width = 266, .Height = 275, .Text = "Plate configuration"}
Dim typeLabel As New System.Windows.Forms.Label With {.Left = 11, .Top = 21, .Width = 240, .Height = 18, .Text = "Plate type"}
typeBox.Left = 11 : typeBox.Top = 46 : typeBox.Width = 243 : typeBox.DropDownStyle = ComboBoxStyle.DropDownList
Dim nLabel As New System.Windows.Forms.Label With {.Left = 11, .Top = 76, .Width = 240, .Height = 18, .Text = "Custom name (only when adding a type)"}
nameBox.Left = 11 : nameBox.Top = 99 : nameBox.Width = 243
Dim thLabel As New System.Windows.Forms.Label With {.Left = 11, .Top = 130, .Width = 110, .Height = 18, .Text = "Thickness (mm)"}
Dim rateLabel As New System.Windows.Forms.Label With {.Left = 132, .Top = 130, .Width = 120, .Height = 18, .Text = "Weight (kg/m²)"}
thicknessBox.Left = 11 : thicknessBox.Top = 152 : thicknessBox.Width = 110
rateBox.Left = 132 : rateBox.Top = 152 : rateBox.Width = 122
Dim addType As New System.Windows.Forms.Button With {.Left = 11, .Top = 182, .Width = 243, .Height = 26, .Text = "Add custom plate type"}
preview.Left = 11 : preview.Top = 219 : preview.Width = 70 : preview.Height = 43 : preview.BackColor = System.Drawing.Color.White : preview.BorderStyle = BorderStyle.FixedSingle
Dim previewText As New System.Windows.Forms.Label With {.Left = 91, .Top = 217, .Width = 160, .Height = 48, .Text = "Visual guide. Thickness check uses the Solid's volume and surface area.", .ForeColor = System.Drawing.Color.DimGray}
materialGroup.Controls.AddRange(New System.Windows.Forms.Control() {typeLabel, typeBox, nLabel, nameBox, thLabel, rateLabel, thicknessBox, rateBox, addType, preview, previewText})
statusLabel.Left = 12 : statusLabel.Top = 340 : statusLabel.Width = 711 : statusLabel.Height = 34 : statusLabel.BorderStyle = BorderStyle.FixedSingle : statusLabel.Padding = New Padding(8, 7, 8, 0)
statusLabel.ForeColor = System.Drawing.Color.FromArgb(31, 78, 121) : statusLabel.Text = "Select bodies, then choose a plate type."
Dim actions As New System.Windows.Forms.GroupBox With {.Left = 12, .Top = 386, .Width = 435, .Height = 101, .Text = "Actions"}
applyButton.Left = 10 : applyButton.Top = 21 : applyButton.Width = 128 : applyButton.Height = 28 : applyButton.Text = "Apply to ticked"
Dim removeButton As New System.Windows.Forms.Button With {.Left = 147, .Top = 21, .Width = 120, .Height = 28, .Text = "Remove setting"}
Dim updateButton As New System.Windows.Forms.Button With {.Left = 276, .Top = 21, .Width = 148, .Height = 28, .Text = "Calculate and write"}
customWeightCheck.Left = 10 : customWeightCheck.Top = 62 : customWeightCheck.Width = 210 : customWeightCheck.Text = "Write Custom Property: Weight"
overrideMassCheck.Left = 225 : overrideMassCheck.Top = 62 : overrideMassCheck.Width = 195 : overrideMassCheck.Text = "Override Physical Mass"
actions.Controls.AddRange(New System.Windows.Forms.Control() {applyButton, removeButton, updateButton, customWeightCheck, overrideMassCheck})
Dim totalGroup As New System.Windows.Forms.GroupBox With {.Left = 457, .Top = 386, .Width = 266, .Height = 101, .Text = "FINAL WEIGHT"}
totalLabel.Left = 8 : totalLabel.Top = 19 : totalLabel.Width = 250 : totalLabel.Height = 28 : totalLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
totalLabel.Font = New System.Drawing.Font("Segoe UI", 15, System.Drawing.FontStyle.Bold) : totalLabel.ForeColor = System.Drawing.Color.Crimson
detailLabel.Left = 8 : detailLabel.Top = 52 : detailLabel.Width = 250 : detailLabel.Height = 37 : detailLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter : detailLabel.ForeColor = System.Drawing.Color.DimGray
totalGroup.Controls.AddRange(New System.Windows.Forms.Control() {totalLabel, detailLabel})
Controls.AddRange(New System.Windows.Forms.Control() {title, subtitle, solidGroup, materialGroup, statusLabel, actions, totalGroup})
AddHandler bodyView.ItemChecked, AddressOf BodyChecked
AddHandler bodyView.SelectedIndexChanged, AddressOf BodyClicked
AddHandler typeBox.SelectedIndexChanged, AddressOf TypeChanged
AddHandler thicknessBox.TextChanged, AddressOf ValuesChanged
AddHandler rateBox.TextChanged, AddressOf ValuesChanged
AddHandler useSelection.Click, AddressOf UseInventorSelection
AddHandler clearSelection.Click, AddressOf ClearBodyTicks
AddHandler reloadButton.Click, AddressOf ReloadBodies
AddHandler applyButton.Click, AddressOf ApplyToBodies
AddHandler removeButton.Click, AddressOf RemoveSettings
AddHandler updateButton.Click, AddressOf CalculateAndWrite
AddHandler addType.Click, AddressOf AddCustomType
AddHandler overrideMassCheck.CheckedChanged, AddressOf OverrideChanged
AddHandler HelpButtonClicked, AddressOf ShowAbout
AddHandler preview.Paint, AddressOf DrawPreview
AddHandler FormClosed, Sub(sender As Object, e As FormClosedEventArgs) Current = Nothing
AddBuiltInTypes()
LoadCustomTypes()
If typeBox.Items.Count > 0 Then typeBox.SelectedIndex = 0
customWeightCheck.Checked = ReadDoc("WriteCustom", "False") = "True"
overrideMassCheck.Checked = ReadDoc("OverrideMass", "False") = "True"
LoadBodies()
formReady = True
End Sub
Private Sub AddBuiltInTypes()
AddType("BUCKLE 3", 3, 25.5, False) : AddType("BUCKLE 4", 4, 33.4, False) : AddType("BUCKLE 5", 5, 41.2, False) : AddType("BUCKLE 6", 6, 49.1, False) : AddType("BUCKLE 8", 8, 64.8, False) : AddType("BUCKLE 10", 10, 80.5, False)
AddType("CHECKERED 3", 3, 27.5, False) : AddType("CHECKERED 4", 4, 35.4, False) : AddType("CHECKERED 5", 5, 43.2, False) : AddType("CHECKERED 6", 6, 51.1, False) : AddType("CHECKERED 8", 8, 66.8, False) : AddType("CHECKERED 10", 10, 82.5, False)
AddType("PERFORATED 3-6-10", 3, 14.5, False) : AddType("PERFORATED 3-10-17", 3, 14.5, False) : AddType("PERFORATED 3-15-24", 3, 14.8, False)
AddType("PERFORATED 5-8-14", 5, 24, False) : AddType("PERFORATED 5-12-18", 5, 25, False) : AddType("PERFORATED 5-15-24", 5, 24, False)
AddType("PERFORATED 8-12-20", 8, 41.5, False) : AddType("PERFORATED 8-15-24", 8, 38.5, False) : AddType("PERFORATED 8-25-32", 8, 39, False)
AddType("GRATING 30", 30, 27.6, False)
End Sub
Private Sub AddType(n As String, t As Double, r As Double, isCustom As Boolean)
Dim p As New PlateType(n, t, r, isCustom)
types.Add(p) : typeBox.Items.Add(p)
End Sub
Private Sub LoadCustomTypes()
Dim saved As String = ReadDoc("CustomTypes", "")
If saved = "" Then Return
For Each row As String In saved.Split(";"c)
Dim d() As String = Row.Split("|"c)
If d.Length = 3 Then
Dim t As Double, r As Double
If Double.TryParse(d(1), NumberStyles.Float, CultureInfo.InvariantCulture, t) AndAlso Double.TryParse(d(2), NumberStyles.Float, CultureInfo.InvariantCulture, r) AndAlso t > 0 AndAlso r > 0 Then AddType(d(0), t, r, True)
End If
Next
End Sub
Private Sub SaveCustomTypes()
Dim rows As New List(Of String)
For Each p As PlateType In types
If p.IsCustom Then rows.Add(p.Name & "|" & p.Thickness.ToString("R", CultureInfo.InvariantCulture) & "|" & p.Rate.ToString("R", CultureInfo.InvariantCulture))
Next
WriteDoc("CustomTypes", String.Join(";", rows.ToArray()))
End Sub
Private Sub LoadBodies()
bodies.Clear() : bodyView.Items.Clear()
For Each body As SurfaceBody In doc.ComponentDefinition.SurfaceBodies
If body.IsSolid Then bodies.Add(body)
Next
RefreshRows()
UseInventorSelection(Nothing, Nothing)
UpdateResult()
End Sub
Private Sub RefreshRows()
Dim checkedBodies As New List(Of SurfaceBody)
For Each row As System.Windows.Forms.ListViewItem In bodyView.Items
If Row.Checked Then checkedBodies.Add(CType(Row.Tag, SurfaceBody))
Next
changingRows = True
Try
bodyView.Items.Clear()
For Each body As SurfaceBody In bodies
Dim row As New System.Windows.Forms.ListViewItem(body.Name)
row.Tag = body
Dim p As PlateType = ReadBody(body)
If p Is Nothing Then
row.SubItems.Add("CAD mass") : row.SubItems.Add("-") : row.SubItems.Add("-") : row.SubItems.Add("-") : row.SubItems.Add("-")
Else
row.SubItems.Add(p.Name) : row.SubItems.Add(p.Thickness.ToString("0.###") & " mm") : row.SubItems.Add(p.Rate.ToString("0.###")) : row.SubItems.Add(PlateMass(body, p).ToString("0.###") & " kg")
Dim measured As Double = 0
Dim checkResult As String = ThicknessOK(body, p.Thickness, measured)
row.SubItems.Add(checkResult)
If checkResult = "CHECK" Then
row.BackColor = System.Drawing.Color.MistyRose
row.ForeColor = System.Drawing.Color.Firebrick
End If
End If
row.Checked = checkedBodies.Contains(body)
bodyView.Items.Add(row)
Next
Finally
changingRows = False
End Try
End Sub
Private Sub TypeChanged(sender As Object, e As EventArgs)
If typeBox.SelectedIndex < 0 Then Return
Dim p As PlateType = DirectCast(typeBox.SelectedItem, PlateType)
nameBox.Text = p.Name : thicknessBox.Text = p.Thickness.ToString(CultureInfo.CurrentCulture) : rateBox.Text = p.Rate.ToString(CultureInfo.CurrentCulture)
preview.Invalidate() : ValidateSelection()
End Sub
Private Sub ValuesChanged(sender As Object, e As EventArgs)
ValidateSelection()
End Sub
Private Sub BodyClicked(sender As Object, e As EventArgs)
If bodyView.SelectedItems.Count = 0 Then Return
Dim body As SurfaceBody = CType(bodyView.SelectedItems(0).Tag, SurfaceBody)
doc.SelectSet.Clear() : doc.SelectSet.Select(body)
Dim p As PlateType = ReadBody(body)
If p IsNot Nothing Then nameBox.Text = p.Name : thicknessBox.Text = p.Thickness.ToString(CultureInfo.CurrentCulture) : rateBox.Text = p.Rate.ToString(CultureInfo.CurrentCulture)
ValidateSelection()
End Sub
Private Sub BodyChecked(sender As Object, e As ItemCheckedEventArgs)
If changingRows OrElse Not IsHandleCreated Then Return
BeginInvoke(New MethodInvoker(AddressOf HighlightTickedBodies))
End Sub
Private Sub HighlightTickedBodies()
doc.SelectSet.Clear()
For Each row As System.Windows.Forms.ListViewItem In bodyView.Items
If Row.Checked Then doc.SelectSet.Select(CType(Row.Tag, SurfaceBody))
Next
ValidateSelection()
End Sub
Private Sub UseInventorSelection(sender As Object, e As EventArgs)
Dim selected As New List(Of SurfaceBody)
For Each item As Object In doc.SelectSet
Dim body As SurfaceBody = TryCast(item, SurfaceBody)
If body IsNot Nothing Then selected.Add(body)
Next
changingRows = True
Try
For Each row As System.Windows.Forms.ListViewItem In bodyView.Items
Row.Checked = selected.Contains(CType(Row.Tag, SurfaceBody))
Next
Finally
changingRows = False
End Try
ValidateSelection()
End Sub
Private Sub ClearBodyTicks(sender As Object, e As EventArgs)
If CheckedRows().Count = 0 Then
ShowStatus("Nothing was ticked. Select bodies in Inventor or tick them in the table.", System.Drawing.Color.DarkOrange)
Return
End If
changingRows = True
Try
For Each row As System.Windows.Forms.ListViewItem In bodyView.Items : Row.Checked = False : Next
Finally
changingRows = False
End Try
doc.SelectSet.Clear()
ShowStatus("Ticks cleared. No body settings were changed.", System.Drawing.Color.FromArgb(31, 78, 121))
End Sub
Private Sub ReloadBodies(sender As Object, e As EventArgs)
LoadBodies()
ShowStatus("Body table refreshed from the current Part.", System.Drawing.Color.FromArgb(31, 78, 121))
End Sub
Private Function CheckedRows() As List(Of System.Windows.Forms.ListViewItem)
Dim result As New List(Of System.Windows.Forms.ListViewItem)
For Each row As System.Windows.Forms.ListViewItem In bodyView.Items
If Row.Checked Then result.Add(Row)
Next
Return result
End Function
Private Function ReadInput(ByRef t As Double, ByRef r As Double) As Boolean
Return Double.TryParse(thicknessBox.Text.Trim().Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, t) AndAlso t > 0 AndAlso Double.TryParse(rateBox.Text.Trim().Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, r) AndAlso r > 0
End Function
Private Sub ValidateSelection()
Dim t As Double, r As Double
Dim rows As List(Of System.Windows.Forms.ListViewItem) = CheckedRows()
If rows.Count = 0 Then ShowStatus("Tick one or more bodies before applying a plate setting.", System.Drawing.Color.DarkOrange) : applyButton.Enabled = False : Return
If Not ReadInput(t, r) Then ShowStatus("Enter a positive Thickness and Weight value.", System.Drawing.Color.Crimson) : applyButton.Enabled = False : Return
Dim warnings As New List(Of String)
For Each row As System.Windows.Forms.ListViewItem In rows
Dim actual As Double = 0
If ThicknessOK(CType(Row.Tag, SurfaceBody), t, actual) = "CHECK" Then warnings.Add(CType(Row.Tag, SurfaceBody).Name & " ≈ " & actual.ToString("0.###") & " mm")
Next
If warnings.Count > 0 Then
ShowStatus("Thickness review: expected " & t.ToString("0.###") & " mm; estimate: " & String.Join(", ", warnings.ToArray()) & ". You may still apply if the geometry is curved or otherwise complex.", System.Drawing.Color.Crimson)
applyButton.Enabled = True
Else
ShowStatus("Ready to apply: " & rows.Count & " selected body/bodies match " & t.ToString("0.###") & " mm.", System.Drawing.Color.FromArgb(0, 110, 65))
applyButton.Enabled = True
End If
End Sub
Private Function ThicknessOK(body As SurfaceBody, expected As Double, ByRef actual As Double) As String
'For a thin plate, 2 × Volume / SurfaceArea estimates its wall thickness.
'Unlike a bounding box, this remains useful when the plate is curved or rotated.
Dim area As Double = body.MassProperties.Area
If area <= 0 Then Return "CHECK"
actual = (2.0 * body.MassProperties.Volume / area) * 10.0 'cm -> mm
Dim tolerance As Double = Math.Max(0.3, expected * 0.08)
If Math.Abs(actual - expected) <= tolerance Then Return "OK"
Return "CHECK"
End Function
Private Sub ApplyToBodies(sender As Object, e As EventArgs)
Dim rows As List(Of System.Windows.Forms.ListViewItem) = CheckedRows()
If rows.Count = 0 Then ShowStatus("Apply did nothing: tick one or more bodies first.", System.Drawing.Color.DarkOrange) : Return
Dim t As Double, r As Double
If Not ReadInput(t, r) Then ShowStatus("Apply did nothing: enter valid Thickness and Weight values.", System.Drawing.Color.Crimson) : Return
ValidateSelection()
If Not applyButton.Enabled Then Return
Dim label As String = nameBox.Text.Trim()
If label = "" Then label = CType(typeBox.SelectedItem, PlateType).Name
Dim tr As Transaction = invApp.TransactionManager.StartTransaction(doc, "Apply Special Plate")
Try
For Each row As System.Windows.Forms.ListViewItem In rows : WriteBody(CType(Row.Tag, SurfaceBody), New PlateType(label, t, r, False)) : Next
tr.End()
RefreshRows() : UpdateResult()
ShowStatus("Applied " & label & " to " & rows.Count & " body/bodies. Click Calculate and write results to update Weight.", System.Drawing.Color.FromArgb(0, 110, 65))
Catch ex As Exception
tr.Abort() : ShowStatus("Apply failed: " & ex.Message, System.Drawing.Color.Crimson)
End Try
End Sub
Private Sub RemoveSettings(sender As Object, e As EventArgs)
Dim rows As List(Of System.Windows.Forms.ListViewItem) = CheckedRows()
If rows.Count = 0 Then ShowStatus("Remove did nothing: tick the bodies whose Special Plate setting you want to remove.", System.Drawing.Color.DarkOrange) : Return
Dim tr As Transaction = invApp.TransactionManager.StartTransaction(doc, "Remove Special Plate")
Try
For Each row As System.Windows.Forms.ListViewItem In rows
Dim sets As AttributeSets = CType(Row.Tag, SurfaceBody).AttributeSets
If sets.NameIsUsed(DataSetName) Then sets.Item(DataSetName).Delete()
Next
tr.End()
RefreshRows() : UpdateResult()
ShowStatus("Removed the saved Special Plate setting from " & rows.Count & " body/bodies. Those bodies now use their actual CAD mass.", System.Drawing.Color.FromArgb(31, 78, 121))
Catch ex As Exception
tr.Abort() : ShowStatus("Remove failed: " & ex.Message, System.Drawing.Color.Crimson)
End Try
End Sub
Private Sub CalculateAndWrite(sender As Object, e As EventArgs)
Dim finalMass As Double, cadMass As Double, plateMass As Double
BuildResult(finalMass, cadMass, plateMass)
Dim savedWeight As Double = RoundWeight(finalMass)
Dim tr As Transaction = invApp.TransactionManager.StartTransaction(doc, "Update Special Plate Weight")
Try
WriteDoc("WriteCustom", customWeightCheck.Checked.ToString())
WriteDoc("OverrideMass", overrideMassCheck.Checked.ToString())
WriteDoc("LastWeight", savedWeight.ToString("R", CultureInfo.InvariantCulture))
If customWeightCheck.Checked Then WriteWeightProperty(savedWeight)
If overrideMassCheck.Checked Then
doc.ComponentDefinition.MassProperties.Mass = savedWeight
Else
doc.ComponentDefinition.MassProperties.MassOverridden = False
End If
tr.End()
RefreshInventorPanels()
UpdateResult()
If overrideMassCheck.Checked Then
ShowStatus("Updated. Physical Mass is overridden with the calculated result.", System.Drawing.Color.FromArgb(0, 110, 65))
Else
ShowStatus("Updated. Physical Mass override was removed, so Inventor now shows its native CAD mass.", System.Drawing.Color.FromArgb(31, 78, 121))
End If
Catch ex As Exception
tr.Abort() : ShowStatus("Update failed: " & ex.Message, System.Drawing.Color.Crimson)
End Try
End Sub
Private Sub OverrideChanged(sender As Object, e As EventArgs)
If Not formReady Then Return
If overrideMassCheck.Checked Then
ShowStatus("Override Mass is enabled. Click Calculate and write results to apply the current calculated weight.", System.Drawing.Color.FromArgb(31, 78, 121))
Return
End If
Dim tr As Transaction = invApp.TransactionManager.StartTransaction(doc, "Remove Physical Mass Override")
Try
doc.ComponentDefinition.MassProperties.MassOverridden = False
WriteDoc("OverrideMass", "False")
tr.End()
RefreshInventorPanels()
UpdateResult()
ShowStatus("Physical Mass override removed. Inventor is now showing its native CAD mass.", System.Drawing.Color.FromArgb(31, 78, 121))
Catch ex As Exception
tr.Abort()
ShowStatus("Could not remove Physical Mass override: " & ex.Message, System.Drawing.Color.Crimson)
End Try
End Sub
Private Sub AddCustomType(sender As Object, e As EventArgs)
Dim n As String = nameBox.Text.Trim()
Dim t As Double, r As Double
If n = "" OrElse n.IndexOfAny(New Char() {"|"c, ";"c}) >= 0 Then ShowStatus("Enter a custom type name. Characters | and ; are not allowed.", System.Drawing.Color.Crimson) : Return
If Not ReadInput(t, r) Then ShowStatus("Enter valid Thickness and Weight values before adding a custom type.", System.Drawing.Color.Crimson) : Return
For Each p As PlateType In types
If String.Equals(p.Name, n, StringComparison.OrdinalIgnoreCase) Then ShowStatus("A plate type with this name already exists.", System.Drawing.Color.DarkOrange) : Return
Next
Dim tr As Transaction = invApp.TransactionManager.StartTransaction(doc, "Add Special Plate Type")
Try
AddType(n, t, r, True) : SaveCustomTypes() : tr.End()
typeBox.SelectedIndex = typeBox.Items.Count - 1
ShowStatus("Custom plate type added and stored in this Part document.", System.Drawing.Color.FromArgb(0, 110, 65))
Catch ex As Exception
tr.Abort() : ShowStatus("Could not add custom type: " & ex.Message, System.Drawing.Color.Crimson)
End Try
End Sub
Private Sub UpdateResult()
Dim finalMass As Double, cadMass As Double, plateMass As Double
Dim assigned As Integer = BuildResult(finalMass, cadMass, plateMass)
totalLabel.Text = FormatWeight(finalMass) & " kg"
detailLabel.Text = "Assigned: " & assigned & " body/bodies" & vbCrLf & "CAD solids: " & FormatWeight(cadMass) & " kg | Plate: " & FormatWeight(plateMass) & " kg"
End Sub
Private Function BuildResult(ByRef finalMass As Double, ByRef cadMass As Double, ByRef specialMass As Double) As Integer
Dim otherMass As Double = 0, assigned As Integer = 0
cadMass = 0 : specialMass = 0
For Each body As SurfaceBody In bodies
Dim rawMass As Double = body.MassProperties.Mass 'Per-body CAD mass; never uses Part Mass override.
cadMass += rawMass
Dim p As PlateType = ReadBody(body)
If p Is Nothing Then
otherMass += rawMass
Else
specialMass += PlateMass(body, p) : assigned += 1
End If
Next
finalMass = otherMass + specialMass
Return assigned
End Function
Private Function PlateMass(body As SurfaceBody, p As PlateType) As Double
Return (body.MassProperties.Volume / (p.Thickness * 1000.0)) * p.Rate
End Function
Private Function ReadBody(body As SurfaceBody) As PlateType
Dim sets As AttributeSets = body.AttributeSets
If Not sets.NameIsUsed(DataSetName) Then Return Nothing
Dim oneSet As AttributeSet = sets.Item(DataSetName)
If Not oneSet.NameIsUsed("Config") Then Return Nothing
Dim d() As String = CStr(oneSet.Item("Config").Value).Split("|"c)
If d.Length <> 3 Then Return Nothing
Dim t As Double, r As Double
If Not Double.TryParse(d(1), NumberStyles.Float, CultureInfo.InvariantCulture, t) OrElse Not Double.TryParse(d(2), NumberStyles.Float, CultureInfo.InvariantCulture, r) OrElse t <= 0 OrElse r <= 0 Then Return Nothing
Return New PlateType(d(0), t, r, False)
End Function
Private Sub WriteBody(body As SurfaceBody, p As PlateType)
Dim sets As AttributeSets = body.AttributeSets
Dim oneSet As AttributeSet = If(sets.NameIsUsed(DataSetName), sets.Item(DataSetName), sets.Add(DataSetName))
Dim value As String = p.Name & "|" & p.Thickness.ToString("R", CultureInfo.InvariantCulture) & "|" & p.Rate.ToString("R", CultureInfo.InvariantCulture)
If oneSet.NameIsUsed("Config") Then oneSet.Item("Config").Value = value Else oneSet.Add("Config", ValueTypeEnum.kStringType, value)
End Sub
Private Function ReadDoc(key As String, fallback As String) As String
If Not doc.AttributeSets.NameIsUsed(DataSetName) Then Return fallback
Dim oneSet As AttributeSet = doc.AttributeSets.Item(DataSetName)
If Not oneSet.NameIsUsed(key) Then Return fallback
Return CStr(oneSet.Item(key).Value)
End Function
Private Sub WriteDoc(key As String, value As String)
Dim sets As AttributeSets = doc.AttributeSets
Dim oneSet As AttributeSet = If(sets.NameIsUsed(DataSetName), sets.Item(DataSetName), sets.Add(DataSetName))
If oneSet.NameIsUsed(key) Then oneSet.Item(key).Value = value Else oneSet.Add(key, ValueTypeEnum.kStringType, value)
End Sub
Private Sub WriteWeightProperty(weight As Double)
Dim props As PropertySet = doc.PropertySets.Item("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
For Each p As Inventor.Property In props
If String.Equals(p.Name, "Weight", StringComparison.OrdinalIgnoreCase) Then p.Delete() : Exit For
Next
props.Add(weight, "Weight")
End Sub
Private Function RoundWeight(weight As Double) As Double
If weight >= 100.0 Then Return Math.Round(weight, 0, MidpointRounding.AwayFromZero)
If weight >= 10.0 Then Return Math.Round(weight, 1, MidpointRounding.AwayFromZero)
If weight >= 1.0 Then Return Math.Round(weight, 2, MidpointRounding.AwayFromZero)
Return Math.Round(weight, 3, MidpointRounding.AwayFromZero)
End Function
Private Function FormatWeight(weight As Double) As String
If weight >= 100.0 Then Return RoundWeight(weight).ToString("0", CultureInfo.CurrentCulture)
If weight >= 10.0 Then Return RoundWeight(weight).ToString("0.0", CultureInfo.CurrentCulture)
If weight >= 1.0 Then Return RoundWeight(weight).ToString("0.00", CultureInfo.CurrentCulture)
Return RoundWeight(weight).ToString("0.000", CultureInfo.CurrentCulture)
End Function
Private Sub RefreshInventorPanels()
'Refresh the document and current view after iProperty/Physical Mass changes.
'Inventor does not expose a separate API to force-refresh only the docked iProperties panel.
Try
doc.Update2(True)
invApp.ActiveView.Update()
Catch
'The saved values remain valid even if the current view cannot be refreshed.
End Try
End Sub
Private Sub ShowAbout(sender As Object, e As EventArgs)
MessageBox.Show("Special Plate Mass" & vbCrLf & vbCrLf &
"Version 1.0" & vbCrLf &
"Developed by Le Thanh Dai" & vbCrLf &
"Email: dai.lethanh2019@gmail.com", _
"About Special Plate Mass", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Private Sub ShowStatus(text As String, color As System.Drawing.Color)
statusLabel.Text = text : statusLabel.ForeColor = color
End Sub
Private Sub DrawPreview(sender As Object, e As PaintEventArgs)
Dim g As System.Drawing.Graphics = e.Graphics
g.Clear(System.Drawing.Color.White)
g.ScaleTransform(preview.ClientSize.Width / 105.0F, preview.ClientSize.Height / 93.0F)
Dim name As String = If(typeBox.SelectedItem Is Nothing, "", CType(typeBox.SelectedItem, PlateType).Name.ToUpperInvariant())
Dim pen As New System.Drawing.Pen(System.Drawing.Color.FromArgb(31, 78, 121), 2)
If name.Contains("PERFORATED") Then
g.DrawRectangle(pen, 12, 12, 78, 68)
For x As Integer = 24 To 76 Step 18 : For y As Integer = 24 To 66 Step 18 : g.FillEllipse(System.Drawing.Brushes.White, x, y, 8, 8) : g.DrawEllipse(pen, x, y, 8, 8) : Next : Next
ElseIf name.Contains("GRATING") Then
For x As Integer = 12 To 92 Step 13 : g.DrawLine(pen, x, 12, x, 80) : Next
For y As Integer = 17 To 78 Step 15 : g.DrawLine(pen, 10, y, 94, y) : Next
ElseIf name.Contains("CHECKERED") Then
g.DrawRectangle(pen, 12, 12, 78, 68)
For x As Integer = 6 To 82 Step 18 : g.DrawLine(pen, x, 79, x + 35, 13) : Next
Else
g.DrawRectangle(pen, 12, 12, 78, 68)
For y As Integer = 20 To 74 Step 15 : g.DrawArc(pen, 18, y, 65, 12, 180, 180) : Next
End If
pen.Dispose()
End Sub
Private Class PlateType
Public ReadOnly Name As String
Public ReadOnly Thickness As Double
Public ReadOnly Rate As Double
Public ReadOnly IsCustom As Boolean
Public Sub New(n As String, t As Double, r As Double, custom As Boolean)
Name = n : Thickness = t : Rate = r : IsCustom = custom
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
End Class