Coating drawing flag automation

Coating drawing flag automation

get2dpk
Participant Participant
576 Views
4 Replies
Message 1 of 5

Coating drawing flag automation

get2dpk
Participant
Participant

Hi guys,

I want to automate the Coating information in drawing directly from 3d Assy.

I will do below steps.

1.Apply colors is 3d Model

get2dpk_1-1664857769085.png

2.Open drawing and place the model

get2dpk_2-1664857856521.png

After this I want the code to perform the below steps

When I run the Code, it should automatically pull the color details and ask the details(user input) like show below

 

get2dpk_3-1664859206963.png

 

 

 

get2dpk_4-1664859222170.png

 

get2dpk_5-1664859241357.png

 

once the details are typed in by the User, The code has to identify and place the flags in the surfaces. the arrow can be anywhere on the surface, user can drag and  adjust as needed.

 

get2dpk_6-1664859592605.png

 

After flag placement, a legend note like below has to be generated (along with Correct RAL code )

 

get2dpk_0-1664860135290.png

 

SO THE OUTPUT WILL LOOK LIKE THIS

get2dpk_1-1664860161749.png

 

Thanks in Advance!😀

0 Likes
577 Views
4 Replies
Replies (4)
Message 2 of 5

james.collinsPWQR2
Advocate
Advocate

Hi get2dpk,

 

After having a go at trying to solve this one, I can see why no one else touched it!

Firstly you may want to take a look at the Inventor Beta forum as they are currently working on a Finishes command at the moment, which will be a lot better than anything below.

I hope this helps to at least get you started. I have included some sample files, so that you can see the output and get the symbol that I used. They were created in 2022, please let me know if you need an older version. Here is the rule that should be stored in you external rules directory. Run it on the model first and then run it on the drawing.

 

 

Imports Linq
Class ThisRule
	' Created by James Collins
	' Allows user to assign a colour and associated treatment to a face (model documents). 
	' Then display the treatment in the drawing via sketch symbols
	' Doesn't check if there are any existing tags!

	' This class will be used when we are adding sybols to the drawing
	Class ColourTreatment
		Public Treatment As String
		Public ColourName As String
		Public RALColourName As String
		Public TagNumber As Double
	End Class

	' Create Dictionary of required colour treatment combinations
	Dim colourTreatmentDict As New Dictionary(Of String, String())
	' This list will be used to keep count of the treatments we can find in this view
	Dim assignedColourTreatments As New List(Of ColourTreatment)
	Dim treatmentSymbolDef As SketchedSymbolDefinition = Nothing
	Dim TreatmentNameD As String = "Treatment"
	Dim RALColourNameD As String = "RALColour"
	Dim BasicColourNameD As String = "BasicColour"
	Dim colourTreatmentSet As String = "colourTreatmentSet"
	Dim treatmentSymbolName As String = "Treatment Tag"
	Dim activeDoc As Document
	Dim viewReferencedDocument As Document
	Dim assyDocument As AssemblyDocument
	Dim partDocument As partDocument
	Dim drawDocument As DrawingDocument
	Dim currentSheet As Sheet
	Dim transObjects As TransientObjects
	Dim transGeometry As TransientGeometry
	Dim selectedTreatmentColour() As String
	' Used for placement of symbols on drawing
	Dim viewOffsetRectLines(3) As Object
	Dim calculatedViewCenter As Point2d


	Sub Main
		assyDocument = TryCast(ThisApplication.ActiveDocument, AssemblyDocument)
		drawDocument = TryCast(ThisApplication.ActiveDocument, DrawingDocument)
		partDocument = TryCast(ThisApplication.ActiveDocument, partDocument)
		activeDoc = ThisApplication.ActiveDocument
		' Set a reference to the command manager
		Dim oCommandMngr As CommandManager = ThisApplication.CommandManager
		' Set references
		transObjects = ThisApplication.TransientObjects
		transGeometry = ThisApplication.TransientGeometry
		If Not drawDocument Is Nothing Then
			GoTo drawingFunctions
		Else If Not assyDocument Is Nothing Then
		Else If Not partDocument Is Nothing Then
		Else
			Exit Sub ' unknown doc type
		End If
		' <##### Hard code more colour treatment combinations below as required:
		' The last three string values in each line represent the rgb values of the RAL colour
		colourTreatmentDict.Add("GALVANISED", New String() {"GREEN", "RAL 6038", 0, 181, 26 })
		colourTreatmentDict.Add("ZINC PLATED", New String() {"RED", "RAL 3024", 255, 45, 33 })
		colourTreatmentDict.Add("HDG", New String() {"VIOLET", "RAL 4005", 118, 104, 154 })
		' Hard code more colour treatment combinations Above ^ #####>
		' Create a temp copy the we can use when assigning coulour to the model
		Dim colourTratmentDictTemp As New Dictionary(Of String, String())(colourTreatmentDict)
		Dim endSelection As String = "End Selection"
		colourTratmentDictTemp.Add(endSelection, New String() {"", "", "", "", "" })
		Dim selectedObject As Object
		' Allows user to keep selecting desired treatment/faces
		addAnotherTreatment :
		Dim treatmentSelection As Object = InputListBox("Select Face Treatment", colourTratmentDictTemp.Keys, _
		1, Title := "List of Treatments to add to faces", ListName := "Available Treatments:")
		' Finish up if nothing is selected or endSelection is selected
		If treatmentSelection Is Nothing Or treatmentSelection = endSelection Then GoTo finishSelection
		' Get the string array of this dictionary item (treatmentSelection)
		selectedTreatmentColour = colourTreatmentDict.Item(treatmentSelection)
		' Basic colour Name based on treatment
		Dim colourNameS As String = selectedTreatmentColour(0)
		' RAL Colour
		Dim RALColourNameS As String = selectedTreatmentColour(1)
		' Remove the treatment, so the user is only left with treatments that havent been applied yet
		colourTratmentDictTemp.Remove(treatmentSelection)
		' Allow user to add colour/treatment to faces
		If treatmentSelection <> endSelection Then
			While True
				'Select faces
				selectedObject = oCommandMngr.Pick(SelectionFilterEnum.kAllEntitiesFilter, _
				"Select Faces to Add Treatment to. Hit Esc when Done.")
				' Finish command if nothing is selected
				If IsNothing(selectedObject) Then
					If colourTratmentDictTemp.Count = 1 Then GoTo finishSelection
					GoTo addAnotherTreatment
					Exit While
				End If
				Call SetFaceColour(selectedObject, treatmentSelection, colourNameS, RALColourNameS)
			End While
		End If
		finishSelection :
		' If this is a part/assembly then exit sub
		If drawDocument Is Nothing Then Exit Sub
		' Drawing only stuff
		drawingFunctions :
		' Select View to get all faces with Colour/Treatments
		' Get the collection of control definitions
		Dim selectedView As Object
		' Get user to select a drawing view to add the symbol to
		selectedView = oCommandMngr.Pick(SelectionFilterEnum.kDrawingViewFilter, _
		"Select View to Tag Treatment Faces")
		If selectedView Is Nothing Then
			MessageBox.Show("Select a Drawing View Next Time!" & vbLf & _
			"", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
			Exit Sub
		End If
		viewReferencedDocument = selectedView.ReferencedDocumentDescriptor.ReferencedDocument
		currentSheet = drawDocument.ActiveSheet
		' Create a dictionary to store the Faces
		Dim requiredFacesDict As New Dictionary(Of Object, Object())
		Call DistinctOccurrences(selectedView, requiredFacesDict)
		Logger.Info("DistinctOccurrences passed")
'		exit sub
		If requiredFacesDict.Count = 0 Then
			MessageBox.Show("Treatments Must be Assigned to the Model" & vbLf & _
			"Before Running this Rule in the Drawing!", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
			Exit Sub
		End If
		' Creates a rectangle around view to place leader/sketch symbols on
		Call ViewOffsetRectangle(selectedView, requiredFacesDict.Count)
		' Create a new transaction to wrap these drawing functions into
		Dim drawingTrans As Transaction = ThisApplication.TransactionManager.StartTransaction( _
		    drawDocument, "Treatment Symbols")
		Call GetViewOccurrenceDocument(selectedView, requiredFacesDict)
		If treatmentSymbolDef Is Nothing Then
			Exit Sub
		End If
		Call AddLegendSymbolsToDrawing()
		' End the transaction for the drawing funtions.
		drawingTrans.End
	End Sub

	Public Sub SetFaceColour(ByRef selectedObject As Object, ByRef treatmentSelection As Object, _
		ByRef colourNameS As String, ByRef RALColourNameS As String)
		If TypeName(selectedObject) Like "Face*" Then
			Dim oFace As Face
			Dim faceDoc As partDocument
			If partDocument Is Nothing Then 'its an assembly
				Logger.Info("assy doc")
				oFace = selectedObject.NativeObject
				Call GetFaceDocument(oFace, faceDoc)
			Else ' Its a part
				oFace = selectedObject
				faceDoc = activeDoc
			End If
			Dim docAssets As Assets = faceDoc.Assets
			Dim foundAsset As Boolean
			For Each docAsset As Asset In docAssets
				If docAsset.DisplayName = colourNameS Then
					Logger.Info("docAsset.DisplayName: " & docAsset.DisplayName)
					foundAsset = True
					Exit For
				End If
			Next
			If foundAsset = False Then
				Dim newAsset As Asset = docAssets.Add(kAssetTypeAppearance, "Generic", , colourNameS)
				Dim colourAssetVal As ColorAssetValue = newAsset.Item("generic_diffuse")
				Dim colourR As Byte = selectedTreatmentColour(2)
				Dim colourG As Byte = selectedTreatmentColour(3)
				Dim colourB As Byte = selectedTreatmentColour(4)
				Logger.Info("RGB: " & colourR & "," & colourG & "," & colourB)
				colourAssetVal.Value = transObjects.CreateColor(colourR, colourG, colourB)
			End If
			' Create a new transaction to wrap the modification to this file into a single undo.
			Dim trans As Transaction = ThisApplication.TransactionManager.StartTransaction( _
			faceDoc, "Treatment Colour")
			' Set the face colour
			Call oFace.SetRenderStyle(kOverrideRenderStyle, faceDoc.RenderStyles.Item(colourNameS))
			' We will store the treatment information in the face attributes
			Call CreateAttributes(oFace, treatmentSelection, colourNameS, RALColourNameS)
			' End the transaction for the previous two actions
			trans.End
		End If
	End Sub

	Public Sub GetFaceDocument(ByRef selectedFace As Object, ByRef selectedFaceDoc As partDocument)
	' Get the document that this face belongs to
		Logger.Info("face parent: " & TypeName(selectedFace.Parent))
		If TypeName(selectedFace.Parent) = "PartComponentDefinition" Then
			Logger.Info(selectedFace.Parent.Document.FullDocumentName)
			selectedFaceDoc = selectedFace.Parent.Document
		Else
			Logger.Info("calling function again")
			Call GetFaceDocument(selectedFace.Parent, selectedFaceDoc)
		End If
	End Sub ']
	

	Public Sub CreateAttributes(ByRef oFace As Face, ByRef treatmentSelection As Object, ByRef colourNameS As String, ByRef RALColourNameS As String)
	' Stores information about the treatment and colour in the faces attribute set
		Logger.Info("about to creat atts")
		Dim attSets As AttributeSets = oFace.AttributeSets
		Dim attSet As AttributeSet
		Dim attNamesDict As New Dictionary(Of String, Object)
		attNamesDict.Add(TreatmentNameD, treatmentSelection)
		attNamesDict.Add(RALColourNameD, RALColourNameS)
		attNamesDict.Add(BasicColourNameD, colourNameS)
		If attSets.NameIsUsed(colourTreatmentSet) = False Then 'create it for the first time
			attSet = attSets.Add(colourTreatmentSet)
		Else
			attSet = attSets.Item(colourTreatmentSet)
		End If
		' Use For Each loops over pairs not found earlier and add as atts
		For Each pair As KeyValuePair(Of String, Object) In attNamesDict
			Dim attName As String = pair.Key
			Dim attValue As String = pair.Value
			If attSet.NameIsUsed(attName) = False Then 'create it for the first time
				att = attSet.Add(attName, kStringType, attValue)
			Else  ' already exists
				att = attSet.Item(attName)
				att.Value = attValue
			End If
		Next
	End Sub


	Public Sub DistinctOccurrences(ByVal drgView As DrawingView, ByVal requiredFacesDict As Dictionary(Of Object, Object()))
		' Loop through all of the curves in the view to find distinct occurrences that contain faces with treatment attributes (coloured faces)
		Dim selectedViewCurves As DrawingCurvesEnumerator = drgView.DrawingCurves
		' Loop through the curves to get unique part file instances
		For Each selectedViewCurve As DrawingCurve In selectedViewCurves
			If selectedViewCurve.ModelGeometry Is Nothing = True Then Continue For
			Try
				Dim modelGeo As Object = selectedViewCurve.ModelGeometry
				Dim containingOcc As ComponentOccurrence
				Dim containingOccDefType As DocumentTypeEnum
				Dim partDoc As partDocument
				Dim modelGeoFaces As Faces
				 ' Part doc so we can access the face directly
				If viewReferencedDocument.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
					modelGeoFaces = modelGeo.Faces
					For Each nativeFace As Face In modelGeoFaces
						Dim hasAttSet As Boolean = nativeFace.AttributeSets.NameIsUsed(colourTreatmentSet)
						If hasAttSet = False Then Continue For
						If requiredFacesDict.ContainsKey(nativeFace) Then Continue For
						requiredFacesDict.Add(nativeFace, New Object() {selectedViewCurve, Nothing})
					Next
				Else ' Assembly document, faceproxy is used to access native face object
					containingOcc = modelGeo.ContainingOccurrence
					containingOccDefType = containingOcc.DefinitionDocumentType
					If containingOccDefType = DocumentTypeEnum.kPartDocumentObject Then
						Logger.Info("###" & containingOcc.Name)
						partDoc = containingOcc.Definition.Document
						modelGeoFaces = modelGeo.Faces
						For Each modelGeoFace As FaceProxy In modelGeoFaces
							Dim nativeFace As Face = modelGeoFace.NativeObject
							' Only continue if it contains desired attribute set
							Dim hasAttSet As Boolean = nativeFace.AttributeSets.NameIsUsed(colourTreatmentSet)
							If hasAttSet = False Then Continue For
							If requiredFacesDict.ContainsKey(nativeFace) Then Continue For
							' containing occurrence may be better than doc as we want to check this occ against the model occ
							requiredFacesDict.Add(nativeFace, New Object() {selectedViewCurve, containingOcc })
						Next
					End If
				End If
			Catch
				Continue For
			End Try
		Next
	End Sub

	Public Sub ViewOffsetRectangle(ByVal selectedView As DrawingView, ByVal requiredFacesDictCount As Integer)
		' Create a rectangle offset from the view perimeter that will be used to place the sketch symbols on
		' that will intersect with the rectangle 
		' and then we can use those intersection points to place the symbols on
		Dim viewHeight As Double = selectedView.Height
		Dim viewWidth As Double = selectedView.Width
		Dim viewLeft As Double = selectedView.Left
		Dim viewTop As Double = selectedView.Top
		Dim viewOffset As Double = 2
		' Want to make sure that we get the actual view center, as the view.center and view.position tend to differ...
		calculatedViewCenter = transGeometry.CreatePoint2d(viewLeft + viewWidth / 2, viewTop - viewHeight / 2)
		' Create the rangebox points of the rectangle
		Dim viewExtentsOffsetBoxMinPoint As Point2d = transGeometry.CreatePoint2d(viewLeft - viewOffset, viewTop - viewHeight - viewOffset)
		Logger.Info("viewExtentsOffsetBoxMinPoint XY: " & viewExtentsOffsetBoxMinPoint.X & ", " & viewExtentsOffsetBoxMinPoint.Y)
		Dim viewExtentsOffsetBoxMaxPoint As Point2d = transGeometry.CreatePoint2d(viewLeft + viewWidth + viewOffset, viewTop + viewOffset)
		Logger.Info("viewExtentsOffsetBoxMaxPoint XY: " & viewExtentsOffsetBoxMaxPoint.X & ", " & viewExtentsOffsetBoxMaxPoint.Y)
		' These are the lines that will define the rectange
		Dim viewOffsetRectLine1, viewOffsetRectLine2, viewOffsetRectLine3, viewOffsetRectLine4 As LineSegment2d
		viewOffsetRectLine1 = transGeometry.CreateLineSegment2d(viewExtentsOffsetBoxMinPoint, _
		transGeometry.CreatePoint2d(viewExtentsOffsetBoxMinPoint.X, viewExtentsOffsetBoxMaxPoint.Y))
		viewOffsetRectLine2 = transGeometry.CreateLineSegment2d(viewOffsetRectLine1.EndPoint, viewExtentsOffsetBoxMaxPoint)
		viewOffsetRectLine3 = transGeometry.CreateLineSegment2d(viewExtentsOffsetBoxMaxPoint, _
		transGeometry.CreatePoint2d(viewExtentsOffsetBoxMinPoint.Y, viewExtentsOffsetBoxMaxPoint.X))
		viewOffsetRectLine4 = transGeometry.CreateLineSegment2d(viewOffsetRectLine3.EndPoint, viewOffsetRectLine1.StartPoint)
		' Add the lines to this array for later use
		viewOffsetRectLines(0) = viewOffsetRectLine1 : viewOffsetRectLines(1) = viewOffsetRectLine2 : viewOffsetRectLines(2) = viewOffsetRectLine3 : viewOffsetRectLines(3) = viewOffsetRectLine4
	End Sub

	' Not a great implementation, often the symbol isn't placed on the rectangle.
	' Take a look at this post if you want something more reliable: https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/auto-ballooning-a-drawing-attach-balloon-to-drawingcurvesegment/m-p/10096249
	Public Function LeaderViewRectIntersection(ByRef geoIntentPoint As Point2d) As Point2d
	' Create mathematical points at the intersection of the curve geometry and the view offset rectangle
		Dim viewCentertoGeoIntentLine As LineSegment2d = transGeometry.CreateLineSegment2d(calculatedViewCenter, geoIntentPoint)
		Dim intPoints As ObjectCollection = Nothing
		intPoints = transObjects.CreateObjectCollection
		Dim intPointsCount As Double = 0
		' Define this first one as 0,0 just in case it we dont find any intersections
		Dim intPoint As Point2d = transGeometry.CreatePoint2d(0, 0)
		' Loop through the rectanglular lines and see if they intersect with any of the drawing curves
		For i = 0 To viewOffsetRectLines.Count - 1
			Dim viewOffsetRectLine As LineSegment2d = viewOffsetRectLines(i)
			Logger.Info(TypeName(viewOffsetRectLine))
			Dim intersectingpoints As ObjectsEnumerator
			' Setting the Tolerance to 0 or 1 didnt provide very good results, so I bumped it to 10
			'	intersectingpoints = viewOffsetRectLine.IntersectWithCurve(viewCentertoGeoIntentLine, 1)
			intersectingpoints = viewCentertoGeoIntentLine.IntersectWithCurve(viewOffsetRectLine, 10)
			If intersectingpoints Is Nothing Then
				Logger.Info("nothing")
				Continue For
			Else
				' Set as the first intersection point
				intPoint = intersectingpoints.Item(1)
				For Each intersectingpointsPoint In intersectingpoints
					' But also add the rest so we can get the closest one
					intPoints.Add(intersectingpointsPoint)
					Logger.Info("intersectingpointsPointXY: " & intersectingpointsPoint.X & ", " & intersectingpointsPoint.Y)
				Next
			End If
			i += 1
		Next
		' ####<If you want to see this visually uncomment the lines below
'		    Dim oSketch As DrawingSketch = drawDocument.ActiveSheet.Sketches.Add
'		    ' Put the sketch in edit mode
'		    oSketch.Edit
'			Call oSketch.SketchLines.AddByTwoPoints(viewCentertoGeoIntentLine.StartPoint, viewCentertoGeoIntentLine.EndPoint)
'			Call oSketch.SketchLines.AddAsTwoPointRectangle(transGeometry.CreatePoint2d(viewOffsetRectLines(0).StartPoint.X, viewOffsetRectLines(0).StartPoint.Y), transGeometry.CreatePoint2d(viewOffsetRectLines(1).EndPoint.X, viewOffsetRectLines(1).EndPoint.Y))
'			oSketch.ExitEdit
		'####>
		' Loop over all of the points to see which one is the closest
		' Should probably have checked to see if point is inside rectangle with something like this : https://stackoverflow.com/questions/2752725/finding-whether-a-point-lies-inside-a-rectangle-or-not
		For Each finalPoint As Point2d In intPoints
			Logger.Info("A: " & finalPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint) & ", B: " & intPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint))
			If finalPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint) < intPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint) Then
				intPoint = finalPoint
			End If
		Next
		Return intPoint
	End Function

	Public Function GetSketchSymbol()
	' Return the required symbol, if it exists
		Dim sketchSymbolDefs As SketchedSymbolDefinitions = drawDocument.SketchedSymbolDefinitions
		For Each sketchSymbolDef As SketchedSymbolDefinition In sketchSymbolDefs
			If sketchSymbolDef.Name = treatmentSymbolName Then
				treatmentSymbolDef = sketchSymbolDef
				Return treatmentSymbolDef
			End If
		Next
	End Function

	Public Sub GetViewOccurrenceDocument(ByVal drgView As DrawingView, _
		ByRef requiredFacesDictionary As Dictionary(Of Object, Object()))
	' Get View Occurrence/Document 
		Dim viewDocCompDef As ComponentDefinition = viewReferencedDocument.ComponentDefinition
		Dim taggedEdges As New ArrayList
		Dim taggedFaces As New ArrayList
		' Get the required symbol, if it exists
		treatmentSymbolDef = GetSketchSymbol()
		If treatmentSymbolDef Is Nothing Then
			MessageBox.Show("Cannot Find Sketch Symbol (" & treatmentSymbolName & ")" & vbLf & _
			"Add it to the Drawing Before Running this Rule Again", "NO SYMBOL", MessageBoxButtons.OK, MessageBoxIcon.Error)
			Exit Sub
		End If
		Dim assignedTreatmentCount As Double = 1
		For Each requiredFace In requiredFacesDictionary
			' Get the string array of this dictionary item
			Dim requiredFaceObjs() As Object = requiredFacesDictionary.Item(requiredFace.Key)
			' Probably the first edge associated with the face
			Dim viewCurve As DrawingCurve = requiredFaceObjs(0)
			Dim modelDoc As Document
			' Part doc so we can access the face directly
			If viewReferencedDocument.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
				modelDoc = viewReferencedDocument
				Call AddSymbolToView(modelDoc, drgView, taggedEdges, taggedFaces, assignedTreatmentCount, Nothing)
			Else ' Assembly Document so we need to access the occurrences
				' Occurrence that owns the face
				Dim containingOccurrence As ComponentOccurrence = requiredFaceObjs(1)
				' Loop through all of the occurrences of the occurrence document in this assembly
				For Each possibleNewEntityOcc As ComponentOccurrence In _
					viewDocCompDef.Occurrences.AllReferencedOccurrences(containingOccurrence.Definition.Document)
					If possibleNewEntityOcc Is containingOccurrence Then
						modelDoc = containingOccurrence.Definition.Document
						Logger.Info(modelDoc.DisplayName)
						Call AddSymbolToView(modelDoc, drgView, taggedEdges, taggedFaces, assignedTreatmentCount, possibleNewEntityOcc)
					End If
				Next
			End If
		Next
	End Sub
	

	Public Sub AddSymbolToView(ByRef modelDoc As Document, ByVal drgView As DrawingView, _
		ByRef taggedEdges As ArrayList, ByRef taggedFaces As ArrayList, _
		ByRef assignedTreatmentCount As Double, ByRef possibleNewEntityOcc As ComponentOccurrence)
		' Add symbols to drawing view
		Dim curveColl As ObjectCollection = Nothing
		Dim drawingCurvesEnum As DrawingCurvesEnumerator = Nothing
		Dim drawingCurve1 As DrawingCurve = Nothing
		Dim edgeProxy1 As EdgeProxy = Nothing
		Dim geoIntent As GeometryIntent = Nothing
		Dim XPos, YPos As Double
		Dim tempObject As Object = Nothing
		Dim facesCollection As ObjectCollection = Nothing
		' Only get the faces that have the correct attribute set
		facesCollection = modelDoc.AttributeManager.FindObjects(colourTreatmentSet, , )
		Logger.Info("facesCollection.Count: " & facesCollection.Count)
		' Only loop over the faces that have the correct attribute set
		For Each attFace As Face In facesCollection
			' Use this to make sure we dont try to get this face again
			Dim attFaceKey As Integer = attFace.TransientKey
			Dim faceColourTreatmentAtts As AttributeSet = attFace.AttributeSets(colourTreatmentSet)
			' Get the required Values from the attributes
			Dim attTreatment As String = faceColourTreatmentAtts.Item(TreatmentNameD).Value
			Dim attRALColour As String = faceColourTreatmentAtts.Item(RALColourNameD).Value
			' Pass over any previously tagged faces
			If taggedFaces.Contains(attFaceKey) Then Continue For
			Logger.Info("attFaceKey: " & attFaceKey)
			For Each attFaceEdge As Edge In attFace.Edges
				Dim attFaceEdgeKey As Integer = attFaceEdge.TransientKey
				' Pass over any that we already have
				If taggedEdges.Contains(attFaceEdgeKey) Then Continue For
				Logger.Info("attFaceEdgeKey: " & attFaceEdgeKey)
				Dim geoIntentPoint As Point2d = Nothing
				' This will fail for any edges that aren't visible
				Try
					' Assembly so we need to get edge via proxy
					If viewReferencedDocument.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
						possibleNewEntityOcc.CreateGeometryProxy(attFaceEdge, tempObject)
						edgeProxy1 = CType(tempObject, EdgeProxy)
						drawingCurvesEnum = drgView.DrawingCurves(edgeProxy1)
					Else ' Part doc so we can access the face directly
						drawingCurvesEnum = drgView.DrawingCurves(attFaceEdge)
					End If
					' If the count is zero then this edge isnt visible in this view so skip it
					If drawingCurvesEnum.Count = 0 Then Continue For
					drawingCurve1 = drawingCurvesEnum(1)
					geoIntent = currentSheet.CreateGeometryIntent(drawingCurve1, 0.5)
					' This point will be used to place the sketch symbol
					geoIntentPoint = geoIntent.PointOnSheet
					Logger.Info("geoIntentPointXY: " & geoIntentPoint.X & ", " & geoIntentPoint.Y)
				Catch E As Exception
					Logger.Info(E.ToString())
					Continue For
				End Try
				Try
					' Find the closest point to geoIntent
					Dim closestPoint As Point2d = Nothing
					closestPoint = LeaderViewRectIntersection(geoIntentPoint)
					Logger.Info("closestPointXY: " & closestPoint.X & ", " & closestPoint.Y)
					' Create a collection for placement points of the symbol and its leader
					curveColl = transObjects.CreateObjectCollection
					' Leader point
					curveColl.Add(closestPoint)
					' Symbol Point
					curveColl.Add(geoIntentPoint)
					' This will be used to give each treatment a unique #
					Dim tagNumber As Double = assignedTreatmentCount
					' Check if the treatment already has an # associated with it
					If assignedColourTreatments.Any(Function(ct) ct.Treatment = attTreatment) Then
						' Get access to the object
						Dim thisAttTreatment = assignedColourTreatments.FirstOrDefault(Function(cT) cT.Treatment = attTreatment)
						' Assign the tag #
						If Not thisAttTreatment Is Nothing Then tagNumber = thisAttTreatment.TagNumber
					Else ' No associated number
						assignedColourTreatments.Add(New ColourTreatment With {.Treatment = attTreatment, _
						.RALColourName = attRALColour, .TagNumber = assignedTreatmentCount })
						assignedTreatmentCount += 1
					End If
					' As this symbol will only have a tag # we will leave the second string empty
					Dim promptStrings = New String() {tagNumber, "" }
					' Add the symbol to the drawing
					currentSheet.SketchedSymbols.AddWithLeader(treatmentSymbolDef, curveColl, 0, 1, promptStrings, True, True)
					' Add this face edge to the arraylist so that we dont tag it twice
					taggedEdges.Add(attFaceEdgeKey)
					' Add this face to the arraylist so that we dont tag it twice
					taggedFaces.Add(attFaceKey)
					' Remove any values associated with these so we start fresh for next edge
					curveColl = Nothing
					drawingCurvesEnum = Nothing
					drawingCurve1 = Nothing
					edgeProxy1 = Nothing
					geoIntent = Nothing
					XPos = Nothing 
					YPos = Nothing 
					tempObject = Nothing
					' Exit after we place a symbol
					GoTo nextFace
				Catch E As Exception
					Logger.Info(E.ToString())
				End Try
			Next
		Next
		nextFace :
		Logger.Info("NEXT FACE")
	End Sub
	
	Public Sub AddLegendSymbolsToDrawing()
		' This section takes care of adding the treatments legend to the upper left hand corner of the drawing
		' Order the tags by their tag number
		Dim byTag As List(Of ColourTreatment) = assignedColourTreatments.OrderBy(Function(cT1) cT1.TagNumber).ToList
		Dim sheetBorder As Border = currentSheet.Border
		Dim sheetTopLeftX As Double = sheetBorder.RangeBox.MinPoint.X + 1
		Dim sheetTopLeftY As Double = sheetBorder.RangeBox.MaxPoint.Y - 1
		Dim sheetTopLeft As Point2d = transGeometry.CreatePoint2d(sheetTopLeftX, sheetTopLeftY)
		For Each tag As ColourTreatment In byTag
			' The second string is the Treatment and RAL name combined
			Dim promptStringsTwo = New String() {tag.TagNumber, tag.Treatment & " - " & tag.RALColourName }
			Logger.Info(tag.TagNumber & ", " &  tag.Treatment & " - " & tag.RALColourName)
			sheetTopLeft.Y = sheetTopLeft.Y - 1.5
			' Add the symbol to the drwaing to create the legend
			Dim legendSymbol As SketchedSymbol = currentSheet.SketchedSymbols.Add(treatmentSymbolDef, sheetTopLeft, 0, 1, promptStringsTwo)
			legendSymbol.Static = True
		Next
	End Sub

End Class ']j

 

 

Good luck,

 

James

0 Likes
Message 3 of 5

get2dpk
Participant
Participant

hi @james.collinsPWQR2 

 

First of all thanks a lot for your Time and Efforts!

 

Unforunately I have Inventor 2020 so I could't able to load the files

Could you please Share them in 2020 Version so I can try your Code,

 

Once Again, Thank you

 

Regards

Pradeep S

0 Likes
Message 4 of 5

james.collinsPWQR2
Advocate
Advocate

Hey Pradeep,

 

You're welcome. It turns out that I must have deleted all versions of Inventor 2020 that I had installed. But ultimately you don't actually need those files, you will just need to create a Sketch Symbol like the one shown below. It will need two prompted text entries (4)(5) and it will also need to be named "Treatment Tag"(1).

jamescollinsPWQR2_0-1668647890236.png

After you have created the sketch symbol and run the rule in the model and then drawing, you should end up with something that looks like this:

jamescollinsPWQR2_1-1668647964725.png

The placement of the symbols is pretty crude, if you want to improve that part of the code I have added comments pointing to an alternative option.

 

Cheers,

 

James

 

 

0 Likes
Message 5 of 5

james.collinsPWQR2
Advocate
Advocate

Hey Pradeep,

 

I have updated code so it now places the leaders outside the drawing view. Here's the updated code:

Imports Linq
Class ThisRule
	' Created by James Collins
	' Allows user to assign a colour and associated treatment to a face (model documents). 
	' Then display the treatment in the drawing via sketch symbols
	' Doesn't check if there are any existing tags!

	' This class will be used when we are adding sybols to the drawing
	Class ColourTreatment
		Public Treatment As String
		Public ColourName As String
		Public RALColourName As String
		Public TagNumber As Double
	End Class

	' Create Dictionary of required colour treatment combinations
	Dim colourTreatmentDict As New Dictionary(Of String, String())
	' This list will be used to keep count of the treatments we can find in this view
	Dim assignedColourTreatments As New List(Of ColourTreatment)
	Dim treatmentSymbolDef As SketchedSymbolDefinition = Nothing
	Dim TreatmentNameD As String = "Treatment"
	Dim RALColourNameD As String = "RALColour"
	Dim BasicColourNameD As String = "BasicColour"
	Dim colourTreatmentSet As String = "colourTreatmentSet"
	Dim treatmentSymbolName As String = "Treatment Tag"
	Dim activeDoc As Document
	Dim viewReferencedDocument As Document
	Dim assyDocument As AssemblyDocument
	Dim partDocument As partDocument
	Dim drawDocument As DrawingDocument
	Dim currentSheet As Sheet
	Dim transObjects As TransientObjects
	Dim transGeometry As TransientGeometry
	Dim selectedTreatmentColour() As String
	' Used for placement of symbols on drawing
	Dim viewOffsetRectLines(3) As Object
	'<<<<NEW 20221216 Create a box that defines the view extents
	Dim viewRangeBox As Box2d '>>>>
	Dim calculatedViewCenter As Point2d


	Sub Main
		assyDocument = TryCast(ThisApplication.ActiveDocument, AssemblyDocument)
		drawDocument = TryCast(ThisApplication.ActiveDocument, DrawingDocument)
		partDocument = TryCast(ThisApplication.ActiveDocument, partDocument)
		activeDoc = ThisApplication.ActiveDocument
		' Set a reference to the command manager
		Dim oCommandMngr As CommandManager = ThisApplication.CommandManager
		' Set references
		transObjects = ThisApplication.TransientObjects
		transGeometry = ThisApplication.TransientGeometry
		If Not drawDocument Is Nothing Then
			GoTo drawingFunctions
		Else If Not assyDocument Is Nothing Then
		Else If Not partDocument Is Nothing Then
		Else
			Exit Sub ' unknown doc type
		End If
		' <##### Hard code more colour treatment combinations below as required:
		' The last three string values in each line represent the rgb values of the RAL colour
		colourTreatmentDict.Add("GALVANISED", New String() {"GREEN", "RAL 6038", 0, 181, 26 })
		colourTreatmentDict.Add("ZINC PLATED", New String() {"RED", "RAL 3024", 255, 45, 33 })
		colourTreatmentDict.Add("HDG", New String() {"VIOLET", "RAL 4005", 118, 104, 154 })
		' Hard code more colour treatment combinations Above ^ #####>
		' Create a temp copy the we can use when assigning coulour to the model
		Dim colourTratmentDictTemp As New Dictionary(Of String, String())(colourTreatmentDict)
		Dim endSelection As String = "End Selection"
		colourTratmentDictTemp.Add(endSelection, New String() {"", "", "", "", "" })
		Dim selectedObject As Object
		' Allows user to keep selecting desired treatment/faces
		addAnotherTreatment :
		Dim treatmentSelection As Object = InputListBox("Select Face Treatment", colourTratmentDictTemp.Keys, _
		1, Title := "List of Treatments to add to faces", ListName := "Available Treatments:")
		' Finish up if nothing is selected or endSelection is selected
		If treatmentSelection Is Nothing Or treatmentSelection = endSelection Then GoTo finishSelection
		' Get the string array of this dictionary item (treatmentSelection)
		selectedTreatmentColour = colourTreatmentDict.Item(treatmentSelection)
		' Basic colour Name based on treatment
		Dim colourNameS As String = selectedTreatmentColour(0)
		' RAL Colour
		Dim RALColourNameS As String = selectedTreatmentColour(1)
		' Remove the treatment, so the user is only left with treatments that havent been applied yet
		colourTratmentDictTemp.Remove(treatmentSelection)
		' Allow user to add colour/treatment to faces
		If treatmentSelection <> endSelection Then
			While True
				'Select faces
				selectedObject = oCommandMngr.Pick(SelectionFilterEnum.kAllEntitiesFilter, _
				"Select Faces to Add Treatment to. Hit Esc when Done.")
				' Finish command if nothing is selected
				If IsNothing(selectedObject) Then
					If colourTratmentDictTemp.Count = 1 Then GoTo finishSelection
					GoTo addAnotherTreatment
					Exit While
				End If
				Call SetFaceColour(selectedObject, treatmentSelection, colourNameS, RALColourNameS)
			End While
		End If
		finishSelection :
		' If this is a part/assembly then exit sub
		If drawDocument Is Nothing Then Exit Sub
		' Drawing only stuff
		drawingFunctions :
		' Select View to get all faces with Colour/Treatments
		' Get the collection of control definitions
		Dim selectedView As Object
		' Get user to select a drawing view to add the symbol to
		selectedView = oCommandMngr.Pick(SelectionFilterEnum.kDrawingViewFilter, _
		"Select View to Tag Treatment Faces")
		If selectedView Is Nothing Then
			MessageBox.Show("Select a Drawing View Next Time!" & vbLf & _
			"", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
			Exit Sub
		End If
		viewReferencedDocument = selectedView.ReferencedDocumentDescriptor.ReferencedDocument
		currentSheet = drawDocument.ActiveSheet
		' Create a dictionary to store the Faces
		Dim requiredFacesDict As New Dictionary(Of Object, Object())
		Call DistinctOccurrences(selectedView, requiredFacesDict)
		Logger.Info("DistinctOccurrences passed")
		If requiredFacesDict.Count = 0 Then
			MessageBox.Show("Treatments Must be Assigned to the Model" & vbLf & _
			"Before Running this Rule in the Drawing!", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
			Exit Sub
		End If
		' Creates a rectangle around view to place leader/sketch symbols on
		Call ViewOffsetRectangle(selectedView, requiredFacesDict.Count)
		' Create a new transaction to wrap these drawing functions into
		Dim drawingTrans As Transaction = ThisApplication.TransactionManager.StartTransaction( _
		    drawDocument, "Treatment Symbols")
		Call GetViewOccurrenceDocument(selectedView, requiredFacesDict)
		If treatmentSymbolDef Is Nothing Then
			Exit Sub
		End If
		Call AddLegendSymbolsToDrawing()
		'<<<<NEW 20221216 Added to ensure view is set to shaded
		If selectedView.ViewStyle <> DrawingViewStyleEnum.kShadedDrawingViewStyle Then
			Try
				selectedView.ViewStyle = DrawingViewStyleEnum.kShadedDrawingViewStyle
			Catch
				Logger.Info("Unable to set View Style to Shaded!")
			End Try
		End If '>>>>
		' End the transaction for the drawing funtions.
		drawingTrans.End
	End Sub

	Public Sub SetFaceColour(ByRef selectedObject As Object, ByRef treatmentSelection As Object, _
		ByRef colourNameS As String, ByRef RALColourNameS As String)
		If TypeName(selectedObject) Like "Face*" Then
			Dim oFace As Face
			Dim faceDoc As partDocument
			If partDocument Is Nothing Then 'its an assembly
				Logger.Info("assy doc")
				oFace = selectedObject.NativeObject
				Call GetFaceDocument(oFace, faceDoc)
			Else ' Its a part
				oFace = selectedObject
				faceDoc = activeDoc
			End If
			Dim docAssets As Assets = faceDoc.Assets
			Dim foundAsset As Boolean
			For Each docAsset As Asset In docAssets
				If docAsset.DisplayName = colourNameS Then
					Logger.Info("docAsset.DisplayName: " & docAsset.DisplayName)
					foundAsset = True
					Exit For
				End If
			Next
			If foundAsset = False Then
				Dim newAsset As Asset = docAssets.Add(kAssetTypeAppearance, "Generic", , colourNameS)
				Dim colourAssetVal As ColorAssetValue = newAsset.Item("generic_diffuse")
				Dim colourR As Byte = selectedTreatmentColour(2)
				Dim colourG As Byte = selectedTreatmentColour(3)
				Dim colourB As Byte = selectedTreatmentColour(4)
				Logger.Info("RGB: " & colourR & "," & colourG & "," & colourB)
				colourAssetVal.Value = transObjects.CreateColor(colourR, colourG, colourB)
			End If
			' Create a new transaction to wrap the modification to this file into a single undo.
			Dim trans As Transaction = ThisApplication.TransactionManager.StartTransaction( _
			faceDoc, "Treatment Colour")
			' Set the face colour
			Call oFace.SetRenderStyle(kOverrideRenderStyle, faceDoc.RenderStyles.Item(colourNameS))
			' We will store the treatment information in the face attributes
			Call CreateAttributes(oFace, treatmentSelection, colourNameS, RALColourNameS)
			' End the transaction for the previous two actions
			trans.End
		End If
	End Sub

	Public Sub GetFaceDocument(ByRef selectedFace As Object, ByRef selectedFaceDoc As partDocument)
	' Get the document that this face belongs to
		Logger.Info("face parent: " & TypeName(selectedFace.Parent))
		If TypeName(selectedFace.Parent) = "PartComponentDefinition" Then
			Logger.Info(selectedFace.Parent.Document.FullDocumentName)
			selectedFaceDoc = selectedFace.Parent.Document
		Else
			Logger.Info("calling function again")
			Call GetFaceDocument(selectedFace.Parent, selectedFaceDoc)
		End If
	End Sub ']
	

	Public Sub CreateAttributes(ByRef oFace As Face, ByRef treatmentSelection As Object, ByRef colourNameS As String, ByRef RALColourNameS As String)
	' Stores information about the treatment and colour in the faces attribute set
		Logger.Info("about to creat atts")
		Dim attSets As AttributeSets = oFace.AttributeSets
		Dim attSet As AttributeSet
		Dim attNamesDict As New Dictionary(Of String, Object)
		attNamesDict.Add(TreatmentNameD, treatmentSelection)
		attNamesDict.Add(RALColourNameD, RALColourNameS)
		attNamesDict.Add(BasicColourNameD, colourNameS)
		If attSets.NameIsUsed(colourTreatmentSet) = False Then 'create it for the first time
			attSet = attSets.Add(colourTreatmentSet)
		Else
			attSet = attSets.Item(colourTreatmentSet)
		End If
		' Use For Each loops over pairs not found earlier and add as atts
		For Each pair As KeyValuePair(Of String, Object) In attNamesDict
			Dim attName As String = pair.Key
			Dim attValue As String = pair.Value
			If attSet.NameIsUsed(attName) = False Then 'create it for the first time
				att = attSet.Add(attName, kStringType, attValue)
			Else  ' already exists
				att = attSet.Item(attName)
				att.Value = attValue
			End If
		Next
	End Sub


	Public Sub DistinctOccurrences(ByVal drgView As DrawingView, ByVal requiredFacesDict As Dictionary(Of Object, Object()))
		' Loop through all of the curves in the view to find distinct occurrences that contain faces with treatment attributes (coloured faces)
		Dim selectedViewCurves As DrawingCurvesEnumerator = drgView.DrawingCurves
		' Loop through the curves to get unique part file instances
		For Each selectedViewCurve As DrawingCurve In selectedViewCurves
			If selectedViewCurve.ModelGeometry Is Nothing = True Then Continue For
			Try
				Dim modelGeo As Object = selectedViewCurve.ModelGeometry
				Dim containingOcc As ComponentOccurrence
				Dim containingOccDefType As DocumentTypeEnum
				Dim partDoc As partDocument
				Dim modelGeoFaces As Faces
				 ' Part doc so we can access the face directly
				If viewReferencedDocument.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
					modelGeoFaces = modelGeo.Faces
					For Each nativeFace As Face In modelGeoFaces
						Dim hasAttSet As Boolean = nativeFace.AttributeSets.NameIsUsed(colourTreatmentSet)
						If hasAttSet = False Then Continue For
						If requiredFacesDict.ContainsKey(nativeFace) Then Continue For
						requiredFacesDict.Add(nativeFace, New Object() {selectedViewCurve, Nothing})
					Next
				Else ' Assembly document, faceproxy is used to access native face object
					containingOcc = modelGeo.ContainingOccurrence
					containingOccDefType = containingOcc.DefinitionDocumentType
					If containingOccDefType = DocumentTypeEnum.kPartDocumentObject Then
						Logger.Info("###" & containingOcc.Name)
						partDoc = containingOcc.Definition.Document
						modelGeoFaces = modelGeo.Faces
						For Each modelGeoFace As FaceProxy In modelGeoFaces
							Dim nativeFace As Face = modelGeoFace.NativeObject
							' Only continue if it contains desired attribute set
							Dim hasAttSet As Boolean = nativeFace.AttributeSets.NameIsUsed(colourTreatmentSet)
							If hasAttSet = False Then Continue For
							If requiredFacesDict.ContainsKey(nativeFace) Then Continue For
							' containing occurrence may be better than doc as we want to check this occ against the model occ
							requiredFacesDict.Add(nativeFace, New Object() {selectedViewCurve, containingOcc })
						Next
					End If
				End If
			Catch
				Continue For
			End Try
		Next
	End Sub

	Public Sub ViewOffsetRectangle(ByVal selectedView As DrawingView, ByVal requiredFacesDictCount As Integer)
		' Create a rectangle offset from the view perimeter that will be used to place the sketch symbols on
		' that will intersect with the rectangle 
		' and then we can use those intersection points to place the symbols on
		Dim viewHeight As Double = selectedView.Height
		Dim viewWidth As Double = selectedView.Width
		Dim viewLeft As Double = selectedView.Left
		Dim viewTop As Double = selectedView.Top
		Dim viewOffset As Double = 2
		' Want to make sure that we get the actual view center, as the view.center and view.position tend to differ...
		calculatedViewCenter = transGeometry.CreatePoint2d(viewLeft + viewWidth / 2, viewTop - viewHeight / 2)
		' Create the rangebox points of the rectangle
		Dim viewExtentsOffsetBoxMinPoint As Point2d = transGeometry.CreatePoint2d(viewLeft - viewOffset, viewTop - viewHeight - viewOffset)
		Logger.Info("viewExtentsOffsetBoxMinPoint XY: " & viewExtentsOffsetBoxMinPoint.X & ", " & viewExtentsOffsetBoxMinPoint.Y)
		Dim viewExtentsOffsetBoxMaxPoint As Point2d = transGeometry.CreatePoint2d(viewLeft + viewWidth + viewOffset, viewTop + viewOffset)
		Logger.Info("viewExtentsOffsetBoxMaxPoint XY: " & viewExtentsOffsetBoxMaxPoint.X & ", " & viewExtentsOffsetBoxMaxPoint.Y)
		' These are the lines that will define the rectange
		Dim viewOffsetRectLine1, viewOffsetRectLine2, viewOffsetRectLine3, viewOffsetRectLine4 As LineSegment2d
		viewOffsetRectLine1 = transGeometry.CreateLineSegment2d(viewExtentsOffsetBoxMinPoint, _
		transGeometry.CreatePoint2d(viewExtentsOffsetBoxMinPoint.X, viewExtentsOffsetBoxMaxPoint.Y))
		viewOffsetRectLine2 = transGeometry.CreateLineSegment2d(viewOffsetRectLine1.EndPoint, viewExtentsOffsetBoxMaxPoint)
		viewOffsetRectLine3 = transGeometry.CreateLineSegment2d(viewExtentsOffsetBoxMaxPoint, _
		transGeometry.CreatePoint2d(viewExtentsOffsetBoxMinPoint.Y, viewExtentsOffsetBoxMaxPoint.X))
		viewOffsetRectLine4 = transGeometry.CreateLineSegment2d(viewOffsetRectLine3.EndPoint, viewOffsetRectLine1.StartPoint)
		' Add the lines to this array for later use
		viewOffsetRectLines(0) = viewOffsetRectLine1 : viewOffsetRectLines(1) = viewOffsetRectLine2 : viewOffsetRectLines(2) = viewOffsetRectLine3 : viewOffsetRectLines(3) = viewOffsetRectLine4
		'<<<<NEW 20221216  These are the points that define the view
		Dim viewMaxPoint = New Double() {viewLeft + viewWidth, viewTop}
		Dim viewMinPoint = New Double() {viewLeft, viewTop - viewHeight}
		' Create the box
		viewRangeBox = transGeometry.CreateBox2d()
		' Set the data the defines the box
		viewRangeBox.PutBoxData(viewMinPoint, viewMaxPoint) '>>>>
	End Sub

	' Not a great implementation, often the symbol isn't placed on the rectangle.
	' Take a look at this post if you want something more reliable: https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/auto-ballooning-a-drawing-attach-balloon-to-drawingcurvesegment/m-p/10096249
	Public Function LeaderViewRectIntersection(ByRef geoIntentPoint As Point2d) As Point2d
	' Create mathematical points at the intersection of the curve geometry and the view offset rectangle
		Dim viewCentertoGeoIntentLine As LineSegment2d = transGeometry.CreateLineSegment2d(calculatedViewCenter, geoIntentPoint)
		Dim intPoints As ObjectCollection = Nothing
		intPoints = transObjects.CreateObjectCollection
		Dim intPointsCount As Double = 0
		' Define this first one as 0,0 just in case it we dont find any intersections
		Dim intPoint As Point2d = transGeometry.CreatePoint2d(0, 0)
		' Loop through the rectanglular lines and see if they intersect with any of the drawing curves
		For i = 0 To viewOffsetRectLines.Count - 1
			Dim viewOffsetRectLine As LineSegment2d = viewOffsetRectLines(i)
			Logger.Info(TypeName(viewOffsetRectLine))
			Dim intersectingpoints As ObjectsEnumerator
			' Setting the Tolerance to 0 or 1 didnt provide very good results, so I bumped it to 10
			'	intersectingpoints = viewOffsetRectLine.IntersectWithCurve(viewCentertoGeoIntentLine, 1)
			intersectingpoints = viewCentertoGeoIntentLine.IntersectWithCurve(viewOffsetRectLine, 10)
			If intersectingpoints Is Nothing Then
				Logger.Info("nothing")
				Continue For
			Else
				' Set as the first intersection point
				intPoint = intersectingpoints.Item(1)
				For Each intersectingpointsPoint In intersectingpoints
					' But also add the rest so we can get the closest one
					intPoints.Add(intersectingpointsPoint)
					Logger.Info("intersectingpointsPointXY: " & intersectingpointsPoint.X & ", " & intersectingpointsPoint.Y)
				Next
			End If
			i += 1
		Next
		' ####<If you want to see this visually uncomment the lines below
'		    Dim oSketch As DrawingSketch = drawDocument.ActiveSheet.Sketches.Add
'		    ' Put the sketch in edit mode
'		    oSketch.Edit
'			Call oSketch.SketchLines.AddByTwoPoints(viewCentertoGeoIntentLine.StartPoint, viewCentertoGeoIntentLine.EndPoint)
'			Call oSketch.SketchLines.AddAsTwoPointRectangle(transGeometry.CreatePoint2d(viewOffsetRectLines(0).StartPoint.X, viewOffsetRectLines(0).StartPoint.Y), transGeometry.CreatePoint2d(viewOffsetRectLines(1).EndPoint.X, viewOffsetRectLines(1).EndPoint.Y))
'			oSketch.ExitEdit
		'####>
		' Loop over all of the points to see which one is the closest
		' Should probably have checked to see if point is inside rectangle with something like this : https://stackoverflow.com/questions/2752725/finding-whether-a-point-lies-inside-a-rectangle-or-not
		For Each finalPoint As Point2d In intPoints
			Logger.Info("A: " & finalPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint) & ", B: " & intPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint))
			If finalPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint) < intPoint.DistanceTo(viewCentertoGeoIntentLine.EndPoint) Then
				'<<<<NEW 20221216 Make sure the point doesn't reside in the view >>>>
				If viewRangeBox.Contains(intPoint) Then Continue For
				intPoint = finalPoint
			End If
		Next
		Return intPoint
	End Function

	Public Function GetSketchSymbol()
	' Return the required symbol, if it exists
		Dim sketchSymbolDefs As SketchedSymbolDefinitions = drawDocument.SketchedSymbolDefinitions
		For Each sketchSymbolDef As SketchedSymbolDefinition In sketchSymbolDefs
			If sketchSymbolDef.Name = treatmentSymbolName Then
				treatmentSymbolDef = sketchSymbolDef
				Return treatmentSymbolDef
			End If
		Next
	End Function

	Public Sub GetViewOccurrenceDocument(ByVal drgView As DrawingView, _
		ByRef requiredFacesDictionary As Dictionary(Of Object, Object()))
	' Get View Occurrence/Document 
		Dim viewDocCompDef As ComponentDefinition = viewReferencedDocument.ComponentDefinition
		Dim taggedEdges As New ArrayList
		Dim taggedFaces As New ArrayList
		' Get the required symbol, if it exists
		treatmentSymbolDef = GetSketchSymbol()
		If treatmentSymbolDef Is Nothing Then
			MessageBox.Show("Cannot Find Sketch Symbol (" & treatmentSymbolName & ")" & vbLf & _
			"Add it to the Drawing Before Running this Rule Again", "NO SYMBOL", MessageBoxButtons.OK, MessageBoxIcon.Error)
			Exit Sub
		End If
		Dim assignedTreatmentCount As Double = 1
		For Each requiredFace In requiredFacesDictionary
			' Get the string array of this dictionary item
			Dim requiredFaceObjs() As Object = requiredFacesDictionary.Item(requiredFace.Key)
			' Probably the first edge associated with the face
			Dim viewCurve As DrawingCurve = requiredFaceObjs(0)
			Dim modelDoc As Document
			' Part doc so we can access the face directly
			If viewReferencedDocument.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
				modelDoc = viewReferencedDocument
				Call AddSymbolToView(modelDoc, drgView, taggedEdges, taggedFaces, assignedTreatmentCount, Nothing)
			Else ' Assembly Document so we need to access the occurrences
				' Occurrence that owns the face
				Dim containingOccurrence As ComponentOccurrence = requiredFaceObjs(1)
				' Loop through all of the occurrences of the occurrence document in this assembly
				For Each possibleNewEntityOcc As ComponentOccurrence In _
					viewDocCompDef.Occurrences.AllReferencedOccurrences(containingOccurrence.Definition.Document)
					If possibleNewEntityOcc Is containingOccurrence Then
						modelDoc = containingOccurrence.Definition.Document
						Logger.Info(modelDoc.DisplayName)
						Call AddSymbolToView(modelDoc, drgView, taggedEdges, taggedFaces, assignedTreatmentCount, possibleNewEntityOcc)
					End If
				Next
			End If
		Next
	End Sub
	

	Public Sub AddSymbolToView(ByRef modelDoc As Document, ByVal drgView As DrawingView, _
		ByRef taggedEdges As ArrayList, ByRef taggedFaces As ArrayList, _
		ByRef assignedTreatmentCount As Double, ByRef possibleNewEntityOcc As ComponentOccurrence)
		' Add symbols to drawing view
		Dim curveColl As ObjectCollection = Nothing
		Dim drawingCurvesEnum As DrawingCurvesEnumerator = Nothing
		Dim drawingCurve1 As DrawingCurve = Nothing
		Dim edgeProxy1 As EdgeProxy = Nothing
		Dim geoIntent As GeometryIntent = Nothing
		Dim XPos, YPos As Double
		Dim tempObject As Object = Nothing
		Dim facesCollection As ObjectCollection = Nothing
		' Only get the faces that have the correct attribute set
		facesCollection = modelDoc.AttributeManager.FindObjects(colourTreatmentSet, , )
		Logger.Info("facesCollection.Count: " & facesCollection.Count)
		' Only loop over the faces that have the correct attribute set
		For Each attFace As Face In facesCollection
			' Use this to make sure we dont try to get this face again
			Dim attFaceKey As Integer = attFace.TransientKey
			Dim faceColourTreatmentAtts As AttributeSet = attFace.AttributeSets(colourTreatmentSet)
			' Get the required Values from the attributes
			Dim attTreatment As String = faceColourTreatmentAtts.Item(TreatmentNameD).Value
			Dim attRALColour As String = faceColourTreatmentAtts.Item(RALColourNameD).Value
			' Pass over any previously tagged faces
			If taggedFaces.Contains(attFaceKey) Then Continue For
			Logger.Info("attFaceKey: " & attFaceKey)
			For Each attFaceEdge As Edge In attFace.Edges
				Dim attFaceEdgeKey As Integer = attFaceEdge.TransientKey
				' Pass over any that we already have
				If taggedEdges.Contains(attFaceEdgeKey) Then Continue For
				Logger.Info("attFaceEdgeKey: " & attFaceEdgeKey)
				Dim geoIntentPoint As Point2d = Nothing
				' This will fail for any edges that aren't visible
				Try
					' Assembly so we need to get edge via proxy
					If viewReferencedDocument.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
						possibleNewEntityOcc.CreateGeometryProxy(attFaceEdge, tempObject)
						edgeProxy1 = CType(tempObject, EdgeProxy)
						drawingCurvesEnum = drgView.DrawingCurves(edgeProxy1)
					Else ' Part doc so we can access the face directly
						drawingCurvesEnum = drgView.DrawingCurves(attFaceEdge)
					End If
					' If the count is zero then this edge isnt visible in this view so skip it
					If drawingCurvesEnum.Count = 0 Then Continue For
					drawingCurve1 = drawingCurvesEnum(1)
					geoIntent = currentSheet.CreateGeometryIntent(drawingCurve1, 0.5)
					' This point will be used to place the sketch symbol
					geoIntentPoint = geoIntent.PointOnSheet
					Logger.Info("geoIntentPointXY: " & geoIntentPoint.X & ", " & geoIntentPoint.Y)
				Catch E As Exception
					Logger.Info(E.ToString())
					Continue For
				End Try
				Try
					' Find the closest point to geoIntent
					Dim closestPoint As Point2d = Nothing
					closestPoint = LeaderViewRectIntersection(geoIntentPoint)
					Logger.Info("closestPointXY: " & closestPoint.X & ", " & closestPoint.Y)
					' Create a collection for placement points of the symbol and its leader
					curveColl = transObjects.CreateObjectCollection
					' Leader point
					curveColl.Add(closestPoint)
					' Symbol Point
					curveColl.Add(geoIntentPoint)
					' This will be used to give each treatment a unique #
					Dim tagNumber As Double = assignedTreatmentCount
					' Check if the treatment already has an # associated with it
					If assignedColourTreatments.Any(Function(ct) ct.Treatment = attTreatment) Then
						' Get access to the object
						Dim thisAttTreatment = assignedColourTreatments.FirstOrDefault(Function(cT) cT.Treatment = attTreatment)
						' Assign the tag #
						If Not thisAttTreatment Is Nothing Then tagNumber = thisAttTreatment.TagNumber
					Else ' No associated number
						assignedColourTreatments.Add(New ColourTreatment With {.Treatment = attTreatment, _
						.RALColourName = attRALColour, .TagNumber = assignedTreatmentCount })
						assignedTreatmentCount += 1
					End If
					' As this symbol will only have a tag # we will leave the second string empty
					Dim promptStrings = New String() {tagNumber, "" }
					' Add the symbol to the drawing
					currentSheet.SketchedSymbols.AddWithLeader(treatmentSymbolDef, curveColl, 0, 1, promptStrings, True, True)
					' Add this face edge to the arraylist so that we dont tag it twice
					taggedEdges.Add(attFaceEdgeKey)
					' Add this face to the arraylist so that we dont tag it twice
					taggedFaces.Add(attFaceKey)
					' Remove any values associated with these so we start fresh for next edge
					curveColl = Nothing
					drawingCurvesEnum = Nothing
					drawingCurve1 = Nothing
					edgeProxy1 = Nothing
					geoIntent = Nothing
					XPos = Nothing 
					YPos = Nothing 
					tempObject = Nothing
					' Exit after we place a symbol
					GoTo nextFace
				Catch E As Exception
					Logger.Info(E.ToString())
				End Try
			Next
		Next
		nextFace :
		Logger.Info("NEXT FACE")
	End Sub
	
	Public Sub AddLegendSymbolsToDrawing()
		' This section takes care of adding the treatments legend to the upper left hand corner of the drawing
		' Order the tags by their tag number
		Dim byTag As List(Of ColourTreatment) = assignedColourTreatments.OrderBy(Function(cT1) cT1.TagNumber).ToList
		Dim sheetBorder As Border = currentSheet.Border
		Dim sheetTopLeftX As Double = sheetBorder.RangeBox.MinPoint.X + 1
		Dim sheetTopLeftY As Double = sheetBorder.RangeBox.MaxPoint.Y - 1
		Dim sheetTopLeft As Point2d = transGeometry.CreatePoint2d(sheetTopLeftX, sheetTopLeftY)
		For Each tag As ColourTreatment In byTag
			' The second string is the Treatment and RAL name combined
			Dim promptStringsTwo = New String() {tag.TagNumber, tag.Treatment & " - " & tag.RALColourName }
			Logger.Info(tag.TagNumber & ", " &  tag.Treatment & " - " & tag.RALColourName)
			sheetTopLeft.Y = sheetTopLeft.Y - 1.5
			' Add the symbol to the drwaing to create the legend
			Dim legendSymbol As SketchedSymbol = currentSheet.SketchedSymbols.Add(treatmentSymbolDef, sheetTopLeft, 0, 1, promptStringsTwo)
			legendSymbol.Static = True
		Next
	End Sub

End Class ']j

The leader placement now looks like below. Please note that sometimes you will get multiple leaders that appear to be going to one face, like on the far left. The top left leader (1) is actually trying to reference the face that isn't shown in the view. This is because there is no easy way (that I know of) to tell if the face connected to the edge is shown in the view. So the end user will have to clean-up a little.

jamescollinsPWQR2_1-1671239442911.png

 

If this is an acceptable solution please mark it so, that way others can easily find it.

 

Cheers,

 

James

0 Likes