Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

Processingで内積・外積の勉強

f:id:fa11enprince:20200121024039j:plain ひょんなことから内積・外積をちゃんと学びなおしたいと思い…
文系であった自分はあまりなじみがないのです。物理も選択せず生物選択でした。
数学は嫌いではないんだけど、計算が得意でなかったです。
とはいえ行列をやっていた関係もあり、全く知らないというわけではないのです。
それに最近避けたいのに避けられない機械学習でもというかnumpyというか、dot、dot、dotばっかりな気がしていますので改めて復習。 グラフィカルに確認したいなと思い、いろいろ見てました。 そもそも何に使うか…

  • 内積:矩形は別の判定方法が簡単に思いつくけど、三角形や円にたいしてある点が当たっているかどうか。(衝突判定)とか2つのベクトルがわかっているときにその角度が鋭角か鈍角か求めたいとき
  • 外積:キャラがジャンプした時の高さを求める

内積や外積が難しいのはそもそも何に使うんよ…ってのが分かりにくいからだと思います。 自分の理解したざっくり定義では、

  • 内積:ある方向に引っ張ったときに元となるベクトルと方向を合わせて水平方向に引っ張れる力や量的なモノ
  • 外積:ある方向に引っ張ったときに元となるベクトルと垂直方向に引っ張れる力や量的なモノ

と理解しました(あってんのか?)てかこれ物理とってたら習う?
ちなみにですが内積については類似度っていう考え方もあるみたいです。

個人的にはここがわかりやすかったです。 基礎の基礎編その1 内積と外積の使い方
理屈だけわかっても仕方ないんで、「内積 衝突判定」でググってみました。
すると、なんかコード例が書いてて素敵!
円と線分の当たり判定を行うには | 自己啓発。人生について考える
なんだこのJavaっぽい言語は…一瞬TypeScriptにも見えるしな…と思い、調べたらProcessingでした。 自分もProcessingで書いてみました。ほうほう…内部でJavaのSwing使ってんのね。
余談ですがProcessing書いてるとPythonとかJavaScript(ES6以降)っぽいなーとうっすら思います。

ソースコード

class Point2D {
  float x;
  float y;
  Point2D(float x, float y) {
    this.x = x;
    this.y = y;
  }
  void disp(color c, float diameter) {
    stroke(c);
    strokeWeight(diameter);
    point(this.x, this.y);
  }
};

class Vector2D {
  float x;
  float y;
  float len;
  Vector2D(float x, float y) {
    this.x = x;
    this.y = y;
  }
  Vector2D(Point2D pointA, Point2D pointB) {
    this.x = pointB.x - pointA.x;
    this.y = pointB.y - pointA.y;
    this.len = dist(pointA.x, pointA.y, pointB.x, pointB.y);
  }
  Vector2D unit() {
    return new Vector2D(this.x / this.len, this.y / this.len);
  }
  float dot(Vector2D vec) {
    return this.x * vec.x + this.y * vec.y;
  }
  float corss(Vector2D vec) {
    return this.x * vec.y - this.y * vec.x;
  }
}

final color BLACK = color(0, 0, 0);
final color WHITE = color(255, 255, 255);
final color BLUE = color(0, 0, 255);
final color GREEN = color(0, 255, 0);
final color RED = color(255, 0, 0);
final float diameter = 20;
final float diameterCenter = 100;
Point2D pointA;
Point2D pointB;
Point2D pointP;

void setup() {
  size(300, 300);
  pointA = new Point2D(20, 20);
  pointB = new Point2D(260, 260);
  pointP = new Point2D(150, 150);
}

void draw() {
  background(WHITE);
  noFill();
  
  stroke(BLACK);
  strokeWeight(2);
  line(pointA.x, pointA.y, pointB.x, pointB.y);
  pointA.disp(BLUE, diameter);
  pointB.disp(GREEN, diameter);

  Vector2D vecAB = new Vector2D(pointA, pointB);
  Vector2D vecAP = new Vector2D(pointA, pointP);
  Vector2D vecBP = new Vector2D(pointB, pointP);

  color c;
  if (isCollision(vecAB, vecAP, vecBP)) {
    drawInnerPointOfCircle(vecAB, vecAP);
    c = RED;
  } else {
    c = BLACK;
  }
  drawCircle(c, pointP);
}

void drawInnerPointOfCircle(Vector2D vecAB, Vector2D vecAP) {
  Vector2D unit = vecAB.unit();
  float len = unit.dot(vecAP);
  Point2D pointX = new Point2D(pointA.x + (unit.x * len), pointA.y + (unit.y * len));
  pointX.disp(color(100,100,255), diameter);
}

void drawCircle(color c, Point2D pointP) {
  strokeWeight(2);
  stroke(c);
  ellipse(pointP.x, pointP.y, diameterCenter, diameterCenter);
}

boolean isCollision(Vector2D vecAB, Vector2D vecAP, Vector2D vecBP) {
  float lenAX = vecAB.unit().dot(vecAP);
  return shortestDistance(lenAX, vecAB, vecAP, vecBP) < diameterCenter / 2;
}

float shortestDistance(float len, Vector2D ab, Vector2D ap, Vector2D bp) {
  if (len < 0 ) {
    return ap.len;
  } else if (len > ab.len) {
    return bp.len;
  } else {
    return abs(ab.unit().corss(ap));
  }
}

void mouseDragged() {
  if (isDragged(pointA, diameter)) {
    pointA.x = mouseX;
    pointA.y = mouseY;
    return;
  }
  if (isDragged(pointB, diameter)) {
    pointB.x = mouseX;
    pointB.y = mouseY;
    return;
  }
}

boolean isDragged(Point2D point, float diameter) {
  return dist(mouseX, mouseY, point.x, point.y) < diameter / 2;
}

スクリーンショット

f:id:fa11enprince:20200121022851p:plain

ちなみにProcessingのダウンロードはこちら https://processing.org/ 最新版だとJava 8が内包されている様子。
JavaFXは外部でメンテナンスだけどSwingは残りましたね…。

サクラエディタで特定のフォルダにYYYYMMDD_番号.txtで保存するマクロを作成

最近の趣味はサクラエディタのPull Requestを眺めることです。 昔から愛用してきたサクラエディタですがマクロを使ったことはありませんでした。
ということで毎日よく簡易的にメモをテキストエディタに書いてYYYYMMDD.txtみたいな形式で保存するのですが、
日付を間違えたり、名前を変更するのをめんどくさがったり、保存先がデスクトップに散ったりなどがありがちなので
デスクトップのmemoというフォルダを用意して新規作成時orマクロ実行時にmemo配下に YYYYMMDD_[無題の後の番号].txtというので自動保存するマクロを作成しました。 古のWSH(JScript)が使えるんですね。

マクロの準備

次のコードをsaveByDate.jsという名前で%APPDATA%\sakuraフォルダに保存します。

// saveByDate.js
// see: https://gist.github.com/RYLSnmm/432a35eb3f885722a4f95e8f0ef9df6b
// デフォルトの設置場所:ユーザーごとにインストールなら
//   %APPDATA%sakuraに本ファイルを設置する
// 共通設定よりマクロを設定 文法はWSHに準拠(JScript)
// 新規/開ファイル後にチェックを入れて設定したほうが捗るかも
(function() {
    if (Editor.GetFilename() != "") { return; }
    
    var wsh_shell = new ActiveXObject("WScript.Shell");
    var DEFAULT = {
        savedir: wsh_shell.ExpandEnvironmentStrings("%USERPROFILE%") + "\\Desktop\\memo",
        filename_template: "{{YYYY}}{{MM}}{{DD}}_{{number}}.txt",
        charset: "UTF-8",
        linebreak: "CRLF"
    };
    var savedir = DEFAULT.savedir;
    var filename_template = DEFAULT.filename_template;
    var charset = DEFAULT.charset;
    var linebreak = DEFAULT.linebreak;
    
    var number = Editor.ExpandParameter("$n");
    var filename = createFromTemplate(filename_template, getNowForTemplate(), {number: number});
    var path = savedir + "\\" + filename;

    var fso = new ActiveXObject("Scripting.FileSystemObject");
    if (!fso.FolderExists(savedir)) {
        fso.CreateFolder(savedir);
    }
    
    Editor.FileSaveAs(path, charset, linebreak);
    
    function createFromTemplate(tstr /*, ...args*/) {
        var obj = mergeObjects(Array.prototype.slice.call(arguments, 1));
        return tstr.replace(/\{\{(.*?)\}\}/g, function(_, name) {
            return obj[name] || "";
        });
    }

    function mergeObjects(objects) {
        var result = {};
        for (var i = 0; i < objects.length; i++) {
            var obj = objects[i];
            for (var k in obj) {
                if (obj.hasOwnProperty(k)) {
                    result[k] = obj[k];
                }
            }
        }
        return result;
    }

    function getNowForTemplate() {
        var d = new Date();
        return {
            YYYY: padLeft(d.getFullYear(), 4),
            MM: padLeft(d.getMonth() + 1, 2),
            DD: padLeft(d.getDate(), 2)
        };
    }

    function padLeft(value, len, char) {
        char = char || "0";
        var padding = Array.apply(null, Array(len + 1)).join(char);
        return (padding + value).slice(-len);
    }
})();

設定

サクラエディタを立ち上げて、設定 > 共通設定 > マクロ タブを選択し、

名前:saveByDate
Id: 0
File: saveByDate.js
自動実行: 新規/開ファイル後にチェック

で右下の設定ボタンを押します。

すると次回から新規作成時にmemoフォルダ配下にYYYYMMDD_[無題の後の番号].txtという名前で
ファイルを保存するようになります。

おまけ

この方法だと、サクラエディタを開いてすぐ閉じてしまうなど
0kBのファイルがそこそこできることがありますので、 次のようなバッチファイルを%USERPROFILE%\Desktop\memoにおいて実行すると消えます。

@echo off
cd %~dp0
for %%F in (*) do if %%~zF equ 0 del "%%F"
pause

Anaconda3とAnaconda2のインストール(Windows)

f:id:fa11enprince:20200115005038j:plain 例によって備忘録です。 Anaconda3とAnaconda2をWindowsで共存させる方法です。 ありふれた記事なのでGit Bashで使う方法も記載しました。 Python2のEOLが到来したというのに何をしているんだという感じですが、
いまだにNodeの安定板がPython2に依存しているっぽい(node-gypとか…)ので
とりあえず備忘録。はやくPython2滅んでくれ。
Nodeのインストーラーも相変わらず、
てな感じですので…。 Anaconda2を環境変数付きでインストール Anaconda3を環境変数付きでインストール ちなみに私はどちらも64bit版を選んでいます。 環境変数は後にインストール(=上のほう)が優先されます。 あれ?順番はインストーラーによるかも。 とりあえず上のほうが優先されるのでできればPython3の環境変数群を上に持っていきます。

次のバッチファイルを作成します

@echo off
rem ユーザの権限によって異なる様子
rem 管理者 %USERPROFILE%\
rem 通常ユーザー(Just Me) C:\Users\%USERNAME%\AppData\Local\Continuum\
rem 全ユーザー(All Users) C:\ProgramData\ -> C:\Users\All Users (Symbolic link) 
rem https://docs.anaconda.com/anaconda/user-guide/faq/
rem https://stackoverflow.com/questions/37117571/where-does-anaconda-python-install-on-windows

cd %USERPROFILE%\Anaconda2
copy python.exe python2.exe

cd %USERPROFILE%\Anaconda2\Scripts
copy anaconda.exe  anaconda2.exe
copy anaconda-script.py  anaconda2-script.py
copy conda.exe  conda2.exe
copy conda-script.py  conda2-script.py
copy easy_install.exe  easy_install2.exe
copy easy_install-script.py  easy_install2-script.py
copy pip.exe  pip2.exe
copy pip-script.py pip2-script.py
copy spyder.exe  spyder2.exe
copy spyder-script.py  spyder2-script.py

pause

これで実行すると

> python2 --version
Python 2.7.16 :: Anaconda, Inc.
> python --version
Python 3.7.4

ちなみにConEmuとかでGit Bashを使っている場合は、

$ cd ~
$ echo "source $HOME/Anaconda2/etc/profile.d/conda.sh" >> .bashrc
$ echo "source $HOME/Anaconda3/etc/profile.d/conda.sh" >> .bashrc
$ echo "alias python2='winpty python2'" >> .bashrc
$ echo "alias python='winpty python'" >> .bashrc

としてください。 なんかwinptyってGit for Windowsで対話モードのコマンドがうまく動かないことがあるそうなのでそのための対処です。 ちなみにこの状態で.bash_profileがないとWARNINGとともに初回ログイン時に勝手に.bash_profileが作られますのでご安心を。
※インストール方法(Just MeかAll Usersか)やユーザ権限によって変わり、
Just Meを選んだ場合は
$HOME/AppData/Local/Continuum/Anaconda2
$HOME/AppData/Local/Continuum/Anaconda3になる。 いずれにしてもwhere condaで調べられる。

npmの設定ファイルの場所

f:id:fa11enprince:20191129234333j:plain npm config setするよりエディタで直接いじりたくなる人向けの内容
npm config listとかで設定を見ると思うが、
そもそもどっちに設定されているんだっけ?
ってのもあるので…
npm -g config listというのもある。

npmの設定ファイルの場所

普通はnpm config setでやると思うが、面倒な場合
プロジェクト毎かユーザ毎かのを書き換える

種別 Linux Windows
プロジェクト毎 /path/to/project/.npmrc C:\path\to\project\.npmrc
ユーザ毎 ~/.npmrc %USERPROFILE%\.npmrc
グローバル $PREFIX/npmrc %APPDATA%\npm\etc\npmrc
ビルトイン /path/to/install/npm/npmrc C:\path\to\install\npm\npmrc

ちなみに
npm config setだとユーザ毎のファイルが
npm -g config setだとグローバルのファイルが書き換わる
紛らわしいがnpm install -gはビルトインのnode_modules
-gを付けないときはプロジェクト毎。

参考

https://stackoverflow.com/questions/15536872/nodejs-npm-global-config-missing-on-windows/22847156
https://stackabuse.com/the-ultimate-guide-to-configuring-npm/