Site Sponsors:
Web Gears - Part III: The Pinwheel Cog 
It is no secret that males are obsessive. Proven by Readers' Digest many years ago, by tracking the infra-red pattern of blood flow when males think about a problem, the blood pretty much stays in our frontal lobe. No so for the females.

Why mention such a scientifically proven, yet completely politically incorrect fact? -Because "being born that way" is the only way that I might possibly explain my present & personal obsession with creating bewooden counters!

Submitted for your obsession therefore (or not =), here is the latest installment to what is proving to be far, far, too much fun:

import turtle


'''
We need to be slightly more careful with the parameters here than in our
other demonstrations - the entire point of this rendition is to create a
3-dimensional array of points that can be used for 'zBite' calculations.

For things to work properly, we must therefore be sure that zStep <> zRange,
as well as that zStep < zRange. Since this is an academic demo, in order
to make things a tad cleaner to read, we removed our in-code parameter
checks.

The use of Cardinal slice-values is important!
(see post at http://soft9000.com/blog9000/add.php?y= ... 122-020104)
'''
def draw_pinwheel(zSlices=10, zRange=100, zStep=10):
zt = turtle.Turtle(shape='turtle')
angle = int(360 / zSlices)
zSegs = int(zRange / zStep) + 1
locs = [[[-1 for z in range(1)] for y in range(zSegs)] for x in range(zSlices)]

zLine = 0
zt.hideturtle()
zt.color('red')
for ref in range(1, 360, angle):
zt.pendown()
zt.left(angle)
zLineSeg = 0
for zSeg in range(1, zRange + zStep, zStep):
zt.pendown()
zt.forward(zSeg)
zt.circle(1)
print(zLine, zLineSeg)
locs[zLine][zLineSeg] = [zt.pos()]
zt.penup()
zt.goto(0, 0)
zLineSeg += 1
zLine += 1
print(locs)
zt.goto(0, 0)

zt.color('black')
for zSub in range(1, zRange + zStep, zStep):
zt.right(90)
zt.forward(zSub)
zt.right(270)
zt.pendown()
zt.circle(zSub)
zt.penup()
zt.home()

zt.color('red')
for zLine in range(zSlices):
lineA = locs[zLine]
lineB = locs[0]
if zLine < (zSlices - 1):
lineB = locs[zLine + 1]
for zSeg in range(1, zSegs):
pointA = lineA[zSeg]
pointB = lineB[zSeg - 1]
zt.penup()
zt.goto(pointA[0][0], pointA[0][1])
zt.pendown()
zt.goto(pointB[0][0], pointB[0][1])
zt.penup()
zt.home()

zt.color('black')
zLoc = zRange + zStep
zt.goto(zLoc * -1, zLoc)
zt.write("draw_pinwheel(zSlices=" + str(zSlices) + ", zRange=" + str(zRange) + ", zStep=" + str(zStep) + ")")
zt.hideturtle()

turtle.hideturtle()
draw_pinwheel(zSlices=10, zRange=200, zStep=100)
turtle.getscreen()._root.mainloop()

We can cut along the red lines to make our pinwheel cog:


Of course, for those of us who feel the need to try various sizes on-the-fly, we retained that distinctive variable-sized 'Web-Gear flavoring:


When working with wood, squaring off a cog often makes for a less brittle latch point:


Next, note the use of a 3-dimensional array:

locs = 
[[[-1 for z in range(1)]
for y in range(zSegs)]
for x in range(zSlices)]
...
for zLine in range(zSlices):
lineA = locs[zLine]
lineB = locs[0]
if zLine < (zSlices - 1):
lineB = locs[zLine + 1]
for zSeg in range(1, zSegs):
pointA = lineA[zSeg]
pointB = lineB[zSeg - 1]
zt.penup()
zt.goto(pointA[0][0], pointA[0][1])
zt.pendown()
zt.goto(pointB[0][0], pointB[0][1])

For those whom might not be used to working with multi-dimensional array complexity, I added the print statements to the code for your 'edutational enjoyment.


From a re-use point of view (no pun intended,) note that one can use this array of points for drawing any type of shape (circles for classic cogs, triangles for gears, etc.)

Cardinal Cog Locations


After a little experimentation, one will discover that not all slices are created equal!

When one is interested in precise pin locations (when aren't we?) then one will have to be sure that the number of slices requested are even whole-circle multiples:

prime_slices = set()
for slices in range(1, 100):
if 360 % slices is 0:
prime_slices.add(slices)
print("Prime slice", slices)
print("There are", len(prime_slices), " proper slices")


For steam-punkers there can some joy to be seen when non-cardinal slice values are used. For the purposes of this simulation however, please note that we should confine our pinwheel cog slice-requests to one of the primary / cardinal cog values.

For example, given the above primary-slice circle-test, note that out of 99 possible slice selections:

Prime slice 1
Prime slice 2 (impeller)
Prime slice 3
Prime slice 4
Prime slice 5
Prime slice 6
Prime slice 8
Prime slice 9
Prime slice 10
Prime slice 12 (hours)
Prime slice 15
Prime slice 18
Prime slice 20
Prime slice 24
Prime slice 30
Prime slice 36
Prime slice 40
Prime slice 45
Prime slice 60
Prime slice 72
Prime slice 90
There are 21 proper slices


Discover also - within our present obsession (counters & clocks) - that the above set of cardinal-slice values under 100 are simply perfect for our needs.

Ultimately however, for those who feel no need to allow several cogs to be cut for a single pattern, here is the simplified version:

import turtle


'''
We need to be slightly more careful with the parameters here than in our
other demonstrations - the entire point of this rendition is to create a
3-dimensional array of points that can be used for 'zBite' calculations.

The use of Cardinal slice-values is important!
(see post at http://soft9000.com/blog9000/add.php?y= ... 122-020104)

For things to work properly, we must therefore be sure that zStep <> zRange,
as well as that zStep < zRange. Since this is an academic demo, in order
to make things a tad cleaner to read, we removed our in-code parameter
checks.
'''
def draw_pin_wheel(zSlices=10, zRange=100, zBite=-1, zSmile=False):
zt = turtle.Turtle(shape='turtle')
angle = int(360 / zSlices)
locs = [[[-1 for z in range(1)] for y in range(2)] for x in range(zSlices)]
if zBite <=0:
zBite = int(zRange / 10)

zLine = 0
zt.hideturtle()
for ref in range(1, 360, angle):
zt.left(angle)
zt.forward(zRange)
zt.circle(1)
locs[zLine][1] = zt.pos()
zt.back(zBite)
locs[zLine][0] = zt.pos()
zt.circle(1)
zt.goto(0, 0)
print(locs[zLine])
zLine += 1

if zSmile:
zt.home()
zt.begin_fill()
for line in range(len(locs)):
zt.penup()
listA = locs[line][0]
zt.goto(listA[0], listA[1])
zt.pendown()
listB = locs[0][0]
if line < zSlices - 1:
listB = locs[line + 1][0]
# Hex-draw the inner 'circle'
zt.goto(listB[0], listB[1])
zt.goto(listA[0], listA[1])
zt.end_fill()

zt.home()
zt.color('red')
for line in range(len(locs)):
zt.penup()
listA = locs[line][0]
zt.goto(listA[0], listA[1])
zt.pendown()
listB = locs[0][1]
if line < zSlices - 1:
listB = locs[line + 1][1]
# Cut-draw the outer 'cut'
zt.goto(listB[0], listB[1])
zt.goto(listA[0], listA[1])

zt.penup()
zt.color('black')
zLoc = zRange + zBite
zt.goto(zLoc * -1, zLoc)
zt.write("draw_pin_wheel(zSlices=" + str(zSlices) + ", zRange=" + str(zRange) + ", zBite=" + str(zBite) + ")")
zt.hideturtle()

turtle.hideturtle()
draw_pin_wheel(zSlices=10, zRange=100, zBite=30, zSmile=True)
turtle.getscreen()._root.mainloop()


Surely looking allot cleaner, the need to colorize the final pattern is suddenly not-so-much:


Note that 'zBite' is also back, as well as entirely optional.



[ view entry ] ( 559 views )   |  permalink  |  related link
Web Gears, Part II 
Well the weekend is here. Time to hit the wood shop once again.

Last weekend we started creating our decimal counter. While the gears for the project are made entirely of wood, the assistive electronics (simple analog motor + a transistorized dump circuit) for the project are presently cooling in the garage.

Setting the sights on the next project, we decided to make the next gearing task out of cogs.

Updating last week's Web Gear generator, we came up with the following:


import turtle


def draw_cog(zSlices=10, zRange=100, zStep=10, zBite=120):
zt = turtle.Turtle(shape='turtle')
angle = int(360 / zSlices)
print(angle)
notpi = 2.85 # the smaller, the larger the cog-spacing. Keep it <= pi.
circumference = 2.0 * notpi * float(zRange)
overhill = circumference / float(zSlices)
zt.hideturtle()
for ref in range(1, 360, angle):
zt.pendown()
zt.left(angle)
zt.forward(zRange)
zt.pencolor('blue')
zt.circle(overhill / 2)
zt.pencolor('green')
zt.left(zBite)
zt.forward(overhill * 1.2)
zt.penup()
zt.right(zBite)
zt.forward(overhill * 1.2)
zt.pencolor('black')
zt.goto(0, 0)

for i in range(1, zRange + zStep, zStep):
zt.right(90)
zt.forward(i)
zt.right(270)
zt.pendown()
zt.circle(i)
zt.penup()
zt.home()

zLoc = zRange + zStep
zt.goto(zLoc * -1, zLoc)
zt.write("draw_cog(zSlices=" + str(zSlices) + ", zRange=" + str(zRange) + ", zStep=" + str(zStep) + ", zBite=" + str(zBite) + ")")
zt.hideturtle()

turtle.hideturtle()
draw_cog(zSlices=10, zRange=200, zStep=100, zBite=145)
turtle.getscreen()._root.mainloop()


Cutting along either the green "zByte" line, or the blue "notpi" circle will allow us to choose the type of cog (pinwheel or classic cog) that we want to cut:




Sharing is caring,

-Randall


P.S: Eliminating "zBite" so as to make the effective angle based upon our "zStep" (nice triangle to re-use there!) is presently on the # TODO: list! (i.e. it's been a long day =)

-Rn


[ view entry ] ( 493 views )   |  permalink  |  related link
Web Gears in Python 
One of the nice things about knowing more than one programming language is that one can choose the right language, for the right job.

Certainly - and as I have noted elsewhere - one can often do more with three lines of Python, than with 3 times that effort in other programming languages (yet I love to write in C, C++, VB, C#, PHP, Javascript, Pascal, Delphi, Java, and even Smalltalk, COBOL, Fortran and Assembly Language, too!)

(Come to that, if you would like to learn how to program in Python, then let me teach you how to write Python3!)

Headhunter Dilemma


Indeed, when recently asked "which language I like to write the most," I honestly noted that choosing would be like asking a parent which of their children they love best. -Depending upon what one is doing, they are all great... in their own ways!

Such can be the problem with selecting coding standards. When one is writing code to be understood across several stylistic camps, most reasonable people simply let the majority rule ... but I digress.

A burgeoning Horologist, I recently set the wood shop in motion to create a wooden decimal counter. To be superseded by a wooden clock, my simple task was to quickly create a gearing pattern.

Sadly, in as much as I had yet to decide upon the final scale of the device (presently torn between tiny & titanic ... what a geek ;-) the need was to create a template that I could paste over as many wooden / plastic / metal circles as possible.

Web Gears?


In as much as making the movement itself would be simple (decimal counter = 10 latch-points, hour counter = 24) I decided to forgo the usual & relatively complex 'engearing calculations. Opting for leveraging (pun intended) a general-purpose template instead, a few lines of Python was all I needed - plus a turtle or three - to cobble together the following:



(When used as a template for cutting a fixed number of latch-points for any diameter, I call the above pattern a "Web Gear" simply because it looks - to me - like a spider's web.)

Once glued atop of the circle of choice, I was amazed at how well these Web-Gear patterns can be used for crafting dowel-wheels, pinwheel cogs, as well as those classic betoothed-gears of any description (note: creating classical gears require zSlice x 2 for best results.)



Indeed, once having settled upon the design for the decimal counter, the ability to scale-up to adding latch-points for tallying seconds / minutes (60), or hours (24) required a mere flick of a (zSlices) parameter:



zCode


Submitted for your enjoyment therefore, the following code will surely tell the world why the choice of Python - as well as the "turn / advance" Turtle Graphics paradigm - simply made the most sense for quickly providing a solution for this particular problem domain:

import turtle


def draw_web(zSlices=10, zRange=100, zStep=10):
zt = turtle.Turtle()
angle = int(360 / zSlices)
print(angle)
zt.hideturtle()
for ref in range(1, 360, angle):
zt.pendown()
zt.left(angle)
zt.forward(zRange)
zt.penup()
zt.goto(0, 0)

for i in range(1, zRange + zStep, zStep):
zt.right(90) # Face South
zt.forward(i) # Move one radius
zt.right(270) # Back to start heading
zt.pendown() # Put the pen back down
zt.circle(i) # Draw a circle
zt.penup() # Pen up while we go home
zt.home() # Head back to the start pos

zLoc = zRange + zStep
zt.goto(zLoc * -1, zLoc)
zt.write("draw_web(zSlices=" + str(zSlices) + ", zRange=" + str(zRange) + ", zStep=" + str(zStep) + ")")


turtle.hideturtle()
draw_web(zSlices=60, zRange=200)
turtle.getscreen()._root.mainloop()

1,000 Words?


Here is zPicture:



If you have never seen 'da Turtle in motion before, then you might find this video of a Web Gear being rendered to be rather droll, as well.

A short, soundless demonstration, see the: Turtle in Action.

Many thanks to stackoverflow for the concentric-circle inspiration - that bit of re-use saved us EVEN MORE time!

Sharing is caring,

-Randall Nagy



[ view entry ] ( 400 views )   |  permalink  |  related link

<<First <Back | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Next> Last>>