kkana's blog

新米コーダーの忘れそうなことメモ

p5.jsのp5.Vector.jsを眺めて改めて分かってなかった と分かったこと

p5.js(http://p5js.org/)はprocessingのjavascript版ライブラリです。この中のp5.Vector.js

https://github.com/processing/p5.js/blob/master/src/math/p5.Vector.js

を読みました。

static関数が分かったきがする

分かった気がするのは2回目ですが・・。前回↓
2つのベクトルから角度を求めるとき - kkana's blog

processingにはベクトル演算用のクラスPVectorがあります。 PVectorにはインスタンス経由で呼び出せるメソッドと、クラス経由で呼び出せるメソッド(静的メソッド)があって
これがp5.jsでは以下のように書き分けられています。

'use strict';

var Vector = function() {
};


Vector.prototype.method = function (x) {
  console.log('prototype Method');
  return x;
};


Vector.method = function (x) {
  console.log('static Method');
  return x;
};

var p = new Vector();
//インスタンスを使った静的でない呼び出し
p = p.method('prototype');
console.log(p);

//静的メソッドを呼び出し
var s = Vector.method('static');
console.log(s);

prototypeにメソッドを追加していくほうはインスタンス経由で呼び出せて
プロパティとしてメソッドを追加していくほうはクラス経由で呼び出せて
「あたかもクラス自身のメンバであるかのように」使えるということ!

この辺のことは

JavaScriptパターン ―優れたアプリケーションのための作法

JavaScriptパターン ―優れたアプリケーションのための作法

ちょうどこの本の5章オブジェクト作成パターンの中の
5.6で書かれています。

ES6のクラス構文でstaticというのを初めてみたんですが、これはES5のときから(構文自体はないがパターンとして)あったので
特別新しい概念ではなかった というのがわかりました。


これはいいな、と思った書き方

引数にVectorオブジェクトがきたときと、配列がきたときの両方に対応できるように描いてある

p5.Vector.prototype.add = function (x, y, z) {
  if (x instanceof p5.Vector) {
    this.x += x.x || 0;
    this.y += x.y || 0;
    this.z += x.z || 0;
    return this;
  }
  if (x instanceof Array) {
    this.x += x[0] || 0;
    this.y += x[1] || 0;
    this.z += x[2] || 0;
    return this;
  }
  this.x += x || 0;
  this.y += y || 0;
  this.z += z || 0;
  return this;
};

return thisが書いてあるのでメソッドチェーン的に書ける

これもさっきの本の5.8連鎖パターンに書かれているやり方ですね。まとめて順番にかけるので便利。
JQueryでも慣れているのでいい。

ちょっと書き直してみた

//ベクトル
class Vector{
  constructor(x, y){
    this.x = x;
    this.y = y;
    return this;
  }
  //加算
  add(x, y){
    if(x instanceof Vector){
      this.x += x.x;
      this.y += x.y;
      return this;
    }
    else{
      this.x += x;
      this.y += y;
      return this;
    }
  }
  static add(vectorA, vectorB){
    var x = vectorA.x + vectorB.x;
    var y = vectorA.y + vectorB.y;
    return new Vector(x, y);
  }
  //減算
  sub(x, y){
    if(x instanceof Vector){
      this.x -= x.x;
      this.y -= x.y;
      return this;
    }
    else{
      this.x -= x;
      this.y -= y;
      return this;
    }
  }
  static sub(vectorA, vectorB){
    var x = vectorA.x - vectorB.x;
    var y = vectorA.y - vectorB.y;
    return new Vector(x, y);
  }
  // ベクトル乗算
  mult(n){
    this.x = this.x * n;
    this.y = this.y * n;
    return this;
  }
  //ベクトル除算
  div(n){
    this.x = this.x / n;
    this.y = this.y / n;
    return this;
  }
  //ベクトルの大きさを返す
  mag(){
    return Math.sqrt(this.x * this.x + this.y * this.y);
  }
  //正規化する
  normalize(){
    var size = this.mag();
    if(size === 0){
      return;
    }
    this.x = this.x * (1 / size);
    this.y = this.y * (1 / size);
    return this;
  }
  //最大値
  limit(max){
    if(this.mag() > max){
      return this.normalize().mult(max);
    }
    else{
      return this;
    }
  }
  //ベクトルの角度を返す
  static angle(vectorA){
    var theta = Math.atan2(vectorA.y, vectorA.x);
    return theta;
  }
  //長さ1のランダムな値を返す
  static random2D(){
    this.x = (Math.random() * 2) - 1;
    this.y = (Math.random() * 2) - 1;
    return this.normalize();
  }
  //角度から長さ1のベクトルを返す
  static fromAngle(angle){
    return new Vector(Math.cos(angle),Math.sin(angle));
  }
  //同じ値をもったVectorを返す
  static copy(vectorA){
    return new Vector(vectorA.x, vectorA.y);
  }
  //ベクトル内積
  static dot(vectorA, vectorB){
    return vectorA.x * vectorB.x + vectorA.y * vectorB.y;
  }
  //ベクトル間の角度を返す
  static angleBetween(vectorA, vectorB){
    var theta = Math.acos((this.dot(vectorA,vectorB))/(vectorA.mag() * vectorB.mag()));
    return theta;
  }
}

ちなみにp5.jsを読むきっかけ

夏からずっと

The Nature of Code

これを読んでいます。
なんと無料(英語版)。ドネーションの額も自分で決められるし内容もアップデートされるし、出版の仕方という点でもほんとすごい取り組みなんですけど
この本の内容もかなり良くて、私みたいなjavascript歴1年(しかもjavascript以外の言語を知らない)のポンコツでもワクワク取り組める 自然現象のシミュレーションの本です。

で、この本はprocessing(Processing.org)を使って物理シミュレーションをやってみる、的なサンプルが大量に載っていて
それをひとつづつ作ってみているところです。

canvas要素でjsを使ってこのサンプルをやってみよう、というふうに取り組んでるんですが
processingで描かれているサンプルをjsに置き換える時にいろんな疑問がでてきました。 おまけに、いままでサンプルコードを再現する時に使い回していた自作のベクトル演算用の関数が、かなり適当に継ぎ足ししていたせいで
だんだんprocessingにあるvectorの機能と離れてきてしまっって、p5.jsの中ではどんな風に書いてあるのかな?と思ったので読んでみました。