質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

Q&A

解決済

1回答

1931閲覧

数値と目盛が一致しない。

P5_USER

総合スコア73

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

0グッド

0クリップ

投稿2018/03/04 03:40

いつもお世話になっています。

前提・実現したいこと

高度計や速度計などの計器を作成しています。
この方の真似事です。
(スクショが何故か張れなかったので、申し訳ありませんがリンクまで飛んで、確認ください。)

発生している問題・エラーメッセージ

phi以外のtheta、psi、kvc、kphが目盛と一致していません。
map()を使っているのにも関わらず、数値と目盛が一致していません。

該当のソースコード

processing

1import hypermedia.net.*; 2UDP udp; 3 4PFont Font;//HUDフォント 5float newX = 0, newY = 0; 6float bank; 7float font_size_small; 8float font_size_large; 9 10float theta = 0;//ピッチ各 11float phi = 0;//バンク角 12float psi = 0;//方位角 13float kvc = 0;//CAS 14float kph = 0;//気圧高度 15void setup() 16{ 17 size(displayWidth, displayHeight); 18 Font = createFont("verdana.ttf", displayHeight/50, true); 19 20 //udp = new UDP (this, 60000); 21 //udp.listen(true); 22} 23 24//void receive (byte[] data, String ip, int port) 25//{ 26// String message = new String(data); 27// String[] rcvMSG = splitTokens(message, " "); 28// theta = float(rcvMSG[0]); 29// phi = float(rcvMSG[1]); 30// psi = float(rcvMSG[2]); 31// kvc = float(rcvMSG[3]); 32// kph = float(rcvMSG[4]); 33//} 34 35void draw() 36{ 37 font_size_small = displayHeight/40; 38 font_size_large = displayHeight/30; 39 textFont(Font, font_size_small); 40 41//↓この5つをtweakモードで検証する。 42 theta = 5; 43 phi = 0;//完了 44 psi = 0; 45 kvc = 0; 46 kph = 5452; 47//↑後で消す 48 49 //bank = atan2(mouseY - displayHeight / 2, mouseX - displayWidth / 2); 50 bank = radians(-phi); 51 //if (keyPressed) { 52 // if (key == '6') { 53 // psi = psi + 10; 54 // } 55 // if (key == '4') { 56 // psi = psi - 10; 57 // } 58 // if (key == '8') { 59 // theta = theta + 10; 60 // } 61 // if (key == '2') { 62 // theta = theta - 10; 63 // } 64 // if (key == '7') { 65 // kvc = kvc + 10; 66 // } 67 // if (key == '1') { 68 // kvc = kvc - 10; 69 // } 70 // if (key == '9') { 71 // kph = kph + 10; 72 // } 73 // if (key == '3') { 74 // kph = kph - 10; 75 // } 76 //} 77 background(0); 78 fill(0, 255, 0); 79 smooth(); 80 azi_scale(); 81 pitch_scale(); 82 spd_scale(); 83 alt_scale(); 84}
void alt_scale() { float mask_width = displayWidth / 8.0; float mask_height = displayHeight / 7.5; int alt_label_max = 100000; //速度の最大表示はMAX100000 [ft] int alt_delta = 200;//高度の表示間隔は20 [ft] int alt_num = alt_label_max / alt_delta; float alt_scale_length = displayHeight * 0.35; float alt_num_distance = alt_scale_length / alt_num; float alt_num_reach = mask_width * 0.35; float alt_scale_main_reach = mask_width * 0.20; float alt_scale_sub_reach = mask_width * 0.10; float alt_num_exist; float alt_scale_sub_exist; map(kph, 0, alt_label_max, 0, alt_scale_length * (alt_label_max / alt_delta)); translate(displayWidth, 0);//画面右上に移動 scale(-1, 1);//x軸左側:正、y軸下側:正 rectMode(CORNER); noStroke(); fill(0); rect(0, 0, mask_width, displayHeight);//高度計の背景をセット stroke(0, 255, 0); line(0, mask_height, mask_width, mask_height);//上側の線 line(mask_width, mask_height, mask_width, displayHeight - mask_height);//側壁の線 translate(mask_width, displayHeight / 2);//中央に移動 scale(-1, 1); for (int i = 0; i <= alt_label_max; i += alt_delta) { alt_num_exist = -(i * alt_num_distance) + kph ; alt_scale_sub_exist = alt_num_exist -alt_num_distance * (alt_label_max/1000); fill(0, 255, 0); text(i, alt_num_reach * 2.3, alt_num_exist + font_size_large * 0.3); line(0, alt_num_exist, alt_scale_main_reach, alt_num_exist); line(0, alt_scale_sub_exist, alt_scale_sub_reach, alt_scale_sub_exist); } scale(-1, 1); translate(-mask_width, -displayHeight / 2);//画面右上に移動 fill(0); noStroke(); rect(0, 0, mask_width, mask_height);//速度計の上端の見切れをセット translate(0, displayHeight);//画面右下に移動 scale(1, -1);//x軸左側:正、y軸上側:正 noStroke(); rect(0, 0, mask_width, mask_height);//高度計の下端の見切れをセット stroke(0, 255, 0); line(0, mask_height, mask_width, mask_height);//下側の線 scale(1, -1); scale(-1, 1); translate(-displayWidth, 0); }
void azi_scale() { int[] azimuth_label_str = {27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36};//方位を数字で格納するための配列 int azi_num = azimuth_label_str.length; float azi_scale_length = displayWidth * 15.0; float azi_num_distance = azi_scale_length / azi_num; float azi_num_exist; float scale_sub_exist; map(psi, 0, 360, -(6) * azi_num_distance, (30) * azi_num_distance); translate(displayWidth / 2, displayHeight / 2); rotate(bank); if (psi + (30) * azi_num_distance < 0) { psi = (6) * azi_num_distance; } if (psi + (-6) * azi_num_distance > 0) { psi = -(30) * azi_num_distance; } noFill(); stroke(0, 255, 0); textAlign(CENTER); for (int i = 0; i <= azi_num - 1; i++) { azi_num_exist = psi + (i-9) * azi_num_distance; scale_sub_exist = azi_num_exist + azi_num_distance / 2; text(nf(azimuth_label_str[i], 2), azi_num_exist, -displayHeight/30 + theta);//数字 line(azi_num_exist, theta, azi_num_exist, -displayHeight/40 + theta);//大目盛 line(scale_sub_exist, theta, scale_sub_exist, -displayHeight/70 + theta);//小目盛 line(azi_num_exist, theta, psi + (i-8) * azi_num_distance, theta); } rotate(-bank); translate(-displayWidth/2, -displayHeight/2); }
void pitch_scale() { int[] pitch_label_str_plus = { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90};//ピッチ角がプラスのラベル int[] pitch_label_str_minus = {-5, -10, -15, -20, -25, -30, -35, -40, -45, -50, -55, -60, -65, -70, -75, -80, -85, -90};//ピッチ角がマイナスのラベル int pitch_num = pitch_label_str_plus.length;//表示するラベルの数 float pitch_scale_length_half = displayHeight * 3.00;//片方のピッチラベルの表示する長さ float pitch_num_distance = pitch_scale_length_half / pitch_num;//ラベルの座標的な間隔 float pitch_num_plus_exist;//ピッチ角が正のラベルの存在するy座標 float pitch_num_minus_exist;//ピッチ角が負のラベルの存在するy座標; float scale_sub_exist;//中間の目盛の存在するy座標 float pitch_num_interval = displayWidth * 0.15;//数字ラベルの存在するx座標 float line_outer = displayWidth * 0.145;//線の外側端点x座標 float line_inner = displayWidth * 0.075;//線の内側端点x座標 map(theta, -90, 90, -pitch_scale_length_half, pitch_scale_length_half); translate(displayWidth / 2, displayHeight / 2); rotate(bank); for (int i=0; i <= pitch_num-1; i++) { pitch_num_plus_exist = - (1 + i) * pitch_num_distance + theta; textAlign(LEFT); text(nf(pitch_label_str_plus[i], 2), pitch_num_interval, pitch_num_plus_exist); textAlign(RIGHT); text(nf(pitch_label_str_plus[i], 2), -pitch_num_interval, pitch_num_plus_exist); line(line_inner, pitch_num_plus_exist - font_size_small, line_outer, pitch_num_plus_exist - font_size_small); line(-line_inner, pitch_num_plus_exist - font_size_small, -line_outer, pitch_num_plus_exist - font_size_small); line(line_outer, pitch_num_plus_exist, line_outer, pitch_num_plus_exist - font_size_small); line(-line_outer, pitch_num_plus_exist, -line_outer, pitch_num_plus_exist - font_size_small); } for (int i=0; i <= pitch_num-1; i++) { pitch_num_minus_exist = (1 + i) * pitch_num_distance + theta; textAlign(LEFT); text(nf(pitch_label_str_minus[i], 2), pitch_num_interval, pitch_num_minus_exist); textAlign(RIGHT); text(nf(pitch_label_str_minus[i], 2), -pitch_num_interval, pitch_num_minus_exist); line(line_inner, pitch_num_minus_exist, line_outer, pitch_num_minus_exist); line(-line_inner, pitch_num_minus_exist, -line_outer, pitch_num_minus_exist); line(line_outer, pitch_num_minus_exist, line_outer, pitch_num_minus_exist - font_size_small); line(-line_outer, pitch_num_minus_exist, -line_outer, pitch_num_minus_exist - font_size_small); } rotate(-bank); translate(-displayWidth / 2, -displayHeight / 2); }
void spd_scale() { float mask_width = displayWidth / 8.0; float mask_height = displayHeight / 7.5; int spd_label_max = 1000; //速度の最大表示はMAX1000 [kt] int spd_delta = 20;//速度の表示間隔は20 [kt] int spd_num = spd_label_max / spd_delta; float spd_scale_length = displayHeight * 0.35; float spd_num_distance = spd_scale_length / spd_num; float spd_num_reach = mask_width * 0.35; float spd_scale_main_reach = mask_width * 0.20; float spd_scale_sub_reach = mask_width * 0.10; float spd_num_exist; float spd_scale_sub_exist; map(kvc, 0, 1000, 0, spd_scale_length * 50); textFont(Font, font_size_large); rectMode(CORNER); noStroke(); fill(0); rect(0, 0, mask_width, displayHeight);//速度計の背景をセット stroke(0, 255, 0); line(mask_width, mask_height, mask_width, displayHeight-mask_height); translate(mask_width, displayHeight / 2); textAlign(RIGHT); //速度計表示 for (int i = 0; i <= spd_label_max; i += spd_delta) { spd_num_exist = -(i * spd_num_distance) + kvc; spd_scale_sub_exist = spd_num_exist - spd_num_distance * (spd_label_max/100); fill(0, 255, 0); text(i, -spd_num_reach, spd_num_exist + font_size_large * 0.3); line(0, spd_num_exist, -spd_scale_main_reach, spd_num_exist); line(0, spd_scale_sub_exist, -spd_scale_sub_reach, spd_scale_sub_exist); } fill(0); translate(-mask_width, -displayHeight / 2); noStroke(); rect(0, 0, displayWidth, mask_height);//速度計の上端の見切れをセット stroke(0, 255, 0); line(0, mask_height, mask_width, mask_height); translate(0, displayHeight); scale(1, -1); noStroke(); rect(0, 0, displayWidth, mask_height);//速度計の下端の見切れをセット stroke(0, 255, 0); line(0, mask_height, mask_width, mask_height); scale(1, -1); translate(0, -displayHeight); }

疑問点

map()という関数は、数字の取り得る幅を同じ比率で変換することが出来る関数であるという認識でよろしいでしょうか?

だとしたら、phi以外のmap()が使われているところは何故、数値と目盛があってくれないのか......

補足情報(FW/ツールのバージョンなど)

Processing 3.3.6

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

質問者さんは

map(kph, 0, alt_label_max, 0, alt_scale_length * (alt_label_max / alt_delta));

などのようにmapを呼び出してはいますが、その肝心の結果を用いていません。

推測ですが、「mapを呼び出すと画面の座標系が変化する」と勘違いしておられるのではないでしょうか?mapは単なる関数ですので、そういう機能はありません。座標系を変化されるのはtranslate, scale, rotateなどの機能です。

HUDを描画する場合、「画面上のHUDの描画位置を表す固定的な座標系」も意識する必要がありますので、(アフィン変換行列を変更するかどうかはさておき)次のような考え方をしてみてはどうでしょう?

java

1float pitch_range = 45; // HUD上の値の範囲(45度と仮定) 2float min_y = 850; // HUD上のpitchの最小値を描画する画面上の座標 3float max_y = 50; // HUD上のpitchの最大値を描画する画面上の座標 4 5float pitch = 20; // 目盛りの中心位置 6 7float pitch_min = pitch - pitch_range * 0.5; // HUD上のpitchの最小値 8float pitch_max = pitch + pitch_range * 0.5; // HUD上のpitchの最大値 9 10// 5度ごとに目盛りを入れるなら 11int min_pitch_scale = ceil(pitch_min / 5) * 5; 12int max_pitch_scale = floor(pitch_max / 5) * 5; 13for (int p = min_pitch_scale; p <= max_pitch_scale; p += 5) { 14 float y = map(p, pitch_min, pitch_max, min_y, max_y); 15 // y座標のところへ目盛りを描画 16}

投稿2018/03/04 05:21

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

P5_USER

2018/03/04 05:37

KSwordOfHaste さん ありがとうございます。 http://www.musashinodenpa.com/p5/index.php?pos=364 にあるmap()の説明を見て、map()に返り値があるのであれば、 入力された実際の数値を目盛の幅に対応した画面の中での対応した数値を 返してくれるのではないか、と考えた次第です。
KSwordOfHaste

2018/03/04 05:41

> map()に返り値があるのであれば 返り値はありますね。 > 入力された実際の数値を目盛の幅に対応した画面の中での対応した数値を返してくれるのではないか その認識で合ってると思いますよ。問題はmapの戻り値を使って計算してない点だけではないでしょうか?
P5_USER

2018/03/04 05:54

なるほど、 今、pitch_scale()のmap(...)に対してtheta = map(theta,-90,90, -pitch_scale_length_half, pitch_scale_length_half) とすると、真ん中の表示はうまくいきました。 map()での返り値を対象の変数に与えてあげないとだめということでしょうか? ただ、kphもkvcも同様にkhp=map(...),kvc=map(...)としたところ、こちらは何故かうまくいくことはありませんでした。 map()に対する認識が誤っているのでしょうか。
KSwordOfHaste

2018/03/04 06:05

自分の回答に書いたmapの使い方が参考にならないでしょうか?
P5_USER

2018/03/04 06:33

float y = map(p, pitch_min, pitch_max, min_y, max_y); のことですよね? float yと新規に設定しているのはどういった意図なんでしょうか?
KSwordOfHaste

2018/03/04 06:56 編集

Javaの元となったC言語の古い仕様では関数の先頭部分で全部のローカル変数を宣言する必要がありました。そのような言語では「変数を追加したり、削除したりする際にあっちこっちを修正しなければならない」という点で「合理的でない」と考えるプログラマーが多かったと思います。 今日コンパイラー言語の多くが「使用する箇所で宣言」できるような仕様になっています。Javaもそのよういう仕様です。ProcessingのJava言語バージョンでも同様です。 こういうふうに使います。 if (...) { float a = ...; // aはこのif文の中だけで使う一時的な変数 ... } //この場所ではaは参照できないし、参照する必要もない。 ---補足--- 上ではif文の例を挙げましたがfor文やwhile文やメソッドの本体を表すあらゆるブロック(つまり'{'と'}'で挟まれた内側)の中で宣言された変数はその内側でだけ存在する変数とできます。
P5_USER

2018/03/04 06:58

なるほど。スコープを意識して、他から意図的に改変されることの無いようにする為なんですね。 教えていただいたコードを参考にして、例えば、速度計のコードを以下のように変えてみました。 //速度計表示 for (int i = 0; i <= spd_label_max; i += spd_delta) { float y = map(kvc, 0, 1000, 0, spd_scale_length * (spd_label_max / spd_delta)); spd_num_exist = -(i * spd_num_distance) + y; spd_scale_sub_exist = spd_num_exist - spd_num_distance * (spd_label_max/100); fill(0, 255, 0); text(i, -spd_num_reach, spd_num_exist + font_size_large * 0.3); line(0, spd_num_exist, -spd_scale_main_reach, spd_num_exist); line(0, spd_scale_sub_exist, -spd_scale_sub_reach, spd_scale_sub_exist); } kvcを40にすると、目盛では100を示していました。 また、kvcを80にすると、200を示していました。 入力に対して出力が2.5倍というマジックナンバーめいた値が気になりますが、他のコードを探してもそれらしきものが見当たりませんでした...
KSwordOfHaste

2018/03/04 07:31

map(x, from_min, from_max, to_min, to_max) とするとfrom_min~from_maxのどこにxが位置するかによってその相対位置をto_min~to_maxの対応する値へ変換するということはおわかりのような気がするのですが・・・ >入力に対して出力が2.5倍 それはfrom_max-from_minに対してto_max-to_minが2.5倍になるような値をmapに指定したからそうなっただけですよ?つまり2.5倍になったのはP5_USERさんがそういう値をmapに指定したからですw;
P5_USER

2018/03/04 08:12

無事解決しました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問