private unsafe void OnExportSelectedButtonClick(object sender, EventArgs e) { ListView.Item selected = listView.FocusedItem; if (selected == null) { // Nothing to export... return; } ArithmeticExpression ae = selected.NumericValueSource as ArithmeticExpression; if (ae == null) { MessageBox.Show(this, Tx.T("dataset.errors.item not supported"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } long xFi = 0, xLi = 0, distance = 0; if (ae.VariableName != null) { double xF_ = graph.MinVisibleX; double xL_ = graph.MaxVisibleX; if (xF_ >= xL_) { MessageBox.Show(this, Tx.T("dataset.errors.cannot determine interval"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (Math.Sign(xF_) != Math.Sign(xL_)) { MessageBox.Show(this, Tx.T("dataset.errors.interval with zero"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Swap first and last for negative "x" values xFi = *(long *)&xF_; xLi = *(long *)&xL_; if (xFi > xLi) { long swap = xLi; xLi = xFi; xFi = swap; } distance = (xLi - xFi); if (distance < 0) { MessageBox.Show(this, Tx.T("dataset.errors.interval too big"), Tx.T("main.error"), MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (distance > 10 * 1000 * 1000) { long sizeInMB = (distance * 8 * 2 / 1024 / 1024); string sizeString; if (sizeInMB > 100L * 1024L) { sizeString = Tx.N(sizeInMB / 1024) + " GB"; } else { sizeString = Tx.N(sizeInMB) + " MB"; } if (MessageBox.Show(this, Tx.T("dataset.errors.file too big", Tx.N(distance), sizeString), Tx.T("main.warning"), MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) { return; } } } using (SaveFileDialog dialog = new SaveFileDialog()) { const string ext = ".fvis-values"; dialog.Filter = Tx.T("dataset.filetype") + " (*" + ext + ")|*" + ext; dialog.FilterIndex = 0; dialog.RestoreDirectory = true; dialog.Title = Tx.T("dataset.save"); string filename = selected.Text; char[] invalidChars = Path.GetInvalidFileNameChars(); for (int i = 0; i < invalidChars.Length; i++) { filename = filename.Replace(invalidChars[i], '_'); } dialog.FileName = filename + ext; if (dialog.ShowDialog(this) != DialogResult.OK) { return; } filename = dialog.FileName; ProgressDialog progressDialog = new ProgressDialog(); progressDialog.Text = Tx.T("dataset.saving.title"); progressDialog.MainInstruction = Tx.T("dataset.saving.description"); progressDialog.Line1 = Tx.T("dataset.saving.progress", "0", Tx.N(xLi - xFi)); progressDialog.Show(this); ThreadPool.UnsafeQueueUserWorkItem(delegate { using (FileStream s = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)) using (BinaryWriter bw = new BinaryWriter(s)) { bw.Write(new[] { (byte)'f', (byte)'V', (byte)'i', (byte)'s' }); const int flags = 0; bw.Write(flags); string description = selected.Text; bw.Write(description); // Save graph viewport settings long axisX = graph.AxisX; long axisY = graph.AxisY; double scaleFactor = graph.ScaleFactor; bw.Write(axisX); bw.Write(axisY); bw.Write(scaleFactor); if (ae.VariableName == null) { // Constant function, save only one value double y = ae.Evaluate(double.NaN); const long count = 2; bw.Write(count); bw.Write(double.MinValue); bw.Write(y); bw.Write(double.MaxValue); bw.Write(y); } else { bw.Write(distance + 1); Stopwatch sw = Stopwatch.StartNew(); long lastProcessed = xFi; for (long xi = xFi; xi <= xLi; xi++) { double x = *(double *)ξ double y = ae.Evaluate(x); bw.Write(x); bw.Write(y); if (sw.ElapsedMilliseconds > 4000) { if (progressDialog.IsCancelled) { break; } sw.Stop(); long delta = (xi - lastProcessed); long rate = delta * 1000 / (long)sw.Elapsed.TotalMilliseconds; TimeSpan remaining = TimeSpan.FromSeconds((xLi - xi) / rate); lastProcessed = xi; BeginInvoke((MethodInvoker) delegate { progressDialog.Line1 = Tx.T("dataset.saving.progress", Tx.N(lastProcessed - xFi), Tx.N(xLi - xFi)); progressDialog.Line2 = Tx.T("main.remaining time", remaining.ToTextString()); progressDialog.Progress = (int)((lastProcessed - xFi) * 100 / (xLi - xFi)); }); sw.Restart(); } } sw.Stop(); } } if (progressDialog.IsCancelled) { try { File.Delete(filename); } catch { // Nothing to do... } } BeginInvoke((MethodInvoker) delegate { progressDialog.TaskCompleted(); }); }, null); } }
private unsafe void OnRunButtonClick(object sender, EventArgs e) { if (!EstimateTime(false)) { return; } double start, end; double.TryParse(startTextBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out start); double.TryParse(endTextBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out end); if (estimatedTime.TotalMinutes > 0.5) { string timeString; if (estimatedTime == TimeSpan.MaxValue) { timeString = Tx.T("time.infinitely"); } else { timeString = estimatedTime.ToTextString(); } if (MessageBox.Show(this, Tx.T("find diffs.errors.interval too big", Tx.N(distance), timeString), Tx.T("main.warning"), MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) { return; } } long starti = *(long *)&start; long endi = *(long *)&end; if (starti > endi) { long swap = starti; starti = endi; endi = swap; } distance = (endi - starti); long currentProcessed = 0, lastProcessed = 0; long differencesFound = 0; SpinLock syncLock = new SpinLock(); ProgressDialog progressDialog = new ProgressDialog { Text = Tx.T("find diffs.finding.title"), MainInstruction = Tx.T("find diffs.finding.description"), Line1 = Tx.T("find diffs.finding.progress", "0", Tx.N(distance)), ShowInTaskbar = false, MinimizeBox = false }; ThreadPool.UnsafeQueueUserWorkItem(delegate { BeginInvoke((MethodInvoker) delegate { progressDialog.ShowDialog(this); }); Stopwatch sw = Stopwatch.StartNew(); Parallel.For(starti, endi, (xi, state) => { double x = *(double *)ξ bool isFirst = true; double computedMinY = double.MaxValue, computedMaxY = double.MinValue; foreach (ListView.Item item in listView.Items) { if (item.NumericValueSource == null || item.CheckState != CheckState.Checked) { continue; } double y = item.NumericValueSource.Evaluate(x); if (isFirst) { isFirst = false; computedMinY = y; computedMaxY = y; } else { if (y > computedMaxY) { computedMaxY = y; } else if (y < computedMinY) { computedMinY = y; } } } bool lockTaken = false; syncLock.Enter(ref lockTaken); if (!isFirst && computedMinY != computedMaxY) { graph.AddDifferenceUnsafe(x, computedMinY, computedMaxY); differencesFound++; } if (sw.ElapsedMilliseconds > 4000) { if (progressDialog.IsCancelled) { if (lockTaken) { syncLock.Exit(); } state.Stop(); return; } sw.Stop(); long delta = (currentProcessed - lastProcessed); long rate = delta * 1000 / (long)sw.Elapsed.TotalMilliseconds; TimeSpan remaining = TimeSpan.FromSeconds((distance - currentProcessed) / rate); lastProcessed = currentProcessed; BeginInvoke((MethodInvoker) delegate { progressDialog.Line1 = Tx.T("find diffs.finding.progress", Tx.N(lastProcessed), Tx.N(distance)); progressDialog.Line2 = Tx.T("main.remaining time", remaining.ToTextString()); progressDialog.Progress = (int)(lastProcessed * 100 / distance); }); sw.Restart(); } currentProcessed++; if (lockTaken) { syncLock.Exit(); } }); sw.Stop(); BeginInvoke((MethodInvoker) delegate { progressDialog.TaskCompleted(); if (!progressDialog.IsCancelled) { MessageBox.Show(this, Tx.T("find diffs.complete.description", Tx.N(distance), Tx.N(differencesFound), Tx.N(differencesFound * 100 / distance)), Tx.T("find diffs.complete.title"), MessageBoxButtons.OK, MessageBoxIcon.Information); } }); }, null); }