--- /dev/null
+import stickfigure;
+
+real u = 6cm;
+
+StickFigure s = StickFigure(standsOn=(0,0), height=u/2);
+
+s.draw();
+dot("crown", s.crownPos(), N, red);
+dot("head", s.headPos(), E, red);
+dot("right shoulder", s.shoulderPos(), E, red);
+dot("left shoulder", s.shoulderPos(leftSide=true), W, red);
+dot("right hand", s.handPos(), E, red);
+dot("left hand", s.handPos(leftSide=true), W, red);
+dot("right foot", s.footPos(), E, red);
+dot("left foot", s.footPos(leftSide=true), W, red);
+dot("stands on", s.standsOnPos(), S, red);
+
+s.standsOn((u,0));
+s.draw();
+dot("chin", s.chinPos(), E, red);
+dot("neck base", s.neckBasePos(), W, red);
+dot("tail", s.tailPos(), E, red);
+dot("center", s.center, W, red);
+dot("stands on", s.standsOnPos(), S, red);
+
+s.rightArmAngle = 30;
+s.leftArmAngle = 40;
+s.rightLegAngle = -20;
+s.leftLegAngle = -30;
+s.standsOn((0,-u));
+s.draw();
+draw(s.footPos()--s.footPos(leftSide=true), dashed);
+dot("stands on", s.standsOnPos(), S, red);
+dot("center", s.center, E, red);
+dot("$30^\circ$ arm angle", s.handPos(), E);
+dot("$40^\circ$ arm angle", s.handPos(leftSide=true), W);
+dot("$-20^\circ$ leg angle", s.footPos(), E);
+dot("$-30^\circ$ leg angle", s.footPos(leftSide=true), W);
+
+s.rightLegAngle = s.leftLegAngle = -45;
+s.rightArmAngle = -60;
+s.standsOn((u, -u));
+s.outline = blue;
+s.fill = red;
+s.draw();
+label("blue outline, red fill", s.crownPos(), N);
real neckHeightRatio;
real torsoHeightRatio;
real shoulderHeightRatio;
+ real legHeightRatio;
+ real centerTorsoRatio;
real armTorsoRatio;
- real armAngle;
+ real rightArmAngle;
+ real leftArmAngle;
+ real rightLegAngle;
+ real leftLegAngle;
pen outline;
pen fill;
-
+
void operator init(pair standsOn=(0,0), real height=10mm) {
- this.center = standsOn+(0,height/2);
this.height = height;
this.headHeightRatio = 0.2;
this.neckHeightRatio = 0.1;
this.torsoHeightRatio = 0.28;
this.shoulderHeightRatio = 0.1;
+ /* at shoulder width, a leg takes this much height:
+ * 1 - head - neck - torso (opposite legAngle)
+ * and this much width:
+ * shoulder/2 (adjavent legAngle)
+ */
+ this.rightLegAngle = -aTan(
+ 2*(1-this.headHeightRatio-this.neckHeightRatio-this.torsoHeightRatio)
+ /this.shoulderHeightRatio);
+ this.leftLegAngle = rightLegAngle;
+ this.legHeightRatio = this.shoulderHeightRatio/2/Cos(this.rightLegAngle);
+ this.centerTorsoRatio = 0.2;
this.armTorsoRatio = 1.2;
- this.armAngle = -70;
+ this.rightArmAngle = -70;
+ this.leftArmAngle = -70;
this.outline = currentpen;
this.fill = currentpen;
+
+ this.center = standsOn +
+ (0, this.height*(this.legHeightRatio*Sin(-this.rightLegAngle)
+ +this.torsoHeightRatio*this.centerTorsoRatio));
}
- pair crownPos() {
- return this.center + (0,this.height/2);
+ /* center a fixed torso fraction (centerTorsoRatio) above tail.
+ * Everything else located from that point.
+ */
+
+ pair tailPos() {
+ return this.center
+ - (0,this.height*this.torsoHeightRatio*this.centerTorsoRatio);
}
-
+
+ pair neckBasePos() {
+ return this.tailPos() + (0,this.height*this.torsoHeightRatio);
+ }
+
pair chinPos() {
- return this.crownPos() - (0,this.height*this.headHeightRatio);
+ return this.neckBasePos() + (0,this.height*this.neckHeightRatio);
+ }
+
+ pair crownPos() {
+ return this.chinPos() + (0,this.height*this.headHeightRatio);
}
-
+
pair headPos() {
return (this.crownPos() + this.chinPos())/2;
}
-
- pair neckBasePos() {
- return this.chinPos() - (0,this.height*this.neckHeightRatio);
- }
- pair shoulderPos(bool rightSide=true) {
+ pair shoulderPos(bool leftSide=false) {
real sign = 1;
- if (rightSide == false)
+ if (leftSide == true)
sign = -1;
return this.neckBasePos() + (sign*this.height*this.shoulderHeightRatio/2,0);
}
-
- pair handPos(bool rightSide=true) {
- pair dArm = this.height*this.torsoHeightRatio*this.armTorsoRatio * dir(armAngle);
- if (rightSide == false)
- dArm = (-dArm.x, dArm.y);
- return this.shoulderPos(rightSide=rightSide) + dArm;
+
+ pair handPos(bool leftSide=false) {
+ real len = this.height*this.torsoHeightRatio*this.armTorsoRatio;
+ real ang;
+ if (leftSide == true) {
+ ang = 180 - this.leftArmAngle;
+ } else{
+ ang = this.rightArmAngle;
+ }
+ return this.shoulderPos(leftSide=leftSide) + len * dir(ang);
}
- pair tailPos() {
- return this.neckBasePos() - (0,this.height*this.torsoHeightRatio);
- }
-
- pair footPos(bool rightSide=true) {
- real legHeightRatio = 1.0 - this.headHeightRatio - this.neckHeightRatio - torsoHeightRatio;
- pair dLeg = (this.height*this.shoulderHeightRatio/2, -this.height*legHeightRatio);
- if (rightSide == false)
- dLeg = (-dLeg.x, dLeg.y);
- return this.tailPos() + dLeg;
+
+ pair footPos(bool leftSide=false) {
+ real len = this.height*this.legHeightRatio;
+ real ang;
+ if (leftSide == true) {
+ ang = 180 - this.leftLegAngle;
+ } else{
+ ang = this.rightLegAngle;
+ }
+ return this.tailPos() + len * dir(ang);
+ }
+
+ pair standsOnPos() {
+ return (this.footPos() + this.footPos(leftSide=true))/2;
+ }
+
+ void standsOn(pair pos) {
+ this.center += pos - this.standsOnPos();
}
void draw(picture pic=currentpicture) {
--this.neckBasePos()
--this.tailPos();
path armsAndShoulders =
- this.handPos(rightSide=true)
- --this.shoulderPos(rightSide=true)
- --this.shoulderPos(rightSide=false)
- --this.handPos(rightSide=false);
+ this.handPos(leftSide=false)
+ --this.shoulderPos(leftSide=false)
+ --this.shoulderPos(leftSide=true)
+ --this.handPos(leftSide=true);
path legs =
- this.footPos(rightSide=true)
+ this.footPos(leftSide=false)
--this.tailPos()
- --this.footPos(rightSide=false);
- draw(pic, armsAndShoulders, outline);
- draw(pic, legs, outline);
- draw(pic, neckAndTorso, outline);
- filldraw(pic, head, fill, outline);
+ --this.footPos(leftSide=true);
+ draw(pic, armsAndShoulders, this.outline);
+ draw(pic, legs, this.outline);
+ draw(pic, neckAndTorso, this.outline);
+ dot(this.handPos(leftSide=false), this.fill);
+ dot(this.handPos(leftSide=true), this.fill);
+ dot(this.footPos(leftSide=false), this.fill);
+ dot(this.footPos(leftSide=true), this.fill);
+ filldraw(pic, head, this.fill, this.outline);
}
}