vexを使ってポイントを任意のルールでソートしようと思ったらちょっと手間取ったのでメモしておきます。
まずsort SOPで答え合わせ
サークルにscatterしてsortSOPにY軸の値でソートさせたのがこちらです。
vexでのソート
このようなコードでソートさせました。ランオーバーはdetailです。高級言語のソート関数に相当するものは存在しないので、argsort関数で別の配列にソート済みの並び順を代入することでソート処理の代わりとします。argsort関数は文字コード及び数値の降順でしかソートできないようです。
float pos_arr[] = {}; // y座標の配列
for(int i=0;i<@numpt;i++) {
vector p = point(0, "P", i);
push(pos_arr, p.y);
}
int ordering[] = argsort(pos_arr); // 数値が大きい順にポイント番号(ただしくは配列のインデックス番号)を格納する
ordering = reverse(ordering); // 小さい順にしたいので反転する。
// visualizeさせるために適当なアトリビュートに代入する
//(ordering配列のまま処理を進めるだけならばこの処理は必要ない)
for(int i=0;i<@numpt;i++) {
setpointattrib(0, "sort_index", ordering[i], i);
}
sort_indexをvisualizeしたのがこちらです。
visualize のために sort_index アトリビュートを設定しましたが、通常は上記のコードで ordering に相当する配列にソート済みポイント番号が入っているのでそれをそのまま使います。
さらに別要素でソートする
argsort 関数(および sort SOP)は stable sort といって、評価順位が同じものは元の順序を保ったままのソート実装だそうです。つまり、別の要素で2度目のソートをしても同じ優先順位を持つ部分では1度目のソート順をキープするはずです。
円ではわかりずらいので2x2のグリッドを用意します。
上段左からグリッド作成時そのまま、SortSOPによるY座標昇順ソート、SortSOPによるX座標降順ソートの順に対応したもの、下段はグリッドそのままをSortSOPによるX座標降順ソートのみ対応したものです。一番右上のグリッドではポイント番号が右方向からかつ上方向からで並んでいるのが確認できます。
これを vex で同等の処理をさせてみます。
float pos_arr[] = {};
int ordering[];
vector p;
// y座標を収集
for(int i=0;i<@numpt;i++) {
p = point(0, "P", i);
push(pos_arr, p.y);
}
// y軸で降順ソートして昇順に変換
ordering = reverse(argsort(pos_arr));
// x座標を収集
pos_arr = {};
for(int i=0;i<@numpt;i++) {
p = point(0, "P", ordering[i]);
push(pos_arr, p.x);
}
// x軸で降順ソートして昇順に変換
ordering = reverse(argsort(pos_arr));
for(int i=0;i<@numpt;i++) {
setpointattrib(0, "index", ordering[i], i);
}
sort SOP のパラメータ設定では対応できない複雑なソートでも、vex であれば対応させられそうです。
実際にポイント番号をソート順に割り振りたい
プログラムでそのまま処理する場合はordering配列をそのまま扱えばいいのですが、実際にポイント番号を入れ替えたい場合は、sort SOPにアトリビュートを元にソートさせてしまった方が簡単です。
これを vex でやるには、ポイントの位置を入れ替えて、頂点をつなぎなおせば可能な気はします。やってみるか?
考察
今回は0から並んだポイント番号をソートさせたので必要なかった(ordering配列が欲しいものそのものだった)ですが、任意の要素をソートさせた場合、reorder関数でソート済みの任意の配列を得る処理が必要です。
参考 vex : argsort