public ReadOnlyMotionFrame(MotionFrame frame)
 {
     if (frame == null)
     {
         throw new ArgumentNullException("frame", "'frame' cannot be null");
     }
     _frame = frame;
 }
        /// <summary>
        /// フレームデータをバイナリ形式から取得します
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static MotionFrame DeserializeBinary(BinaryReader reader, MotionDataSet parent)
        {
            decimal     time  = reader.ReadDecimal();
            int         count = reader.ReadInt32();
            MotionFrame ret   = new MotionFrame(parent, time, count);

            for (int i = 0; i < count; i++)
            {
                uint             id   = reader.ReadUInt32();
                MotionObjectInfo info = parent.GetObjectInfoById(id);
                if (info == null)
                {
                    throw new InvalidDataException(string.Format("unexpected id:{0} in frame at:{1}", id, time));
                }
                MotionObject @object = info.GetEmptyObject();
                @object.ReadBinary(reader);

                ret[info] = @object;
            }
            return(ret);
        }
        private void bgwRender_DoWork(object sender, DoWorkEventArgs e)
        {
            TimeController timeController = _timeController;
            MotionDataSet  dataSet        = _dataSet;

            if (dataSet == null || timeController == null)
            {
                Bitmap infoImage = new Bitmap(_width, _height);
                using (Graphics gfx = Graphics.FromImage(infoImage)) {
                    gfx.Clear(Color.DimGray);
                    gfx.DrawString("Error...", this.Font, Brushes.LightGray, new PointF());
                }
                setPictureImage(pictGraph, infoImage);
                return;
            }

            RangeSet <int> existAll    = null;             // 選択されたオブジェクトが被欠損なインデックス
            List <int>     clipIndices = new List <int>(); // グラフ上の各x座標のインデックスの範囲
            Collection <MotionObjectInfo> infoList;

            // メッセージを表示
            setText(labelInfo, "データ欠損情報");
            infoList = dataSet.GetSelectedObjectInfoList();
            if (infoList.Count == 0)
            {
                Bitmap infoImage = new Bitmap(_width, _height);
                using (Graphics gfx = Graphics.FromImage(infoImage)) {
                    gfx.Clear(Color.DimGray);
                    gfx.DrawString("選択オブジェクトなし", this.Font, Brushes.Ivory, new PointF());
                }
                setPictureImage(pictGraph, infoImage);
                return;
            }
            else
            {
                Bitmap infoImage = new Bitmap(_width, _height);
                using (Graphics gfx = Graphics.FromImage(infoImage)) {
                    gfx.Clear(Color.DimGray);
                    gfx.DrawString("読み込み中...", this.Font, Brushes.LightGray, new PointF());
                }
                setPictureImageImmediate(pictGraph, infoImage);
            }
            // 選択された全オブジェクトの非欠損のandを取る
            foreach (var info in infoList)
            {
                if (bgwRender.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
                if (existAll == null)
                {
                    existAll = getExistenceList(info.Id);
                }
                else
                {
                    existAll = existAll.GetIntersect(getExistenceList(info.Id));
                }
            }
            // 各x座標に対応する時間に対応するフレームのインデックスを求める
            // clipIndices[0] から (clipIndices[1] - 1)には,[x=0に対応する時刻]から[x=1に対応する時刻の直前]までに含まれるインデックスが入るようにする
            for (int x = 0; x <= _width; x++)
            {
                decimal time  = positionToTime(x);
                int     index = dataSet.GetFrameIndexAt(time);
                // ちょうどtimeの値がフレームの時間と一緒のときだけ特別対応
                Motion.MotionFrame frame = dataSet.GetFrameByIndex(index);
                if (frame == null || frame.Time != time)
                {
                    index++; // 取得されたインデックスは,今回のループのx座標に対応する時間範囲に入らない
                }
                clipIndices.Add(index);
            }
            lock (_lockAccessGraphImage) {
                // グラフの作成
                _graphImage = new Bitmap(_width, _height);
                using (Graphics gfx = Graphics.FromImage(_graphImage)) {
                    gfx.Clear(Color.Black);

                    for (int x = 0; x < _width; x++)
                    {
                        // 今回のx座標に対応するフレームインデックスの範囲
                        int clipCount = clipIndices[x + 1] - clipIndices[x];
                        RangeSet <int> .Range clipRange = new RangeSet <int> .Range(clipIndices[x], clipIndices[x + 1]);

                        // 今回の範囲の被欠損情報を取得
                        RangeSet <int> existClipped = existAll.GetClipped(clipRange);
                        int            existCount   = existClipped.Total();

                        Pen pen = Pens.LightGreen;
                        if (existCount == clipCount)
                        {
                            pen = Pens.YellowGreen;
                        }
                        if (existCount > 0)
                        {
                            gfx.DrawLine(pen, new Point(x, _height - 1), new Point(x, _height - 1 - _height * existCount / clipCount));
                        }
                    }
                    // 選択範囲の欠損割合の計算
                    decimal     selectBegin      = timeController.VisibleBeginTime;
                    decimal     selectEnd        = timeController.VisibleEndTime;
                    int         selectBeginIndex = dataSet.GetFrameIndexAt(selectBegin);
                    int         selectEndIndex   = dataSet.GetFrameIndexAt(selectEnd);
                    MotionFrame selectBeginFrame = dataSet.GetFrameByIndex(selectBeginIndex);
                    MotionFrame selectEndFrame   = dataSet.GetFrameByIndex(selectEndIndex);
                    if (selectBeginFrame == null || selectBeginFrame.Time != selectBegin)
                    {
                        selectBeginIndex++; // clipIndicesを求めるときと同じ処理
                    }
                    if (selectEndFrame == null || selectEndFrame.Time != selectEnd)
                    {
                        selectEndIndex++;
                    }
                    RangeSet <int> whole            = existAll.GetClipped(new RangeSet <int> .Range(selectBeginIndex, selectEndIndex));
                    int            selectClipCount  = selectEndIndex - selectBeginIndex;
                    int            selectExistCount = whole.Total();
                    int            missingCount     = selectClipCount - selectExistCount;
                    double         percentage       = selectClipCount == 0 ? 0 : (100.0 - 100.0 * selectExistCount / selectClipCount);
                    setText(labelInfo, string.Format("欠落フレーム数: {0} (選択フレーム数 {1}, {2}% 欠損) ({3} オブジェクト)", missingCount, selectClipCount, Math.Round(percentage, 2), infoList.Count));
                }
            }
        }
        /// <summary>
        /// CreateObjectの結果に基づいてプレビューを表示します.
        /// </summary>
        protected virtual void SetPreview()
        {
            if (_operation == null)
            {
                return;
            }
            // 処理の種類を判別したい
            IMotionOperationCreateObject   createOpe  = _operation as IMotionOperationCreateObject;
            IMotionOperationEditObject     editOpe    = _operation as IMotionOperationEditObject;
            IMotionOperationGeneral        generalOpe = _operation as IMotionOperationGeneral;
            IMotionOperationOutputSequence outputOpe  = _operation as IMotionOperationOutputSequence;

            // 前回のプレビュー用オブジェクトを消しておく
            motionDataViewer.ClearPreviewObjects();

            // 作成や編集でなければプレビューしない
            if (createOpe == null && editOpe == null)
            {
                panelPreview.Visible = false;
                return;
            }

            panelPreview.Visible = true;
            // 引数チェック.失敗したら表示しない
            string errorMessage = "";

            if (!_operation.ValidateArguments(_exec.Parameters, ref errorMessage))
            {
                return;
            }
            // フレーム取得.失敗したら表示しない
            MotionFrame frame = _console.MotionDataSet.GetFrameAt(TimeController.Singleton.CurrentTime);

            if (frame == null)
            {
                return;
            }
            // 作成/編集結果のオブジェクトと,プレビュー時のみに表示されるオブジェクトを分類する
            IList <MotionObject> previewObjs    = null;
            IList <MotionObject> previewSubObjs = null;

            if (createOpe != null)
            {
                previewSubObjs = createOpe.CreateObjects(_targetInfoList, _exec.Parameters, new ReadOnlyMotionFrame(frame), true);
                previewObjs    = createOpe.CreateObjects(_targetInfoList, _exec.Parameters, new ReadOnlyMotionFrame(frame), false);
            }
            else if (editOpe != null)
            {
                previewSubObjs = editOpe.EditObject(_targetInfoList, _exec.Parameters, new ReadOnlyMotionFrame(frame), true);
                previewObjs    = editOpe.EditObject(_targetInfoList, _exec.Parameters, new ReadOnlyMotionFrame(frame), false);
            }
            if (previewObjs == null)
            {
                return;
            }
            if (previewSubObjs == null)
            {
                previewSubObjs = previewObjs;
            }
            if (previewSubObjs.Count >= previewObjs.Count)
            {
                previewSubObjs = previewSubObjs.Skip(previewObjs.Count).ToList();
            }
            // プレビュー対象をビューに登録しつつ,重心を求める
            Vector3 sum   = Vector3.Empty;
            int     count = 0;

            if (previewObjs != null)
            {
                foreach (var @object in previewObjs)
                {
                    if (@object != null)
                    {
                        sum += @object.GravityPoint;
                        motionDataViewer.AddPreviewObject(@object, false);
                        count++;
                    }
                }
                foreach (var @object in previewSubObjs)
                {
                    if (@object != null)
                    {
                        sum += @object.GravityPoint;
                        motionDataViewer.AddPreviewObject(@object, true);
                        count++;
                    }
                }
                if (editOpe != null)
                {
                    foreach (MotionObjectInfo info in _targetInfoList)
                    {
                        motionDataViewer.AddPreviewRemoveObject(info);
                    }
                }
            }
            // ビューのカメラを重心の方に向ける
            if (count > 0)
            {
                sum *= 1f / count;
                motionDataViewer.ViewCamera.SetTarget(sum, false);
            }
        }