Eyeshotにてクリックで3Dオブジェクトの座標を選択

弊社の案件では3Dオブジェクトを表示するのにEyeshotライブラリを使用しています。

ある機能改造にて、Eyeshotで表示している3Dオブジェクトをクリックして座標を選択し、
コードからオブジェクトを基準座標に移動させることとなりました。

クリックして座標選択可能かわからなかったため調べてみたところ、
以下のScreenToWorldというメソッドにより実現できるとわかりました。

public Point3D ScreenToWorld(Point mousePos)

これはEyeshotの3D表示コントロールであるViewportLayoutクラスに定義されたメソッドで、
引数でマウスカーソル位置のスクリーン座標を与えることで、
戻り値として、カーソル下に3D物体があればその表面のワールド座標を、なければnullを返すメソッドとなっています。

これをマウスクリックイベントに登録したメソッド内で呼んで解決……かと思ったのですが、
そうもいかず、座標選択できるものとそうでないものがあり、
どうも3Dオブジェクトが半透明(カラーにα値の設定あり)の場合はScreenToWorldがnullを返してしまうようでした。

ちらつき発生しますが、クリック時に一時的に3Dモデルを不透明(α値最大)とすると座標選択でき、
無事改造内容実現できました。

以上です。

C#でダブルバッファを使って画面のちらつきを防ぐ方法

今回は、C#でダブルバッファを使って画面のちらつきを防ぐ方法についてです。

画面がちらつくという現象は、画面の描画が速く行われるときに起こります。例えばウィンドウをリサイズしたりすると、画面の一部が更新されます。
このとき画面の更新が一瞬で行われると、画面がちらついて見えることがあります。これは、画面の更新がユーザーの目に追いつかないために起こります。

画面のちらつきを防ぐには、ダブルバッファという技術を使います。
ダブルバッファとは、画面に表示するデータを2つのバッファに分けて管理する方法です。
一つのバッファは、画面に表示されるバッファで、もう一つのバッファは、画面に表示する準備をするバッファです。
画面の更新が必要になったときには、準備されたバッファを画面に表示するバッファと入れ替えます。
このようにすると、画面の更新が一瞬で行われるのではなく、スムーズに行われるので、画面のちらつきが防げます。

C#のWindowsFormsでダブルバッファを使うには、DoubleBufferedプロパティを使用します。
DoubleBufferedプロパティは、コントロールのダブルバッファを有効にするかどうかを表すプロパティです。
DoubleBufferedプロパティをtrueにすると、コントロールのダブルバッファが有効になります。
ただし、単に自身のコントロールのDoubleBufferedをtrueにするだけでは、子コントロールのちらつきは防げません。
子コントロールも含めて全てのコントロールのDoubleBufferedをtrueにする必要があります。
しかし、子コントロールのDoubleBufferedは、通常は外部から設定できません。
そこで、リフレクションを使って、外部から子コントロールのDoubleBufferedを設定できるようにし、子コントロールのDoubleBufferedプロパティを再帰的にtrueに設定します。

このようにして、C#でダブルバッファを使って画面のちらつきを防ぐことができます。

変なシステムを作らないために。

こんにちは mtjです。

プログラマーの仕事をしていると 世の中のどうしてこうなった ようなシステムを見るともやもやする機会が増えます。
そこからこうなった原因はどこなんだろうと考えるのも面白いですがそうならないためにを考えていきます。

まず変なシステムを作らないためにはお客さんの要望をしっかり聞く事が大事です
・何をしたいか。
・その後どう使うか。
・どのような人が使うか。
のようにしっかり要点をまとめ、お客さんの依頼通りのシステムだけでなく 用途にあったシステムを作っていくことが重要だと思います。

依頼主は依頼主の知識内でしか想像できませんし、開発側も開発側の知識しかありません。
その2つを上手くすり合わせし必要なシステムを作ることが大事だと思います。

しかし、提案だけではシステムは上手くいきません。
システムはそこから作る人の問題もあるため結局はお客さんの伝える能力、開発側の依頼を受ける能力、開発側の開発自体の能力等すべて揃って初めて良いシステムになると思います。

自分も変なシステムを作らないようにそういった意識を持って開発していきたいと思います。

画面のデザインは難しい

2024年 本年もどうぞよろしくお願い申し上げます。

先日Windowsのソフトで画面の実装を行う機会があり、
それほど複雑な画面ではないものの、ユーザーにとって視認性の高い画面にする必要がありました。

仕様書の段階で画面のイメージは概ね出来上がっていたものの、
実装段階になるとデザインがなかなか上手くできずに困り、
結局、この件ではデザイナの方にデザインをお願いすることになりました。

WPFやMVVMなどのフレームワークが整っている環境でも、
実際にはデザイナではない開発者が、画面のデザインや実装も担当する場合が多いと思います。
その場合でもデザイナの方が行った目標とするデザイン(ゴール)がきちんとあれば、
実装はとてもやりやすいと感じました。

2023年お疲れ様でした

今年も早いものでもう終わりですね。

弊社は今年も本日は午前のみ業務で午後からは大掃除を行い、仕事納めとなります。
年末年始ゆっくりと過ごしたいです。

皆様本年はお世話になりました。
来年も何卒よろしくお願いいたします。
それではよいお年をお迎えください。

Stopwatchクラスの拡張メソッド

C#のStopwatchクラスを使用する際によくあるパターンとして、あるフラグによってスタートまたはリセットしたり、リスタートまたはリセットしたりする場合があります。
せっかくなので拡張メソッドを作成してみました。
実装はしょうもない内容ですが、これによりコードがスッキリします。

public static void StartOrReset(this Stopwatch swbool start) {
    if (start) {
        sw.Start();
    } else {
        sw.Reset();
    }
}
public static void RestartOrReset(this Stopwatch swbool restart) {
    if (restart) {
        sw.Restart();
    } else {
        sw.Reset();
    }
}

ツールの勉強、知識

こんにちは mtjです。

開発にはバージョン管理ソフトというツール または サービス等を利用し複数人で開発が行いやすいように開発します。
しかしこれを使用しない会社も存在します、大体がツールを使うための知識不足かのらりくらりと同じ昔の手法でやりたいからだと思います

開発というのはプログラム等の知識だけでなく そういった開発自体を便利にするためのツールを上手く使うための知識も必要になると思います
日々新しく出たIDE バージョン管理ツール 入力サポートツール等の知識を入れ開発の速度が遅れていかないように自分も気をつけたいと思います。

管理ツールを使わない会社では
・共有フォルダにプロジェクトを入れる
・バージョン別にファイルを別名で保存する。
・コメントでコード内に変更点を記載する(旧コードをコメントアウトしながら)
・同じファイルを編集する場合は声がけして行う
ような感じでかなり古い体制で開発を行っているようです。

マイコン開発でのリンカ設定

C言語でマイコン開発を行っている中で、関数外で宣言した変数の値が書き換えられない現象に遭遇しました。

static bool _initializedA;           // A
static bool _initializedB = false;   // B

void init() {
  _initializedA = true;
  _initializedB = true;
}

上のようなコードで、Aは関数内で書き換え可能ですが、Bは書き換えされず、関数を抜けても _initializedB の値が false のままという内容でした。コンパイルおよび実行時にも警告やエラーが発生せず、最初理由がよく分かりませんでした。

原因はリンカの設定によるものでした。Bのほうは初期値ありなので.dataセクション(ROM)に配置され、リンカのデフォルトの設定ではROMからRAMへのマップが行われていませんでした。

実はこのときは普段使用しているものとは異なるマイコンでの開発であったため、開発環境も普段とは異なり、デフォルトのリンカの設定がこのようになっているとは知りませんでした。

C言語での開発はオープン系言語と比べると、このような点でも難しく感じます。せめて警告やエラーが発生すればもっと早く気が付けるのですが、言語知識だけでなく、経験や経験に基づく感も必要なようです。

C#のrecord型と、.Net5未満での使用時のエラーについて

随分前に追加されたrecord型を今更ながら使い始めました。

内部的にはクラスと同じ扱いで、プロパティは全て不変とは以前から知っていたのですが、
先日recordもstructと同様にIEquatableが実装されていると聞き、
それならDictionaryのキーなどでも使いやすく、
1行で定義を済ませられるのも楽で良いなと思い使ってみることにした次第です。

ひとまず、以下のようなrecordを定義してみました。

/// <summary> 汎用結果クラス </summary>
/// <param name="Succ"> 成功したか </param>
/// <param name="ErrMsg"> 失敗時のエラーメッセージ </param>
record Result(bool Succ, string ErrMsg = "");

/// <summary> 汎用結果クラス </summary>
/// <param name="Succ"> 成功したか </param>
/// <param name="Value"> 戻り値 </param>
/// <param name="ErrMsg"> 失敗時のエラーメッセージ </param>
record Result(bool Succ, T Value = default, string ErrMsg = "");

よくタプルで成否のbool値と成功時の戻り値、失敗時のエラーメッセージを書いていたのですが、
クラスにするほどでもないけれど一々書くには若干手間だったので、
手軽に定義・使用できて良かったです。

今のところ以下のような場合にrecordを使うのが良いのかなと思っています。
・不変にしたい
・辞書のキーとしてのみ使用する
・特にメソッドなど実装予定なし

どこで使うべきかは正直、手を動かして使ってみないことには見極められない気がしているので、
今後も機を見て使っていこうと思います。

また、業務プロジェクト(C#9.0, .Netframework4.6-4.8)でrecordを宣言すると、
次のようなエラーが出て使用できませんが、
「定義済みの型’System.Runtime.CompileServices.IsExternalInit’は定義またはインポートされていません。」
以下の記事の通り、IsExternalInitクラスを自前でinternalで定義するとエラー解消し、使用できました。
(記事タイトル通り、record型だけでなくinitアクセサも使用できるようになりました)

言語か.netのバージョンが不足しているのだと思い諦めかけたのですが、
調べてみたら解決して良かったです。

以上です。

お手軽リレー接点出力

最近の案件でリレー接点出力を1点だけ制御する必要があったため、「DSD TECH」の「SH-UR01A」というUSB接続のリレー接点出力を使用しました。
仮想COM通信でコマンドを送信するだけで制御が出来るので、とても簡単です。

普段はコンテックなどのI/Oデバイスを使用しますが、1,2点程度の場合は「SH-UR01A」のほうがお手軽そうです。