private void Work() { Viewport viewport_prev = new Viewport(); Viewport viewport_curr = new Viewport(); bool drew = false; while (true) { long beg = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); // 当前帧开始的时间 double dX = 0, dY = 0; // 获取画面的几何信息, 保存thread local var pendingActions = msgq.CheckOut(); if (pendingActions.Length == 0) { long end = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long delta = end - beg; int ms = (int)(period - delta); Thread.Sleep(ms); continue; // 注意不是执行剩余的循环体, 而是开始新的循环. } // 「打草稿」阶段 foreach (var act in pendingActions) { if (act is ViewportMessage) { if (act is MoveMessage) { var a = act as MoveMessage; dX += a.dXScreen; dY += a.dYScreen; } else if (act is ZoomMessage) { var a = act as ZoomMessage; viewport_curr.Zoom(a.nScroll, a.XScreen, a.YScreen); } else if (act is ResizeMessage) { var a = act as ResizeMessage; viewport_curr.Resize(a.WScreen, a.HScreen); } else if (act is ThumbJumpMessage) { var a = act as ThumbJumpMessage; viewport_curr.X = a.CenterXScreen * thumbDensity - viewport_curr.ToActualPixel(viewport_curr.OutW) / 2; viewport_curr.Y = a.CenterYScreen * thumbDensity - viewport_curr.ToActualPixel(viewport_curr.OutH) / 2; } } else if (act is PolylineMessage) { drew = true; if (act is AddVertexMessage) { var a = act as AddVertexMessage; double x = viewport_curr.X + viewport_curr.ToActualPixel(a.x); double y = viewport_curr.Y + viewport_curr.ToActualPixel(a.y); poly.AddVertex(a.idv, x, y, a.prev); } else if (act is ConnectVertexMessage) { var a = act as ConnectVertexMessage; poly.ConnectVertex(a.idv1, a.idv2); } else if (act is MoveVertexMessgae) { var a = act as MoveVertexMessgae; double dx = viewport_curr.ToActualPixel(a.dx); double dy = viewport_curr.ToActualPixel(a.dy); poly.MoveVertex(a.idv, dx, dy); } else if (act is DeleteVertexMessage) { var a = act as DeleteVertexMessage; poly.DeleteVertex(a.idv); } } else if (act is ComputeMessage) { if (act is Ki67Message) { var a = act as Ki67Message; if (!quantTasks.ContainsKey(a.idv)) { poly.QueryChain(a.idv, out List <double> x, out List <double> y, out BoundingBox bb); byte[] data = slide.LoadRegionBMP(bb); //using (var fs = new FileStream(@"C:\Users\winston\Pictures\aaa.bmp", FileMode.Create)) //{ // fs.Write(data, 0, data.Length); //} var task = new Ki67Task(a.idv, data, x, y); quantTasks.Add(a.idv, task); task.Start(); } } } else if (act is FileMessage) { if (act is LoadSlideMessage) { var a = act as LoadSlideMessage; slide.Open(a.Path, viewport_curr); viewport_curr.OutW = a.WCanvas; viewport_curr.OutH = a.HCanvas; canvasThumb.Dispatcher.Invoke(() => { using (var ms = new System.IO.MemoryStream(slide.LoadThumbJPG())) { var bi = new BitmapImage(); bi.BeginInit(); bi.CacheOption = BitmapCacheOption.OnLoad; bi.StreamSource = ms; bi.EndInit(); UniformToFill(viewport_curr.SlideW, viewport_curr.SlideH, out double thumbW, out double thumbH); (canvasThumb.Width, canvasThumb.Height) = (thumbW, thumbH); canvasThumb.UpdateLayout(); imageThumb.ImageSource = bi; //Console.WriteLine($"actualWH=({canvasThumb.ActualWidth},{canvasThumb.ActualHeight})"); } }, System.Windows.Threading.DispatcherPriority.Send); } else if (act is CloseSlideMessage) { //poly.Close(); slide.Close(); } } } viewport_curr.Move(dX, dY); #region 摆放前端对象 byte[] img = slide.LoadRegionBMP(viewport_curr); List <Object> items = poly.LoadRegionShapes(viewport_curr); canvasMain.Dispatcher.Invoke(() => { #region 重新绘制矢量物体 canvasMain.Children.Clear(); foreach (var item in items) { if (item is V) { var v = item as V; DrawVertex(v, viewport_curr); } else if (item is E) { var e = item as E; DrawEdge(e, viewport_curr); } } canvasMain.UpdateLayout(); #endregion #region 重新绘制位图 BitmapImage bi = null; using (var ms = new System.IO.MemoryStream(img)) { bi = new BitmapImage(); bi.BeginInit(); bi.CacheOption = BitmapCacheOption.OnLoad; bi.StreamSource = ms; bi.EndInit(); } imageMain.ImageSource = bi; #endregion }, System.Windows.Threading.DispatcherPriority.Send); canvasThumb.Dispatcher.Invoke(() => { canvasThumb.Children.Clear(); DrawOnThumb(canvasThumb, viewport_curr); }, System.Windows.Threading.DispatcherPriority.Send); viewport_prev.CopyFrom(viewport_curr); var scores = new Dictionary <int, double>(); var to_remove = new List <int>(); foreach (var _ in quantTasks) { var t = _.Value; if (!double.IsNaN(t.Result)) { scores.Add(t.HeadId, t.Result); to_remove.Add(t.HeadId); } } foreach (var _ in to_remove) { quantTasks.Remove(_); } scoreBoard.Dispatcher.Invoke(() => { foreach (var _ in scores) { scoreBoard.Text = $"PolygonId: {_.Key}. Ki67={(int)(_.Value * 100)}%\r\n"; } }, System.Windows.Threading.DispatcherPriority.Send); // 如果end-beg小于period, 则忙等到period for (long end = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); // 当前帧结束的时间 end - beg < period; end = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) { Thread.Sleep(1); // 降低cpu占用率. 改善阅览体验. } #endregion } }