よろしくお願いします。
TMemoryStream にデータが入っているのですが。
ここには Double X, doubleY の位置情報があります。
プログラム的に、作成される場所では以下のように作成されています。
for i := 0 to N do {
MemStr.write(DblX, SizeOf(Double))
MemStr.write(DblY, SizeOf(Double))
}
このデータから処理を行うのですが、
MemStrが渡されてきて
このままでは処理しにくいので、
Xp: array [0..N] of Double;
Yp: array [0..N] of Double;
として処理したいのですが
N が不定なのでどうしたものかと悩んでいます。
とりあえず
N := MemStr.Size / 8 / 2;
となるのはわかるのですが、
この後どうやってAllocMemするのかもわかりません。
もっと他にやりやすい方法があればそれもおしえてくれませんか?
◇2個のDouble値を要素とする構造体の動的配列
◇MemoryStream.Memory
中級者なら、このキーワードで理解できるね?
えー、動的配列で Length() 使うだけじゃないの。
動的配列は、まさに実行時にサイズを決められることが利点なわけで。
えっと、
MemoryStreamには Double の線分データ(x1, y1, x2, y2)として
データが4個ずつ連続して入っています。
これを TList で線分ごとにリスト化しようとしています。
現在以下のようになっているのですが、未だに動作しません。
どうすればよいのでしょうか?
var
PNum: array of Double;
begin
PNum := AllocMem(SizeOf(Double) * 4);
PNum[0] := X1;
PNum[1] := Y1;
PNum[2] := X1;
PNum[3] := Y1;
List.Add(PNum);
end;
消去する場合は
var
i: Integer;
PNum: array of Double;
begin
for i := 1 to Count do begin
PNum := List.Items[i];
FreeMem(PNum);
end;
end;
動的配列のメモリ割り当ては SetLengthで出来るんだから、
わざわざTListやAllocMemを持ち出す必要はないんじゃないの?
質問の内容が最初と微妙に変化してますね。
このような場合は、レコード型かクラスのインスタンスのリストを作るのが常道です。
クラスの方が好ましいのですが、ここでは質問内容に近いレコード型のリストをつくる例を示します。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// データの型とそのポインタの定義
type
PSenbunData = ^TSenbunData;
TSenbunData = record
X1,Y1,X2,Y2: double;
end;
var
ms: TMemoryStream;
lt: TList;
// メモリストリームとリストのインスタンスを作成
procedure TForm1.FormCreate(Sender: TObject);
begin
ms := TMemoryStream.Create;
lt := TList.Create;
end;
// メモリストリームとリストのインスタンスを破棄
procedure TForm1.FormDestroy(Sender: TObject);
var
i: integer;
begin
ms.Free;
for i := lt.Count - 1 downto 0 do
Dispose(PSenbunData(lt[i])); //項目は個別に破棄
lt.Free;
end;
// 2つのデータをメモリストリームに入れる
procedure TForm1.Button1Click(Sender: TObject);
var
x1,y1,x2,y2,x3,y3,x4,y4: Double;
begin
x1 := 1.2; y1 := 2.3;
x2 := 3.4; y2 := 4.5;
x3 := 5.6; y3 := 6.7;
x4 := 7.8; y4 := 8.9;
ms.Write(x1, SizeOf(Double));
ms.Write(y1, SizeOf(Double));
ms.Write(x2, SizeOf(Double));
ms.Write(y2, SizeOf(Double));
ms.Write(x3, SizeOf(Double));
ms.Write(y3, SizeOf(Double));
ms.Write(x4, SizeOf(Double));
ms.Write(y4, SizeOf(Double));
end;
// メモリストリームからデータを読み込んでリストに追加
procedure TForm1.Button2Click(Sender: TObject);
var
n, i: integer;
pData: PSenbunData;
begin
n := ms.Size div SizeOf(TSenbunData);
ms.Position := 0;
for i := 0 to n-1 do
begin
New(pData);
ms.Read(pData^, SizeOf(TSenbunData));
lt.Add(pData);
end;
end;
// リストの項目にアクセスして表示
procedure TForm1.Button3Click(Sender: TObject);
var
data: TSenbunData;
i: integer;
begin
Memo1.Clear;
for i := 0 to lt.Count -1 do
begin
data := PSenbunData(lt[i])^;
Memo1.Lines.Add(FloatToStr(data.X1));
Memo1.Lines.Add(FloatToStr(data.Y1));
Memo1.Lines.Add(FloatToStr(data.X2));
Memo1.Lines.Add(FloatToStr(data.Y2));
end;
end;
end.
TList を使うのは
線分の削除や追加をやりやすくするためなのですが
具体的には、
PaintBoxにベクターデータの線を描画します。
この線は連続した閉じた図形のデータです。
また、デフォルトはMemoryStreamにデータが入れられ、
これからポイントの座標を取り込みます。
このデータは数千個になる場合もあります。
そこから編集でポイントを追加したり削除したりして
データを変更していきます。
最初は
TVPoint = class(TPersistent)
public
X1: double;
Y1: double;
X2: double;
Y2: double;
end;
というクラスを作って、
VPoint = TVPoint.Create;
を行って
List.Add(VPoint);
でデータを作っていたのですが
少ないデータならいいのですが、ポイント数が多くなると
どうもCreateで時間がかかるのか処理が遅いので
Doubleの配列を使ってやろうと思ったのです。
それから最後に、SetLength を使ってどのようにすればいいのか
わからないのですが、教えてください。
’うんと’さんどうもありがとうございます。
おかげさまで思い通りのことができました。
ツイート | ![]() |