Hide all drawing hidden lines that aren't from an iFeature

Hide all drawing hidden lines that aren't from an iFeature

chaines59GWR
Contributor Contributor
970 Views
13 Replies
Message 1 of 14

Hide all drawing hidden lines that aren't from an iFeature

chaines59GWR
Contributor
Contributor

I have created a way of hiding all hidden lines except for ones that are a result of an iFeature, however this take actually several million years to complete.

 

I was wondering if anyone might know a faster way of achieving this? 

 

 

Sub Main

	Dim oDoc As DrawingDocument = ThisDoc.Document
	Dim oView As DrawingView = ThisApplication.CommandManager.Pick(kDrawingViewFilter, "Select View")

	For Each oCurve As DrawingCurve In oView.DrawingCurves

		Logger.Info(oCurve.ModelGeometry.Type.ToString)

		Dim BeVisible As Boolean = False

		If oCurve.ModelGeometry.Type = ObjectTypeEnum.kFaceProxyObject
			
			Try

			If oCurve.ModelGeometry.NativeObject.CreatedByFeature.Type = ObjectTypeEnum.kiFeatureObject

				BeVisible = True

			End If
			
			Catch
				
			End Try

		ElseIf oCurve.ModelGeometry.Type = ObjectTypeEnum.kEdgeProxyObject

			For Each oFace In oCurve.ModelGeometry.NativeObject.Faces

				If oFace.CreatedByFeature.Type = ObjectTypeEnum.kiFeatureObject

					BeVisible = True

					Exit For

				End If

			Next

		End If

		For Each oSegment As DrawingCurveSegment In oCurve.Segments

			If BeVisible = True

				oSegment.Visible = True
				oCurve.LineWeight = 0.036

			Else

				Try
					If oSegment.HiddenLine = True

						oSegment.Visible = False

					End If

				Catch

				End Try

				oCurve.LineType = LineTypeEnum.kDefaultLineType

			End If

		Next

	Next

End Sub

 

 

 

0 Likes
Accepted solutions (1)
971 Views
13 Replies
Replies (13)
Message 2 of 14

WCrihfield
Mentor
Mentor

Hi @chaines59GWR.  I think you would reduce processing time my finding the iFeature in 'the model' first, then supplying that as the 'ModelObject' it is asking for in the DrawingView.DrawingCurves property, to get a DrawingCurvesEnumerator with far fewer DrawingCurve objects in it.  Then you will not need to test each curve to check what it represents, and can move right on to iterating the curve's segments to turn their visibility off.  But another step which may make the overall process even faster would be to collect them into an ObjectCollection, then use the Sheet.ChangeLayer method to switch them to a Layer that you have turned off.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 3 of 14

chaines59GWR
Contributor
Contributor

I have seen that right clicking on a component and toggling its "hidden lines" option does a mass update of all hidden lines. Is there a way to easily trigger this or made hundreds of line segments invisible quickly?

 

I like the layer idea and I very may well go with it, but we don't have a layer at the moment that's not on

 

Probably going to start an object collection, and toggle them all off once I've collected all of the segments

0 Likes
Message 4 of 14

WCrihfield
Mentor
Mentor

That right-click dialog has been asked about a ton of times, but unfortunately, there is no super simple alternative to it on the Inventor API side that compares to that.  The process I mentioned about getting the model object and supplying that to get the filtered collection is the closest.  But then, you either have to iterate every individual curve segment, changing property values, or you have to do the Layer thing, but you can create a custom Layer on the fly, and set it how you want it, then specify that Layer as the one to switch them to.  Unfortunately, there is no super easy way to undo that action later (after the rule has finished) that will put all that stuff back on their original layers, and settings.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 14

chaines59GWR
Contributor
Contributor

I have tried to get the drawing curves of just the iFeature, but it wont accept it as an object.

 

Sub Main

	Dim oView As DrawingView = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, "Select Drawing View")
	Dim oAsm As AssemblyDocument = oView.ReferencedDocumentDescriptor.ReferencedDocument
	
	Dim oiFeatSegments As New List(Of DrawingCurveSegment)
	
	For Each oComp As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences.AllLeafOccurrences
		
		If oComp.Definition.Features.iFeatures.Count > 0 
			
			For Each iFeat As iFeature In oComp.Definition.Features.iFeatures
				
				oCurves = oView.DrawingCurves(iFeat)
			
			Next
		End If	
	Next
End Sub

Is that expected?

0 Likes
Message 6 of 14

WCrihfield
Mentor
Mentor

Hi @chaines59GWR.  I initially thought you were talking about a drawing of a part, directly.  If it is a drawing of an assembly directly, then that changes things.  The error you are seeing with that code example is likely because of 'context' (3D model coordinate space) differences.  You can only specify a model object that is 'directly' referenced within the Document that is being directly referenced by the drawing view.  When we look at the DrawingView.DrawingCurves online help page's description about the 'model object', we see 'Feature' (and an iFeature is definitely a type of Feature), and we also see that it mentions 'proxies'.  Proxies are sort of like geometric copies of model entities that are being 'referenced' from within other Documents which gets transformed (position & orientation changed) into the model space of an assembly.  That proxy geometry in the assembly is not the 'original' geometry, which would only exist within the other Document's ComponentDefinition (context).

 

So, since the drawing view references an assembly, and the 'real' iFeatures are down within the definitions of other referenced documents represented by component occurrences in the assembly, we will need to dig down to those 'real' iFeatures, then use those to get a reference to their 'proxy' geometry (iFeatureProxy) that only exists within the parent level assembly's context.  And even that is assuming that all component occurrences represent parts, and none are sub assemblies.  If any are sub assemblies, and any component occurrences within those sub assemblies (or even lower in the overall assembly structure), then it gets even more complex, and we may need to use a 'recursive' routine to find them, and get their 'top level' proxy geometry.  The point is, we cant supply something to that DrawingView that only exists down within some other referenced document...it has to be something that is directly in the context of the Document that is being directly referenced by that view, so we must find the 'proxy' versions of those iFeatures to supply to that DrawingCurves property, not the 'original' iFeatures themselves.

 

We get access to 'proxies' through the ComponentOccurrence object's method named CreateGeometryProxy.  That method asks for 2 things.  The first is a variable representing the geometry object that only exists within the context of that exact same ComponentOccurrence's Definition.  The second thing it wants is a variable that you want to represent the 'proxy' of that first object, which only exists in this ComponentOccurrence's parent assembly's context.  We usually declare that second variable before using that method, but do not give it a value yet, then that method sets its value.  Then we can use that second variable to refer to that higher level proxy object from that point on in our code.  But sometimes even a proxy is still in the 'mid' level of an assembly, such as within a sub-assembly, instead of being in the context of the top level assembly yet.  So we sometimes need to repeat that step, using the ComponentOccurrence representing the sub assembly next, in order to get the proxy that only exists in the context of the top level of the main assembly.  Then we can finally use that top level proxy for our measurements, constraints, or in this case in the DrawingCurves property.  The idea of proxies, what they are, and how they work, can be complicated to wrap your mind around at first.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 7 of 14

chaines59GWR
Contributor
Contributor

Got your method to work, and it certainly speeds up the collection of line segments, hiding the line segments still takes a looooong time.

 

Sub Main

	Dim StartTime As DateTime = Now

	Dim oView As DrawingView = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, "Select Drawing View")
	Dim oAsm As AssemblyDocument = oView.ReferencedDocumentDescriptor.ReferencedDocument

	Dim oSegments As New List(Of DrawingCurveSegment)

	For Each oCurve As DrawingCurve In oView.DrawingCurves

		For Each oSegment As DrawingCurveSegment In oCurve.Segments

			If oSegment.HiddenLine = True Then oSegments.Add(oSegment)

		Next

	Next

	Logger.Info("ALL SEGMENTS COUNTED [" & Round(Now.Subtract(StartTime).TotalSeconds, 1) & "s]") : StartTime = Now

	For Each oComp As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences.AllLeafOccurrences

		If oComp.Definition.Features.iFeatures.Count <> 0

			For Each iFeat As iFeature In oComp.Definition.Features.iFeatures

				oComp.CreateGeometryProxy(iFeat, iFeatProxy)

				For Each oiFeatCurve As DrawingCurve In oView.DrawingCurves(iFeatProxy)

					For Each oiFeatSegment As DrawingCurveSegment In oiFeatCurve.Segments

						If oiFeatSegment.HiddenLine = True And oSegments.Contains(oiFeatSegment) Then oSegments.Remove(oiFeatSegment)

					Next

				Next

			Next

		End If

	Next

	Logger.Info("ALL SEGMENTS REMOVED [" & Round(Now.Subtract(StartTime).TotalSeconds, 1) & "s]") : StartTime = Now
	
	For Each oSegment As DrawingCurveSegment In oSegments
		
		oSegment.Visible = False
		
	Next
	
	Logger.Info("ALL SEGMENTS HIDDEN [" & Round(Now.Subtract(StartTime).TotalSeconds, 1) & "s]")

End Sub

 

The times are as so:

ALL SEGMENTS COUNTED [4.7s]
ALL SEGMENTS REMOVED [1.9s]
ALL SEGMENTS HIDDEN [314.9s]

 

That 314 sticks out like a sore thumb, is it possible to "defer updates" so that the drawing view does not update till all lines are hidden so its not trying to render thousands of changes?

 

 

0 Likes
Message 8 of 14

WCrihfield
Mentor
Mentor

My advice at this point would be to eliminate the whole first section of code where it is getting 'all' drawing curves in the whole view, and putting them all into a List.  That step is not necessary.  You are already iterating through the 'filtered' collection of DrawingCurves in the second section of your code.  Plus that 'List.Contains()' method call within that second iteration is likely taking a long time to process, and is completely unnecessary.  Instead of taking curves out of the List at that point, that should be where you are initially putting them into the List.  Not only that, but since you are only using that list to later iterate through each individual segment within it, turning their visibility off, you could just be doing that visibility change within the primary iteration directly, without needing to ever put them into a list.  That would prevent the whole secondary iteration loop, and all the processing associated with that.

Try this edited version of your code, and see if it works a little faster.

 

Sub Main
	Dim StartTime As DateTime = Now
	Dim oView As DrawingView = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, "Select Drawing View")
	If oView Is Nothing Then Return
	Dim oAsm As AssemblyDocument = oView.ReferencedDocumentDescriptor.ReferencedDocument
	For Each oComp As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences.AllLeafOccurrences
		If oComp.Suppressed Then Continue For
		If TypeOf oComp.Definition Is VirtualComponentDefinition Then Continue For
		For Each iFeat As Inventor.iFeature In oComp.Definition.Features.iFeatures
			Dim iFeatProxy As Inventor.iFeatureProxy = Nothing
			oComp.CreateGeometryProxy(iFeat, iFeatProxy)
			Dim oDCurves As DrawingCurvesEnumerator = Nothing
			'if proxy was obtained from lower level component in sub assembly, then
			'proxy obtained may not yet be in context of main assembly yet
			'a top level proxy can only be obtained directly from top level components
			'or from the proxies of lower level components that exist at highest level
			'proxies at deeper levels will need to be stepped up to highest level
			Try : oDCurves = oView.DrawingCurves(iFeatProxy) : Catch : End Try
			If oDCurves Is Nothing OrElse oDCurves.Count = 0 Then Continue For
			For Each oiFeatCurve As DrawingCurve In oDCurves
				For Each oiFeatSegment As DrawingCurveSegment In oiFeatCurve.Segments
					If oiFeatSegment.HiddenLine = True Then oiFeatSegment.Visible = False
				Next oiFeatSegment
			Next oiFeatCurve
		Next iFeat
	Next oComp
	Logger.Info("ALL SEGMENTS HIDDEN [" & Round(Now.Subtract(StartTime).TotalSeconds, 1) & "s]")
End Sub

 

...Or, you can do it with the Layer idea, like this...

 

Sub Main
	Dim StartTime As DateTime = Now
	Dim oView As DrawingView = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, "Select Drawing View")
	If oView Is Nothing Then Return
	Dim oAsm As AssemblyDocument = oView.ReferencedDocumentDescriptor.ReferencedDocument
	Dim oObjColl As ObjectCollection = ThisApplication.TransientObjects.CreateObjectCollection
	For Each oComp As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences.AllLeafOccurrences
		If oComp.Suppressed Then Continue For
		If TypeOf oComp.Definition Is VirtualComponentDefinition Then Continue For
		For Each iFeat As Inventor.iFeature In oComp.Definition.Features.iFeatures
			Dim iFeatProxy As Inventor.iFeatureProxy = Nothing
			oComp.CreateGeometryProxy(iFeat, iFeatProxy)
			Dim oDCurves As DrawingCurvesEnumerator = Nothing
			'if proxy was obtained from lower level component in sub assembly, then
			'proxy obtained may not yet be in context of main assembly yet
			'a top level proxy can only be obtained directly from top level components
			'or from the proxies of lower level components that exist at highest level
			'proxies at deeper levels will need to be stepped up to highest level
			Try : oDCurves = oView.DrawingCurves(iFeatProxy) : Catch : End Try
			If oDCurves Is Nothing OrElse oDCurves.Count = 0 Then Continue For
			For Each oiFeatCurve As DrawingCurve In oDCurves
				For Each oiFeatSegment As DrawingCurveSegment In oiFeatCurve.Segments
					If oiFeatSegment.HiddenLine = True Then oObjColl.Add(oiFeatSegment)
				Next oiFeatSegment
			Next oiFeatCurve
		Next iFeat
	Next oComp
	Dim oSheet As Inventor.Sheet = oView.Parent
	Dim oDDoc As DrawingDocument = oSheet.Parent
	Dim oMyLayer As Inventor.Layer = oDDoc.StylesManager.Layers.Item(1).Copy("Hidden iFeature Curves")
	oMyLayer.Visible = False
	oView.Parent.ChangeLayer(oObjColl, oMyLayer)
	Logger.Info("ALL SEGMENTS HIDDEN [" & Round(Now.Subtract(StartTime).TotalSeconds, 1) & "s]")
End Sub

 

If this solved your problem, or answered your question, please click ACCEPT SOLUTION .
Or, if this helped you, please click (LIKE or KUDOS) 👍.

 

After looking back at the title of this discussion, I may have misunderstood the task you were trying to do in these two code examples.  You are not trying to control the visibility of iFeature hidden lines, but trying to turn off 'all other' hidden lines that do not belong to any iFeatures.  My mistake.  But you probably understand the process better now than you did before, so maybe this will still help somehow.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 14

chaines59GWR
Contributor
Contributor

I wasn't clear sorry, my adding and removing of items in the list takes 5 seconds.

 

Hiding each individual line takes 5 minutes. 

0 Likes
Message 10 of 14

WCrihfield
Mentor
Mentor

And yes, there is a way to turn 'defer updates' on/off by by code.  It is different, depending on the document type, but for drawings, it is in the 'Document Settings' (manually), and that setting can be accessed through the DrawingDocument.DrawingSettings property, which returns a DrawingSettings object, then use its DeferUpdates property, which is Read/Write, with a Boolean value.  Not sure if that will work for this situation, but definitely worth trying out.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 11 of 14

chaines59GWR
Contributor
Contributor

Defer updates didn't work, and I modified my code to use the change layer process and hiding still takes a long time but about a 1/5th of the time as hiding each line one at a time. Still crazy.

 

Also I'm hiding everything that is a hidden line that ISNT  an iFeature. The only thing hidden I want to be shown are iFeatures. 

0 Likes
Message 12 of 14

marcin_otręba
Advisor
Advisor
Accepted solution

hi,

 

try this method instead:

first create object collection for gathering all segments you want to manipulate, then using select multiple select it and just execute DrawingEntityVisibilityCtxCmd:

 

i simplified your code to my testing purposes 

Sub Main

	Dim StartTime As DateTime = Now

	Dim oView As DrawingView = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kDrawingViewFilter, "Select Drawing View")
	Dim oAsm As AssemblyDocument = oView.ReferencedDocumentDescriptor.ReferencedDocument
Dim objcol As ObjectCollection = ThisApplication.TransientObjects.CreateObjectCollection

	Dim oSegments As New List(Of DrawingCurveSegment)

	For Each oCurve As DrawingCurve In oView.DrawingCurves

		For Each oSegment As DrawingCurveSegment In oCurve.Segments

			If oSegment.HiddenLine = True Then oSegments.Add(oSegment)
objcol.Add(oSegment)
		Next

	Next

ThisApplication.ActiveDocument.SelectSet.SelectMultiple(objcol)
	thisapplication.CommandManager.ControlDefinitions("DrawingEntityVisibilityCtxCmd").Execute
	Logger.Info("ALL SEGMENTS HIDDEN [" & Round(Now.Subtract(StartTime).TotalSeconds, 1) & "s]")

End Sub

 

Hi, maybe you want to check my apps:


DrawingTools   View&ColoringTools   MRUFolders

Message 13 of 14

WCrihfield
Mentor
Mentor

Good idea with the selection and command execution idea @marcin_otręba.  It does seem like the process that the user interface tools use behind the scenes to do these types of tasks are somehow able to get the job done faster than our traditional Inventor API code methods are able to do it.  Maybe they somehow incorporate multi-threading capabilities or something like that in their supporting code, not sure.  The process of capturing the group of drawing curves multiple times (once to get them all, potentially multiple other times when specifying specific model objects to filter out), then iterating through two levels of every entity in those collections, takes a long time, no matter what we are doing with them.

 

On a side note...I don't know why I didn't really pay attention to this earlier but, if testing how much time these tasks are taking is important, and you want to get accurate results, then you should not capture the start time before the 'Pick' function is used, but after that point.  Because that Pick function starts a user interface selection session, which can last an unknown/dynamic amount of time, depending on how long the user takes to manually select that type of object.  There are also likely cleaner ways of doing something like that, such as using the built-in System.Diagnostics.StopWatch object.  You can create a new instance of that Class using the 'New' keyword, then you can use its super convenient properties and methods for keeping track of how long code based tasks take, and can get the results in multiple formats (units of time, or 'ticks').

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 14 of 14

chaines59GWR
Contributor
Contributor

This was the solution, one large update! Goes from minutes to seconds. Whole thing only takes 6 seconds now.