//TODO (CR Sept 2010): same comment as with the ProgressGraphic stuff; the API is unclear //as to what it is doing (return value) because it's trying to account for the async loading. /// <summary> /// Attempts to start loading the overlay data asynchronously, if not already loaded. /// </summary> /// <param name="progress">A value between 0 and 1 indicating the progress of the asynchronous loading operation.</param> /// <param name="message">A string message detailing the progress of the asynchronous loading operation.</param> /// <returns></returns> public bool BeginLoad(out float progress, out string message) { // update the last access time _largeObjectData.UpdateLastAccessTime(); // if the data is already available without blocking, return success immediately //TODO (CR Sept 2010): because unloading the volume involves disposing it, if every operation that uses it //isn't in the same lock (e.g. lock(_syncVolumeDataLock)) you could be getting a disposed/null volume here. VolumeData volume = _volume; if (volume != null) { message = SR.MessageFusionComplete; progress = 1f; return(true); } lock (_syncLoaderLock) { message = SR.MessageFusionInProgress; progress = 0; if (_volumeLoaderTask == null) { // if the data is available now, return success volume = _volume; if (volume != null) { message = SR.MessageFusionComplete; progress = 1f; return(true); } _volumeLoaderTask = new BackgroundTask(c => this.LoadVolume(c), false, null) { ThreadUICulture = Application.CurrentUICulture }; _volumeLoaderTask.Run(); _volumeLoaderTask.Terminated += OnVolumeLoaderTaskTerminated; } else { // TODO (CR Apr 2013): See comment in OnVolumeLoaderTaskTerminated; if the task were not created // on the UI thread, _volumeLoaderTask could be set to null before hitting this instruction. if (_volumeLoaderTask.LastBackgroundTaskProgress != null) { message = _volumeLoaderTask.LastBackgroundTaskProgress.Progress.Message; progress = _volumeLoaderTask.LastBackgroundTaskProgress.Progress.Percent / 100f; } } } return(false); }
private VolumeData LoadVolume(IBackgroundTaskContext context) { // TODO (CR Apr 2013): Ideally, loading and unloading could be done with minimal locking; this way, // Unload actually has to wait for Load to finish and vice versa. I think a quicker way would be to // have a _loading field - have this method set it inside the lock, then proceed to do the load, // then set the _volume field when done. Have Unload check _loading and just return, otherwise set _volume to null. // Basically, you don't need to lock the entire load operation - you only need to guarantee that multiple loads // can't occur at once, and that Unload actually unloads it. // wait for synchronized access lock (_syncVolumeDataLock) { _largeObjectData.Lock(); try { // if the data is now available, return it immediately // (i.e. we were blocked because we were already reading the data) if (_volume != null) { return(_volume); } // load the volume data if (context == null) { _volume = VolumeData.Create(_frames); } else { _volume = VolumeData.Create(_frames, (n, count) => context.ReportProgress(new BackgroundTaskProgress(n, count, SR.MessageFusionInProgress))); } // update our stats _largeObjectData.BytesHeldCount = 2 * _volume.ArrayLength; _largeObjectData.LargeObjectCount = 1; _largeObjectData.UpdateLastAccessTime(); // regenerating the volume data takes a few seconds _largeObjectData.RegenerationCost = LargeObjectContainerData.PresetComputedData; // register with memory manager MemoryManager.Add(this); return(_volume); } finally { _largeObjectData.Unlock(); } } }
private void UnloadVolume() { // wait for synchronized access lock (_syncVolumeDataLock) { // dump our data if (_volume != null) { _volume.Dispose(); _volume = null; } // update our stats _largeObjectData.BytesHeldCount = 0; _largeObjectData.LargeObjectCount = 0; // unregister with memory manager MemoryManager.Remove(this); } this.OnUnloaded(); }
public VolumeSlice(Volume volume, VolumeSliceArgs sliceArgs, Vector3D imagePositionPatient, float? spacingBetweenSlices = null) : this(volume.CreateReference(), sliceArgs, imagePositionPatient, spacingBetweenSlices) {}
public void Dispose() { if (_volume != null) { _volume.OnReferenceDisposed(); _volume = null; } }
public VolumeReference(Volume volume) { _volume = volume; _volume.OnReferenceCreated(); }
private static vtkImageData CreateVtkVolume(Volume volume) { var vtkVolume = new vtkImageData(); vtkVolume.RegisterVtkErrorEvents(); vtkVolume.SetDimensions(volume.ArrayDimensions.Width, volume.ArrayDimensions.Height, volume.ArrayDimensions.Depth); vtkVolume.SetOrigin(0, 0, 0); vtkVolume.SetSpacing(volume.VoxelSpacing.X, volume.VoxelSpacing.Y, volume.VoxelSpacing.Z); if (volume.BitsPerVoxel == 16) { if (!volume.Signed) { using (var array = new vtkUnsignedShortArray()) { array.SetArray((ushort[]) volume.Array, (VtkIdType) volume.ArrayLength, 1); vtkVolume.SetScalarTypeToUnsignedShort(); vtkVolume.GetPointData().SetScalars(array); } } else { using (var array = new vtkShortArray()) { array.SetArray((short[]) volume.Array, (VtkIdType) volume.ArrayLength, 1); vtkVolume.SetScalarTypeToShort(); vtkVolume.GetPointData().SetScalars(array); } } } else if (volume.BitsPerVoxel == 8) { if (!volume.Signed) { using (var array = new vtkUnsignedCharArray()) { array.SetArray((byte[]) volume.Array, (VtkIdType) volume.ArrayLength, 1); vtkVolume.SetScalarTypeToUnsignedChar(); vtkVolume.GetPointData().SetScalars(array); } } else { using (var array = new vtkSignedCharArray()) { array.SetArray((sbyte[]) volume.Array, (VtkIdType) volume.ArrayLength, 1); vtkVolume.SetScalarTypeToSignedChar(); vtkVolume.GetPointData().SetScalars(array); } } } else { throw new NotSupportedException("Unsupported volume scalar type."); } // This call is necessary to ensure vtkImageData data's info is correct (e.g. updates WholeExtent values) vtkVolume.UpdateInformation(); return vtkVolume; }
private VolumeData LoadVolume(IBackgroundTaskContext context) { // TODO (CR Apr 2013): Ideally, loading and unloading could be done with minimal locking; this way, // Unload actually has to wait for Load to finish and vice versa. I think a quicker way would be to // have a _loading field - have this method set it inside the lock, then proceed to do the load, // then set the _volume field when done. Have Unload check _loading and just return, otherwise set _volume to null. // Basically, you don't need to lock the entire load operation - you only need to guarantee that multiple loads // can't occur at once, and that Unload actually unloads it. // wait for synchronized access lock (_syncVolumeDataLock) { _largeObjectData.Lock(); try { // if the data is now available, return it immediately // (i.e. we were blocked because we were already reading the data) if (_volume != null) return _volume; // load the volume data if (context == null) _volume = VolumeData.Create(_frames); else _volume = VolumeData.Create(_frames, (n, count) => context.ReportProgress(new BackgroundTaskProgress(n, count, SR.MessageFusionInProgress))); // update our stats _largeObjectData.BytesHeldCount = 2*_volume.ArrayLength; _largeObjectData.LargeObjectCount = 1; _largeObjectData.UpdateLastAccessTime(); // regenerating the volume data takes a few seconds _largeObjectData.RegenerationCost = LargeObjectContainerData.PresetComputedData; // register with memory manager MemoryManager.Add(this); return _volume; } finally { _largeObjectData.Unlock(); } } }