BASIC DRAWING MODULE Four_Bar_Mech( ! ! Draws and animates a four-bar mechanism. ! ! You can select various outputs by setting switches ! and recompiling the module: ! ! o You can get a dimensioned drawing that you can use to design ! the mechanism with, ! ! o You can get a drawing of the component parts, suitable for ! building the mechanism, ! ! o Or, you can get an animation showing the mechanism in motion ! tracing it's travel path. ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !Four_Bar_Mech Demo module. !Copyright (C) 2006 Ruven Gottlieb !All Rights Reserved ! !This program is free software; you can redistribute it and/or !modify it under the terms of the GNU General Public License !as published by the Free Software Foundation; either version 2 !of the License, or (at your option) any later version. ! !This program is distributed in the hope that it will be useful, !but WITHOUT ANY WARRANTY; without even the implied warranty of !MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !GNU General Public License for more details. ! !You should have received a copy of the GNU General Public License !along with this program; if not, write to the Free Software !Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! VECTOR Input_Ground > "Input-Ground Joint: "; VECTOR Follower_Ground > "Follower-Ground Joint: "; FLOAT Input_Length > "Input Link Length: "; FLOAT Follower_Length > "Follower Link Length: "; FLOAT Tracer_Position > "Tracer Point Position: "; FLOAT Tracer_Length > "Tracer Point Length: "); !********************************************************** FLOAT Incr_Angle; ! Incremental angle of construction ! lines from Input_Ground FLOAT PAPERSIZE_X; FLOAT PAPERSIZE_Y; FLOAT SCALE; FLOAT Baseline; ! Baseline for ground links. Used to ! determine co-ordinate system axis for ! relative angles ! of construction lines to decide proper ! alternate to get correct intersect for ! coupler link. FLOAT SCALE_X; FLOAT SCALE_Y; INT Alt_v; INT Animate; INT Const; INT Cutouts; INT Design; INT Dim; INT Drawings; INT Increment; INT Level; INT MaxIncrements; INT PS_DPI; INT Pen; INT Pix; INT TextSize; INT i; VECTOR Incr_FC; ! Increment Follower-Coupler arc. VECTOR Pos, Start, End; ! Temporary variables VECTOR MINPOS, MAXPOS; STRING Plotfile*132; STRING File_Dir*132; STRING Filename*132; STRING EachFile*132; STRING Message*132; STRING Ground*10; BEGINMODULE ! Initial Values: ! Generate animation of mechanism: Animate:=1; ! Generate dimensioned drawings of components: Drawings := 0; ! Plotfile directory: File_Dir:="varkon/app/Four_Bar/doc/plot/"; Filename:="Four_Bar"; set(TSIZE=50); cacc_view(20); ! Set line thickness: set(WIDTH=0.25); ! Set dimension line thickness: Pen:=20; set(PEN=Pen); ! Blank dimension lines: Dim:=0; ! Blank entities during pix generation: Pix:=0; ! Blank all construction entities: Const:=1; ! Blank during design phase Design:=0; ! Maximum increments for animation: MaxIncrements:=50; ! Text size for dimensions: TextSize:=50; ! Co-ordinate system name for axis of ground joints. Ground:="Ground"; ! Metric dimensions of paper: PAPERSIZE_X := 8.5 * 25.4; PAPERSIZE_Y := 11 * 25.4; IF Animate = 1 THEN ! Blank ("=1) elements not wanted in animation: Pix:=0; Design:=1; Dim:=1; ENDIF; !******************************************** ! Starting positions of mechanism: ! Input Link: lin_ang(#1, Input_Ground, 90, Input_Length:BLANK=Design); ldim(#23, startp(#1), endp(#1), on(#1,0.3)+vec(-100,0), 2:DTSIZ=TextSize, DASIZ=TextSize, DNDIG=3, PEN=Pen, BLANK=Dim ); part(#28, CenterMark(Input_Ground,2,0)); ! Follower Link: lin_ang(#2,Follower_Ground, 90, Follower_Length:BLANK=Design); ldim(#26, startp(#2), endp(#2), on(#2,0.3)+vec(130,0), 2:DTSIZ=TextSize, DASIZ=TextSize, DNDIG=3, PEN=Pen, BLANK=Dim ); part(#29, CenterMark(Follower_Ground,2,0)); ! Coupler Link: lin_free(#3, endp(#1), endp(#2):BLANK=Design); ldim(#27, startp(#3), endp(#3), on(#3,0.3)+vec(0,100), 2:DTSIZ=TextSize, DASIZ=TextSize, DNDIG=3, PEN=Pen, BLANK=Dim ); ! Path tracer point: lin_perp(#33, on(#3,Tracer_Position), #3, Tracer_Length:LFONT=1,LDASHL=5); part(#34, CenterMark(endp(#33),2,0)); ! ***** Generate intermediate positions of mechanism: ************** ! Baseline:=angle(Follower_Ground.x, Follower_Ground.y); csys_1p(#4, "Ground", Input_Ground, 0,0, Baseline:BLANK=Const); arc_1pos(#5, Input_Ground, Input_Length, 90, 450:BLANK=Const); arc_1pos(#6, Follower_Ground, Follower_Length, 90, 450:BLANK=Const); mode_local(#4); for Increment:=0 to MaxIncrements+1 do ! Each position gets it's own level, ! so we can generate animation later: Level:=Increment+1; set(LEVEL=Level); Incr_FC:=on(#5,Increment/MaxIncrements); lin_free(#7, Input_Ground, Incr_FC:BLANK=Pix); part(#20, CenterMark(Input_Ground,2,0)); Pos:=endp(refc(7,Level)); Incr_Angle:=angle(Pos.x, Pos.y); !Arc from follower, Coupler-Length radius: arc_1pos(#9, Incr_FC, arcl(#3):BLANK=1); ! Adjust these if you have tangency troubles. ! ! NB: Weird things happen when input and follower links are equal. IF Incr_Angle >= 0 AND Incr_Angle <= 90 then Alt_v:=1; Message:="Q1:"+str(Incr_Angle,1,0); ELIF Incr_Angle > 90 AND Incr_Angle <= 180 then Alt_v:=1; Message:="Q2:"+str(Incr_Angle,1,0); ELIF Incr_Angle < 0 AND Incr_Angle <= -90 then Alt_v:=1; Message:="Q3:"+str(Incr_Angle,1,0); ELIF Incr_Angle < 0 AND Incr_Angle > -90 then Alt_v:=-1; Message:="Q4:"+str(Incr_Angle,1,0); ELSE Message:="Error: *** Unknown quadrant ***"; ENDIF; ! Coupler link in incremental positions: lin_free(#11, endp(refc(7,Level)), intersect( refc(9,Level), #6, Alt_v):BLANK=Pix); ! Uncomment to show message: !text(#14, Pos+vec(0,10), 0, Message:BLANK=0); ! Input link in incremental positions: lin_free(#15, endp(refc(11,Level)), Follower_Ground:BLANK=Pix); part(#21, CenterMark(Follower_Ground,2,0)); ! Path tracer point in incremental positions: lin_perp(#31, on(refc(11,Level), Tracer_Position), refc(11,Level), Tracer_Length:LFONT=1,LDASHL=5); part(#32, CenterMark(endp(refc(31,Level)),2,0)); endfor; ! Generate curve describing path of tracer point. set(LEVEL=MaxIncrements+3); for Increment:=1 to MaxIncrements+2 do if Increment = 1 then Start:=endp(refc(31,MaxIncrements+2)); End:=endp(refc(31,Increment)); elif Increment = MaxIncrements+2 then Start:=endp(refc(31,Increment)); End:=endp(refc(31,1)); else Start:=endp(refc(31,Increment)); End:=endp(refc(31,Increment+1)); endif; lin_free(#69, Start, End:LFONT=1,LDASHL=10); endfor; ! Generate animation frames of incremental positions: if Animate = 1 then ! Get size of model at all points: ! ! WARNING: ! ! MINPOS doesn't take into account a dimension text ! in outer boundary! ! First, unblank all the increment levels. Blanked levels won't count. ! Take care to blank large construction arcs, etc. for i:=0 to MaxIncrements+2 do unblank_lev(i, 0); endfor; Level:=MaxIncrements+5; set (LEVEL=Level); unblank_lev(Level, 0); ! Determine the correct scale to fit the model within ! the boundaries of the 612x792 pixel ! ( (8.5"x11") * 72 dpi ) plot window. ! ! NB: act_scl() doesn't provide the proper scale. msize_view(MINPOS, MAXPOS); rep_view(1, 0); ! Get the model boundaries by measuring these: lin_free(#24, MINPOS, vec(MAXPOS.x,MINPOS.y)); lin_free(#25, MINPOS, vec(MINPOS.x,MAXPOS.y)); ! Get scales for X and Y axes because model aspect ratio varies. SCALE_X:=PAPERSIZE_X / arcl(#24); SCALE_Y:=PAPERSIZE_Y / arcl(#25); ! Use largest scale that will allow the model to fit ! into 612x792 pixel plot window. ! If Y > X AND X * SCALE_Y <= PAPERSIZE_X if arcl(#25) > arcl(#24) AND arcl(#24) * SCALE_Y <= PAPERSIZE_X then SCALE:=SCALE_Y; else SCALE:=SCALE_X; endif; Message:="Scale: "+str(SCALE,1); text(#19, vec(0,0), 0, Message:LEVEL=Level, BLANK=0); ! Generate a file of the full visible model to use ! with ImageMagick to get the proper canvas size to use ! when cropping the images. os("cd "+File_Dir+";./cleanup.sh"); Plotfile:=File_Dir+"SIZE.PLT"; plot_win(MINPOS, MAXPOS, Plotfile); ! Show each level consecutively to animate movement: ! Blank all levels to clean up final image: for i:=0 to MaxIncrements+5 do blank_lev(i, 0); endfor; ! Unblank the travel-path curve: unblank_lev(MaxIncrements+3, 0); for Increment := 1 to MaxIncrements do ! Unblank the current level unblank_lev(Increment, 0); rep_view(0, 0); ! Send current window to plotfile: EachFile:=Filename+"_"+str(Increment+99,1,0)+".PLT"; Plotfile:=File_Dir+EachFile; plot_win(MINPOS, MAXPOS, Plotfile); blank_lev(Increment, 0); endfor; !TODO: Make an fbutton for this; now it runs by default: ! ! Run shellscript for ImageMagick to generate GIF89A animation. ! Comment out for testing. Conversions take some time. ! os("cd "+File_Dir+";xterm -e ./plot2img "+str(SCALE,1)+" 2"+" jpg"+";exit"); else if Drawings = 1 then ! Blank main model, and show only drawings, ! and print to file. for i:=0 to MaxIncrements+4 do blank_lev(i, 0); endfor; erase_view(0); Level:=MaxIncrements+4; set (LEVEL=Level); unblank_lev(Level, 0); part(#30, Links_Drawing()); EachFile:=Filename+"_Drawings.PLT"; Plotfile:=File_Dir+EachFile; msize_view(MINPOS, MAXPOS); plot_win(MINPOS, MAXPOS, Plotfile); else ! or just show the design with dimensions and travel path. for i:=0 to MaxIncrements+4 do blank_lev(i, 0); endfor; unblank_lev(0, 0); unblank_lev(MaxIncrements+3, 0); rep_view(1, 0); EachFile:=Filename+"_Design.PLT"; Plotfile:=File_Dir+EachFile; msize_view(MINPOS, MAXPOS); ! WARNING: ! ! MINPOS doesn't take into account a dimension text ! in outer boundary! plot_win(MINPOS, MAXPOS, Plotfile); endif; endif; ENDMODULE