Subject: Make-your-own-blades?
I've been having a discussion elsewhere about making your own figure skating blades, and have made some progress towards designing software to do part of it.
I'd like to get feedback here too. The GoldenSkate administrators say I have to remove all external links, so I have done so, and attached relevant images. Since this board doesn't let me attach anything, I have included things inline here
I would love any feedback you folks could give me, on how practical it would be, since I have little craft experience, and almost none working with metals.
====================================================================
title: DrawBlade program to draw figure skating blade runners.
Mitch Grunes's DrawBlade program to draw figure skating blades.
This was part of an idea for making one's own blades.
The idea is to attach the printed shapes created using my DrawBlade program to a piece of sheet steel (also called a bar) of the right thickness, cut around it with a jig saw. In later iterations, my idea was to use a strip cutting jig and an improvised circle cutting jig (made from a long thin wooden board with nails in it), to make the cuts smooth and clean. With a more little work I could move the lines so you could cut on the outside of the line, rather than the center, and I could extend the cut lines, to simplify cutting. Some jigsaws can be adjusted to cut cross picks instead of straight cut picks, but I haven't addressed that.
I guess one needs a milling machine to narrow the working part of the blade to the exact desired thickness?
Early prototypes for individual testing would use cheap steel, final versions would use more expensive steel (like 440C stainless steel), and the edge would be hardened with a torch.
The resulting blade runner (or the runner and toe pick separately) would be bolted using right-angle aluminum channels onto an aluminum mounting plate. I could modify mark the positions of a bunch of (countersink) holes in the runner and toepick so they could be mounted at various heights, and at various forward/backward tilts (or alternately, various forward/backward positions) depending on which holes you use.
I also explored the idea of using other software to generate an image file, a PDF, and a DXF (to import into CAD/CAM software, to guide CNC hardware, like a milling machine, instead of cutting with a jig saw).
====================================================================
My definitions of blade terms, and alternate definitions
There is no standardization of definitions of terminology for blades.
So let me clarify my usage of "rocker", "rocker radius", "sweet spot", and the front and back toepick teeth:
The bottom part of most blades, but not including the toe picks for figure skates, has a long-wise curved shape, or sequence of several segments of curved shape, that I any many other people call the "rocker profile." But some people refer to that entire section as the "rocker". ("segment" is my terminology for this idea, not used by anyone else I know, so no one else should complain - I hope.)
Nordic skates are designed for cross-country skating or for skating on large ponds, lakes, canals and streams. They typicall have no curvature on the bottom of the blade, which is the fastest design for skating in a straight line. This program is not currently designed to draw those blades. There is no "rocker" or sweet spot of any type.
Skating on vertically curved blade bottoms (segments with "rocker curvature") makes it easier to do turns and spins, but pushing and stopping are less effective. The more rocker curvature (which means the smallest rocker radius) glide in straight lines less easily, resulting in slower speeds when skating straight.
Most short and long track speed skating blades have a single fairly long radius of curvature. Typically in the 18-23 foot range. It helps them skate around the curved arcs of the track, which are very gradual curves. Incidentally, those blades are also horizontally warped, or can be adjusted to be, which helps too, because they always skate in a CCW (counterclockwise) direction. They call the radius of curvature the "rocker" or "rocker radius". E.g., some speed skaters say "23' rockers" are best. (I'm not sure if that is specific to long track speed skating??)
Modern hockey blades typically continuously vary the radius of curvature (although older hockey rocker profiling machines varied curvature in many small steps; maybe some blades are still made that way??). The innermost parts are least curved, and are most effective to push, stop, and change irection. One also glides there to minimize friction, and go fast. But the ends are very curved, so they can do fast turns.
Offsensive hockey skaters (who mostly skate forwards) often modify their blades (or have a skate tech modify them - often using a profiling machine such as are made by CAG) so the position the least curved part is a mm or two forwards of the blade center. Defensive hockey skaters (who mostly skate backwards) often position it a mm or two backwards of the blade center. According to Blademaster, the leading manufacturer of powered sharpening machines, when skating on large skating rinks (Olympic size or larger), some agressive skaters chose profiles with a no rocker curvature in the center, which they call a "flat", so they can skate and stop and change directions while going very fast.
All figure skate blades I know of are divided into several segments with different fixed radii of curvature on the bottom part of the blade.
Traditionally MK (Originally made by Mitchel & King Blades), Ultima (made by or for Jackson Skates) blades have 2 segments. Usually JW (originally made by John Wilson Skates) have 3 segments. (MK and JW are now owned by the same company, HD Sports, and I think the blades are manufactured by the same production line in Sheffield, England. But they still use different trade names for different blade models.) Paramount and some other companies tend to roughly imitate both their designs, with some differences. There are other minor brands. The most expensive HD Sports blades tend to dominate high level competitions, in part because if a skater wins a medal at such a competition, and are using something else, they often give them a free MK or JW blade. (E.g., someone told me that Irina Slutskaya won a medal at a World level competition in Club 2000 blades. They are made by MK, but are often considered beginner level blades, and cost more than an order of magnitude less than the top blades. So she was given a more expensive pair of blades free.) Perhaps they sometimes also sponser them. And they occaisionally give away blades to influential coaches and figure skating directors. Their blades are not cheap. I would love to have MK Dance blades, and used to, but at my skating level and budget, I can't justify it. Oh well.
The main length of the blade, in the back, is the least curved, and is what I call the "main rocker" segment. But "main rocker" is also used by some others to describe its radius of curvature. E.g., traditionally, MK blades had a 7' main rocker radius, and JW had an 8' main rocker radius. The part of of the blade forward of what I call the main rocker segment is called the "spin rocker", though that may also refer to the radius(es) of curvature of that segment, or those segments. Because it is more curved, it is used for spins and forward-to-backwards turns. (Where backwards-to-forwards turns are best done varies according to different coaches.)
For 3 segment blades made by JW, there is a complication I don't understand: When skating on the forward transition point between the main rocker and the back spin rocker ("forward sweet spot" by my definition), the toe pick touches. Which means you can barely use the forward spin rocker segment at all - and not at all after a very few sharpenings, unless you keep trimming the back toe pick. Thus the forward spin rocker section becomes virtually useless. It only touches during high jumps and jump landings, when the blade is pushed deep into the ice, or on very soft, warm ice.
I think a few figure skating blades have been designed with another spin-rocker segment in the back. (Of course, some blades have an accidental such segment caused by poor sharpening techniques.)
I call the point(s) along the length of figure skating blades where the rocker curvature changes "sweet spot(s)".
"Sweet spot" was used that way by a skate tech trusted (Don Giese, a speed/figure/hockey coach, and onetime masters class USA speed skating champion at several distances. He sold me my first boots & blades, as well as a skate sharpening toolkit, and inline skates, and was the first person to do a good job sharpening my blades. AFAICT, it was also the way skate tech Mike Cunningham (who had many world class customers, and was many times the USFSA official skate sharpener at International events like the Olympics) used it. (I say that because he talked about the desirability of changing the rocker profile to move "the sweet spot", as though it were a single point. (He kindly allowed me to watch him work one day/week for a few months.)
But some people in the skating community use "sweet spot" to refer to the entire spin rocker segment, or group of segments, even if some of them are in the section of the blade that can't be skated on, because the toe pick gets in the way - which seems to be true of the forward segment of JW blades. And some use "sweet spot" to refer to the entire segment or specific point that a particular skater or coach does a specific spin or turn on. In general, and in sports, "sweet spot" often refers to an optimal point or position.
User tstop4me keeps complaining about my usage of "sweet spot", because he says it confuses skaters whose coaches or skate techs use it differently.
The front part of a figure skating blade, the "toepick" (or toe pick in some people's lingo) consists of several sharp teeth. It is sometimes used to do forward-to-backward turns (usually called forward turns), scratch spins, forward jumps (which start moving and facing forwards), backward jumps, and pivots (except some usual and difficult pivots and spins are done off the "tail" (the back part of the blade). What I call the "drag pick" (or back toepick tooth), some people call the "scratch pick." What I call the "frontmost pick", some people call the "king pick". Apparently some people can sometimes reach it. In a few cases (specifically certain ice dance blades, like the most popular MK Dance) the drag pick is blunted instead of sharp.
[Link removed _ExternalDiscussion.rtf [NOT Included here. Among other things, someone with machinist/engineering skills responded, and indicated I should try to produce a file format that CAD/CAM software could import
WilsonbladeRadius.JPG An old image (I'm not sure where I got it) showing typical rocker radiuses for MK and JW blades at that time. Note that some sources give a 27 inch instead of the 2 foot back spin rocker for many JW blades that this image lists. In addition, some sources give 12 inches instead of 9 inches for the MK spin rocker.
7foot.png: image of 7 foot rocker section cropped out of rocker.png
9inch.png: Similar for 9 inch rocker
sweetspot.png: Shows how two rocker segment of different rocker radii can be cleanly pasted together. The idea is that the tangent lines are the same at the boundary. Or equivalently that the radial lines are the same.
sweetspot2.png: Similar, but labelled.
====================================================================
--- FILE DrawBlade.f90 --- (Fortran 90 free format source code for my software)
! Program DrawBlade Draws a skating blade runner using postscript.
! The intention was so I could try to make my own blades.
! See [Link removed] for more info.
! It is mostly for figure skating blades, but could be used for
! hockey and speed skating blades.
!
! Written by Mitchell Grunes.
! This is a free format fortran 90 program.
! Cygwin or linux compiles this using
! gfortran -Wall DrawBlade.f90 -o DrawBlade
! Cygwin produces executable DrawBlade.exe; Linux produces DrawBlade.
! Postscript language reference: [Links removed]
! Can convert postscript to PDF using [Links removed]
! Can possibly convert postscript to Cad format using a free Cad
! program, like [Links removed]
! Or FreeCAD. [Link removed] Says it can import PDF.
! Or LibreCad? [Link removed]
! Doesn't appear able to import postscript or pdf.
! Or LinuxCAD?
! And search google for "Free 2D CAD software like AutoCAD"
! Or maybe use [Link removed] pstoedit to convert postscript to DXF?
! [Link removed] thandxflib describes a fortran
! library to write DXF.
! [Link2 removed]
! [Link removed]
! has instructions on using lpr to print postscript files
! Perhaps I should use
! [Link removed]
! to instead write PDF files?
! Or
! [Link Removed]
! to create a DWG file?
! not used yet:
! x1 y1 x2 y2 r arct Draw tangent arc. (To create rounded corner.)
! For my definitions of technical terms (there is no standardization!), like
! "rocker", "rocker segment", spin rocker, sweet spot, and toe pick tooth names,
! see file index.html.
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
character*100 ParmFile,PsFile ! Name of BladeDraw & Postscript files.
print*,'Enter 1 to input from blade parameter file, 0 to make a new one:'
io=1
read*,io
if(io.eq.0)print*,'Blade parameter file (Enter blank for "DrawBlade.txt") to write:'
if(io.ne.0)print*,'Blade parameter file (Enter blank for "DrawBlade.txt") to read:'
read(*,'(a)')ParmFile
if(ParmFile.eq.' ')ParmFile='DrawBlade.txt'
print*,'ParmFile=',ParmFile
if(io.eq.0)open (1,file=ParmFile,status='new',err=1)
if(io.ne.0)open (1,file=ParmFile,status='old')
goto 2
1 print*,'File already exists - overwrite(0=no,1=yes?):'
i=0
read*,i
if(i.eq.0)stop 'Cannot continue'
if(io.eq.0)open (1,file=ParmFile,status='unknown')
2 print*,'Output postscript file (Enter blank for "DrawBlade.ps"):'
if(io.eq.0)then
read(*,'(a)')PsFile
if(PsFile.eq.' ')PSFile='DrawBlade.ps'
write(1,'(a)')PSFile
else
read(1,'(a)')PSFile
if(PsFile.eq.' ')PSFile='DrawBlade.ps'
endif
print*,'PsFile=',PSFile
open (2,file=PsFile,status='unknown')
write(2,'(a)')'%!PS' ! So print spools detect start of file
write(2,'(a)')'% ***Figure Skating Blade Profile created by Mitch Grunes''s DrawBlade***'
call WriteBlank
call ReadInt('Add arc radius lines for illustrations(0=no? 1?)',iExtra,1)
xmin=1e20 ! Initialize x,y min,max in inches.
ymin=1e20
xmax=-1e20
ymax=-1e20
print*,'Some MK blades have 1 main rocker and 1 spin rockers.'
print*,' (7 foot=84" main rocker, 9" spin rocker)'
print*,'Many JW blades have 1 main rocker and 2 spin rockers.'
print*,' (8 foot=96" main rocker, 27" (24"??) & 12" spin rockers)'
call ReadInt('# of rocker length segments(2? 3?)',nRocker,2)
write(2,'(a)')'/MyPath newpath {'
do iRocker=1,nRocker
call WriteBlank
print'(a,i0,a)','***Rocker #',iRocker,'***'
if(iRocker.eq.1)then
print'(a)','This is the main rocker segment!'
elseif(iRocker.eq.2.and.nRocker.gt.2)then
print'(a)','This is the backmost spin rocker segment!'
elseif(iRocker.eq.nRocker.and.nRocker.eq.2)then
print'(a)','This is the spin rocker segment!'
elseif(iRocker.eq.nRocker.and.nRocker.gt.2)then
print'(a)','This is the frontmost spin rocker segment!'
else
print'(a)','This is an intermediate spin rocker segment!'
endif
if( iRocker.eq.1)DefaultR=84
if( iRocker.eq.2)DefaultR=9
if(nRocker.eq.3.and.iRocker.eq.1)DefaultR=96
if(nRocker.eq.3.and.iRocker.eq.2)DefaultR=27
if(nRocker.eq.3.and.iRocker.eq.3)DefaultR=12
call ReadFlt('Rocker radius (inches)',R,DefaultR)
if(iRocker.eq.1)print'(a)',&
& 'Rocker segment lengths are measured along curve, not straight!'
call ReadFlt('Curved length of rocker segment (inches)',ArcLength,8.)
DeltaTheta=ArcLength/R*180/3.1415926535897932 !Angle width from center, in degrees
! print*,'deltaTheta=',deltatheta !##
if(iRocker.eq.1)then
Theta2=-90 ! Make Place 1st "sweet spot" (intersection of
! main rocker segment with first spin
! rocker segment) hoizontal, by making the
! tangent line vertical.
Theta1=Theta2-DeltaTheta ! Radial angle at start of main rocker
! segment.
call ReadFlt('x value of leftmost point on blade(0?)',x,0.)
x=x-R*cosd(theta1) ! 1st "sweet spot", by my definition
! (the intersection of main rocker segment
! with the first spin rocker segment).
xCenter=x ! Center of main rocker arc.
call ReadFlt('y value of lowest point on blade (0?)',y,0.)
yCenter=y+R
! print*,'deltaTheta=',deltatheta !##
! print*,'main rocker theta1=',theta1,'theta2=',theta2 !##
else
xCenter=x-R*cosd(theta2)
yCenter=y-R*sind(theta2)
Theta1=Theta2
Theta2=Theta2+DeltaTheta
! print*,'theta1=',theta1!##
! print*,'theta2=',theta2!##
endif ! if(iRocker.eq.1)then
! Draw main rocker circular arc to path.
print'(a,g0)','Direction angle of curve start=',Theta1+90
print'(a,g0)','Direction angle of curve end=',Theta2+90 !##
write(2,'(a,i0,a,g0,1x,g0,a,g0,a)') '% ***Rocker Segment ',iRocker, &
& ' Center=',xCenter,yCenter,' inches Radius=',R,'***'
write(2,'(a,g0,1x,g0,a)') '%***Angle range=',Theta1,Theta2,' deg***'
write(2,'(a,g0,a)') '% ***(Curved length=',ArcLength,')***'
call DrawArc(xCenter,yCenter,R,theta1,theta2)
If(iRocker.eq.1)SaveHeight1=yCenter+R*sind(theta1)
enddo ! do irocker=1,nrocker
! Draw toepick.
call WriteBlank
call ReadInt('# of toepick teeth',nPick,4)
do iPick=1,nPick
call WriteBlank
print'(a,i0,a)','***Toepick tooth# ',iPick,'***'
write(2,'(a,i0,a)')'% ***ToePick #',iPick,' from back***'
if(iPick.eq.1)print'(a)','This is the drag pick!'
if(ipick.eq.nPick)print'(a)','This is the frontmost tooth!'
if(iPick.eq.1)then
print*,' '
print'(a)','If the drag pick points forwards from the curve,'
print'(a)','The following angle is >90 deg, else it''s <=90.'
call ReadFlt('Angle from curve to drag pick(140?)',angle,140.)
! print'(a,g0)','Direction angle of curve end=',Theta2+90
Theta2=angle+(Theta2+90-180) ! Turn into angle to draw back edge
! of drag pick from current x,y.
! print*,'back edge direction=',Theta2
DefaultTAng=70 ! (Applies to other teeth)
DefaultTLen=.25
else ! if(iPick.eq.1)then
DefaultTAng=70
call ReadFlt('Degrees from last tooth to this tooth',angle,DefaultTAng)
Theta2=angle+(Theta2-180) ! Turn into angle to draw back edge of
! that tooth from current x,y
! print*,'Theta2 for this tooth=',Theta2 !##
endif ! if(iPick.eq.1)then
! Draw back of that tooth.
call ReadFlt('Length of back of that tooth',PickLen,DefaultTLen)
write(2,'(a,g0,a,g0,a)') &
& '% *Angle to back of tooth=',angle,' Length=',PickLen,'*'
call LineTo(x+PickLen*cosd(Theta2),y+PickLen*sind(Theta2))
call ReadFlt('Degrees in angle at bottom of tooth',angle,DefaultTAng)
Theta2=(Theta2+180)-angle ! Turn into angle to draw front edge
! of current tooth from current x,y
! print*,'Theta2 for front edge=',Theta2 !##
call ReadFlt('Length of front of that tooth',PickLen,DefaultTLen)
! Draw front of the tooth
write(2,'(a,g0,a,g0,a)') &
& '% *Angle to front of tooth=',angle,' length ',PickLen,'*'
call LineTo(x+PickLen*cosd(Theta2),y+PickLen*sind(Theta2))
enddo ! do iPick=1,nPick
print*,' '
if(io.eq.0)write(1,*)' '
call WriteBlank
call ReadFlt('Height of runner(0 to not draw top? 1?)',Height,1.)
if(Height.gt.0)then
if(Height.lt.ymax)stop 'Height cannot be shorter than part of the blade!'
xSave=x
ySave=y
write(2,'(a)')'% ***Draw top of blade runner***'
call MoveTo(xmin,SaveHeight1) ! Height is measured over back sweet spot
call LineTo(xmin,SaveHeight1+Height)
call LineTo(xSave,SaveHeight1+Height)
call LineTo(xSave,ySave)
endif
call WriteBlank
write(2,'(a)')'% ***Diagram Setup***'
write(2,'(a)')'} def'
write(2,'(a)')'1 setlinecap' ! Set shape of line ends for stroke
! (0=butt,1=round,2=square).
write(2,'(a)')'1 setlinejoin' ! Set shape of corners for stroke
! (0=miter,1=round,2=bevel).
print*,'*** Setup Drawing Geometry ***'
print*,'Horizontal Blade length=',xmax-xmin
print'(a)','Add boundary lines & 1" tics to let you check'
print'(a)','printer scaling, and whether the blade fits on page!'
call ReadFlt('Scaled Tic Length (inches) (0=none; .2?)',TicLen,.2)
call ReadFlt('Paper margin size (inches) (.5?)',TheMargin,.5)
xmin2=xmin-2*TicLen ! Allow space for tics
ymin2=ymin-2*TicLen
xmax2=xmax+2*TicLen
ymax2=ymax+2*TicLen
if(TicLen.gt.0)ymax2=max(ymax2,ymin+1.001)! (I always draw at least 2 tics,
! so can check y scaling too.)
print'(a)','To print blade + Tics (if chosen) + margins at full'
print'(a,g0,a,g0,a)','scale takes ', &
& xmax2-xmin2+TheMargin*2,' x ',ymax2-ymin2+TheMargin*2,' inches.'
print*,'Depending on paper size, that may fit with'
print*,'no rotation, 90 degree rotation, or, if you are desperate,'
print*,'diagonal rotation. Typical X x Y paper sizes are'
print*,'8.5"x11" (Letter), 8.5"*14" (Legal), 11"x17" (Tabloid),'
print*,'Ghostview supports all of those, e.g.,'
print*,' gv -media=Letter DrawBlade.ps'
print*,' gv -media=Legal DrawBlade.ps'
print*,' gv -media=Tabloid DrawBlade.ps'
print*,'(See [Link removed] for other size names)'
print*,' but many printers don''t.'
print*,' If you just want coordinates to guide a CAD'
print*,'program, just use pretend sizes that are a little larger'
print*,'than the blade.'
call ReadFlt('X-axis paper size(8.5?)',xPap,8.5)
call ReadFlt('Y-axis paper size(11?)' ,yPap,11.)
print*,'Somewhat longer blades fit with diagonal rotation.'
write(2,'(a,g0,a,g0,a)')'% *** This plot is designed for ',xPap,' x ',yPap,' Paper.***'
write(2,'(a,g0,1x,g0,a)')'<< /PageSize [',xPap*72,yPap*72,'>> setpagedevice'
call ReadInt('Rotation angle(0? 90? -1 to try diagonal fit)',irotate,90)
print*,'If you think the blade won''t fit at full scale, scale it by'
print*,'.5, and use a fancy photocopier to zoom it back out.'
call ReadFlt('Scale factor(1? .5?)',scale,1.)
write(2,'(a,g0,a)')'% Scale by ',scale,'*72 from Postscript 1/72 inch units.'
write(2,'(g0,1x,g0,a)')72*scale,72*scale,' scale'
call ReadFlt('Line width (inches) (.01?)',WidLin,.01)
write(2,'(g0,a)')WidLin/scale,' setlinewidth' ! Graphics line width in 1/72 inch (point) units.
call SetGeometry(TheMargin,xmin2,xmax2,ymin2,ymax2,xPap,yPap, &
& irotate,scale)
print '(2(a,g0,1x,g0))' ,&
& '%Blade boundaries x: ',xmin,xmax,' y: ',ymin,ymax
write(2,'(2(a,g0,1x,g0))') &
& '%Blade boundaries x: ',xmin,xmax,' y: ',ymin,ymax
write(2,'(a)')'MyPath stroke'
if(TicLen.ne.0)then
call WriteBlank
write(2,'(a)')'% ***X-axis & tic marks at scaled 1 inch intervals***'
! draw dropped x-axis & corners
call DrawSeg(xmin,ymin-1.5*TicLen,xmax,ymin-1.5*TicLen)
call DrawSeg(xmin,ymin-1.5*TicLen,xmin,ymin- .5*TicLen)
call DrawSeg(xmax,ymin-1.5*TicLen,xmax,ymin- .5*TicLen)
!do xx=xmin,xmax+.0001 ! Draw x tics at scaled 1 inch intervals
do i=0,ifix(xmax-xmin+.0001) ! Some may go beyond page boundaries.
xx=xmin+i
call DrawSeg(xx,ymin-2*TicLen,xx,ymin-1.5*TicLen)
enddo
write(2,'(a)')'% ***Y-axis & tic marks at scaled 1 inch intervals***'
! Draw left shifted y-axis & corners.
! Extend tic range to include more.
call DrawSeg(xmin-1.5*TicLen,ymin,xmin-1.5*TicLen,ymax)
call DrawSeg(xmin-1.5*TicLen,ymin,xmin- .5*TicLen,ymin)
call DrawSeg(xmin-1.5*Ticlen,ymax,xmin- .5*TicLen,ymax)
! Draw right shifted y-axis & corners
call DrawSeg(xmax+1.5*TicLen,ymin,xmax+1.5*TicLen,ymax)
call DrawSeg(xmax+1.5*TicLen,ymin,xmax+ .5*TicLen,ymin)
call DrawSeg(xmax+1.5*Ticlen,ymax,xmax+ .5*TicLen,ymax)
!do yy=ymin,max(ymax,ymin+20)-ymin ! Draw y tics at scaled 1 inch intervals.
do i=0,ifix(max(ymax,ymin+20)-ymin) ! Some may go beyond page boundaries.
yy=ymin+i
call DrawSeg(xmin-2*TicLen,yy,xmin-1.5*TicLen,yy)
call DrawSeg(xmax+2*TicLen,yy,xmax+1.5*TicLen,yy)
enddo
endif
call WriteBlank
write(2,'(a)')'% ***Finished!***'
write(2,'(a)')'showpage' ! prints the prepared page.
close(1)
close(2)
stop 'DrawBlade completed successfuly.'
end
! --------------------------------------------------------------------------------------
subroutine ReadInt(Prompt,num,iDefault) ! Read prompted integer, echo to parameter
! File, or to screen if from file.
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
character*(*) Prompt
1 num=iDefault
if(io.eq.0)then
print'(a)',prompt//':'
print'(a,i0,a)','Enter / for default=',iDefault,')'
read*,num
write(1,'(i17,6x,a)')num,prompt
else
print'(a,$)',prompt//':' ! Print prompt first, in case of i/o error.
read(1,*,end=99)num
print'(i0)',num
endif
return
99 print*,'*****Parameter file too short - continue editing from keyboard!*****'
io=0
open(1,access='append')
goto 1
end
! --------------------------------------------------------------------------------------
subroutine WriteBlank ! Prints blank line on screen, parameter
! file (if io.eq.0), and postscript.
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
print*,' '
if(io.eq.0)write(1,*)' '
write(2,*)' '
return
end
! --------------------------------------------------------------------------------------
subroutine Readflt(Prompt,val,Default) ! Similar for float point
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
character*(*) Prompt
1 val=Default
if(io.eq.0)then
print'(a)',prompt//':'
print'(a,g0,a)','(Enter / for default=',Default,')'
val=Default
read*,val
write(1,'(g21.9,2x,a)')val,prompt
else
print'(a,$)',prompt//':'
read(1,*,end=99)val
print'(g0)',val
endif
return
99 print*,'*****Parameter file too short - continue editing from keyboard!*****'
io=0
open(1,access='append')
goto 1
end
! --------------------------------------------------------------------------------------
subroutine MinMaxEndxy(xx,yy)
! Revise xmin,ymin,xmax,ymax,x,y to include (xx,yy)
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
xmin=min(xmin,xx)
ymin=min(ymin,yy)
xmax=max(xmin,xx)
ymax=max(ymax,yy)
x=xx
y=yy
!print*,'MinMaxEndxy ',xx,yy,' xymin=',xmin,ymin,' xymax=',xmax,ymax !##
return
end
! --------------------------------------------------------------------------------------
subroutine MoveTo(xx,yy) ! Move to xx,yy, to path.
write(2,'(g0,1x,g0,a)')xx,yy,' moveto'
call MinMaxEndxy(xx,yy) ! Revise xmin,ymin,xmax,ymax,x,y.
return
end
! --------------------------------------------------------------------------------------
subroutine LineTo(xx,yy) ! Similar, but draw line
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
write(2,'(g0,1x,g0,a)')xx,yy,' lineto'
call MinMaxEndxy(xx,yy)
return
end
! --------------------------------------------------------------------------------------
! Draw CCW circular arc to path.
subroutine DrawArc(xCenter,yCenter,R,theta1,theta2)
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
! Input parameters:
! xCenter,yCenter=center of circle
! R=radius of circle
! theta1,theta2=Angle range. Theta1.lt.theta2, and both must be in [-180 to 0] deg.
! xmin,ymin,xmax,ymax = min, max x & y (from previous values)
! Modified parameters:
! xmin,ymin,xmax,ymax = min, max x & y (including these values)
! x,y=ending x,y
write(2,'(5(g0,1x),a)')xCenter,yCenter,R,theta1,theta2,'arc'
call MinMaxEndxy(xCenter+R*cosd(theta1),yCenter+R*sind(theta1))
if(iExtra.ne.0)then ! Extra: draw radius lines
write(2,'(a)')'% ***Next 3 lines are radius lines, not part of blade***'
write(2,'(g0,1x,g0,a)')xCenter+R*cosd(theta1),yCenter+R*sind(theta1),' moveto'
write(2,'(g0,1x,g0,a)')xCenter,yCenter,' lineto'
write(2,'(g0,1x,g0,a)')xCenter+R*cosd(theta2),yCenter+R*sind(theta2),' lineto'
endif
! Include bottom of circle in min,max
if(theta1.lt.-90.and.theta2.gt.-90) &
&call MinMaxEndxy(xCenter+R*cosd(-90. ),yCenter+R*sind(-90. ))
call MinMaxEndxy(xCenter+R*cosd(theta2),yCenter+R*sind(theta2))
return
end
! --------------------------------------------------------------------------------------
subroutine DrawSeg(x1,y1,x2,y2) ! Draw line segment outside path,
! but don't change min,max x,y values
write(2,'(a,g0,1x,g0,a,g0,1x,g0,a)') &
& 'newpath ',x1,y1,' moveto ',x2,y2,' lineto stroke'
end
! --------------------------------------------------------------------------------------
! Setup rotation, and translation,
! so everything fits.
subroutine SetGeometry(TheMargin,xmin2,xmax2,ymin2,ymax2,xPap,yPap, &
& irotate,scale)
real R(2,2) ! Rotation matrix
real x1(2), x2(2), x3(2), x4(2) ! Corners of zone box x4 x3
! x1 x2
real xp1(2),xp2(2),xp3(2),xp4(2) ! Same after rotation.
!print*,'SetGeometry Margin=',TheMargin,' xmin2max2=',xmin2,xmax2, &
! &' ymin2max2=',ymin2,ymax2,' xyPap=',xPap,yPap, &
! & 'irotate=',irotate,'scale=',scale ! ##
x1=(/xmin2,ymin2/) ! Corners of coordinate range box.
x2=(/xmax2,ymin2/) ! With tic borders.
x3=(/xmax2,ymax2/)
x4=(/xmin2,ymax2/)
!print*,'x1=',x1 !##
!print*,'x2=',x2 !##
!print*,'x3=',x3 !##
!print*,'x4=',x4 !##
if(irotate.gt.90.or.rotate.lt.-1)then
stop 'Rotation angle must be between 0 and 90!'
elseif(irotate.ge.0.and.irotate.le.90)then
i1=irotate
i2=irotate
elseif(irotate.eq.-1)then
i1=0
i2=90
else
stop 'Invalid rotation angle!'
endif
do i=i1,i2 ! Search through rotations.
rotate=i
if(rotate.eq.0)then ! Exact 0 or 90 degree rotation matrix exactly.
R=reshape( (/1,0,0,1/),(/2,2/) )
elseif(rotate.eq.90)then
R=reshape( (/0,1,-1,0/),(/2,2/) )
else ! Otherwise calculate rotation matrix
R=reshape( (/cosd(rotate),sind(rotate),-sind(rotate),cosd(rotate)/),(/2,2/) )
endif
!print*,'R= ',R
!print*,'calculated',reshape( (/cosd(rotate),sind(rotate),-sind(rotate),cosd(rotate)/),(/2,2/) )
! Calculate rotated corners
xp1=scale*matmul(R,x1) ! Inefficient - I don't use them all.
xp2=scale*matmul(R,x2) ! I don't care.
xp3=scale*matmul(R,x3) ! "p" means prime, i.e., rotated.
xp4=scale*matmul(R,x4)
!print*,'xp1=',xp1 !##
!print*,'xp2=',xp2 !##
!print*,'xp3=',xp3 !##
!print*,'xp4=',xp4 !##
!print*,' ' !##
! Rotated box geometry for 0<=rotate<=90
! xp3
! xp4
! xp2
! xp1
xpmin2=xp4(1) ! Minimum and maximum rotated limits.
xpmax2=xp2(1)
ypmin2=xp1(2)
ypmax2=xp3(2)
!print*,'xpminmax2=',xpmin2,xpmax2,'ypminmax2=',ypmin2,ypmax2 !##
! Does it fit on the page?
if(xpmax2-xpmin2.le.xPap-2*TheMargin.and. &
& ypmax2-ypmin2.le.yPap-2*TheMargin) goto 10
enddo
stop 'Sorry! Does not fit on requested page size.'
10 print '(a,g0,a)','Rotation angle=',rotate,' works!'
! Final coordinate transformation will be
! scale*(Xp matmul + A); I now find A)
print*,'Left alignment seems intuitive, maybe can print on small width paper.'
print*,'But right alignment may show more of radius lines.'
iDefault=2
call ReadInt('1=Left Align,2=Right Align)',i,iDefault)
if(i.eq.1)then ! scale*(xpmin2+Ax)=TheMargin
Ax=TheMargin/scale-xpmin2
! print*,'Ax=',TheMargin,'/',scale,'-',xpmin2,'=',Ax !##
else ! scale*(xpmax2+Ax)=xPap-TheMargin
Ax=(xPap-TheMargin)/scale-xpmax2
! print*,'Ax=','(',xPap,'-',TheMargin,')/',scale,'-',xpmax2,'=',Ax !##
endif
!print*,'Ax=',Ax !##
Ay=TheMargin/scale-ypmin2 ! Always use Bottom alignment.
! scale*(ypmin2+Ay)=TheMargin
! print*,'Ay=',TheMargin,'/',scale,'-',ypmin2,'=',Ay
if(Ax.ne.0.or.Ay.ne.0)write(2,'(g0,1x,g0,a)') Ax,Ay,' translate'
! I thought that rotate should come
! before translate, but that doesn't
! seem to work. This does. Which means
! there is something about Postscript
! that I don't understand.
write(2,'(a,g0)')'% Rotation angle=',rotate
if(rotate.ne.0)write(2,'(g0,a)')rotate,' rotate'
return
end
====================================================================
-- _ToDo.rtf A list of things about DrawBlade that could be improved --
1. I didn't take into account the width of the lines. In particular if I try to cut with a jig saw on the outside (rather than the center) of the printed lines, that would distort the shape, especially of the toe picks. Perhaps the suggested line width should be adjusted too, to be easier to read.
2. I don't know how and if CAD programs deal with that - whether, when inputing Postscript, and/or images, they take that into account, when creating computer guided cutting and drilling instructions.
3. I can't afford AutoCAD, but there are free CAD programs I could play with that could maybe teach me how they are used. The ones I have looked up on the web so far can't take in postscript. But some of them might take in PDFs - and there are free tools to convert Postscript to PDF.
4. Likewise, a CAD program would need to take into account the width of the cutting tool. Again, I don't know if CAD programs take that into account.
5. I need an option to extend the cut lines at toepick corners, so I can cut them more accurately. And I don't know whether CAD programs do that either.
6. Some blades will be too long to fit on printed paper. So scale down by a factor of two. And/or split the diagram in two, with clear marked points to tape the printed pages together.
7. I need to add the mounting chassis. And add countersunk mounting holes.
Some of these could be fixed in a few days. But learning about CAD/CAM programs, would take longer. Sorry for the delay. But there are also issues regarding the possible breakage of expensive CNC milling machines - which scare me. Maybe CAD/CAM support isn't needed for my purposes. I only started to worry about it, because the only person who responded to me wanted to use AutoCAD.
8. Need to measure position of runner wrt to staunchions and/or something else, like the front of the mounting plate.
9. Be able to adjust Blade size - but usually that just means changing the main rocker length in the parameter file.
10. Evaluate heel lift, and the height of the (back) sweet spot wrt the height of the drag pick (also called scratch pick), and the height of the top toepick tooth when the back toepick tooth barely touches. These are good checks on measured shapes, if one initially wants to imitate an existing blade. But eventually, one should design one's one. E.g., reshape the rocker profile and toepick to match your personal anatomy and preferences.
11. Discuss hardening, shimming to fit the outsole and heel with a cut hockey puck or equivalent.
====================================================================
====================================================================
-- DrawBlade.txt -- The parameter file it generated during the sample run. This is a text file that you can edit to make minor modifications, and the program has an option to read from it. Note that I chose an extra wide line width, and to draw radial lines. I also chose to draw 1 inch tic marks along the x and y axis. These are needed because many printer apps don't scale things correctly by default. For my example I chose 8.5x14 inch size paper, because the sample blade shape was too long to fit on letter size paper.
--contents--
DrawBlade.ps
1 Add arc radius lines for illustrations(0=no? 1?)
3 # of rocker length segments(2? 3?)
96.0000000 Rocker radius (inches)
8.00000000 Curved length of rocker segment (inches)
0.00000000 x value of leftmost point on blade(0?)
0.00000000 y value of lowest point on blade (0?)
27.0000000 Rocker radius (inches)
1.50000000 Curved length of rocker segment (inches)
12.0000000 Rocker radius (inches)
1.00000000 Curved length of rocker segment (inches)
4 # of toepick teeth
140.000000 Angle from curve to drag pick(140?)
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
70.0000000 Degrees from last tooth to this tooth
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
70.0000000 Degrees from last tooth to this tooth
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
70.0000000 Degrees from last tooth to this tooth
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
1.00000000 Height of runner(0 to not draw top? 1?)
0.200000003 Scaled Tic Length (inches) (0=none; .2?)
0.500000000 Paper margin size (inches) (.5?)
8.50000000 X-axis paper size(8.5?)
14.0000000 Y-axis paper size(11?)
90 Rotation angle(0? 90? -1 to try diagonal fit)
1.00000000 Scale factor(1? .5?)
0.299999993E-01 Line width (inches) (.01?)
2 1=Left Align,2=Right Align)
====================================================================
-- DrawBlade.ps --
The principle output file, containing Postscript text commands from that sample run. Clearly labelled to be human readable. You could look at it to see parameters that you would need to guide a CAD program. Program that display it need to be told the paper size is 8.5"x14" or larger. And some programs would be confused because some of the line segments are outside that boundary...
Omitted for brevity.
====================================================================
DrawBlade.png
An image file created by an old version of Paintshop Pro from DrawBlade.ps. Many other programs, like GhostView, can make such conversions.
====================================================================
DrawBlade_labeled.png
Similar, but I edited it to add explanatory remarks on the input parameters used by DrawBlade.
====================================================================
rocker.png
A printable set of circular arcs with typical rocker curvatures generated by my [Link removed]IDL language rockerprofiles.pro program...
====================================================================
I have other rocker curve images that I now prefer produced by my DrawArcs program. Without getting into details these include:
====================================================================
DrawArcs is a program to draw skate blade rocker curves, with length scales along each curve, and straight line inch scales along the boundaries and centerline.
====================================================================
-- DrawArcs1.txt
The parameter file it generated during a run. This is a text file that you can edit to make minor modifications, and the program has an option to read from it.
This run includes rocker radii radii 6" - 108" at 3 inch intervals.
--contents--
DrawArcs1.ps
0.010000000 Line width (inches) (.01?)
0.550000000 Margin Size(.51?)
8 # of rocker curves/inch(8?)
108.000000 Highest rocker length(108?)
3.00000000 Rocker Length Decrement(3?)
====================================================================
DrawArcs.ps The principle output file, containing Postscript text commands from that
run. Labelled to be human readable, though it is a bit long.
ghostview can display it with
gv -media=Letter DrawArcs1.ps
====================================================================
DrawArcs1.png An Image file prepared from same.
====================================================================
There are similar files for other intervals:
DrawArcs2.txt for 6" - 30" at 1 inch intervals
DrawArcs2.ps
DrawArcs2.png
DrawArcs3.txt for 8" - 18" at 1 inch intervals, but more widely spaced, so you can more clearly see the radial line directions.
DrawArcs3.ps
DrawArcs3.png
====================================================================
I planned to attach the images. But for some reason the board won't let me. I could maybe attach them as links. But the moderator said not to include any links.
I've been having a discussion elsewhere about making your own figure skating blades, and have made some progress towards designing software to do part of it.
I'd like to get feedback here too. The GoldenSkate administrators say I have to remove all external links, so I have done so, and attached relevant images. Since this board doesn't let me attach anything, I have included things inline here
I would love any feedback you folks could give me, on how practical it would be, since I have little craft experience, and almost none working with metals.
====================================================================
title: DrawBlade program to draw figure skating blade runners.
Mitch Grunes's DrawBlade program to draw figure skating blades.
This was part of an idea for making one's own blades.
The idea is to attach the printed shapes created using my DrawBlade program to a piece of sheet steel (also called a bar) of the right thickness, cut around it with a jig saw. In later iterations, my idea was to use a strip cutting jig and an improvised circle cutting jig (made from a long thin wooden board with nails in it), to make the cuts smooth and clean. With a more little work I could move the lines so you could cut on the outside of the line, rather than the center, and I could extend the cut lines, to simplify cutting. Some jigsaws can be adjusted to cut cross picks instead of straight cut picks, but I haven't addressed that.
I guess one needs a milling machine to narrow the working part of the blade to the exact desired thickness?
Early prototypes for individual testing would use cheap steel, final versions would use more expensive steel (like 440C stainless steel), and the edge would be hardened with a torch.
The resulting blade runner (or the runner and toe pick separately) would be bolted using right-angle aluminum channels onto an aluminum mounting plate. I could modify mark the positions of a bunch of (countersink) holes in the runner and toepick so they could be mounted at various heights, and at various forward/backward tilts (or alternately, various forward/backward positions) depending on which holes you use.
I also explored the idea of using other software to generate an image file, a PDF, and a DXF (to import into CAD/CAM software, to guide CNC hardware, like a milling machine, instead of cutting with a jig saw).
====================================================================
My definitions of blade terms, and alternate definitions
There is no standardization of definitions of terminology for blades.
So let me clarify my usage of "rocker", "rocker radius", "sweet spot", and the front and back toepick teeth:
The bottom part of most blades, but not including the toe picks for figure skates, has a long-wise curved shape, or sequence of several segments of curved shape, that I any many other people call the "rocker profile." But some people refer to that entire section as the "rocker". ("segment" is my terminology for this idea, not used by anyone else I know, so no one else should complain - I hope.)
Nordic skates are designed for cross-country skating or for skating on large ponds, lakes, canals and streams. They typicall have no curvature on the bottom of the blade, which is the fastest design for skating in a straight line. This program is not currently designed to draw those blades. There is no "rocker" or sweet spot of any type.
Skating on vertically curved blade bottoms (segments with "rocker curvature") makes it easier to do turns and spins, but pushing and stopping are less effective. The more rocker curvature (which means the smallest rocker radius) glide in straight lines less easily, resulting in slower speeds when skating straight.
Most short and long track speed skating blades have a single fairly long radius of curvature. Typically in the 18-23 foot range. It helps them skate around the curved arcs of the track, which are very gradual curves. Incidentally, those blades are also horizontally warped, or can be adjusted to be, which helps too, because they always skate in a CCW (counterclockwise) direction. They call the radius of curvature the "rocker" or "rocker radius". E.g., some speed skaters say "23' rockers" are best. (I'm not sure if that is specific to long track speed skating??)
Modern hockey blades typically continuously vary the radius of curvature (although older hockey rocker profiling machines varied curvature in many small steps; maybe some blades are still made that way??). The innermost parts are least curved, and are most effective to push, stop, and change irection. One also glides there to minimize friction, and go fast. But the ends are very curved, so they can do fast turns.
Offsensive hockey skaters (who mostly skate forwards) often modify their blades (or have a skate tech modify them - often using a profiling machine such as are made by CAG) so the position the least curved part is a mm or two forwards of the blade center. Defensive hockey skaters (who mostly skate backwards) often position it a mm or two backwards of the blade center. According to Blademaster, the leading manufacturer of powered sharpening machines, when skating on large skating rinks (Olympic size or larger), some agressive skaters chose profiles with a no rocker curvature in the center, which they call a "flat", so they can skate and stop and change directions while going very fast.
All figure skate blades I know of are divided into several segments with different fixed radii of curvature on the bottom part of the blade.
Traditionally MK (Originally made by Mitchel & King Blades), Ultima (made by or for Jackson Skates) blades have 2 segments. Usually JW (originally made by John Wilson Skates) have 3 segments. (MK and JW are now owned by the same company, HD Sports, and I think the blades are manufactured by the same production line in Sheffield, England. But they still use different trade names for different blade models.) Paramount and some other companies tend to roughly imitate both their designs, with some differences. There are other minor brands. The most expensive HD Sports blades tend to dominate high level competitions, in part because if a skater wins a medal at such a competition, and are using something else, they often give them a free MK or JW blade. (E.g., someone told me that Irina Slutskaya won a medal at a World level competition in Club 2000 blades. They are made by MK, but are often considered beginner level blades, and cost more than an order of magnitude less than the top blades. So she was given a more expensive pair of blades free.) Perhaps they sometimes also sponser them. And they occaisionally give away blades to influential coaches and figure skating directors. Their blades are not cheap. I would love to have MK Dance blades, and used to, but at my skating level and budget, I can't justify it. Oh well.
The main length of the blade, in the back, is the least curved, and is what I call the "main rocker" segment. But "main rocker" is also used by some others to describe its radius of curvature. E.g., traditionally, MK blades had a 7' main rocker radius, and JW had an 8' main rocker radius. The part of of the blade forward of what I call the main rocker segment is called the "spin rocker", though that may also refer to the radius(es) of curvature of that segment, or those segments. Because it is more curved, it is used for spins and forward-to-backwards turns. (Where backwards-to-forwards turns are best done varies according to different coaches.)
For 3 segment blades made by JW, there is a complication I don't understand: When skating on the forward transition point between the main rocker and the back spin rocker ("forward sweet spot" by my definition), the toe pick touches. Which means you can barely use the forward spin rocker segment at all - and not at all after a very few sharpenings, unless you keep trimming the back toe pick. Thus the forward spin rocker section becomes virtually useless. It only touches during high jumps and jump landings, when the blade is pushed deep into the ice, or on very soft, warm ice.
I think a few figure skating blades have been designed with another spin-rocker segment in the back. (Of course, some blades have an accidental such segment caused by poor sharpening techniques.)
I call the point(s) along the length of figure skating blades where the rocker curvature changes "sweet spot(s)".
"Sweet spot" was used that way by a skate tech trusted (Don Giese, a speed/figure/hockey coach, and onetime masters class USA speed skating champion at several distances. He sold me my first boots & blades, as well as a skate sharpening toolkit, and inline skates, and was the first person to do a good job sharpening my blades. AFAICT, it was also the way skate tech Mike Cunningham (who had many world class customers, and was many times the USFSA official skate sharpener at International events like the Olympics) used it. (I say that because he talked about the desirability of changing the rocker profile to move "the sweet spot", as though it were a single point. (He kindly allowed me to watch him work one day/week for a few months.)
But some people in the skating community use "sweet spot" to refer to the entire spin rocker segment, or group of segments, even if some of them are in the section of the blade that can't be skated on, because the toe pick gets in the way - which seems to be true of the forward segment of JW blades. And some use "sweet spot" to refer to the entire segment or specific point that a particular skater or coach does a specific spin or turn on. In general, and in sports, "sweet spot" often refers to an optimal point or position.
User tstop4me keeps complaining about my usage of "sweet spot", because he says it confuses skaters whose coaches or skate techs use it differently.
The front part of a figure skating blade, the "toepick" (or toe pick in some people's lingo) consists of several sharp teeth. It is sometimes used to do forward-to-backward turns (usually called forward turns), scratch spins, forward jumps (which start moving and facing forwards), backward jumps, and pivots (except some usual and difficult pivots and spins are done off the "tail" (the back part of the blade). What I call the "drag pick" (or back toepick tooth), some people call the "scratch pick." What I call the "frontmost pick", some people call the "king pick". Apparently some people can sometimes reach it. In a few cases (specifically certain ice dance blades, like the most popular MK Dance) the drag pick is blunted instead of sharp.
[Link removed _ExternalDiscussion.rtf [NOT Included here. Among other things, someone with machinist/engineering skills responded, and indicated I should try to produce a file format that CAD/CAM software could import
WilsonbladeRadius.JPG An old image (I'm not sure where I got it) showing typical rocker radiuses for MK and JW blades at that time. Note that some sources give a 27 inch instead of the 2 foot back spin rocker for many JW blades that this image lists. In addition, some sources give 12 inches instead of 9 inches for the MK spin rocker.
7foot.png: image of 7 foot rocker section cropped out of rocker.png
9inch.png: Similar for 9 inch rocker
sweetspot.png: Shows how two rocker segment of different rocker radii can be cleanly pasted together. The idea is that the tangent lines are the same at the boundary. Or equivalently that the radial lines are the same.
sweetspot2.png: Similar, but labelled.
====================================================================
--- FILE DrawBlade.f90 --- (Fortran 90 free format source code for my software)
! Program DrawBlade Draws a skating blade runner using postscript.
! The intention was so I could try to make my own blades.
! See [Link removed] for more info.
! It is mostly for figure skating blades, but could be used for
! hockey and speed skating blades.
!
! Written by Mitchell Grunes.
! This is a free format fortran 90 program.
! Cygwin or linux compiles this using
! gfortran -Wall DrawBlade.f90 -o DrawBlade
! Cygwin produces executable DrawBlade.exe; Linux produces DrawBlade.
! Postscript language reference: [Links removed]
! Can convert postscript to PDF using [Links removed]
! Can possibly convert postscript to Cad format using a free Cad
! program, like [Links removed]
! Or FreeCAD. [Link removed] Says it can import PDF.
! Or LibreCad? [Link removed]
! Doesn't appear able to import postscript or pdf.
! Or LinuxCAD?
! And search google for "Free 2D CAD software like AutoCAD"
! Or maybe use [Link removed] pstoedit to convert postscript to DXF?
! [Link removed] thandxflib describes a fortran
! library to write DXF.
! [Link2 removed]
! [Link removed]
! has instructions on using lpr to print postscript files
! Perhaps I should use
! [Link removed]
! to instead write PDF files?
! Or
! [Link Removed]
! to create a DWG file?
! not used yet:
! x1 y1 x2 y2 r arct Draw tangent arc. (To create rounded corner.)
! For my definitions of technical terms (there is no standardization!), like
! "rocker", "rocker segment", spin rocker, sweet spot, and toe pick tooth names,
! see file index.html.
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
character*100 ParmFile,PsFile ! Name of BladeDraw & Postscript files.
print*,'Enter 1 to input from blade parameter file, 0 to make a new one:'
io=1
read*,io
if(io.eq.0)print*,'Blade parameter file (Enter blank for "DrawBlade.txt") to write:'
if(io.ne.0)print*,'Blade parameter file (Enter blank for "DrawBlade.txt") to read:'
read(*,'(a)')ParmFile
if(ParmFile.eq.' ')ParmFile='DrawBlade.txt'
print*,'ParmFile=',ParmFile
if(io.eq.0)open (1,file=ParmFile,status='new',err=1)
if(io.ne.0)open (1,file=ParmFile,status='old')
goto 2
1 print*,'File already exists - overwrite(0=no,1=yes?):'
i=0
read*,i
if(i.eq.0)stop 'Cannot continue'
if(io.eq.0)open (1,file=ParmFile,status='unknown')
2 print*,'Output postscript file (Enter blank for "DrawBlade.ps"):'
if(io.eq.0)then
read(*,'(a)')PsFile
if(PsFile.eq.' ')PSFile='DrawBlade.ps'
write(1,'(a)')PSFile
else
read(1,'(a)')PSFile
if(PsFile.eq.' ')PSFile='DrawBlade.ps'
endif
print*,'PsFile=',PSFile
open (2,file=PsFile,status='unknown')
write(2,'(a)')'%!PS' ! So print spools detect start of file
write(2,'(a)')'% ***Figure Skating Blade Profile created by Mitch Grunes''s DrawBlade***'
call WriteBlank
call ReadInt('Add arc radius lines for illustrations(0=no? 1?)',iExtra,1)
xmin=1e20 ! Initialize x,y min,max in inches.
ymin=1e20
xmax=-1e20
ymax=-1e20
print*,'Some MK blades have 1 main rocker and 1 spin rockers.'
print*,' (7 foot=84" main rocker, 9" spin rocker)'
print*,'Many JW blades have 1 main rocker and 2 spin rockers.'
print*,' (8 foot=96" main rocker, 27" (24"??) & 12" spin rockers)'
call ReadInt('# of rocker length segments(2? 3?)',nRocker,2)
write(2,'(a)')'/MyPath newpath {'
do iRocker=1,nRocker
call WriteBlank
print'(a,i0,a)','***Rocker #',iRocker,'***'
if(iRocker.eq.1)then
print'(a)','This is the main rocker segment!'
elseif(iRocker.eq.2.and.nRocker.gt.2)then
print'(a)','This is the backmost spin rocker segment!'
elseif(iRocker.eq.nRocker.and.nRocker.eq.2)then
print'(a)','This is the spin rocker segment!'
elseif(iRocker.eq.nRocker.and.nRocker.gt.2)then
print'(a)','This is the frontmost spin rocker segment!'
else
print'(a)','This is an intermediate spin rocker segment!'
endif
if( iRocker.eq.1)DefaultR=84
if( iRocker.eq.2)DefaultR=9
if(nRocker.eq.3.and.iRocker.eq.1)DefaultR=96
if(nRocker.eq.3.and.iRocker.eq.2)DefaultR=27
if(nRocker.eq.3.and.iRocker.eq.3)DefaultR=12
call ReadFlt('Rocker radius (inches)',R,DefaultR)
if(iRocker.eq.1)print'(a)',&
& 'Rocker segment lengths are measured along curve, not straight!'
call ReadFlt('Curved length of rocker segment (inches)',ArcLength,8.)
DeltaTheta=ArcLength/R*180/3.1415926535897932 !Angle width from center, in degrees
! print*,'deltaTheta=',deltatheta !##
if(iRocker.eq.1)then
Theta2=-90 ! Make Place 1st "sweet spot" (intersection of
! main rocker segment with first spin
! rocker segment) hoizontal, by making the
! tangent line vertical.
Theta1=Theta2-DeltaTheta ! Radial angle at start of main rocker
! segment.
call ReadFlt('x value of leftmost point on blade(0?)',x,0.)
x=x-R*cosd(theta1) ! 1st "sweet spot", by my definition
! (the intersection of main rocker segment
! with the first spin rocker segment).
xCenter=x ! Center of main rocker arc.
call ReadFlt('y value of lowest point on blade (0?)',y,0.)
yCenter=y+R
! print*,'deltaTheta=',deltatheta !##
! print*,'main rocker theta1=',theta1,'theta2=',theta2 !##
else
xCenter=x-R*cosd(theta2)
yCenter=y-R*sind(theta2)
Theta1=Theta2
Theta2=Theta2+DeltaTheta
! print*,'theta1=',theta1!##
! print*,'theta2=',theta2!##
endif ! if(iRocker.eq.1)then
! Draw main rocker circular arc to path.
print'(a,g0)','Direction angle of curve start=',Theta1+90
print'(a,g0)','Direction angle of curve end=',Theta2+90 !##
write(2,'(a,i0,a,g0,1x,g0,a,g0,a)') '% ***Rocker Segment ',iRocker, &
& ' Center=',xCenter,yCenter,' inches Radius=',R,'***'
write(2,'(a,g0,1x,g0,a)') '%***Angle range=',Theta1,Theta2,' deg***'
write(2,'(a,g0,a)') '% ***(Curved length=',ArcLength,')***'
call DrawArc(xCenter,yCenter,R,theta1,theta2)
If(iRocker.eq.1)SaveHeight1=yCenter+R*sind(theta1)
enddo ! do irocker=1,nrocker
! Draw toepick.
call WriteBlank
call ReadInt('# of toepick teeth',nPick,4)
do iPick=1,nPick
call WriteBlank
print'(a,i0,a)','***Toepick tooth# ',iPick,'***'
write(2,'(a,i0,a)')'% ***ToePick #',iPick,' from back***'
if(iPick.eq.1)print'(a)','This is the drag pick!'
if(ipick.eq.nPick)print'(a)','This is the frontmost tooth!'
if(iPick.eq.1)then
print*,' '
print'(a)','If the drag pick points forwards from the curve,'
print'(a)','The following angle is >90 deg, else it''s <=90.'
call ReadFlt('Angle from curve to drag pick(140?)',angle,140.)
! print'(a,g0)','Direction angle of curve end=',Theta2+90
Theta2=angle+(Theta2+90-180) ! Turn into angle to draw back edge
! of drag pick from current x,y.
! print*,'back edge direction=',Theta2
DefaultTAng=70 ! (Applies to other teeth)
DefaultTLen=.25
else ! if(iPick.eq.1)then
DefaultTAng=70
call ReadFlt('Degrees from last tooth to this tooth',angle,DefaultTAng)
Theta2=angle+(Theta2-180) ! Turn into angle to draw back edge of
! that tooth from current x,y
! print*,'Theta2 for this tooth=',Theta2 !##
endif ! if(iPick.eq.1)then
! Draw back of that tooth.
call ReadFlt('Length of back of that tooth',PickLen,DefaultTLen)
write(2,'(a,g0,a,g0,a)') &
& '% *Angle to back of tooth=',angle,' Length=',PickLen,'*'
call LineTo(x+PickLen*cosd(Theta2),y+PickLen*sind(Theta2))
call ReadFlt('Degrees in angle at bottom of tooth',angle,DefaultTAng)
Theta2=(Theta2+180)-angle ! Turn into angle to draw front edge
! of current tooth from current x,y
! print*,'Theta2 for front edge=',Theta2 !##
call ReadFlt('Length of front of that tooth',PickLen,DefaultTLen)
! Draw front of the tooth
write(2,'(a,g0,a,g0,a)') &
& '% *Angle to front of tooth=',angle,' length ',PickLen,'*'
call LineTo(x+PickLen*cosd(Theta2),y+PickLen*sind(Theta2))
enddo ! do iPick=1,nPick
print*,' '
if(io.eq.0)write(1,*)' '
call WriteBlank
call ReadFlt('Height of runner(0 to not draw top? 1?)',Height,1.)
if(Height.gt.0)then
if(Height.lt.ymax)stop 'Height cannot be shorter than part of the blade!'
xSave=x
ySave=y
write(2,'(a)')'% ***Draw top of blade runner***'
call MoveTo(xmin,SaveHeight1) ! Height is measured over back sweet spot
call LineTo(xmin,SaveHeight1+Height)
call LineTo(xSave,SaveHeight1+Height)
call LineTo(xSave,ySave)
endif
call WriteBlank
write(2,'(a)')'% ***Diagram Setup***'
write(2,'(a)')'} def'
write(2,'(a)')'1 setlinecap' ! Set shape of line ends for stroke
! (0=butt,1=round,2=square).
write(2,'(a)')'1 setlinejoin' ! Set shape of corners for stroke
! (0=miter,1=round,2=bevel).
print*,'*** Setup Drawing Geometry ***'
print*,'Horizontal Blade length=',xmax-xmin
print'(a)','Add boundary lines & 1" tics to let you check'
print'(a)','printer scaling, and whether the blade fits on page!'
call ReadFlt('Scaled Tic Length (inches) (0=none; .2?)',TicLen,.2)
call ReadFlt('Paper margin size (inches) (.5?)',TheMargin,.5)
xmin2=xmin-2*TicLen ! Allow space for tics
ymin2=ymin-2*TicLen
xmax2=xmax+2*TicLen
ymax2=ymax+2*TicLen
if(TicLen.gt.0)ymax2=max(ymax2,ymin+1.001)! (I always draw at least 2 tics,
! so can check y scaling too.)
print'(a)','To print blade + Tics (if chosen) + margins at full'
print'(a,g0,a,g0,a)','scale takes ', &
& xmax2-xmin2+TheMargin*2,' x ',ymax2-ymin2+TheMargin*2,' inches.'
print*,'Depending on paper size, that may fit with'
print*,'no rotation, 90 degree rotation, or, if you are desperate,'
print*,'diagonal rotation. Typical X x Y paper sizes are'
print*,'8.5"x11" (Letter), 8.5"*14" (Legal), 11"x17" (Tabloid),'
print*,'Ghostview supports all of those, e.g.,'
print*,' gv -media=Letter DrawBlade.ps'
print*,' gv -media=Legal DrawBlade.ps'
print*,' gv -media=Tabloid DrawBlade.ps'
print*,'(See [Link removed] for other size names)'
print*,' but many printers don''t.'
print*,' If you just want coordinates to guide a CAD'
print*,'program, just use pretend sizes that are a little larger'
print*,'than the blade.'
call ReadFlt('X-axis paper size(8.5?)',xPap,8.5)
call ReadFlt('Y-axis paper size(11?)' ,yPap,11.)
print*,'Somewhat longer blades fit with diagonal rotation.'
write(2,'(a,g0,a,g0,a)')'% *** This plot is designed for ',xPap,' x ',yPap,' Paper.***'
write(2,'(a,g0,1x,g0,a)')'<< /PageSize [',xPap*72,yPap*72,'>> setpagedevice'
call ReadInt('Rotation angle(0? 90? -1 to try diagonal fit)',irotate,90)
print*,'If you think the blade won''t fit at full scale, scale it by'
print*,'.5, and use a fancy photocopier to zoom it back out.'
call ReadFlt('Scale factor(1? .5?)',scale,1.)
write(2,'(a,g0,a)')'% Scale by ',scale,'*72 from Postscript 1/72 inch units.'
write(2,'(g0,1x,g0,a)')72*scale,72*scale,' scale'
call ReadFlt('Line width (inches) (.01?)',WidLin,.01)
write(2,'(g0,a)')WidLin/scale,' setlinewidth' ! Graphics line width in 1/72 inch (point) units.
call SetGeometry(TheMargin,xmin2,xmax2,ymin2,ymax2,xPap,yPap, &
& irotate,scale)
print '(2(a,g0,1x,g0))' ,&
& '%Blade boundaries x: ',xmin,xmax,' y: ',ymin,ymax
write(2,'(2(a,g0,1x,g0))') &
& '%Blade boundaries x: ',xmin,xmax,' y: ',ymin,ymax
write(2,'(a)')'MyPath stroke'
if(TicLen.ne.0)then
call WriteBlank
write(2,'(a)')'% ***X-axis & tic marks at scaled 1 inch intervals***'
! draw dropped x-axis & corners
call DrawSeg(xmin,ymin-1.5*TicLen,xmax,ymin-1.5*TicLen)
call DrawSeg(xmin,ymin-1.5*TicLen,xmin,ymin- .5*TicLen)
call DrawSeg(xmax,ymin-1.5*TicLen,xmax,ymin- .5*TicLen)
!do xx=xmin,xmax+.0001 ! Draw x tics at scaled 1 inch intervals
do i=0,ifix(xmax-xmin+.0001) ! Some may go beyond page boundaries.
xx=xmin+i
call DrawSeg(xx,ymin-2*TicLen,xx,ymin-1.5*TicLen)
enddo
write(2,'(a)')'% ***Y-axis & tic marks at scaled 1 inch intervals***'
! Draw left shifted y-axis & corners.
! Extend tic range to include more.
call DrawSeg(xmin-1.5*TicLen,ymin,xmin-1.5*TicLen,ymax)
call DrawSeg(xmin-1.5*TicLen,ymin,xmin- .5*TicLen,ymin)
call DrawSeg(xmin-1.5*Ticlen,ymax,xmin- .5*TicLen,ymax)
! Draw right shifted y-axis & corners
call DrawSeg(xmax+1.5*TicLen,ymin,xmax+1.5*TicLen,ymax)
call DrawSeg(xmax+1.5*TicLen,ymin,xmax+ .5*TicLen,ymin)
call DrawSeg(xmax+1.5*Ticlen,ymax,xmax+ .5*TicLen,ymax)
!do yy=ymin,max(ymax,ymin+20)-ymin ! Draw y tics at scaled 1 inch intervals.
do i=0,ifix(max(ymax,ymin+20)-ymin) ! Some may go beyond page boundaries.
yy=ymin+i
call DrawSeg(xmin-2*TicLen,yy,xmin-1.5*TicLen,yy)
call DrawSeg(xmax+2*TicLen,yy,xmax+1.5*TicLen,yy)
enddo
endif
call WriteBlank
write(2,'(a)')'% ***Finished!***'
write(2,'(a)')'showpage' ! prints the prepared page.
close(1)
close(2)
stop 'DrawBlade completed successfuly.'
end
! --------------------------------------------------------------------------------------
subroutine ReadInt(Prompt,num,iDefault) ! Read prompted integer, echo to parameter
! File, or to screen if from file.
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
character*(*) Prompt
1 num=iDefault
if(io.eq.0)then
print'(a)',prompt//':'
print'(a,i0,a)','Enter / for default=',iDefault,')'
read*,num
write(1,'(i17,6x,a)')num,prompt
else
print'(a,$)',prompt//':' ! Print prompt first, in case of i/o error.
read(1,*,end=99)num
print'(i0)',num
endif
return
99 print*,'*****Parameter file too short - continue editing from keyboard!*****'
io=0
open(1,access='append')
goto 1
end
! --------------------------------------------------------------------------------------
subroutine WriteBlank ! Prints blank line on screen, parameter
! file (if io.eq.0), and postscript.
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
print*,' '
if(io.eq.0)write(1,*)' '
write(2,*)' '
return
end
! --------------------------------------------------------------------------------------
subroutine Readflt(Prompt,val,Default) ! Similar for float point
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
character*(*) Prompt
1 val=Default
if(io.eq.0)then
print'(a)',prompt//':'
print'(a,g0,a)','(Enter / for default=',Default,')'
val=Default
read*,val
write(1,'(g21.9,2x,a)')val,prompt
else
print'(a,$)',prompt//':'
read(1,*,end=99)val
print'(g0)',val
endif
return
99 print*,'*****Parameter file too short - continue editing from keyboard!*****'
io=0
open(1,access='append')
goto 1
end
! --------------------------------------------------------------------------------------
subroutine MinMaxEndxy(xx,yy)
! Revise xmin,ymin,xmax,ymax,x,y to include (xx,yy)
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
xmin=min(xmin,xx)
ymin=min(ymin,yy)
xmax=max(xmin,xx)
ymax=max(ymax,yy)
x=xx
y=yy
!print*,'MinMaxEndxy ',xx,yy,' xymin=',xmin,ymin,' xymax=',xmax,ymax !##
return
end
! --------------------------------------------------------------------------------------
subroutine MoveTo(xx,yy) ! Move to xx,yy, to path.
write(2,'(g0,1x,g0,a)')xx,yy,' moveto'
call MinMaxEndxy(xx,yy) ! Revise xmin,ymin,xmax,ymax,x,y.
return
end
! --------------------------------------------------------------------------------------
subroutine LineTo(xx,yy) ! Similar, but draw line
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
write(2,'(g0,1x,g0,a)')xx,yy,' lineto'
call MinMaxEndxy(xx,yy)
return
end
! --------------------------------------------------------------------------------------
! Draw CCW circular arc to path.
subroutine DrawArc(xCenter,yCenter,R,theta1,theta2)
common xmin,ymin,xmax,ymax,x,y,WidLin,io,iExtra
! Input parameters:
! xCenter,yCenter=center of circle
! R=radius of circle
! theta1,theta2=Angle range. Theta1.lt.theta2, and both must be in [-180 to 0] deg.
! xmin,ymin,xmax,ymax = min, max x & y (from previous values)
! Modified parameters:
! xmin,ymin,xmax,ymax = min, max x & y (including these values)
! x,y=ending x,y
write(2,'(5(g0,1x),a)')xCenter,yCenter,R,theta1,theta2,'arc'
call MinMaxEndxy(xCenter+R*cosd(theta1),yCenter+R*sind(theta1))
if(iExtra.ne.0)then ! Extra: draw radius lines
write(2,'(a)')'% ***Next 3 lines are radius lines, not part of blade***'
write(2,'(g0,1x,g0,a)')xCenter+R*cosd(theta1),yCenter+R*sind(theta1),' moveto'
write(2,'(g0,1x,g0,a)')xCenter,yCenter,' lineto'
write(2,'(g0,1x,g0,a)')xCenter+R*cosd(theta2),yCenter+R*sind(theta2),' lineto'
endif
! Include bottom of circle in min,max
if(theta1.lt.-90.and.theta2.gt.-90) &
&call MinMaxEndxy(xCenter+R*cosd(-90. ),yCenter+R*sind(-90. ))
call MinMaxEndxy(xCenter+R*cosd(theta2),yCenter+R*sind(theta2))
return
end
! --------------------------------------------------------------------------------------
subroutine DrawSeg(x1,y1,x2,y2) ! Draw line segment outside path,
! but don't change min,max x,y values
write(2,'(a,g0,1x,g0,a,g0,1x,g0,a)') &
& 'newpath ',x1,y1,' moveto ',x2,y2,' lineto stroke'
end
! --------------------------------------------------------------------------------------
! Setup rotation, and translation,
! so everything fits.
subroutine SetGeometry(TheMargin,xmin2,xmax2,ymin2,ymax2,xPap,yPap, &
& irotate,scale)
real R(2,2) ! Rotation matrix
real x1(2), x2(2), x3(2), x4(2) ! Corners of zone box x4 x3
! x1 x2
real xp1(2),xp2(2),xp3(2),xp4(2) ! Same after rotation.
!print*,'SetGeometry Margin=',TheMargin,' xmin2max2=',xmin2,xmax2, &
! &' ymin2max2=',ymin2,ymax2,' xyPap=',xPap,yPap, &
! & 'irotate=',irotate,'scale=',scale ! ##
x1=(/xmin2,ymin2/) ! Corners of coordinate range box.
x2=(/xmax2,ymin2/) ! With tic borders.
x3=(/xmax2,ymax2/)
x4=(/xmin2,ymax2/)
!print*,'x1=',x1 !##
!print*,'x2=',x2 !##
!print*,'x3=',x3 !##
!print*,'x4=',x4 !##
if(irotate.gt.90.or.rotate.lt.-1)then
stop 'Rotation angle must be between 0 and 90!'
elseif(irotate.ge.0.and.irotate.le.90)then
i1=irotate
i2=irotate
elseif(irotate.eq.-1)then
i1=0
i2=90
else
stop 'Invalid rotation angle!'
endif
do i=i1,i2 ! Search through rotations.
rotate=i
if(rotate.eq.0)then ! Exact 0 or 90 degree rotation matrix exactly.
R=reshape( (/1,0,0,1/),(/2,2/) )
elseif(rotate.eq.90)then
R=reshape( (/0,1,-1,0/),(/2,2/) )
else ! Otherwise calculate rotation matrix
R=reshape( (/cosd(rotate),sind(rotate),-sind(rotate),cosd(rotate)/),(/2,2/) )
endif
!print*,'R= ',R
!print*,'calculated',reshape( (/cosd(rotate),sind(rotate),-sind(rotate),cosd(rotate)/),(/2,2/) )
! Calculate rotated corners
xp1=scale*matmul(R,x1) ! Inefficient - I don't use them all.
xp2=scale*matmul(R,x2) ! I don't care.
xp3=scale*matmul(R,x3) ! "p" means prime, i.e., rotated.
xp4=scale*matmul(R,x4)
!print*,'xp1=',xp1 !##
!print*,'xp2=',xp2 !##
!print*,'xp3=',xp3 !##
!print*,'xp4=',xp4 !##
!print*,' ' !##
! Rotated box geometry for 0<=rotate<=90
! xp3
! xp4
! xp2
! xp1
xpmin2=xp4(1) ! Minimum and maximum rotated limits.
xpmax2=xp2(1)
ypmin2=xp1(2)
ypmax2=xp3(2)
!print*,'xpminmax2=',xpmin2,xpmax2,'ypminmax2=',ypmin2,ypmax2 !##
! Does it fit on the page?
if(xpmax2-xpmin2.le.xPap-2*TheMargin.and. &
& ypmax2-ypmin2.le.yPap-2*TheMargin) goto 10
enddo
stop 'Sorry! Does not fit on requested page size.'
10 print '(a,g0,a)','Rotation angle=',rotate,' works!'
! Final coordinate transformation will be
! scale*(Xp matmul + A); I now find A)
print*,'Left alignment seems intuitive, maybe can print on small width paper.'
print*,'But right alignment may show more of radius lines.'
iDefault=2
call ReadInt('1=Left Align,2=Right Align)',i,iDefault)
if(i.eq.1)then ! scale*(xpmin2+Ax)=TheMargin
Ax=TheMargin/scale-xpmin2
! print*,'Ax=',TheMargin,'/',scale,'-',xpmin2,'=',Ax !##
else ! scale*(xpmax2+Ax)=xPap-TheMargin
Ax=(xPap-TheMargin)/scale-xpmax2
! print*,'Ax=','(',xPap,'-',TheMargin,')/',scale,'-',xpmax2,'=',Ax !##
endif
!print*,'Ax=',Ax !##
Ay=TheMargin/scale-ypmin2 ! Always use Bottom alignment.
! scale*(ypmin2+Ay)=TheMargin
! print*,'Ay=',TheMargin,'/',scale,'-',ypmin2,'=',Ay
if(Ax.ne.0.or.Ay.ne.0)write(2,'(g0,1x,g0,a)') Ax,Ay,' translate'
! I thought that rotate should come
! before translate, but that doesn't
! seem to work. This does. Which means
! there is something about Postscript
! that I don't understand.
write(2,'(a,g0)')'% Rotation angle=',rotate
if(rotate.ne.0)write(2,'(g0,a)')rotate,' rotate'
return
end
====================================================================
-- _ToDo.rtf A list of things about DrawBlade that could be improved --
1. I didn't take into account the width of the lines. In particular if I try to cut with a jig saw on the outside (rather than the center) of the printed lines, that would distort the shape, especially of the toe picks. Perhaps the suggested line width should be adjusted too, to be easier to read.
2. I don't know how and if CAD programs deal with that - whether, when inputing Postscript, and/or images, they take that into account, when creating computer guided cutting and drilling instructions.
3. I can't afford AutoCAD, but there are free CAD programs I could play with that could maybe teach me how they are used. The ones I have looked up on the web so far can't take in postscript. But some of them might take in PDFs - and there are free tools to convert Postscript to PDF.
4. Likewise, a CAD program would need to take into account the width of the cutting tool. Again, I don't know if CAD programs take that into account.
5. I need an option to extend the cut lines at toepick corners, so I can cut them more accurately. And I don't know whether CAD programs do that either.
6. Some blades will be too long to fit on printed paper. So scale down by a factor of two. And/or split the diagram in two, with clear marked points to tape the printed pages together.
7. I need to add the mounting chassis. And add countersunk mounting holes.
Some of these could be fixed in a few days. But learning about CAD/CAM programs, would take longer. Sorry for the delay. But there are also issues regarding the possible breakage of expensive CNC milling machines - which scare me. Maybe CAD/CAM support isn't needed for my purposes. I only started to worry about it, because the only person who responded to me wanted to use AutoCAD.
8. Need to measure position of runner wrt to staunchions and/or something else, like the front of the mounting plate.
9. Be able to adjust Blade size - but usually that just means changing the main rocker length in the parameter file.
10. Evaluate heel lift, and the height of the (back) sweet spot wrt the height of the drag pick (also called scratch pick), and the height of the top toepick tooth when the back toepick tooth barely touches. These are good checks on measured shapes, if one initially wants to imitate an existing blade. But eventually, one should design one's one. E.g., reshape the rocker profile and toepick to match your personal anatomy and preferences.
11. Discuss hardening, shimming to fit the outsole and heel with a cut hockey puck or equivalent.
====================================================================
====================================================================
-- DrawBlade.txt -- The parameter file it generated during the sample run. This is a text file that you can edit to make minor modifications, and the program has an option to read from it. Note that I chose an extra wide line width, and to draw radial lines. I also chose to draw 1 inch tic marks along the x and y axis. These are needed because many printer apps don't scale things correctly by default. For my example I chose 8.5x14 inch size paper, because the sample blade shape was too long to fit on letter size paper.
--contents--
DrawBlade.ps
1 Add arc radius lines for illustrations(0=no? 1?)
3 # of rocker length segments(2? 3?)
96.0000000 Rocker radius (inches)
8.00000000 Curved length of rocker segment (inches)
0.00000000 x value of leftmost point on blade(0?)
0.00000000 y value of lowest point on blade (0?)
27.0000000 Rocker radius (inches)
1.50000000 Curved length of rocker segment (inches)
12.0000000 Rocker radius (inches)
1.00000000 Curved length of rocker segment (inches)
4 # of toepick teeth
140.000000 Angle from curve to drag pick(140?)
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
70.0000000 Degrees from last tooth to this tooth
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
70.0000000 Degrees from last tooth to this tooth
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
70.0000000 Degrees from last tooth to this tooth
0.250000000 Length of back of that tooth
70.0000000 Degrees in angle at bottom of tooth
0.250000000 Length of front of that tooth
1.00000000 Height of runner(0 to not draw top? 1?)
0.200000003 Scaled Tic Length (inches) (0=none; .2?)
0.500000000 Paper margin size (inches) (.5?)
8.50000000 X-axis paper size(8.5?)
14.0000000 Y-axis paper size(11?)
90 Rotation angle(0? 90? -1 to try diagonal fit)
1.00000000 Scale factor(1? .5?)
0.299999993E-01 Line width (inches) (.01?)
2 1=Left Align,2=Right Align)
====================================================================
-- DrawBlade.ps --
The principle output file, containing Postscript text commands from that sample run. Clearly labelled to be human readable. You could look at it to see parameters that you would need to guide a CAD program. Program that display it need to be told the paper size is 8.5"x14" or larger. And some programs would be confused because some of the line segments are outside that boundary...
Omitted for brevity.
====================================================================
DrawBlade.png
An image file created by an old version of Paintshop Pro from DrawBlade.ps. Many other programs, like GhostView, can make such conversions.
====================================================================
DrawBlade_labeled.png
Similar, but I edited it to add explanatory remarks on the input parameters used by DrawBlade.
====================================================================
rocker.png
A printable set of circular arcs with typical rocker curvatures generated by my [Link removed]IDL language rockerprofiles.pro program...
====================================================================
I have other rocker curve images that I now prefer produced by my DrawArcs program. Without getting into details these include:
====================================================================
DrawArcs is a program to draw skate blade rocker curves, with length scales along each curve, and straight line inch scales along the boundaries and centerline.
====================================================================
-- DrawArcs1.txt
The parameter file it generated during a run. This is a text file that you can edit to make minor modifications, and the program has an option to read from it.
This run includes rocker radii radii 6" - 108" at 3 inch intervals.
--contents--
DrawArcs1.ps
0.010000000 Line width (inches) (.01?)
0.550000000 Margin Size(.51?)
8 # of rocker curves/inch(8?)
108.000000 Highest rocker length(108?)
3.00000000 Rocker Length Decrement(3?)
====================================================================
DrawArcs.ps The principle output file, containing Postscript text commands from that
run. Labelled to be human readable, though it is a bit long.
ghostview can display it with
gv -media=Letter DrawArcs1.ps
====================================================================
DrawArcs1.png An Image file prepared from same.
====================================================================
There are similar files for other intervals:
DrawArcs2.txt for 6" - 30" at 1 inch intervals
DrawArcs2.ps
DrawArcs2.png
DrawArcs3.txt for 8" - 18" at 1 inch intervals, but more widely spaced, so you can more clearly see the radial line directions.
DrawArcs3.ps
DrawArcs3.png
====================================================================
I planned to attach the images. But for some reason the board won't let me. I could maybe attach them as links. But the moderator said not to include any links.