ワム80000 モデルあらためて完
ブレーキカーに着手
ブレーキカーに着手。
まだこんなかんじ。詳細な各部寸法がわからん・・。
ブレーキカー更新
今日は、各コンポーネント内にあったゴミデータを掃除した。
ブレーキカーについては、車高の変更と機器の装着をした。ちなみに、黄色いのはメタローチという装置だそうだ。聴いたこと無いものだったので調べたら、メタル+アプローチの合成語で昔日立が使っていた商標の模様。要するに金属の接近を検知する近接センサである。こいつで貨車の車輪が近づいたことを検知するみたい。
今日はここまで。明日はブレーキの詳細を作る予定。
平行ではない、かつ交わらない線を滑らかに繋げる簡易的な方法
モデリングをしていると、平行ではない、かつ交わらない(つまり、ねじれの位置にある)2本の線をなめらかにつなげる曲線を描きたくなる。たとえば、柔らかいケーブルを2点間でつなげる場合だ。検索の仕方が下手なのか、どうやればいいのか解説しているページがなかったので独自にやり方を考えてみた。
滑らかに繋げる の定義
「滑らかに繋げる」の条件を定義する。円弧と直線が滑らかにつながる条件は、円弧のもととなる円と直線が接すること。これを描き方で言い換えると、「円弧の中心点が直線の端部から円弧の半径の距離にいること」となる。
2本の平行な直線を滑らかに繋げる場合
2本の平行な直線を滑らかにつなげたいならば両者の中間に円弧の中心を置き、半円を描いてつなげれば、少なくとも滑らかにはつながる。
2本の交わる直線を滑らかに繋げる場合
平行ではないが延長すると交わる直線の場合は、以下の手順で滑らかに繋げることができる。
1. 直線を延長し、交点を見つける。
2. 交点を中心とした円を描き、直線と交点までの距離を確認する。
3. 等距離でない場合は、遠い方を延長して等距離にする。
4. 垂直二等分線を描くため、両端を結ぶ直線を描く。(円は邪魔なので消しました)
5. 交点から直線の中点へと線を描く(これが垂直二等分線)。円弧の中心はこの直線上にある。必要に応じて延長する。
5. 直先端部と垂直な直線が垂直二等分線と交わる場所が、円弧の中心となる。
ちなみに、SketchUp!だと2点円弧を選べば上記4, 5は不要である。
2本の平行ではなく交わらない(ねじれの位置にある)直線を滑らかに結ぶ場合
本題である。この条件では、両方の直線に対し同時に直角となる円弧は存在しない。多分。何しろ、円弧を描くには両直線が乗っている平面が必要なのだが、これが描けないのだ。そこで、2個の円弧で繋げることにする。
1. まず、両直線を繋げる。
2. 一方の直線と、今作った直線を使って直角三角形を作る。これが1つ目の円弧が乗る仮の平面となる。
直角三角形の直角な直線同士に接するように円弧を描く。
あとで回転しやすくするため、円弧及び一部平面以外を消す。このとき、円弧につながる直角三角形の辺の一部を残したほうが、後の作業がやりやすくなる。
試しに先ほど残した辺の一部を延長すると、直線端部と交わっていることがわかる(そこに線を伸ばしたんだから当たり前であるが)。
ここまでくれば、「2本の交わる直線を滑らかに繋げる」と同じ手法が使える。ただし、このままでは半径0の円弧でつなぐことになるので、先程作った円弧を好みに応じて角度を変える。円弧を作ったときの直線を中心に回転させれば、円弧と直線の滑らかな接続を維持できる。
下記は結果の一例。
コントロールカー完成
モータカー仮完成
L4カーのモータカー、仮完成。こいつはリニアモータと給電部を持っているんだけど、給電部を写真に取りそこねてしまい形状が分からないので、まだ仮。
昔とった写真に写っていたら更新する。
L4カー ディスタンスカー(作りかけ)
ディスタンスカー、目立った役割が貨車の検知ぐらいしかないのに、妙に複雑な構造が多い。特に、上記画像手前のケーブルホルダーとか。なんでもっと素直な実装にできないのか、小一時間問い詰めたい。今日はここまで。
L4カー ディスタンスカー 完成(仮)
ディスタンスカー、仮完成。特徴は末端にあるスカート及びメタローチと、中央にある回転灯?ぐらいか。ケーブルの本数が左右非対称なんだけど、状態がよくわからないのでとりあえず1本ずつ書いて仮完成。
L4カーの導入先
L4カー全体像(仮)
L4カーの全体像。長すぎてよくわからん・・・。ところどころに寸法の矛盾があるように見えるので、ちょっと手直し必要だなあ。
Visual Studio2017でWindowsXp用プログラムをビルドする
事情によりWindowsXp用プログラムをビルドすることになったんだけど、WINVER等の定数をいじっても、出来上がったソフトが動かなかった。確か、有効な実行ファイルではありませんとか言われる。なんでかなーと思いながらオプションながめてたら、こんなの発見。Visual Studio 2017ではプラットフォームツールセットをXp用に変えないとだめみたい。
モータカー集電部
モータカーの集電部を作ってるんだけど、部品点数が多い上にバネまでいて苦戦中。日付変わる前に終わらなかった・・
モータカー 集電部 完成
結局モータカーの集電部完成させてしまった。電線むき出しだし、本体に絶縁無しで直接つないでいるように見えるから、正しくはアースなんだろうけど。
これ、バネで集電部を押し付ける構造なんだが、なんでこんなに部品多いんだろう・・・。もしかして、モータカーを設置する際には3連ナットの左右2個および集電部を外して、レールと干渉しないようにするためなのか?
L4カー モータカーをちまちま更新
モータカーを引き続き更新。
謎の箱更新
写真照合したら寸法狂っていたので修正。また、箱と本体の接続方法を修正。ついでに、ケーブルが出てくるところを正確な形状にした。
摺電部
L4カーの摺電部の構造はこうなってるっぽい。すなわち、摺電部はスプリングによりレールに押し付けられていて、接触角の変化は回転軸が吸収する。やってることはシンプルなんだけど、部品点数が多い。これは多分、本体をレール上に置くときのことを考えてのこと。スプリングで摺電部を押し付けるという構造なので、レールが無いときは摺電部がレール位置よりも内側に来る。これでは、車体をレール上に置けない。そこで、おそらく下図のようにパーツを外してから本体を置けるようにしていると思われる。・・・それでも、なぜアームの支点がこんな構造なのかは謎なんだけど。
ダイアログのコントロール上でも右クリックでメニューを出したい
ダイアログ上で右クリックした際にメニューを表示するには、OnRButtonUpあたりをオーバーライドしてやればいい。しかし、OnRButtonUpはダイアログ上のプログレスバー等の上で右クリックした場合には呼び出されない。これは、ボタンの上で左クリックした場合等を考えると当然の挙動である。
これを解決する方法は2つある。
今回のように、どのコントロールの上で右クリックしてもメニューを出す場合は2.が圧倒的に楽である。では、OnRButtonUpを呼び出す処理に割り込むにはどうすればいいか?MFCではWindowProc()をオーバーライドすればよい。Spy++でメッセージの流れを見たところ、WM_SETCURSORをトリガーに各コントロールのOnRButtonUpを呼び出しているようなので、これに割り込むことにする。
以下、サンプルコード。
CProgressCtrlのSetStateが反映されない
CProgressCtrlの色を変えようとしたがハマったのでメモ。
CProgressCtrlは、WindowsThemeが有効だとプログレスバーの色を変えるSetBarColorが無視される。そこで、SetStateでPBST_NORMAL, PBST_PAUSED, PBST_ERRORのいずれかを指定することでテーマに沿った色に変えることにした。しかし、なぜか変わらない!
ブレークポイントを設定したら変わることに気づいたので、ためしにバーの値更新周期を50msから500msにしてみたら、動いた。こんなの気づかないよ・・・。どこにもドキュメントされてないし。
以下、更新部分のソースコード。
追記:どうやら、プログレスバーの長さが変わっている最中にSetStateしても無視されるようだ。Vista以降では、SetPosで長さを変えると、その長さに向かってプログレスバーが伸びるアニメーションをする。このアニメーションをキャンセルすることで、瞬時にSetStateが有効になる。
以下、サンプルコード。
タブコントロール内のダイアログがESCキーで閉じてしまうのを防ぐ
ProgressCtrlの上に文字を表示
ブログをやっていてよかったこと
最近、ブログをやっていて良かったなーと思うのは、過去に調べたことが記録されていること。ブログの定義から、当たり前なんだけど。今作っているプログラムにしても、過去のブログ記事が非常に役立っている。Unicode<->マルチバイトの変換とか。
CInfoProgressCtrlの更新(プログレスバー伸長速度を切替可能に)
CInfoProgressCtrlはCProgressCtrlを継承することでプログレスバーの上に文字を表示できるようにしているのだが、このプログレスバーの欠点の一つに、バーを伸ばす速度が制限されている、というのがある。バーが縮む方向ならば瞬時に縮むので、これを利用して
SetPos(a+1);
SetPos(a);
というコードで回避するのが一般的である。ただし、これではaがRangeの上限に等しかった場合に対応できない。a+1まで伸ばせないからだ。これに対処するには、
SetRange(0,a+1);
SetPos(a+1);
SetPos(a);
SetRange(0, max);
というようなコードを書けば良い。しかし、毎回これを書くのは面倒なのでCInfoProgressCtrlを書き換え、自動でこれをできるようにした。
今回、Publicな関数としてbool SetSmoothMove(bool smooth)を追加した。これの引数smoothにfalseを設定すると、上記処理を自動でするようになる。なお、初期値はtrueなので既存のコードへの影響はないはず。