242b39eb79485495c77945d2a2d155536a7e096c
[course.git] / asymptote / stickfigure.asy
1 /* sticfigure drawings in asymptote.
2  *
3  * Copyright (C) 2008-2009 W. Trevor King <wking@drexel.edu>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19                         
20 struct StickFigure {
21   pair center;
22   real height;
23   real headHeightRatio;
24   real neckHeightRatio;
25   real torsoHeightRatio;
26   real shoulderHeightRatio;
27   real armTorsoRatio;
28   real armAngle;
29   pen outline;
30   pen fill;
31   
32   void operator init(pair standsOn=(0,0), real height=10mm) {
33     this.center = standsOn+(0,height/2);
34     this.height = height;
35     this.headHeightRatio = 0.2;
36     this.neckHeightRatio = 0.1;
37     this.torsoHeightRatio = 0.28;
38     this.shoulderHeightRatio = 0.1;
39     this.armTorsoRatio = 1.2;
40     this.armAngle = -70;
41     this.outline = currentpen;
42     this.fill = currentpen;
43   }
44
45   pair crownPos() {
46     return this.center + (0,this.height/2);
47   }
48   
49   pair chinPos() {
50     return this.crownPos() - (0,this.height*this.headHeightRatio);
51   }
52   
53   pair headPos() {
54     return (this.crownPos() + this.chinPos())/2;
55   }
56   
57   pair neckBasePos() {
58     return this.chinPos() - (0,this.height*this.neckHeightRatio);
59   }
60
61   pair shoulderPos(bool rightSide=true) {
62     real sign = 1;
63     if (rightSide == false)
64       sign = -1;
65     return this.neckBasePos() + (sign*this.height*this.shoulderHeightRatio/2,0);
66   }
67   
68   pair handPos(bool rightSide=true) {
69     pair dArm = this.height*this.torsoHeightRatio*this.armTorsoRatio * dir(armAngle);
70     if (rightSide == false)
71       dArm = (-dArm.x, dArm.y);
72     return this.shoulderPos(rightSide=rightSide) + dArm;
73   }
74
75   pair tailPos() {
76     return this.neckBasePos() - (0,this.height*this.torsoHeightRatio);
77   }    
78   
79   pair footPos(bool rightSide=true) {
80     real legHeightRatio = 1.0 - this.headHeightRatio - this.neckHeightRatio - torsoHeightRatio;
81     pair dLeg = (this.height*this.shoulderHeightRatio/2, -this.height*legHeightRatio);
82     if (rightSide == false)
83       dLeg = (-dLeg.x, dLeg.y);
84     return this.tailPos() + dLeg;
85   }
86
87   void draw(picture pic=currentpicture) {
88     path head =
89       shift(this.headPos())
90       *scale(this.height*this.headHeightRatio/2)
91       *unitcircle;
92     path neckAndTorso =
93       this.chinPos()
94       --this.neckBasePos()
95       --this.tailPos();
96     path armsAndShoulders =
97       this.handPos(rightSide=true)
98       --this.shoulderPos(rightSide=true)
99       --this.shoulderPos(rightSide=false)
100       --this.handPos(rightSide=false);
101     path legs =
102       this.footPos(rightSide=true)
103       --this.tailPos()
104       --this.footPos(rightSide=false);
105     draw(pic, armsAndShoulders, outline);
106     draw(pic, legs, outline);
107     draw(pic, neckAndTorso, outline);
108     filldraw(pic, head, fill, outline);
109   }
110 }