WaBis

walter.bislins.ch

Script: Krümmungskreis Animation

Diese Seite zeigt das JavaScript der Krümmungskreis Animation.
#INCLUDE JsGraph.inc
#INCLUDE ControlPanel.inc

function ModelObj() {
  this.barWidth = 1;
  this.alpha = 0.5;
  this.dalpha = Math.PI / 500;
  this.alphaSpeed = 0.2;
  this.lastTime = 0;
  this.r = 8;
  this.d = 10;
  this.a = 20;
  this.r_last = 0;
  this.d_last = 0;
  this.a_last = 0;
  this.beta = 0;
  this.x = 0;
  this.y = 0;
  this.dx = 0;
  this.dy = 0;
  this.ddx = 0;
  this.ddy = 0;
  this.delta = 0.00001;
  this.R = 0;
  this.Zx = 0;
  this.Zy = 0;
  this.xpoly = [];
  this.ypoly = [];
  this.xmin = 0;
  this.xmax = 0;
  this.ymax = 0;
  this.Update();
}

ModelObj.prototype.xy = function( alpha ) {
  var c = this.r * Math.cos( alpha );
  var h = this.r * Math.sin( alpha );
  var b = this.d - c;
  var f = Math.sqrt( b*b + h*h );
  var g = f - this.a;
  var e = b * g / f;
  this.x = this.d - e;
  this.y = g * h / f;
  this.beta = (f == 0) ? 0 : Math.acos( b / f );
  if (h < 0) this.beta *= -1;
}

ModelObj.prototype.diffxy = function( a ) {
  this.xy( a + this.delta );
  var dx = this.x;
  var dy = this.y;
  var ddx = dx;
  var ddy = dy;
  this.xy( a - this.delta );
  dx -= this.x;
  dy -= this.y;
  ddx += this.x;
  ddy += this.y;
  this.xy( a );
  ddx -= 2 * this.x;
  ddy -= 2 * this.y;
  var d2 = 2 * this.delta;
  var dd2 = this.delta * this.delta;
  this.dx = dx / d2;
  this.dy = dy / d2;
  this.ddx = ddx / dd2;
  this.ddy = ddy / dd2;
}

ModelObj.prototype.CompCirc = function() {
  this.R = 0;
  this.diffxy( this.alpha );
  var tlen2 = this.dx * this.dx + this.dy * this.dy;
  var nom = Math.pow( tlen2, 1.5 );
  var denom = this.dx * this.ddy - this.ddx * this.dy;
  this.R = nom / denom;
  if (denom == 0) return;
  var tlen = Math.sqrt( tlen2 );
  this.Zx = this.x - this.R * this.dy / tlen;
  this.Zy = this.y + this.R * this.dx / tlen;
}

ModelObj.prototype.Update = function() {
  // Update alpha 
  if (this.alphaSpeed > 0) {
    if (this.lastTime == 0) this.lastTime = xTimeMS();
    var nowTime = xTimeMS();
    var deltaTime = nowTime - this.lastTime;
    this.lastTime = nowTime;
    this.alpha += this.alphaSpeed * deltaTime * Math.PI / 1000;
    if (this.alpha > 4 * Math.PI || this.alpha < 0) this.alpha = 0;
    if (this.alpha > 2 * Math.PI) this.alpha -= 2 * Math.PI;
  } else {
    this.lastTime = 0;
  }
  // prevent d = r
  var rd = Math.abs( this.d - this.r );
  if (rd < this.barWidth) {
    this.d = (this.d > this.r) ? this.r+this.barWidth : this.r-this.barWidth;
  }
  if (this.d != this.d_last || this.a != this.a_last || this.r != this.r_last) {
    this.ComputePoly();
    this.d_last = this.d;
    this.a_last = this.a;
    this.r_last = this.r;
  }
  this.CompCirc();
  this.xy( this.alpha );
}

ModelObj.prototype.ComputePoly = function() {
  var px = [];
  var py = [];
  this.xmin = 0;
  this.xmax = 0;
  this.ymax = 0;
  var max = Math.max;
  var limit = Math.PI - this.dalpha / 2;
  for (var ang = 0; ang <= limit; ang += this.dalpha) {
    this.xy( ang );
    px.push( this.x );
    py.push( this.y );
    if (this.x < this.xmin) this.xmin = this.x;
    if (this.x > this.xmax) this.xmax = this.x;
    if (Math.abs(this.y) > this.ymax) this.ymax = Math.abs(this.y);
  }
  this.xy( Math.PI );
  px.push( this.x );
  py.push( this.y );
  if (this.x < this.xmin) this.xmin = this.x;
  if (this.x > this.xmax) this.xmax = this.x;
  if (Math.abs(this.y) > this.ymax) this.ymax = Math.abs(this.y);
  // mirror poly
  for (var i = px.length-1; i >= 0; i--) {
    px.push( px[i] );
    py.push( -py[i] );
  }
  this.xpoly = px;
  this.ypoly = py;
}

Model = new ModelObj();

var ModelAnimation = NewGraph2D( {
  Width: '100%', Height: '66%',
  DrawFunc: DrawModel,
  AutoReset: false
} );

function DrawModel( g ) {
  var barWidth = Model.barWidth;
  var circPadding = 1;
  var winPadding = 5;
  var max = Math.max;

  var barLen = max( Model.d + Model.r, Model.a ) + 1.5 * barWidth;
  var winXmin = Model.r;
  if (Model.d < Model.r) winXmin = barLen - Model.r;
  winXmin = max( winXmin, -Model.xmin ) + winPadding;
  var winXmax = max( barLen + Model.r, Model.xmax ) + winPadding;
  var winY = winXmin;
  winY = max( winY, Model.ymax ) + winPadding;
  var winW = winXmin + winXmax;
  var winH = 2 * winY;
  var vpRatio = g.VpInnerWidth / g.VpInnerHeight;
  var gRatio = winW / winH;
  if (gRatio > vpRatio) {
    winH = winW / vpRatio;
    winY = winH / 2;
  } else {
    winW = winH * vpRatio;
    var pad = (winW - (winXmin + winXmax)) / 2;
    winXmin += pad;
    winXmax += pad;
  }
  g.Reset();
  g.SetAngleMeasure( 'rad' );
  g.SetWindow( -winXmin, -winY, winXmax, winY );

  var markerSize = 0.5 * barWidth * g.ScaleWinX();
  g.SetMarkerSize( markerSize );

  g.SetLineAttr( '#ccc', 1 );
  g.Axes();
  g.SetLineAttr( '#ddd', 1 );
  g.Grid( 10, 10 );
  g.Circle( 0, 0, Model.r );

  var x = Model.r * Math.cos( Model.alpha );
  var y = Model.r * Math.sin( Model.alpha );

  // draw radial bar
  g.TransRotate( Model.alpha );
  g.SetAreaAttr( 'white', 'black', 2 );
  g.RectWH( -barWidth/2, -barWidth/2, Model.r+barWidth, barWidth, 3 );
  g.ResetTrans();
  g.SetAreaAttr( 'gray', 'gray', 2 );
  g.Marker( 0, 0 );

  // draw other bar
  g.TransRotate( -Model.beta );
  g.TransMove( x, y );
  g.SetAreaAttr( 'white', 'blue', 2 );
  g.RectWH( -barWidth/2, -barWidth/2, barLen, barWidth, 3 );
  g.Line( Model.a, -barWidth/2, Model.a, barWidth/2 );
  g.Line( 0, 0, Model.a, 0 );
  g.SetAreaAttr( 'gray', 'gray', 2 );
  g.Marker( 0, 0 );

  g.ResetTrans();
  g.TransRotate( -Model.beta );
  g.TransMove( Model.d, 0 );
  g.SetAreaAttr( 'white', 'blue', 2 );
  g.RectWH( -0.75*barWidth, -0.75*barWidth, 1.5*barWidth, 1.5*barWidth, 3 );

  // draw anchor point
  g.ResetTrans();
  g.SetAreaAttr( 'blue', 'blue', 2 );
  g.Marker( Model.d, 0 );

  // draw green curve
  g.SetAreaAttr( 'white', 'green', 1 );
  g.SetMarkerSize( 8 );
  g.Marker( Model.x, Model.y, 3 );
  g.SetMarkerSize( markerSize );
  g.SetLineAttr( 'green', 2 );
  g.Polygon( Model.xpoly, Model.ypoly );

  // draw osculating circle
  if (Model.R != 0) {
    var zdx = Model.x - Model.Zx;
    var zdy = Model.y - Model.Zy;
    var cosrot = zdx / Math.abs(Model.R);
    if (cosrot > 1) cosrot = 1;
    if (cosrot < -1) cosrot = -1;
    var rot = Math.acos( cosrot );
    if (zdy < 0) rot *= -1;
    g.SetLineAttr( 'red', 1 );
    g.Line( Model.Zx, Model.Zy, Model.x, Model.y );
    g.SetMarkerSymbol( 'Plus' );
    g.SetMarkerSize( 16 );
    g.Marker( Model.Zx, Model.Zy );
    g.SetLineAttr( 'red', 2 );
    g.Circle( Model.Zx, Model.Zy, Math.abs( Model.R ), 1, rot );
  }
}

function UpdateModel() {
  Model.Update();
  ModelSliders.Update();
  DrawModel( ModelAnimation );
  NextFrame();
}

var AnimationFrame = null;

function NextFrame() {
  if (Model.alphaSpeed == 0) return;
  AnimationFrame = requestAnimationFrame( UpdateModelFromAnimationFrame );
}

function UpdateModelFromAnimationFrame() {
  cancelAnimationFrame( AnimationFrame );
  AnimationFrame = null;
  UpdateModel();
}

NextFrame();

var ModelSliders = ControlPanels.NewSliderPanel( { 
  ModelRef: 'Model', 
  OnModelChange: UpdateModel, 
  Format: 'fix0', Digits: 2 
} );

ModelSliders.AddValueSliderField( { Name: 'a', Min: 0, Max: 50 } );
ModelSliders.AddValueSliderField( { Name: 'd', Min: 0, Max: 30 } );
ModelSliders.AddValueSliderField( { Name: 'r', Min: 0, Max: 15 } );
ModelSliders.AddValueSliderField( { Name: 'alpha', Label: '&alpha;', Min: 0, Max: 3*Math.PI } );
ModelSliders.AddValueSliderField( { Name: 'alphaSpeed', Label: 'v<sub>&alpha;</sub>', Min: 0, Max: 1 } );

ModelSliders.Render();

More Page Infos / Sitemap
Created Montag, 27. Juli 2015
Scroll to Top of Page
Changed Sonntag, 21. August 2016