WaBis

walter.bislins.ch

Animation des Krüger-Flaps Mechanismus (JavaScript)

Auf dieser Seite wird die Animation des Krüger-Flaps Mechanismus mit zugehörigem JavaScript gezeigt.

Wie das unten gezeigte Modell berechnet und programmiert wird, kann unter Animation des Krüger-Flaps Mechanismus erklärt nachgelesen werden.

Klicke auf die Animation, um sie automtisch ablaufen zu lassen oder zu stoppen, oder verwende den Schieberegler.

JavaScript

Im folgenden JavaScript ist am Ende ersichtlich, wie die automatische Animation programmiert wird.

// Include some JavaScript modules (Wiki-Syntax)
#INCLUDE JsGraph.inc
#INCLUDE ControlPanel.inc
#INCLUDE ModelAnimation.inc

function PointFromAngleLength( P0, Pref, ang, len ) {
  // returns a point at distance len from P0 at angle ang from ray P0 to Pref
  var eref = JsgVect2.Norm( JsgVect2.Sub( Pref, P0 ) );
  var ep = JsgVect2.Rotate( eref, ang );
  return JsgVect2.Add( P0, JsgVect2.Scale( ep, len ) );
}

function Intersect2Circles( A, a, B, b ) {
  // A, B = [ x, y ]
  // return = [ Q1, Q2 ] or [ Q ] or [] where Q = [ x, y ]
  var AB0 = B[0] - A[0];
  var AB1 = B[1] - A[1];
  var c = Math.sqrt( AB0 * AB0 + AB1 * AB1 );
  if (c == 0) {
    // same center: A = B
    return [];
  }
  var x = (a*a + c*c - b*b) / (2*c);
  var y = a*a - x*x;
  if (y < 0) {
    // no intersection
    return [];
  }
  if (y > 0) y = Math.sqrt( y );
  // compute unit vectors ex and ey
  var ex0 = AB0 / c;
  var ex1 = AB1 / c;
  var ey0 = -ex1;
  var ey1 =  ex0;
  var Q1x = A[0] + x * ex0;
  var Q1y = A[1] + x * ex1;
  if (y == 0) {
    // one touch point
    return [ [ Q1x, Q1y ] ];
  } 
  // two intersections
  var Q2x = Q1x - y * ey0;
  var Q2y = Q1y - y * ey1;
  Q1x += y * ey0;
  Q1y += y * ey1;
  return [ [ Q1x, Q1y ], [ Q2x, Q2y ] ];
}

function FlapsModelObject() {
  // Parameters
  this.AnimationTime = 5;

  // Variable
  this.Alpha = 0;

  // Model Geometry
  this.StartAngle = 10.2 / 180 * Math.PI;
  this.EndAngle = -135 / 180 * Math.PI;
  this.P1 = [ 0, 0 ];
  this.P2 = [ -200, -15 ];
  this.Omega2 = -0.32108;
  this.Omega3 = 0.056018;
  this.Len13 = 180.4;
  this.Len34 = 159.0;
  this.Len36 = 234.9;
  this.Len24 = 237.8;
  this.Len25 = 352.6;
  this.Len57 =  78.8;
  this.Len67 = 119.1;

  // Computed Points -> Update
  this.P3 = [ 0, 0 ];
  this.P4 = [ 0, 0 ];
  this.P5 = [ 0, 0 ];
  this.P6 = [ 0, 0 ];
  this.P7 = [ 0, 0 ];

  this.Update();  
}

FlapsModelObject.prototype.Update = function() {
  var Pref = JsgVect2.Add( this.P1, [ 1, 0 ] );
  this.P3 = PointFromAngleLength( this.P1, Pref, this.StartAngle-this.Alpha, this.Len13 );
  var Q = Intersect2Circles( this.P2, this.Len24, this.P3, this.Len34 );
  if (Q.length < 2) return;
  this.P4 = Q[1];
  this.P5 = PointFromAngleLength( this.P2, this.P4, this.Omega2, this.Len25 );
  this.P6 = PointFromAngleLength( this.P3, this.P4, this.Omega3, this.Len36 );
  var Q = Intersect2Circles( this.P5, this.Len57, this.P6, this.Len67 );
  if (Q.length < 2) return;
  this.P7 = Q[1];
}

function DrawFlapsModel( g ) {
  g.SetAngleMeasure( 'rad' );
  g.SetWindow( -466.5, -492.1, 307.2, 163.3 );

  DrawWing( g, FlapsModel );
  DrawPart3( g, FlapsModel );
  DrawPart1( g, FlapsModel );
  DrawPart4( g, FlapsModel );
  DrawPart2( g, FlapsModel );
  DrawPart5( g, FlapsModel );
}

function DrawWing( g, mod ) {

  g.SetAreaAttr( '#dff', '#000', 3 );
  g.TransMove( mod.P1 );

  // draw skeleton    
  g.OpenPath();
  g.BezierCurve( 210.4, 133.0, 40.4, 133.0, -20.3, 123.2, -87.8, 107.8 );
  g.BezierCurveTo( -174.9, 88.3, -262.6, 17.7, -262.6, -15.0 );
  g.BezierCurveTo( -262.6, -54.1, -220.3, -63.3, -184.7, -79.2 );
  g.LineTo( 139.4, -191.8 );
  g.LineTo( 210.4, -212.6 );
  g.LineTo( 210.4, 133.0 );
  g.Path( 2 );

  // draw outline
  g.OpenPath();
  g.BezierCurve( 210.4, 133.0, 40.4, 133.0, -20.3, 123.2, -87.8, 107.8 );
  g.BezierCurveTo( -174.9, 88.3, -262.6, 17.7, -262.6, -15.0 );
  g.BezierCurveTo( -262.6, -54.1, -220.3, -63.3, -184.7, -79.2 );
  g.Path( 1 );

  g.Polygon( [ 130.2, 142.4, 139.4, 210.4 ], [ -178.3, -183.2, -191.8, -212.6 ] );

  g.ResetTrans();

}

function DrawPart1( g, mod ) {

  g.SetAreaAttr( '#aaf', '#00f', 2 );

  var u = JsgVect2.Norm( [ 179.7, 11.1 ] );
  var v = JsgVect2.Norm( JsgVect2.Sub( mod.P3, mod.P1 ) );
  g.TransRotate( JsgVect2.Angle( u, v ) );
  g.TransMove( mod.P1 );

  // draw outline 
  g.OpenPath();
  g.Line( 0, 33.9, 179.7, 33.9 );
  g.LineTo( 189.2, 16.1 );
  g.ArcTo( 172.4, 2.9, -11.1 );
  g.LineTo( 157.6, 16.1 );
  g.LineTo( 68.5, -8.1 );
  g.LineTo( 13.4, -31.2 );
  g.ArcTo( 0, 33.9, -33.9, true );
  g.Path( 3 );

  // draw skeleton    
  g.Line( 146.3, 33.9, 157.6, 16.1 );
  g.Polygon( [ 24.6, 28.4, 143.8, 148.4, 65.7, 36.3, 31.9 ], [ 23.2, 27.6, 27.6, 19.5, -1.8, -14.6, -12.2 ] );
  g.ArcPt( 31.9, -12.2, 24.6, 23.2, 33.9 );
  g.Circle( 0, 0, 16.1 );
  g.Circle( 0, 0, 27.6 );
  g.Circle( 179.7, 11.1, 8.0 );

  g.SetBgColor( 'white' );
  g.Circle( 0, 0, 11.1, 3 );
  g.Circle( 179.7, 11.1, 5.0, 3 );

  g.ResetTrans();

  g.SetBgColor( 'white' );
  g.SetLineWidth( 2 );
  g.Circle( mod.P1, 11.1, 3 );
  g.Circle( mod.P3, 5, 3 );
}

function DrawPart2( g, mod ) {

  g.SetAreaAttr( '#8d8', '#0a0', 2 );

  var u = JsgVect2.Norm( [ 159.5, 6.2 ] );
  var v = JsgVect2.Norm( JsgVect2.Sub( mod.P4, mod.P3 ) );
  g.TransRotate( JsgVect2.Angle( u, v ) );
  g.TransMove( mod.P3 );

  // draw outline
  g.OpenPath();
  g.Line( 0.0, -11.3, 159.5, -11.3 );
  g.ArcTo( 164.8, -10.3, 17.5 );
  g.LineTo( 236.4, 12.3 );
  g.ArcTo( 232.1, 31.9, 10.2 );
  g.LineTo( 158.4, 23.4 );
  g.ArcTo( 151.9, 21.7, 17.5 );
  g.Polygon( [ 151.9, 116.2, 5.4, 5.4, -2.5 ], [ 21.7, 8.3, 25.7, 14.9, 11.1 ] );
  g.ArcTo( 0.0, -11.3, 11.3 );
  g.Path( 3 );

  // draw skeleton    
  g.ArcPt( 0.0, -11.3, -2.5, 11.1, 11.3, true );
  g.ArcPt( 232.1, 31.9, 236.4, 12.3, 10.2, true );
  g.Circle( 159.5, 6.2, 11.5 );
  g.Polygon( [ 142.3, 137.0, 116.2, 24.4, 18.6, 18.6, 24.4, 139.7, 144.2 ], [ 8.3, 9.6, 1.3, 16.1, 11.8, 0.0, -5.4, -5.4, -2.1 ] );
  g.ArcPt( 144.2, -2.1, 142.3, 8.3, -17.5 );
  g.Polygon( [ 176.7, 182.2, 215.0, 216.9, 215.5, 211.8, 177.9, 174.2 ], [ 3.1, 1.3, 11.8, 15.3, 21.7, 24.2, 20.3, 16.1 ] );
  g.ArcPt( 174.2, 16.1, 176.7, 3.1, -17.5 );

  g.SetBgColor( 'white' );
  g.Circle( 0, 0, 5.4, 3 );
  g.Circle( 159.5, 6.2, 8.3, 3 );
  g.Circle( 234.3, 22.0, 4.7, 3 );

  g.ResetTrans();

  g.SetLineWidth( 2 );
  g.SetBgColor( 'white' );
  g.Circle( mod.P3, 5.4, 3 );
  g.Circle( mod.P4, 8.3, 3 );
  g.Circle( mod.P6, 4.7, 3 );
}

function DrawPart3( g, mod ) {

  g.SetAreaAttr( '#d88', '#a00', 2 );

  var u = JsgVect2.Norm( [ 231.9, 51.6 ] );
  var v = JsgVect2.Norm( JsgVect2.Sub( mod.P4, mod.P2 ) );
  g.TransRotate( JsgVect2.Angle( u, v ) );
  g.TransMove( mod.P2 );

  // draw outline
  g.OpenPath();
  g.Line( 312.9, -46.1, 351.4, -46.1 );
  g.ArcTo( 354.7, -28.9, 8.6 );
  g.LineTo( 312.9, -15.6 );
  g.LineTo( 312.9, -46.1 );
  g.Path( 3 );

  g.OpenPath();
  g.Line( 17.5, 0.0, 17.5, 29.9 );
  g.ArcTo( 79.8, 38.0, -31.6 );
  g.LineTo( 97.6, -16.6 );
  g.LineTo( 102.5, -50.9 );
  g.LineTo( 312.9, -50.9 );
  g.LineTo( 312.9, -15.6 );
  g.LineTo( 306.3, -13.6 );
  g.LineTo( 248.5, -5.0 );
  g.LineTo( 248.5, 51.6 );
  g.ArcTo( 220.9, 63.4, 16.1 );
  g.LineTo( 172.8, 7.1 );
  g.LineTo( 96.0, 77.6 );
  g.ArcTo( -17.5, 29.9, 66.9 );
  g.LineTo( -17.5, 0.0 );
  g.ArcTo( 17.5, 0.0, 17.5 );
  g.Path( 3 );

  g.Polygon( [ 69.7, 338.8, 328.3, 87.1, 69.7 ], [ -57.5, -57.5, -50.9, -50.9, -57.5 ], 3 );

  g.Line( 69.7, -57.5, 37.7, -57.5 );
  g.Line( 69.7, -57.5, 54.3, -50.6 );
  g.Circle( 54.3, -50.6, 4.5, 3 );
  g.Rect( 361.8, -50.9, 374.3, -57.5, 3 );
  g.Line( 338.8, -57.5, 374.3, -57.5 );

  // draw skeleton    
  g.Polygon( [ 104.1, 108.7, 152.7, 170.9, 104.1 ], [ -17.5, -46.1, -46.1, 0.4, -17.5 ] );
  g.Polygon( [ 161.6, 240.3, 240.3, 179.1, 161.6 ], [ -46.1, -46.1, -9.8, -0.8, -46.1 ] );
  g.Polygon( [ 248.5, 306.3, 306.3, 248.5, 248.5 ], [ -46.1, -46.1, -19.5, -11.1, -46.1 ] );

  g.OpenPath();
  g.Line( -9.7, 29.9, 11.4, 29.9 );
  g.ArcTo( 85.5, 40.7, -37.8 );
  g.LineTo( 102.5, -10.9 );
  g.LineTo( 165.1, 5.6 );
  g.LineTo( 91.0, 72.4 );
  g.ArcTo( -9.7, 29.9, 59.7 );
  g.Path( 1 );

  g.OpenPath();
  g.Polygon( [ 216.7, 181.6, 240.3, 240.3 ], [ 46.0, 5.7, -3.4, 37.6 ] );
  g.ArcTo( 216.7, 46.0, -16.1 );
  g.Path( 1 );

  g.ResetTrans();

  g.SetAreaAttr( 'white', '#a00', 2 );
  g.Circle( mod.P2, 10.1, 3 );
  g.Circle( mod.P5, 4.3, 3 );
  g.Circle( mod.P4, 8.3, 3 );
}

function DrawPart4( g, mod ) {

  g.SetAreaAttr( '#dc8', '#a50', 2 );

  var u = JsgVect2.Norm( [ -71.0, 34.8 ] );
  var v = JsgVect2.Norm( JsgVect2.Sub( mod.P5, mod.P7 ) );
  g.TransRotate( JsgVect2.Angle( u, v ) );
  g.TransMove( mod.P7 );

  g.OpenPath();
  g.Line( -63.0, -9.6, 14.9, -9.6 );
  g.LineTo( 8.8, 3.8 );
  g.ArcTo( -2.8, 9.2, 9.6 );
  g.LineTo( -63.0, -9.6 );
  g.Path( 3 );

  g.OpenPath();
  g.Line( -22.4, 3.2, -64.0, 41.5 );
  g.ArcTo( -79.1, 29.7, 9.6 );
  g.LineTo( -55.9, -7.3 );
  g.LineTo( -22.4, 3.2 );
  g.Path( 3 );

  g.OpenPath();
  g.BezierCurve( -71.0, -0.7, -71.0, -0.7, -71.0, -2.0, -53.1, -20.2 );
  g.BezierCurveTo( -35.0, -38.8, -22.4, -44.3, -6.6, -44.3 );
  g.BezierCurveTo( 9.8, -44.3, 22.6, -44.3, 31.4, -35.6 );
  g.BezierCurveTo( 42.9, -24.4, 35.7, -9.6, 24.2, -9.6 );
  g.LineTo( -63.0, -9.6 );
  g.LineTo( -71.0, -0.7 );
  g.Path( 3 );

  // draw skeleton    
  g.Circle( 0.0, 0.0, 9.6 );
  g.Circle( -71.0, 34.8, 9.6 );

  g.ResetTrans();

  g.SetAreaAttr( 'white', '#a50', 2 );
  g.Circle( mod.P7, 5.1, 3 );
  g.Circle( mod.P5, 5.1, 3 );
}

function DrawPart5( g, mod ) {

  g.SetAreaAttr( '#dad', '#d0d', 2 );

  var u = JsgVect2.Norm( [ 119.8, 0.0 ] );
  var v = JsgVect2.Norm( JsgVect2.Sub( mod.P7, mod.P6 ) );
  g.TransRotate( JsgVect2.Angle( u, v ) );
  g.TransMove( mod.P6 );

  // draw outline
  g.RectWH( 0.0, -4.5, 119.8, 9.0, 3 );
  g.Circle( 0.0, 0.0, 8.0, 3 );
  g.Circle( 119.8, 0.0, 8.0, 3 );

  g.ResetTrans();

  g.SetBgColor( 'white' );
  g.SetLineWidth( 2 );
  g.Circle( mod.P6, 4.5, 3 );
  g.Circle( mod.P7, 4.5, 3 );
}

var FlapsModel = new FlapsModelObject();

function HandleFlapsModelChange() {
  FlapsModel.Update();
  FlapsModelSlider.Update();
  FlapsModelGraph.Redraw();
}

var FlapsModelGraph = NewGraph2D( {
  Id: 'FlapsModelCanvas',
  Width: '100%',
  Height: '84.71%',
  DrawFunc: DrawFlapsModel,
  AutoReset: true,
  ScaleRef: 800,
  AutoScalePix: true
} );

function HandleFlapsModelSliderMove() {

  FlapsModelAnimation.Stop();

  // if Alpha is near start position
  if (Math.abs(FlapsModel.Alpha) < (5/180*Math.PI)) {
    FlapsModelAnimation.ResetToState(0);
  }

  // if Alpha is near end position
  if (Math.abs(FlapsModel.Alpha-(FlapsModel.StartAngle-FlapsModel.EndAngle)) < (5/180*Math.PI)) {
    FlapsModelAnimation.ResetToState(1);
  }

  HandleFlapsModelChange();

}

var FlapsModelSlider = ControlPanels.NewPanel( { 
  Name: 'FlapsSetting',
  ModelRef: 'FlapsModel',
  OnModelChange: HandleFlapsModelSliderMove
} );

FlapsModelSlider.AddSliderField( {
  Name: 'Alpha', 
  Label: 'Position',
  Min: 0, 
  Max: -(FlapsModel.EndAngle - FlapsModel.StartAngle)
} );

FlapsModelSlider.Render();

var FlapsModelAnimation = NewModelAnimation( {
  ModelRef: FlapsModel,
  OnModelChange: HandleFlapsModelChange
} );

FlapsModelAnimation.AnimationToState( 1, {
  TaskList: [
    { 
      ValueRef: 'Alpha',
      EndValue: FlapsModel.StartAngle - FlapsModel.EndAngle,
      Speed: -(FlapsModel.StartAngle - FlapsModel.EndAngle) / FlapsModel.AnimationTime,
      Sweep: 'smooth'
    }
  ]
} );

FlapsModelAnimation.AnimationToState( 0, {
  TaskList: [
    { 
      ValueRef: 'Alpha',
      EndValue: 0,
      Speed: -(FlapsModel.StartAngle - FlapsModel.EndAngle) / FlapsModel.AnimationTime,
      Sweep: 'smooth'
    }
  ]
} );

xAddEvent( 'FlapsModelCanvas', 'click', function(e) {
  if (FlapsModelAnimation.IsRunning) {
    FlapsModelAnimation.Stop();
  } else {
    FlapsModelAnimation.Next(true);
  }
} );

Weitere Infos zur Seite
Erzeugt Dienstag, 24. Mai 2016
von wabis
Zum Seitenanfang
Geändert Samstag, 20. August 2016
von wabis