Add stickfigure-test.asy and allow independent leg and arm movement.
authorW. Trevor King <wking@drexel.edu>
Fri, 20 May 2011 19:26:01 +0000 (15:26 -0400)
committerW. Trevor King <wking@drexel.edu>
Fri, 20 May 2011 19:26:01 +0000 (15:26 -0400)
asymptote/Makefile
asymptote/stickfigure-test.asy [new file with mode: 0644]
asymptote/stickfigure.asy

index ebac727d85f907d288f41d60bd215a4d07cf8fd4..a76cdb7f4bf7c3f1e306e8435efe971a9b98dda7 100644 (file)
@@ -16,7 +16,7 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-MODULES = Circ ElectroMag Mechanics
+MODULES = Circ ElectroMag Mechanics stickfigure
 
 all : pdfs pngs
 
diff --git a/asymptote/stickfigure-test.asy b/asymptote/stickfigure-test.asy
new file mode 100644 (file)
index 0000000..b5eba83
--- /dev/null
@@ -0,0 +1,46 @@
+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);
index 242b39eb79485495c77945d2a2d155536a7e096c..527cbb6720725fd1944d79c759abbd49b2d12fd2 100644 (file)
@@ -24,64 +24,105 @@ struct StickFigure {
   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) {
@@ -94,17 +135,21 @@ struct StickFigure {
       --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);
   }
 }