鳥の巣箱

ネトゲしたり、機械いじったり、ソフト書いたり、山篭ったり、ギャンブルしたりする人

3周年記念アップデート。。。ムラサメよこせ(

スマログ3周年アップデートきました。

新ジョブヴァルキリー実装で、新武器までひっさげてきちゃいましたよこの子ってやつです。
しかもつおい(小並感

まぁ、ヴァルキリーは今回私スルーしますがね!

それよりも今回やるべきは。。。

続きを読む

MoveTo、LineToメソッドで描いた線とPen.Widthの特性。。。とScanLineについて。

TBitmapコンポーネントなどには、そのBitmap上に線を引くために
・MoveTo(x,y)
・LineTo(x,y)
というメソッドが用意されてます。

MoveTo(x,y)で線の始点になる座標を指定し、LineTo(x,y)で指定した座標まで直線を描きます。

また、Pen.Widthプロパティで線の太さを指定できます。
Pen.Widthプロパティに1を指定すれば1ピクセル、2を指定すれば2ピクセルの太さの線を描けます。

ではこれをふまえて、以下のプログラムを見てみます。

procedure LineDraw;
var 
    Bitmap  : TBitmap;
begin
    Bitmap  := TBitmap.Create;
    
    Bitmap.Width    := 10;
    Bitmap.Height   := 10;

    Bitmap.Canvas.Pen.Color := clRed;
    Bitmap.Canvas.Pen.Width := 1;

    Bitmap.Canvas.MoveTo(5,0);
    Bitmap.Canvas.LineTo(10,0);
end;

解説用にざっくり書きましたので、実用性等は言及無しで(
上記のプロシージャは、新たにBitmapを生成して縦横10×10の大きさに指定しています。
このBitmapに(5,0)から(5,10)に向かって太さ1ピクセルの赤い縦線を描きます。

つまりこうですね。
f:id:tsubakurame-1913:20160906175507p:plain


これは簡単です。誰にでもイメージできると思います。
では、もし仮にPen.Widthが2以上になった時は、どのように描画されるのでしょうか?
縦に2ピクセル分塗られるわけですが、それはx=5の位置ともう1ヶ所はどこでしょうか?
x=4なのか、x=6なのか。。。

ということでこれを調べましょう。
どうやって調べるかというと。
指定したピクセルの色情報を抜き出すことで、どのピクセルが塗られているのかを調べることにします。

そのためにScanLineを使います。

上記のソースをちょっといじりましょう。

procedure LineDraw;
var 
    Bitmap  : TBitmap;
    pByte   : PByteArray;
begin
    Bitmap  := TBitmap.Create;

    Bitmap.Width        := 10;
    Bitmap.Height       := 10;
    Bitmap.PixelFormat  := pf24bit;

    Bitmap.Canvas.Pen.Color := clBlack;
    Bitmap.Canvas.Pen.Width := 2;

    Bitmap.Canvas.MoveTo(5,0);
    Bitmap.Canvas.LineTo(10,0);

    pByte   := Bitmap.ScanLine[0];
end;

こうなります。
PixelFormatはいろいろ種類がありますが、24bitが一般的です。
RGBそれぞれ8bit(0~255)×3です。

pByte  := Bitmap.ScanLine[0];

でpByteにBitmap上、y=0の1行分のデータがまるっと配列として代入されます。
このとき、RGBカラー情報がすべて別に代入されるので、配列の要素数としてはwidth×3となります。
今回だと30ってことですね。
配列の並び順としては、RGBではなく逆のBGRで並んでいることに注意。

あとは、pByteをMemoコンポーネントでもcsvにして吐き出すでもいいので出力してやればOK。


ということで、Pen.Widthを2~5まで変化させて、どのように直線が描かれるのかをまとめたのが以下の画像です。

f:id:tsubakurame-1913:20160906181239p:plain
f:id:tsubakurame-1913:20160906181241p:plain

と、このような結果になりました。
Pen.Widthが奇数の時は、指定した座標を中心に描画。
Pen.Widthが偶数の時は、指定した座標よりマイナス方向へはみ出して描画されるようです。

仕事が詰まっているので今回は必要だった縦方向のみの検証です。
おそらく横方向にも同じ特性が言えるのではないかと思います。


精密な描画を求められた時、1ピクセルの計算ズレも致命な欠陥に繋がるのでこの特性は覚えておきたいですね。

HAL Driverが使えるSTM32系開発環境を作る

オヒサシブリデス


ARM Coreは昨今の組込技術には無くてはならない存在になってますね。
きがついたら
hbol.jp

Softbankが買収してたりと、最近になってARMという存在を知らなかった人にも名前くらいは浸透したのではないでしょうか。


さて、もちろん私もこの業界にいる限り避けては通れない存在です。
ARM Core CPUを販売しているメーカーのひとつにSTMicroがあります。STM32シリーズは価格が安く機能が充実しているものが多いので重宝されます。
今回はこのSTM32系の開発環境を構築していく手順をまとめます。


今回使用したものは、STMicro社のNucleo-F030R8ボードです。
評価ボードなので、ICEもついてて非常に使いやすいです。
秋月で1500円くらいで売ってます。
搭載されてるCPUはSTM32030R8T6で、STM32F0xシリーズに分類されます。


この記事では上記のボード、CPUを前提に進めますがそれ以外のものでも基本大丈夫なはずです。
少々手を加える必要はありますが。


STMicroが提供しているライブラリは現時点で2種類

Standard Peripheral Driver(通称SPD)
Hardware Abstraction Layer(通称HAL)
があります。
SPDの方が最初に提供されていたライブラリなのですが、後にHALが登場。
なのでネットなどを調べてもSPDを用いたものと、HALを用いたものでは出てくる量が全然違います。特に日本語(
しかし、STMicroは今後HALを推し進めていくようです。
さらには、一部評価ボードなどではもうSPDで操作できない部分もあるようで完全に切り捨てるようですね(
SPDとHALは互換性もないので、楽してSPDを使うと今後使えなくなった時にキッツイので。。。
なのでHALを使うことを目標に環境を立ち上げます。


色々と試行錯誤の末デバッグ環境までこぎつけた感じなので、もしかしたらいらない工程が含まれてるかもしれません。
とりあえず、現時点での私の環境をそのまま再現する手順を書きました。
これいらなかったとかアレばコメントなどください。

続きを読む

特定サイズのダミーファイルを生成するコマンド

とある事情により、HDDの空き容量を調整するためにダミーファイルを大量に生成する必要がでてきたので
ついでに紹介。

Windows XP以降のコマンドプロンプトには、fsutil.exeというツールが用意されており
これを使うことでとても簡単にしかもサクサクとダミーファイルを生成することができる。

使い方はこんな感じ

fsutil file createnew filename xxx

filenameはそのまま生成されるファイル名を、xxxにはファイルサイズを指定します。
当然2進接頭辞で指定しないと正確なサイズにはなりません。

1kB : 1024
1MB : 1048576
1GB : 1073741824

といった具合。
ディスクのフォーマットによって作成できる1つあたりのサイズは当然決まってきますので、その範囲を超えないように。

一つのファイルをつくるならこれで簡単にできますが、例えば「1GBのダミーを100個」とかいう場合、いちいちコマンドを叩くのは大変なのでバッチファイルを作ってしまいます。

for /L %%n (1,1,100) do fsutil file createnew %%n 1073741824

と、たった1行のバッチファイルを作成するだけですぐ作れます。
この例だとファイル名1~100で1つあたり1GBのダミーファイルを生成してくれます。
生成される場所はバッチファイルがあるディレクトリです。


なお、これで生成にかかる時間は数秒程度です。
全然時間は食いませんね。


ディスク容量をあらかじめ確保する必要がある場合や、負荷テスト、その他いろいろな試験などなど使う場面は多々あるかも?

HDD容量の取得とLARGE_INTEGERの扱い

HDD容量を取得する場合は、Windows APIにあるGetDiskFreeSpace関数を使うと各変数に色々値をぴったんこしてくれるわけですが

僕、最初普通にこの「GetDiskFreeSpace関数」の方を使ってたんですね。

そしたら正しい値が返ってこないというわけで。

https://msdn.microsoft.com/ja-jp/library/cc429305.aspx

MSDNを読んでみたら、そりゃそうだって感じなんですが
それぞれのポインタ変数はDWORD型で定義されてるんで、32bitしかデータ長がないわけで。

ページ下の方にも書いてありましたけど、2GB以上の容量を持つ場合正確な値を返さないともありますね。

そりゃ無理だわ。


ってことで、上位版(?)の「GetDiskFreeSpaceEx関数」の方を使ってみました。

https://msdn.microsoft.com/ja-jp/library/cc429308.aspx

Exってついてるあたり凄みを感じちゃう!!!ってのはとりあえず置いといて。


この関数はそれぞれPULARGE_INTEGER(ポインタ型でなければULARGE_INTEGER)で定義されてるので、64bitまで扱えます。

ここで引っかかってしまったのが、ULARGE_INTEGERの扱い方。

こいつ、構造体だったんですな(

プロトタイプ宣言だと

typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG HighPart;
    };
    struct {
        DWORD LowPart;
        LONG HighPart;
    } u;
    LONGLONG QuadPart;
} LARGE_INTEGER;

typedef LARGE_INTEGER *PLARGE_INTEGER;


typedef union _ULARGE_INTEGER {
    struct {
        DWORD LowPart;
        DWORD HighPart;
    };
    struct {
        DWORD LowPart;
        DWORD HighPart;
    } u;
    ULONGLONG QuadPart;
} ULARGE_INTEGER;

typedef ULARGE_INTEGER *PULARGE_INTEGER;

となってます。
これを見ると分かる通り、上位32bitと下位32bit(それぞれDWORD型)のメンバで構成されてるようで
LowPartが下位32bit、HighPartが上位32bitになります。
2つまとめたのがQuadPartで、これがLONGLONG型。

つまるところ、LARGE_INTEGER64bit分をまとめて数値代入したりなんだりするには、QuadPartを使わなきゃいけないぜ!ってこと。

それをふまえて。。。

Function TForm1.HDDFreeSpace:ULARGE_INTEGER;
var
  lpRootPathName : PWideChar;
  FreeByteAvailable, TotalNumberOfByte : Int64;
  TotalNumberOfFreeByte : ULARGE_INTEGER;
  Root : string;
begin
  //  string型をPWideChar型に変換
  Root := 'C:\';
  GetMem(lpRootPathName,length(root)+1);
  StrPCopy(lpRootPathName,root);
  FreeMem(lpRootPathName);

  GetDiskFreeSpaceEX(lpRootPathName, FreeByteAvailable, TotalNumberOfByte, @TotalNumberOfFreeByte);
  Result := TotalNumberOfFreeByte;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(HDDFreeSpace.QuadPart.ToString);
end;

あ、System.SysUtilsをuses句に追加は必要。
このソースだと、Cドライブのみなんで数行追加するなりなんなりで汎用性は高めてください←

普段から「あ、こんな関数あるんだーこれ使えばよくねー?」みたいな軽いノリでざっくり組むから変なところに引っかかる(

ちゃんと読まなきゃダメな(