Public Sub UserFinishCustomProfile() GetInventorApplication() If invApp IsNot Nothing Then If invApp.ActiveDocumentType = Inventor.DocumentTypeEnum.kAssemblyDocumentObject Then Dim asmDoc As AssemblyDocument = invApp.ActiveDocument If TypeOf asmDoc.ActivatedObject Is Inventor.PlanarSketch Then Dim psProfile As PlanarSketch = asmDoc.ActivatedObject If psProfile.Name <> "Clearance Profile" Then If MsgBox("Do you want to change the sketch name to 'Clearance Profile'? (highly recommended)", MsgBoxStyle.YesNo, "Clearance Profile Sketch Name") = MsgBoxResult.Yes Then psProfile.Name = "Clearance Profile" End If End If Dim pDeckEdge As Point = Nothing Dim coCarDecks As List(Of ComponentOccurrence) = GetSubOccurrenceProxiesByName(asmDoc.ComponentDefinition, "CarDeck", False) Dim coCARDeck As ComponentOccurrence = Nothing If coCarDecks.Count > 0 Then coCARDeck = coCarDecks(0) End If If coCARDeck IsNot Nothing Then Dim wp As WorkPoint = FindWorkPoint(coCARDeck.Definition, "Deck Edge") If wp IsNot Nothing Then pDeckEdge = wp.Point End If If pDeckEdge IsNot Nothing Then Dim trans As Inventor.Transaction = Nothing If DebugMode = False Then trans = invApp.TransactionManager.StartTransaction(asmDoc, "Create Clearance Profile") End If 'get lines from user Dim skLines As New List(Of SketchLine) Dim selSet As SelectSet = asmDoc.SelectSet If selSet.Count > 0 Then For Each ent As Object In selSet If TypeOf ent Is SketchLine Then skLines.Add(ent) End If Next Else MsgBox("Please select the profile lines first.") Exit Sub End If Try psProfile.ExitEdit() Catch ex As Exception 'already exited End Try 'need to sort these lines and arrange them by vertical position and width 'make list of points from each line and then sort vertically. Dim skPoints As New List(Of SketchPoint) Dim skPointsCache As New List(Of Point) For Each sl As SketchLine In skLines Dim booDuplicate As Boolean = False Dim startPoint As Point = sl.StartSketchPoint.Geometry3d Dim endPoint As Point = sl.EndSketchPoint.Geometry3d For i As Integer = skPointsCache.Count - 1 To 0 Step -1 Dim skp As Point = skPointsCache(i) If Distance(skp, startPoint) < 0.0625 Then booDuplicate = True Exit For End If Next If booDuplicate = False Then SyncLock skPoints skPoints.Add(sl.StartSketchPoint) End SyncLock SyncLock skPointsCache skPointsCache.Add(startPoint) End SyncLock End If booDuplicate = False For i As Integer = skPointsCache.Count - 1 To 0 Step -1 Dim skp As Point = skPointsCache(i) If Distance(skp, endPoint) < 0.0625 Then booDuplicate = True Exit For End If Next If booDuplicate = False Then SyncLock skPoints skPoints.Add(sl.EndSketchPoint) End SyncLock SyncLock skPointsCache skPointsCache.Add(endPoint) End SyncLock End If Next 'sl.Construction = True 'clean data from existing linework For Each sl As SketchLine In psProfile.SketchLines ProfileLine.RemoveAttributes(sl) sl.LineType = LineTypeEnum.kDefaultLineType sl.Construction = True Next For Each sp As SketchPoint In psProfile.SketchPoints ProfilePoint.RemoveAttributes(sp) sp.HoleCenter = False Next 'sort point by vertical 'skPoints.Sort(Function(x, y) (x.Geometry3d.Y.CompareTo(y.Geometry3d.Y))) 'find all values positive/negative and start labeling profilepoints Dim skpPrimary As New List(Of SketchPoint) Dim skpSecondary As New List(Of SketchPoint) For Each skPoint As SketchPoint In skPoints If skPoint.Geometry3d.Z > 0 Then skpPrimary.Add(skPoint) If skPoint.Geometry3d.Z < 0 Then skpSecondary.Add(skPoint) Debug.Print(skPoint.Geometry3d.Y & "," & skPoint.Geometry3d.Z & ": " & skpPrimary.Count & ", " & skpSecondary.Count) Next 'sort the two lists skpPrimary = SortProfilePointList(skpPrimary, True) 'skpPrimary.Sort(Function(x, y) ' Dim comp As Integer = Math.Round(x.Geometry3d.Y, 8).CompareTo(Math.Round(y.Geometry3d.Y, 8)) ' If comp = 0 Then ' comp = Math.Round(x.Geometry3d.Z, 8).CompareTo(Math.Round(y.Geometry3d.Z, 8)) ' End If ' Return comp ' End Function) skpSecondary = SortProfilePointList(skpSecondary, False) 'skpSecondary.Sort(Function(x, y) ' Dim comp As Integer = Math.Round(x.Geometry3d.Y, 8).CompareTo(Math.Round(y.Geometry3d.Y, 8)) ' If comp = 0 Then ' comp = Math.Round(y.Geometry3d.Z, 8).CompareTo(Math.Round(x.Geometry3d.Z, 8)) ' End If ' Return comp ' End Function) If skpPrimary.Count <> skpSecondary.Count Then 'all is not good we need one point on each side that matches For Each skPointPrimary As SketchPoint In skpPrimary Dim booFound As Boolean = False For Each skPointSecondary As SketchPoint In skpSecondary If skPointPrimary.Geometry3d.Y = skPointSecondary.Geometry3d.Y AndAlso skPointPrimary.Geometry3d.Z = (skPointSecondary.Geometry3d.Z * -1) Then booFound = True Exit For End If Next If booFound = False Then skpSecondary.Add(psProfile.SketchPoints.Add(psProfile.ModelToSketchSpace(tg.CreatePoint(skPointPrimary.Geometry3d.X, skPointPrimary.Geometry3d.Y, skPointPrimary.Geometry3d.Z * -1)))) End If Next For Each skPointSecondary As SketchPoint In skpSecondary Dim booFound As Boolean = False For Each skPointPrimary As SketchPoint In skpPrimary If skPointSecondary.Geometry3d.Y = skPointPrimary.Geometry3d.Y AndAlso skPointSecondary.Geometry3d.Z = (skPointPrimary.Geometry3d.Z * -1) Then booFound = True Exit For End If Next If booFound = False Then skpPrimary.Add(psProfile.SketchPoints.Add(psProfile.ModelToSketchSpace(tg.CreatePoint(skPointSecondary.Geometry3d.X, skPointSecondary.Geometry3d.Y, skPointSecondary.Geometry3d.Z * -1)))) End If Next skpPrimary = SortProfilePointList(skpPrimary, True) skpSecondary = SortProfilePointList(skpSecondary, False) End If If skpPrimary.Count = skpSecondary.Count Then 'remove all existing atr and wide dimensions and parameters For Each dc As DimensionConstraint In psProfile.DimensionConstraints If dc.Parameter.Name.Contains("ATR") OrElse dc.Parameter.Name.Contains("WIDE") Then dc.Delete() End If Next ATRWideRoundReset(asmDoc) 'For Each param As Parameter In asmDoc.ComponentDefinition.Parameters.UserParameters ' If param.Name.Contains("ATR") OrElse param.Name.Contains("WIDE") Then ' param.Delete() ' End If 'Next 'For Each prop As Inventor.Property In asmDoc.PropertySets.Item(Tools.UserDefinedPropertySetID) ' If prop.Name.Contains("ATR") OrElse prop.Name.Contains("WIDE") Then ' prop.Delete() ' End If 'Next 'having removed narrow steps points as best as possible, check to see if there is an atrD point Dim booHasATRD As Boolean = False If skpSecondary(0).Geometry3d.IsEqualTo(pDeckEdge) Then If skpSecondary(1).Geometry3d.Y = pDeckEdge.Y Then 'this is atrD worthy, set the first point to atrD and the second to atr1 booHasATRD = True End If End If Dim pPointsPrimary As New List(Of ProfilePoint) Dim pPointsSecondary As New List(Of ProfilePoint) Dim intATR As Integer = 1 If booHasATRD = True Then pPointsPrimary.Add(New ProfilePoint(skpPrimary(0), "ATRD", True)) pPointsSecondary.Add(New ProfilePoint(skpSecondary(0), "ATRD.2", False)) End If For i As Integer = 0 To skpPrimary.Count - 1 If i = 0 AndAlso booHasATRD = True Then Continue For End If pPointsPrimary.Add(New ProfilePoint(skpPrimary(i), "ATR" & intATR, True)) pPointsSecondary.Add(New ProfilePoint(skpSecondary(i), "ATR" & intATR & ".2", False)) intATR += 1 Next Dim PrimaryProfile As New List(Of ProfileLine) Dim SecondaryProfile As New List(Of ProfileLine) For i As Integer = 0 To pPointsPrimary.Count - 2 Dim pPoint As ProfilePoint = pPointsPrimary(i) Dim pPoint2 As ProfilePoint = pPointsPrimary(i + 1) Dim sl As SketchLine = psProfile.SketchLines.AddByTwoPoints(pPoint.SketchPoint, pPoint2.SketchPoint) If pPoint.IsPrimarySide Then PrimaryProfile.Add(New ProfileLine(sl, pPoint.PointID, True, pPoint, pPoint2)) Else SecondaryProfile.Add(New ProfileLine(sl, pPoint.PointID, True, pPoint, pPoint2)) End If Dim pPoint3 As ProfilePoint = pPointsSecondary(i) Dim pPoint4 As ProfilePoint = pPointsSecondary(i + 1) Dim sl2 As SketchLine = psProfile.SketchLines.AddByTwoPoints(pPoint3.SketchPoint, pPoint4.SketchPoint) If pPoint3.IsPrimarySide Then PrimaryProfile.Add(New ProfileLine(sl2, pPoint3.PointID, False, pPoint3, pPoint4)) Else SecondaryProfile.Add(New ProfileLine(sl2, pPoint3.PointID, False, pPoint3, pPoint4)) End If Next Dim lastPoint1 As ProfilePoint = pPointsPrimary(pPointsPrimary.Count - 1) Dim lastPoint2 As ProfilePoint = pPointsSecondary(pPointsSecondary.Count - 1) Dim slTop As SketchLine = psProfile.SketchLines.AddByTwoPoints(lastPoint1.SketchPoint, lastPoint2.SketchPoint) PrimaryProfile.Add(New ProfileLine(slTop, "Top", False, lastPoint1, lastPoint2)) 'create dimension constraints 'create mirror line: Dim slMirror As SketchLine = Nothing 'look for an existing mirror line For Each sl As SketchLine In psProfile.SketchLines If sl.StartSketchPoint.Geometry.X = 0 AndAlso sl.StartSketchPoint.Geometry.Y = 0 AndAlso sl.EndSketchPoint.Geometry.Y = 0 Then 'this is mirror line slMirror = sl Exit For End If Next 'create line if not found If slMirror Is Nothing Then Dim sp1 As SketchPoint = psProfile.SketchPoints.Add(tg.CreatePoint2d(0, 0), False) psProfile.GeometricConstraints.AddGround(sp1) Dim sp2 As SketchPoint = psProfile.SketchPoints.Add(psProfile.ModelToSketchSpace(tg.CreatePoint(0, 1, 0)), False) psProfile.GeometricConstraints.AddGround(sp2) slMirror = psProfile.SketchLines.AddByTwoPoints(sp1, sp2) End If Dim dDimensionOffset As Double = 15 * 2.54 Dim sdcProfileVert As New List(Of DimensionConstraint) Dim sdcProfileHorz As New List(Of DimensionConstraint) For i As Integer = 0 To PrimaryProfile.Count - 2 'add vertical dimension constraint Dim sdcVert As DimensionConstraint = psProfile.DimensionConstraints.AddTwoPointDistance(slMirror.StartSketchPoint, PrimaryProfile(i).StartProfilePoint.SketchPoint, DimensionOrientationEnum.kHorizontalDim, tg.CreatePoint2d(PrimaryProfile(0).StartProfilePoint.SketchPoint.Geometry.X / 2, PrimaryProfile(0).StartProfilePoint.SketchPoint.Geometry.Y + ((1 + i) * dDimensionOffset)), True) With sdcVert.Parameter .Name = PrimaryProfile(i).StartProfilePoint.PointID .DisplayFormat = ParameterDisplayFormatEnum.kArchitecturalDisplayFormat .Visible = True .Precision = Inventor.LinearPrecisionEnum.kSixteenthsFractionalLinearPrecision .ExposedAsProperty = True ' MsgBox(.InUse) With .CustomPropertyFormat .PropertyType = CustomPropertyTypeEnum.kTextPropertyType .Units = Inventor.UnitsTypeEnum.kFootLengthUnits .Precision = CustomPropertyPrecisionEnum.kSixteenthsFractionalLengthPrecision '.ShowUnitsString = True End With End With sdcProfileVert.Add(sdcVert) 'add horizontal dimension constraints Dim sdcHorz As DimensionConstraint = psProfile.DimensionConstraints.AddTwoPointDistance(PrimaryProfile(i).StartProfilePoint.SketchPoint, SecondaryProfile(i).StartProfilePoint.SketchPoint, DimensionOrientationEnum.kVerticalDim, tg.CreatePoint2d(lastPoint1.SketchPoint.Geometry.X + ((1 + i) * dDimensionOffset), 0), True) With sdcHorz.Parameter .Name = sdcVert.Parameter.Name.Replace("ATR", "WIDE") .Visible = True .Precision = Inventor.LinearPrecisionEnum.kSixteenthsFractionalLinearPrecision .ExposedAsProperty = True With .CustomPropertyFormat .PropertyType = CustomPropertyTypeEnum.kTextPropertyType .Units = Inventor.UnitsTypeEnum.kFootLengthUnits .Precision = CustomPropertyPrecisionEnum.kSixteenthsFractionalLengthPrecision '.ShowUnitsString = True End With End With sdcProfileHorz.Add(sdcHorz) Next For i As Integer = PrimaryProfile.Count - 1 To PrimaryProfile.Count - 1 'add vertical dimension constraint at top Dim sdcVert As DimensionConstraint = psProfile.DimensionConstraints.AddTwoPointDistance(slMirror.StartSketchPoint, PrimaryProfile(i).StartProfilePoint.SketchPoint, DimensionOrientationEnum.kHorizontalDim, tg.CreatePoint2d(PrimaryProfile(0).StartProfilePoint.SketchPoint.Geometry.X / 2, PrimaryProfile(0).StartProfilePoint.SketchPoint.Geometry.Y + (PrimaryProfile.Count * dDimensionOffset)), True) With sdcVert.Parameter .Name = PrimaryProfile(i).StartProfilePoint.PointID .DisplayFormat = ParameterDisplayFormatEnum.kArchitecturalDisplayFormat .Visible = True .Precision = Inventor.LinearPrecisionEnum.kSixteenthsFractionalLinearPrecision .ExposedAsProperty = True ' MsgBox(.InUse) With .CustomPropertyFormat .PropertyType = CustomPropertyTypeEnum.kTextPropertyType .Units = Inventor.UnitsTypeEnum.kFootLengthUnits .Precision = CustomPropertyPrecisionEnum.kSixteenthsFractionalLengthPrecision '.ShowUnitsString = True End With End With sdcProfileVert.Add(sdcVert) 'add horizontal dimension constraints at top Dim sdcHorz As DimensionConstraint = psProfile.DimensionConstraints.AddTwoPointDistance(PrimaryProfile(i).StartProfilePoint.SketchPoint, PrimaryProfile(i).EndProfilePoint.SketchPoint, DimensionOrientationEnum.kVerticalDim, tg.CreatePoint2d(lastPoint1.SketchPoint.Geometry.X + (PrimaryProfile.Count * dDimensionOffset), 0), True) With sdcHorz.Parameter .Name = sdcVert.Parameter.Name.Replace("ATR", "WIDE") .Visible = True .Precision = Inventor.LinearPrecisionEnum.kSixteenthsFractionalLinearPrecision .ExposedAsProperty = True With .CustomPropertyFormat .PropertyType = CustomPropertyTypeEnum.kTextPropertyType .Units = Inventor.UnitsTypeEnum.kFootLengthUnits .Precision = CustomPropertyPrecisionEnum.kSixteenthsFractionalLengthPrecision '.ShowUnitsString = True End With End With sdcProfileHorz.Add(sdcHorz) Next Dim acd As AssemblyComponentDefinition = psProfile.Parent Dim adoc As AssemblyDocument = acd.Document If adoc.RequiresUpdate Then adoc.Update() 'add rounding formulas, format parameters, and export for use as iProperty ATRWideRoundReset(adoc) CreateAndEditCustomProperty("ProfileOffset", TTSMainDataCore.MathTools.DecimalInchToFeetInch(ProfileOffset / 2.54, TTSMainDataCore.MathTools.FractionalPrecision.Sixteenth), adoc, True) Else MsgBox("Please make right and left side of your profile symmetrical, I can not fix it.") Exit Sub End If If trans IsNot Nothing Then trans.End() Else MsgBox("Please use a standard car design with component named 'CarDeck' with workpoint named 'Deck Edge'.") End If Else MsgBox("Please activate the 2d sketch to be used.") End If Else MsgBox("Please open the clearance model assembly file and activate the 2d sketch to be used.") End If End If End Sub Public Function SortProfilePointList(ByVal skpPrimary As List(Of SketchPoint), isPrimary As Boolean) As List(Of SketchPoint) Dim skp As New List(Of SketchPoint) skp.AddRange(skpPrimary) 'first perform a pure vertical sort skp.Sort(Function(x, y) x.Geometry3d.Y.CompareTo(y.Geometry3d.Y)) 'not using geometry 3d speeds things up??? Dim booChanged As Boolean Do booChanged = False For i As Integer = 0 To skp.Count - 2 Dim a As SketchPoint = skp(i) Dim b As SketchPoint = skp(i + 1) If Math.Round(a.Geometry3d.Y, 8) = Math.Round(b.Geometry3d.Y, 8) Then If i < skp.Count - 2 Then Dim c As SketchPoint = skp(i + 2) Debug.Print(i & "," & a.Geometry3d.Y & "," & a.Geometry3d.Z & "," & b.Geometry3d.Y & "," & b.Geometry3d.Z & "," & c.Geometry3d.Y & "," & c.Geometry3d.Z) If a.Geometry3d.Z < b.Geometry3d.Z Then If c.Geometry3d.Z <= a.Geometry3d.Z Then 'swap a and b skp.Remove(b) skp.Insert(i, b) booChanged = True Exit For End If ElseIf a.Geometry3d.Z > b.Geometry3d.Z Then If c.Geometry3d.Z >= a.Geometry3d.Z Then 'swap a and b skp.Remove(b) skp.Insert(i, b) booChanged = True Exit For End If End If End If End If Next Debug.Print(booChanged) Loop Until boochanged = False Return skp End Function Public Sub ATRWideRoundReset(docAsm As Inventor.AssemblyDocument) 'find "Clearance Profile" sketch Dim skClearanceProfile As PlanarSketch = Nothing For Each psk As PlanarSketch In docAsm.ComponentDefinition.Sketches If psk.Name = "Clearance Profile" Then skClearanceProfile = psk Exit For End If Next Dim dcATRs As New List(Of DimensionConstraint) Dim dcWides As New List(Of DimensionConstraint) If skClearanceProfile IsNot Nothing Then For Each dc As Inventor.DimensionConstraint In skClearanceProfile.DimensionConstraints If dc.Parameter.Name.Contains("ATR") Then If Not dc.Parameter.Name = "ATRD" Then dcATRs.Add(dc) ElseIf dc.Parameter.Name.Contains("WIDE") Then If Not dc.Parameter.Name = "WIDED" Then dcWides.Add(dc) End If Next Else MsgBox("Can not find sketch named 'Clearance Profile'") End If 'look for existing atr-wide rounded parameters'clear them out Dim exATRs As List(Of Parameter) = GetParameterValues(docAsm, "ATR", True) If exATRs.Count > 0 Then Dim exATRRs As New List(Of Parameter) For Each param As Parameter In exATRs If param.Name.Substring(param.Name.Length - 1, 1) = "R" Then exATRRs.Add(param) Next For Each param As Parameter In exATRRs exATRs.Remove(param) Next For Each param As Parameter In exATRRs RemoveParameterAndIProperty(param, dcATRs, docAsm) Next For Each param As Parameter In exATRs RemoveParameterAndIProperty(param, dcATRs, docAsm) Next End If Dim exWides As List(Of Parameter) = GetParameterValues(docAsm, "WIDE", True) If exWides.Count > 0 Then Dim exWideRs As New List(Of Parameter) For Each param As Parameter In exWides If param.Name.Substring(param.Name.Length - 1, 1) = "R" Then exWideRs.Add(param) Next For Each param As Parameter In exWideRs exWides.Remove(param) Next For Each param As Parameter In exWideRs RemoveParameterAndIProperty(param, dcWides, docAsm) Next For Each param As Parameter In exWides RemoveParameterAndIProperty(param, dcWides, docAsm) Next End If 'once old parameters are cleared out, create new ones based soley on the existence of the parameters found from the dimensions Dim dcATRWIDES As New List(Of DimensionConstraint) dcATRWIDES.AddRange(dcATRs) dcATRWIDES.AddRange(dcWides) For Each dc As DimensionConstraint In dcATRWIDES dc.Parameter.ExposedAsProperty = False Dim iProp As [Property] = FindiProperty(Tools.UserDefinedPropertySetID, dc.Parameter.Name, docAsm) If iProp IsNot Nothing Then iProp.Delete() ExportParameterAsFeetInches(dc.Parameter) Dim paraRound As Inventor.Parameter = Nothing Dim paramName As String = dc.Parameter.Name If paramName.ToUpper.Contains("ATR") Or paramName.ToUpper.Contains("WIDE") Then 'round(( ATR1 - 0.49 in ) / 1 in) * 1 in Dim sign As String = "+" Dim strExpression As String = "round(( " & paramName & " " & sign & " 0.49 in ) / 1 in) * 1 in" Dim dRemainderInches As Double = (CDbl(dc.Parameter.Value) * 2.54) Mod 1 If 0.09 < dRemainderInches AndAlso dRemainderInches < 1 / 32 Then strExpression = "round(( " & dc.Parameter.Name & " ) / 1 in) * 1 in" End If Dim strName As String = dc.Parameter.Name & "R" Try Dim uParams As UserParameters = docAsm.ComponentDefinition.Parameters.UserParameters paraRound = uParams.AddByExpression(strName, strExpression, Inventor.UnitsTypeEnum.kInchLengthUnits) Catch ex As Exception Dim eh As New ErrorHandler(ex) eh.HandleIt() End Try End If ExportParameterAsFeetInches(paraRound) Next If dcWides.Count > 0 Then Dim intRoundDown As Integer dcWides.Sort(Function(x, y) CInt(x.Parameter.Name.Replace("WIDE", "")).CompareTo(CInt(y.Parameter.Name.Replace("WIDE", "")))) For i As Integer = 0 To dcWides.Count - 1 dcWides(i).Parameter.ExposedAsProperty = False Dim iProp As [Property] = FindiProperty(Tools.UserDefinedPropertySetID, dcWides(i).Parameter.Name, docAsm) If iProp IsNot Nothing Then iProp.Delete() ExportParameterAsFeetInches(dcWides(i).Parameter) 'if next value is smaller than current value then this is the last integer we want to round down If i > 0 Then 'must always be 1 below the max count Dim dblValue As Double = dcWides(i - 1).Parameter.Value Dim dblValue2 As Double = dcWides(i).Parameter.Value If Math.Round(dblValue, 8) < Math.Round(dblValue2, 8) Then 'get integer value from name Dim strNumber As String = dcWides(i).Parameter.Name strNumber = strNumber.ToUpper.Replace("WIDE", "") intRoundDown = CInt(strNumber) 'Exit For End If End If Next For i As Integer = 1 To intRoundDown - 1 'get ATR rounded value by name = ATR1R Dim uParam As UserParameter = docAsm.ComponentDefinition.Parameters.UserParameters.Item("ATR" & i & "R") If uParam IsNot Nothing Then uParam.Expression = "round(( " & "ATR" & i & " - 0.49 in ) / 1 in) * 1 in" Dim dRemainderInches As Double = (CDbl(uParam.Value) * 2.54) Mod 1 If 0.09 < dRemainderInches AndAlso dRemainderInches < 1 / 32 Then uParam.Expression = "round(( " & "ATR" & i & " ) / 1 in) * 1 in" End If End If Next End If If docAsm.RequiresUpdate = True Then docAsm.Update2(True) End Sub Public Function Distance(point1 As Point, point2 As Point) As Double Return ((point2.X - point1.X) ^ 2 + (point2.Y - point1.Y) ^ 2 + (point2.Z - point1.Z) ^ 2) ^ 0.5 End Function