Find angle between adjacent faces

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Find angle between adjacent faces

Post by sliptonic »

I want to calculate the angle between two selected faces that have a common edge. For example face 2 and 3 in this image.
But since both faces 1 and 3 have the same normal, selecting either 1 and 2 or 2 and 3 yields 120 degrees. How can I distinguish between these cases?
I would expect 2,3 to be 60 degrees and 1,2 to be 300 degrees.

2022-05-16_11-30.png
2022-05-16_11-30.png (12.97 KiB) Viewed 1645 times

Code: Select all


import math

f1 = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]
f2 = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[1]
v1 = f1.normalAt(0,0)
v2 = f2.normalAt(0,0)

print(math.degrees(v2.getAngle(v1)))

edwilliams16
Veteran
Posts: 3109
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Find angle between adjacent faces

Post by edwilliams16 »

To make the problem well-defined mathematically, I think you are asking for the angle between the face planes measured exterior to the object. Convex intersections would be returned > 180 deg and concave < 180 deg? Is that correct? I'm not seeing another way to resolve the inherent ambiguity.
wmayer
Founder
Posts: 20243
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Find angle between adjacent faces

Post by wmayer »

With the angle alone you cannot distinguish between the two cases. As already mentioned you have to distinguish between a convex area (face 1+2) and a concave area (face 2+3).

Now all what you need is e.g. a point that lies on one face but not on the adjacent face, i.e. the point must not be part of the common edge. Compute the distance of this point with the adjacent face.

If the distance is negative you have the convex case like face 1+2.
If the distance is positive you have the concave case like face 2+3.
If the distance is zero the two planes are co-planar.
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: Find angle between adjacent faces (and other experiments)

Post by sliptonic »

Here's another one. In case it isn't obvious, I'm trying to figure out some of the issues related to cutting dovetails on a milling machine. Ultimately I'm offsetting the red line (common edge). Now that I have the angle between the faces, I need to figure out the Width of Cut (base of blue triangle) and Depth of Cut (height)

As an intermediate step, I think I need to find the pink line segment. It lies on plane of the green face and passes through the midpoint of the common edge and is perpendicular to the common edge.
2022-05-17_09-55.png
2022-05-17_09-55.png (23.62 KiB) Viewed 1461 times
edwilliams16
Veteran
Posts: 3109
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Find angle between adjacent faces

Post by edwilliams16 »

I made the assumption that the red edge is straight and the green face is planar and that you can already access these. I get them by selection.

Code: Select all

#select edge then face - assumed straight and planar
sel = Gui.Selection.getSelectionEx()[0]
edge, face = sel.SubObjects
edgeCenter = edge.CenterOfGravity  
fsp =face.Surface.parameter(edgeCenter)
faceNormal = face.normalAt(*fsp)
pinkLine = Part.Line() #temporary infinite line
pinkLine.Direction = faceNormal.cross(edge.Curve.Direction)
pinkLine.Location=edgeCenter
#find where pinkLine crosses the face edges
intersections = [pinkLine.intersect(faceEdge.Curve, 1e-7) for faceEdge in face.Edges if len(pinkLine.intersect(faceEdge.Curve, 1e-7)) >0]
#print(f'start = {edgeCenter}  {intersections}')
ends = [App.Vector(pa[0].X, pa[0].Y, pa[0].Z) for pa in intersections]
pinkLine = Part.LineSegment(*ends)  #construct line segment 
Part.show(pinkLine.toShape())
EDIT: fixed script bug that made it look like it worked when it didn't...
Last edited by edwilliams16 on Tue May 17, 2022 11:27 pm, edited 1 time in total.
dtay
Posts: 20
Joined: Fri Jan 17, 2020 12:52 pm

Re: Find angle between adjacent faces

Post by dtay »

I'm not so good at python or math, but I figured I'd give this puzzle a try :)

The code below assumes that the adjacent edge of the blue triangle points up in Z and only the undercut is selected.

Code: Select all

import math

f1 = FreeCADGui.Selection.getSelectionEx()[0].SubObjects[0]
a = f1.BoundBox.XMax-f1.BoundBox.XMin
b = f1.BoundBox.ZMax-f1.BoundBox.ZMin
ang = math.atan(a/b)


#X/Z start point
x1, z1 = f1.BoundBox.XMax, f1.BoundBox.ZMax

stnum=5
bstp=b/stnum

for stp in range(1,stnum+1):
    x=x1-bstp*stp*math.tan(ang)
    z=z1-bstp*stp
    print("X={} Z={}".format(x,z))
I would be interested in what a more elegant approach might look like...
edwilliams16
Veteran
Posts: 3109
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Find angle between adjacent faces

Post by edwilliams16 »

dtay wrote: Tue May 17, 2022 10:17 pm
It looks like you've assumed that the dovetail section is in the X-Z plane, which it might not be. And the OP wanted the line to be at the mid-point in Y...
edwilliams16
Veteran
Posts: 3109
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Find angle between adjacent faces

Post by edwilliams16 »

edwilliams16 wrote: Tue May 17, 2022 10:12 pm I made the assumption that the red edge is straight and the green face is planar and that you can already access these. I get them by selection.

Code: Select all

#select edge then face - assumed straight and planar
sel = Gui.Selection.getSelectionEx()[0]
edge, face = sel.SubObjects
edgeCenter = edge.CenterOfGravity  
fsp =face.Surface.parameter(edgeCenter)
faceNormal = face.normalAt(*fsp)
pinkLine = Part.Line() #temporary infinite line
pinkLine.Direction = faceNormal.cross(edge.Curve.Direction)
pinkLine.Location=edgeCenter
#find where pinkLine crosses the face edges
intersections = [pinkLine.intersect(faceEdge.Curve, 1e-7) for faceEdge in face.Edges if len(pinkLine.intersect(faceEdge.Curve, 1e-7)) >0]
#print(f'start = {edgeCenter}  {intersections}')
ends = [App.Vector(pa[0].X, pa[0].Y, pa[0].Z) for pa in intersections]
pinkLine = Part.LineSegment(*ends)  #construct line segment 
Part.show(pinkLine.toShape())
EDIT: fixed script bug that made it look like it worked when it didn't... Added my test file
Attachments
pinkline.FCStd
(12.18 KiB) Downloaded 13 times
Post Reply