/// <summary> // CTLファイル・DATファイルからデータを読み込む /// </summary> /// <returns>読み込んだデータを格納したPARDataクラス</returns> public PARData ReadData() { var data = new PARData(); using (var reader = new StreamReader(_ctlFilename)) { string line; // 区切り文字に対応する正規表現 var regex = new Regex(@"\s+"); while ((line = reader.ReadLine()) != null) { var cols = regex.Split(line); switch (cols[0].ToUpper()) { // X軸の情報 case "XDEF": data.SizeX = int.Parse(cols[1]); data.StartX = float.Parse(cols[3]); data.StepX = float.Parse(cols[4]); break; // Y軸の情報 case "YDEF": data.SizeY = int.Parse(cols[1]); data.StartY = float.Parse(cols[3]); data.StepY = float.Parse(cols[4]); break; // Z軸の情報 case "ZDEF": data.SizeZ = int.Parse(cols[1]); data.StartZ = float.Parse(cols[3]); data.StepZ = float.Parse(cols[4]); break; // データが無い領域の値 case "UNDEF": data.NoDataValue = float.Parse(cols[1]); break; // データセットのパス case "DSET": if (!String.IsNullOrEmpty(_datFilename)) break; var dset = cols[1]; // ^で始まる場合は、データセットはctlファイルからの相対パスとなる if (dset.StartsWith("^")) { dset = dset.Substring(1); _datFilename = Path.Combine(Path.GetDirectoryName(_ctlFilename), dset); } else { _datFilename = dset; } break; } } } // データセットを読み込み readDataset(_datFilename, data); return data; }
public MarchingCubes(PARData data) { // 以下プロパティアクセスによるパフォーマンス低下を避けるためのコード _sizeX = data.SizeX; _sizeY = data.SizeY; _sizeZ = data.SizeZ; _sizeXY = _sizeX * _sizeY; var stepX = data.StepX; var stepY = data.StepY; var stepZ = data.StepZ; var startX = data.StartX; var startY = data.StartY; var startZ = data.StartZ; var rawData = data.RawData; _verticesBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Vertex)) * _sizeX * _sizeY * _sizeZ); GC.AddMemoryPressure(Marshal.SizeOf(typeof(Vertex)) * _sizeX * _sizeY * _sizeZ); // unsafeを用いることによりパフォーマンス向上 unsafe { var vptr = (Vertex*)_verticesBuffer.ToPointer(); var ptr = (float*)rawData.ToPointer(); for (var z = 0; z < _sizeZ; z++) { for (var y = 0; y < _sizeY; y++) { for (var x = 0; x < _sizeX; x++) { vptr->Point = new Vec3 ( startX + stepX * x, startY + stepY * y, startZ + stepZ * z ); vptr->Value = *ptr; vptr++; ptr++; } } } } }
/// <summary> /// DATファイルから格子点のデータを読み込む /// </summary> /// <param name="datFilename">DATファイルのパス</param> /// <param name="data">読み込んだデータを格納するPARDataオブジェクト</param> private void readDataset(string datFilename, PARData data) { // プロパティアクセスによるオーバーヘッドを抑えるため、ローカル変数にキャッシュしておく var sizeX = data.SizeX; var sizeY = data.SizeY; var sizeZ = data.SizeZ; // 全ての格子点の数 * 4バイト(floatのサイズ) var bufSize = sizeX * sizeY * sizeZ * 4; // 格子点における値を格納する配列を確保 // あえてアンマネージドメモリから確保するのは、古い.NETのバージョンにおいてLOH(Large Object Heap)が // フラグメンテーションするのを防ぐため。また若干アロケーションにかかる時間も短縮される var rawData = Marshal.AllocHGlobal(bufSize); // BinaryReaderは直接IntPtrの指すメモリへ読み込めないため、byte配列を経由する var buf = new byte[bufSize]; // GCへアンマネージドメモリからメモリを確保したことを通知する GC.AddMemoryPressure(bufSize); // データセットを読み込む // BinaryReaderはbyte配列への読み込みにしか対応していないので、まずはbyte配列に書き出す using (var reader = new BinaryReader(File.OpenRead(_datFilename))) { reader.Read(buf, 0, buf.Length); } // バッファの中身をfloat配列へコピーする Marshal.Copy(buf, 0, rawData, buf.Length); // GCが働くように buf = null; data.RawData = rawData; }