Creating a bounding box of planes by selecting 2 sides?

Creating a bounding box of planes by selecting 2 sides?

shiftctrl.io
Enthusiast Enthusiast
2,226 Views
25 Replies
Message 1 of 26

Creating a bounding box of planes by selecting 2 sides?

shiftctrl.io
Enthusiast
Enthusiast

Hi all,

 

I'm exploring different approaches to a problem which I'm hoping to solve using a bounding box of planes. I'm not sure if this is even possible, but if it is, any guidance in the right direction would go a long way. 

 

Lets assume we have a rectangular box with an open front, Ideally what I would like to achieve is - an engineer clicks a add-in followed by clicking the inner right and left panels, then the add-in adds the 4 planes needed. I've attached two screenshots to depict what I'm trying to achieve. 

 

This is in part for something that I am working on, and in part for my learning. 

 

Has anyone made something like this before, anything similar that I may examine the code? Or ideas on how to approach this problem? A large part of this exercise if my personal knowledge as I'm trying to get to the point where I can create add-ins in my sleep. 

 

Thank you.

 

Inventor_YqefxZM6a2.png

 

Inventor_JqtQSWNMcd.png

 

 

0 Likes
Accepted solutions (1)
2,227 Views
25 Replies
Replies (25)
Message 2 of 26

WCrihfield
Mentor
Mentor

It's hard to tell from the second image, so...

Is the bottom plane on the top face of the bottom board, the bottom face of the bottom board, or at the bottom face of the selected side board?

Is the left plane right on the selected face, or on the opposite side of the selected board?

Are all four of the new planes supposed to be the interior faces of the cabinet boards?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 3 of 26

shiftctrl.io
Enthusiast
Enthusiast

Yes, sorry if it wasn't clear. All the planes are on the inside faces of the cabinet.

0 Likes
Message 4 of 26

_dscholtes_
Advocate
Advocate

I was writing a whole lot of text, but ended up with a much shorter and more generic approach that might work.

- Do not select any walls, select the back instead.

- Get the corner points of each solid making up the box, but disregard the corner points of the selected back.
- Determine which corners make up the inside area of the cabinet.
- Use sets of three corners / points to create planes.

 

Determining which corner points make up the inside area of the cabinet and which set of three points to use for a plane can be done by comparing coordinates of each corner. It would be helpful if the walls were aligned according the origin planes.

Message 5 of 26

shiftctrl.io
Enthusiast
Enthusiast

That's a very interesting approach.

 

In my use case, we sometimes have a long (unknown) length of cabinets, but I would need these planes in only the one which requires "further processing". Any ideas on how I could go about determining the inside of the specific cabinet without some sort of user selection to guide me?  

0 Likes
Message 6 of 26

WCrihfield
Mentor
Mentor

What about getting the overall model's bounding box size (fairly easy), then just using math to subtract top,bottom,sides, & back material thicknesses from the bounding box size?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 26

JhoelForshav
Mentor
Mentor

Hi @shiftctrl.io 

If the model is an assembly containing only the 5 panels as component occurrences I thought of an approach that doesn't require you to select any face to begin with.

I made a simple iLogic rule to test it and it works as expected 🙂

 

Sub Main
Dim oAsm As AssemblyDocument = ThisDoc.Document
Dim oCoM As Point = oAsm.ComponentDefinition.MassProperties.CenterOfMass
Dim oFaces As ObjectCollection = ThisApplication.TransientObjects.CreateObjectCollection
For Each oOcc As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences
	Dim oFaceProx As FaceProxy
	Dim oDist As Double = 0
	Dim closestFace As FaceProxy
	For Each oFace In oOcc.Definition.SurfaceBodies(1).Faces
		Call oOcc.CreateGeometryProxy(oFace, oFaceProx)
		If oDist = 0 Then
			oDist = oFaceProx.GetClosestPointTo(oCoM).VectorTo(oCoM).Length
			closestFace = oFaceProx
		Else
			Dim thisDist As Double = oFaceProx.GetClosestPointTo(oCoM).VectorTo(oCoM).Length
			If thisDist < oDist
				oDist = thisDist
				closestFace = oFaceProx
			End If
		End If

	Next
	oFaces.Add(closestFace)
Next
For Each oFace As FaceProxy In oFaces
	AddWorkPlaneInAssembly(oAsm, oFace, 0)
Next

End Sub
Sub AddWorkPlaneInAssembly(oAsm As AssemblyDocument, oFace As Object, oOffset As Double)
	'Add Fixed plane (only way to add a plane in assembly environment)
	Dim oDef As AssemblyComponentDefinition = oAsm.ComponentDefinition
	Dim oOriginPnt As Point
	Dim oXaxis, oYaxis As UnitVector
	oOriginPnt = ThisApplication.TransientGeometry.CreatePoint(0, 0, 0)
	oXaxis = ThisApplication.TransientGeometry.CreateUnitVector(1, 0, 0)
	oYaxis = ThisApplication.TransientGeometry.CreateUnitVector(0, 1, 0)
	Dim oPlane As WorkPlane = oDef.WorkPlanes.AddFixed(oOriginPnt, oXaxis, oYaxis)
	'Constrain the plane
	oPlane.AutoResize = True
	oDef.Constraints.AddFlushConstraint(oFace, oPlane, oOffset)
	oPlane.AutoResize = False
End Sub

The code uses the assemblys center of gravity to get a point inside the box. For each occurrence in the assembly it then finds the closest face to that point. Then it takes those faces and creates workplanes on them.

 

Before running iLogic-rule:

1bild.PNG

And after:

2bild.PNG

Message 8 of 26

_dscholtes_
Advocate
Advocate

@shiftctrl.io I'm not familiar with the cabinet business (and English is not my native language) so I don't understand what is meant with 'length of cabinets ... in only the one which'. It's the plural of cabinets in combination with the single of one. Do you mean you have multiple boxes like in your image stacked next to each other?
 And how do you know which one requires 'further processing' if you don't want some 'sort of user selection to guide me'?

By the way, after looking at your second image a bit longer, I don't think it's necessary to select the back wall to discard its corners. It just saves analyzing 8 points. 

 

@JhoelForshav 

That's an elegant way to determine the faces making up the requested inside area (compared to my brute-force method). I learned something new (.GetClosestPointTo). I'm not sure if @shiftctrl.io  requires the back plane though.                           

Message 9 of 26

WCrihfield
Mentor
Mentor

Is the end goal just to create the planes, or do you want to get the size of the available interior space?

Here's a quickie rule that  should get the interior size, using the model's RangeBox, then subtracting wall thicknesses.

It's not the most intuitive, but should work if the model is oriented the same way each time.

'This assumes the model is a multi-body part file, and not an assembly.
Dim oPDoc As PartDocument = ThisApplication.ActiveDocument
Dim oPDef As PartComponentDefinition = oPDoc.ComponentDefinition
'Asuming X-Axis is along width, Y-Axis is along Depth, and Z-Axis is along Height
Dim oBox As Box = oPDef.RangeBox
Dim oMinCoords(), oMaxCoords() As Double
oBox.MinPoint.GetPointData(oMinCoords)
oBox.MinPoint.GetPointData(oMaxCoords)
Dim oWidth As Double = (oMaxCoords(0) -oMinCoords(0))
Dim oDepth As Double = (oMaxCoords(1) -oMinCoords(1))
Dim oHeight As Double = (oMaxCoords(2) -oMinCoords(2))

'These values can either be manual entry, InputBox, captured from the models or Parameters.
'If the model components/bodies had names specific to their positions (top,right,etc.)
'you could extract the thickness parameter from them to use here.
Dim oRRWall As Double = .375
Dim oSWall As Double = .5
Dim oTWall As Double = .5
Dim oBWall As Double = .75

oWidth = oWidth - (oSWall * 2)
oDepth = oDepth - oRRWall
oHeight = oHeight - (oBWall + oTWall)
MsgBox("The available interior space is:" & vbCrLf & _
oWidth.ToString & " Wide x " & oDepth.ToString & " Deep x " & oHeight.ToString & " Tall.")

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 10 of 26

robertast
Collaborator
Collaborator

@shiftctrl.io 

You better tell the essence of the problem itself. And the guys will definitely help you and find a solution and solve the problem. Something tells me that these planes cannot solve the problem. I know a lot about cabinets, but I have no idea why these surfaces might be needed, what task they can solve. 🙄

Are you by any chance trying to create "SOLIDWORKS SWOOD" in the inventor?

 

Message 11 of 26

shiftctrl.io
Enthusiast
Enthusiast

Your solution is quite brilliant. Your answer most certainly solved the problem of adding the desired planes in the condition shown, however, part of the reason why I noted that a engineer would select two sides is that the rectangle (or cabinet) might at times have a vertical divider. In said case, do you have any suggestions to modify the logic so that it would apply the planes within the desired partition?

 

I should have asked this question with the following image in the beginning, though didn't anticipate such an elegant solution. 

 

Inventor_9RydPELB5x.png

0 Likes
Message 12 of 26

robertast
Collaborator
Collaborator

@shiftctrl.io 

 

Additional planes are unnecessary for partitions. All parts already have their surfaces

 

To help, I’ll ask you one question. When you work, you use the "multi-body" or "assembly" method

0 Likes
Message 13 of 26

_dscholtes_
Advocate
Advocate

Instead of using the center of mass, the code from @JhoelForshav should determine the 'center point' between the two selected vertical walls. That would work for any cabinet, no matter the amount of partitions.  A shortcut could be made to detect a single partition cabinet which uses the center of mass to avoid user interaction.


Message 14 of 26

robertast
Collaborator
Collaborator

@_dscholtes_ 

You did not understand. In designing a cabinet, all these troubles are not needed. They won't do any good

0 Likes
Message 15 of 26

JhoelForshav
Mentor
Mentor
Accepted solution

Hi @shiftctrl.io 

Try this code, it should work 🙂

The difficult part here was to find the direction to searc for the faces in the panels that is not selected, since there are an infinite number of perpendicular faces to those two selected. I ended up using the edges of one of the faces outer edgeloop to get the directions to investigate.

 

Now it works as requested in your original post.

Sub Main
Dim oAsm As AssemblyDocument = ThisDoc.Document
Dim oDef As AssemblyComponentDefinition = oAsm.ComponentDefinition
Dim oTG As TransientGeometry = ThisApplication.TransientGeometry
Dim cmdM As CommandManager = ThisApplication.CommandManager
Dim oOcc1 As ComponentOccurrence = cmdM.Pick(SelectionFilterEnum.kAssemblyLeafOccurrenceFilter, "Pick first panel.")
If oOcc1 Is Nothing Then Exit Sub
Dim oOcc2 As ComponentOccurrence = cmdM.Pick(SelectionFilterEnum.kAssemblyLeafOccurrenceFilter, "Pick second panel.")
If oOcc2 Is Nothing Then Exit Sub

Dim oCol As ObjectCollection = ThisApplication.TransientObjects.CreateObjectCollection

Dim oPt1 As Point = oOcc1.MassProperties.CenterOfMass
Dim oPt2 As Point = oOcc2.MassProperties.CenterOfMass
Dim oPt1Pt2 As Vector = oPt1.VectorTo(oPt2)

'Find first two planes:
Dim oFirstFaces As ObjectsEnumerator = oDef.FindUsingVector(oPt1, oPt1Pt2.AsUnitVector, {SelectionFilterEnum.kPartFacePlanarFilter })
'Add the two first planes found (inside planes) to collection
oCol.Add(oFirstFaces(1))
oCol.Add(oFirstFaces(2))

'Move oPt1 to be the centerpoint of the partition
oPt1Pt2.ScaleBy(1 / 2)
oPt1.TranslateBy(oPt1Pt2)

'Use the outer edgeloop of one of the faces to get directions for finding the other faces
For Each oLoop As EdgeLoopProxy In oFirstFaces(1).EdgeLoops
	If oLoop.IsOuterEdgeLoop
		For Each oEdge As EdgeProxy In oLoop.Edges
			If TypeOf (oEdge.Geometry) Is LineSegment
				Dim oLine As LineSegment = oEdge.Geometry
				Dim oFoundEnts As ObjectsEnumerator = _
				oDef.FindUsingVector(oPt1, oLine.Direction, _
				{SelectionFilterEnum.kPartFacePlanarFilter })
				If oFoundEnts.Count > 0
					Dim oInvVector As UnitVector = oTG.CreateUnitVector _
					(oLine.Direction.X * -1, oLine.Direction.Y * -1, oLine.Direction.Z * -1)
					Dim oFoundEnts2 As ObjectsEnumerator = _
					oDef.FindUsingVector(oPt1, oInvVector, _
					{SelectionFilterEnum.kPartFacePlanarFilter })
					If oFoundEnts2.Count > 0
						oCol.Add(oFoundEnts(1))
						oCol.Add(oFoundEnts2(1))
					End If
				End If
			End If
		Next
		Exit For
	End If
Next
For Each oFace As FaceProxy In oCol
AddWorkPlaneInAssembly(oAsm, oFace, 0)
Next
End Sub

Sub AddWorkPlaneInAssembly(oAsm As AssemblyDocument, oFace As Object, oOffset As Double)
	Dim oDef As AssemblyComponentDefinition = oAsm.ComponentDefinition
	Dim oOriginPnt As Point
	Dim oXaxis, oYaxis As UnitVector
	oOriginPnt = ThisApplication.TransientGeometry.CreatePoint(0, 0, 0)
	oXaxis = ThisApplication.TransientGeometry.CreateUnitVector(1, 0, 0)
	oYaxis = ThisApplication.TransientGeometry.CreateUnitVector(0, 1, 0)
	Dim oPlane As WorkPlane = oDef.WorkPlanes.AddFixed(oOriginPnt, oXaxis, oYaxis)
	oPlane.AutoResize = True
	oDef.Constraints.AddFlushConstraint(oFace, oPlane, oOffset)
	oPlane.AutoResize = False
End Sub

The result in your latest picture will be obtained by selecting theese two components (with no respect to selection order)

selection.PNG

Message 16 of 26

_dscholtes_
Advocate
Advocate

@robertast To me, it doesn't matter if all this trouble is of no good in designing cabinets. I saw an interesting problem / request and decided to give my 2 cents. As a bonus, I learned an interesting approach to this problem.

 

@JhoelForshav I'm wondering why you didn't use the code you posted before, but with a shifted reference point? To be honest, I need to study the code and check the used vba methods to understand what is happening (I don't have time for that now). Your first code I understood at first glance.

0 Likes
Message 17 of 26

JhoelForshav
Mentor
Mentor

Hi @_dscholtes_ 

I agree with you that there's no point in questioning why @shiftctrl.io want to create these planes, it's just a fun challenge 🙂

 

The reason I don't use the first code is because it will look through all the components in the assembly and get the closest face to the point for each of these components. Then I'd have to add functionality to check which face of multiple parallell faces that should be used. Actually two parallell faces should be used, the ones closest to the point on each side of the point with respect to the face's own normal. Of course it's doable but why create and evaluate proxies of every face in the entire assembly if we don't have to? The code would be a complete mess and also unnessecarily slow 🙂

Message 18 of 26

robertast
Collaborator
Collaborator

@JhoelForshav  codes work beautifully and quickly, he has no unsolvable problems. But it is very difficult to understand their structure. 🙂

He is a genius in the programming environment 👍

Message 19 of 26

_dscholtes_
Advocate
Advocate

@JhoelForshav What do you think of the option of finding the top and bottom walls (faces) by casting a ray up and down from the 'center point' between the two selected vertical walls? When I look at the .FindUsingRay code part in this Manufacturing DevBlog article, it looks pretty simple (although they cast it in a part file, not an assembly).

0 Likes
Message 20 of 26

JhoelForshav
Mentor
Mentor

@_dscholtes_ 

That's pretty much what I do in the latest code. I use FindUsingVector but it's pretty much the same thing .

In FindUsingVector we have a selectionfilter argument that comes in handy (Since we know we only want to find planar faces), and also we don't have to create an enumerator for LokationPoints that we have no use for 🙂

The problem is that we don't know which direction is up/down. Sure, we could say the assembly must be oriented in a way that up/down is always along the Z-axis for example, but I prefer the code working regardless of the assemblys orientation.

Thats why I use the outer edges of the face to determine directions to shoot these rays along and check for faces:)