screw and spring macro

Show off your FreeCAD projects here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
corporate-lemur
Posts: 8
Joined: Sat Feb 02, 2013 1:07 am

screw and spring macro

Post by corporate-lemur »

Ok, so I couldn't get the images to upload, but I discovered that the "Part.makeHelix()" function breaks down the the helix is too long.

I created a workaround that allows you to make a helix of pretty much any dimension. I didn't do an exhaustive debug, but it worked where it didn't before, so that's something.

Included in the code below (I also couldn't get my HelicalShapes.py file to upload...) are 2 implementations of my helix fix.

The Spring() function requires 4 selected sketches (using Sketcher or Draft if you'd like) - create a circle for the spring's base, a circle for the spring's cross section, a line for its axis, and a line for its pitch.

The Screw() function creates the threads of a screw. It requires 3 sketches - create a circle for the screw's base, a profile shape for the thread's cross section (usually a triangle), and a line representing the axis. It finds a line in the thread profile to use as the pitch (the longest line that is perpendicular to the base).

Again, sorry I couldn't show the pictures... I realize that's gonna make it harder to figure out how to use this... I guess this may help anyone who just happens to be looking for this.

Code: Select all

import Part, FreeCADGui, FreeCAD, math, PartGui
from FreeCAD import Base

def HelixOK(H):
	#This tells you whether the helix keeps its form well, or goes haywire at the top.
	#It's part of a workaround for a bug in the Part.makeHelix function.
	L=H.Edges[0].Length
	R=H.Edges[0].valueAt(0).sub(H.Edges[0].centerOfCurvatureAt(0)).Length
	C=[]
	Csum=0
	n=10
	for i in range(n):
		center=H.Edges[0].centerOfCurvatureAt(L/10*i)
		offset=math.sqrt(center.x**2+center.y**2)
		C.append(offset)
		Csum+=offset

	Cavg=Csum/n
	Cstdev=0
	for each in C:
		Cstdev+=(each-Cavg)**2

	Cstdev=math.sqrt(Cstdev)/n
		
	state = (Cstdev<.01)	
	return state
	
def FixHelix(Pitch,Height,Radius):
	#This function replaces Part.makeHelix(), creating a helix that won't go crazy at the top.
	Helix=Part.makeHelix(Pitch,Height,Radius)
	OK=False
	n=0
	while not OK:
		for i in range(n):
				H2=Helix.copy()
				H2.translate(Base.Vector(0,0,Height))
				HEdges=Helix.Edges
				HEdges.extend(H2.Edges)
				Helix=Part.Wire(HEdges)
		if HelixOK(Helix):
			OK=True
		else:
			n+=1
			Height=math.floor(Height/Pitch)*Pitch/2
			Helix=Part.makeHelix(Pitch,Height,Radius)
	return Helix
	
def Spring():
	#Select (0) a circle for the spring diameter, (1) a circle for the cross section,
	#(2) a line whose length is the height of the spring, and (3) a line whose
	#length is the pitch, in that order.
	
	Radius = FreeCADGui.Selection.getSelection()[0].Shape.Edges[0].Curve.Radius
	try:
		Profile = FreeCADGui.Selection.getSelection()[1].Shape.Wires[0]
	except:
		Profile = FreeCADGui.Selection.getSelection()[1].Shape.Edges[0]
	Height = FreeCADGui.Selection.getSelection()[2].Shape.Length
	Pitch = FreeCADGui.Selection.getSelection()[3].Shape.Length
	Helix=FixHelix(Pitch,Height,Radius)
	Spring = Helix.makePipeShell([Profile],1,1)
	Part.show(Spring)	
	return Spring
	
def Screw():
	#Select (0) a circle for the screw outer diameter, (1) a triangle or polygon for the thread profile,
	#and (2) a line whose length is the length of the screw.
	#Note: the profile must have at least one line that is perpendicular to the circle.
	#This function only creates the threads; you have to make your own cylinder for the core.
	Circle = FreeCADGui.Selection.getSelection()[0].Shape.Edges[0]
	Radius = Circle.Curve.Radius
	Profile = FreeCADGui.Selection.getSelection()[1].Shape.Wires[0]
	Height = FreeCADGui.Selection.getSelection()[2].Shape.Length
	PitchFinder = FreeCADGui.Selection.getSelection()[1].Shape.Edges
	C=Circle.centerOfCurvatureAt(0).sub(Circle.valueAt(0)).normalize()
	T=Circle.tangentAt(0)
	N=T.cross(C).normalize()

	#Finds the largest vertical line in the profile sketch; uses that as the pitch.
	Pitch=0.
	for eachedge in PitchFinder:
		if eachedge.tangentAt(0).sub(N).Length < .001 and eachedge.Length>Pitch:
			Pitch = eachedge.Length
			
	Helix=FixHelix(Pitch,Height,Radius)
	Screw = Helix.makePipeShell([Profile],1,1)
	Part.show(Screw)
	return Screw
Post Reply