using PaintDotNet.Annotation; using PaintDotNet.Annotation.Command; using PaintDotNet.Annotation.Enum; using PaintDotNet.Annotation.Label; using PaintDotNet.Annotation.Measure; using PaintDotNet.Annotation.Other; using PaintDotNet.Base.DedicatedAnalysis.Inclusions.Model; using PaintDotNet.Base.SettingModel; using PaintDotNet.SystemLayer; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Reflection; using System.Threading; using System.Windows.Forms; namespace PaintDotNet { /// /// 主面板 /// public class DocumentStitchView : UserControl, ISurfaceBox { private IContainer components = null; // 中心画布 public PanelEx panel; private static WeakReference doubleBufferSurfaceWeakRef = null; private StitchSurface doubleBufferSurface = null; /// /// 绘制线程 /// private Threading.ThreadPool threadPool = new Threading.ThreadPool(); private RenderContext renderContext; /// /// 为了保证图片绘制在画布中心 /// 设置的偏移量 /// private int offsetW = 0; private int offsetH = 0; private int offsetHalfW = 0; private int offsetHalfH = 0; /*private int offsetW = 300; private int offsetH = 150; private int offsetHalfW = 150; private int offsetHalfH = 75;*/ /// /// 图层及文档信息 /// private StitchDocument document; /// /// 图像内存块及其属性 /// protected StitchSurface compositionSurface; /// /// 【标注、测量】list of draw objects /// private GraphicsList graphicsList; /// /// 【标注、测量、视场、其它】当前激活的工具 /// public DrawToolType _activeTool; /// /// 工具的集合 /// protected static Dictionary tools; /// /// 初始化标记 /// private bool initialized; /// /// 待渲染的列表 /// private StitchSurfaceBoxRendererList rendererList; private StitchSurfaceBoxBaseRenderer baseRenderer; /// /// 窗体状态 /// private FormWindowState oldWindowState = FormWindowState.Minimized; /// /// 缩放比例 /// private ScaleFactor scaleFactor = new ScaleFactor(1, 1); /// /// 在toolPointer的工具下,是否绘制鼠标划选的矩形 /// public bool drawRectangle = false; /// /// 在toolPointer的工具下,鼠标划选的矩形 /// public Rectangle rectangle; public DocumentStitchView() { InitializeComponent(); this.document = null; this.compositionSurface = null; this.panel.ScaleFactor = this.scaleFactor; this.panel.Paint += new PaintEventHandler(this.panelPaint); this.panel.MouseMove += new MouseEventHandler(this.MouseEvent_Move); this.panel.MouseDown += new MouseEventHandler(this.MouseEvent_Down); this.panel.MouseUp += new MouseEventHandler(this.MouseEvent_Up); this.panel.MouseClick += new MouseEventHandler(this.MouseEvent_Click); this.rendererList = new StitchSurfaceBoxRendererList(this.panel.Size, this.panel.Size); this.rendererList.Invalidated += new InvalidateEventHandler(Renderers_Invalidated); this.baseRenderer = new StitchSurfaceBoxBaseRenderer(this.rendererList); this.rendererList.Add(this.baseRenderer, false); this.initialized = true; } public new void Refresh() { base.Refresh(); } //public OpenCvSharp.Mat OldMat //{ // get // { // //备注:待调试->>200827 add by scc // if (this.CompositionSurface != null && CompositionSurface != null && CompositionSurface.mat != null) // return this.CompositionSurface.mat/*.Clone()*/; // //备注:待调试->>200827 add by scc // else if (this.CompositionSurface != null && CompositionSurface != null && CompositionSurface.Thumborigin != null) // return OpenCvSharp.Extensions.BitmapConverter.ToMat(this.CompositionSurface.Thumborigin/*CreateAliasedBitmap()*/); // else // return null; // } //} //public OpenCvSharp.Mat BoxMat //{ // get // { // //备注:待调试 // //if (this.AppWorkspace.ActiveDocumentWorkspace != null) // //{ // return OpenCvSharp.Extensions.BitmapConverter.ToMat(this.BoxBitmap); // //} // } //} /// /// 初始化工具 /// protected void InitToolsAndManager() { // 一是用于存储,二是用于调整层级 GraphicsList = new GraphicsList(this); // init Tools //tools = new Tool[(int)DrawToolType.NumberOfDrawTools]; if (tools != null) return; tools = new Dictionary(); tools.Add(DrawToolType.Pointer, typeof(ToolPointer)); //其它 //手型工具 tools.Add(DrawToolType.MoveMode, typeof(PanTool)); //图片裁剪 tools.Add(DrawToolType.ImageCut, typeof(ImageCutTool)); //null tools.Add(DrawToolType.NullTool, typeof(ToolNull)); } [Browsable(false)] public override bool Focused { get { return base.Focused || panel.Focused; } } private void Renderers_Invalidated(object sender, InvalidateEventArgs e) { Rectangle rect = SurfaceToClient(e.InvalidRect); rect.Inflate(1, 1); Invalidate(rect); } public StitchSurface GetDoubleBuffer(Size size) { StitchSurface localDBSurface = null; Size oldSize = new Size(0, 0); // If we already have a double buffer surface reference, but if that surface // is already disposed then don't worry about it. if (this.doubleBufferSurface != null && this.doubleBufferSurface.IsDisposed) { oldSize = this.doubleBufferSurface.Size; this.doubleBufferSurface = null; } // If we already have a double buffer surface reference, but if that surface // is too small, then nuke it. if (this.doubleBufferSurface != null && (this.doubleBufferSurface.Width < size.Width || this.doubleBufferSurface.Height < size.Height)) { oldSize = this.doubleBufferSurface.Size; this.doubleBufferSurface.Dispose(); this.doubleBufferSurface = null; doubleBufferSurfaceWeakRef = null; } // If we don't have a double buffer, then we'd better get one. if (this.doubleBufferSurface != null) { // Got one! localDBSurface = this.doubleBufferSurface; } else if (doubleBufferSurfaceWeakRef != null) { // First, try to get the one that's already shared amongst all SurfaceBox instances. localDBSurface = doubleBufferSurfaceWeakRef.Target; // If it's disposed, then forget about it. if (localDBSurface != null && localDBSurface.IsDisposed) { oldSize = localDBSurface.Size; localDBSurface = null; doubleBufferSurfaceWeakRef = null; } } // Make sure the surface is big enough. if (localDBSurface != null && (localDBSurface.Width < size.Width || localDBSurface.Height < size.Height)) { oldSize = localDBSurface.Size; localDBSurface.Dispose(); localDBSurface = null; doubleBufferSurfaceWeakRef = null; } // So, do we have a surface? If not then we'd better make one. if (localDBSurface == null) { Size newSize = new Size(Math.Max(size.Width, oldSize.Width), Math.Max(size.Height, oldSize.Height)); localDBSurface = new StitchSurface(newSize, this.compositionSurface.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb ? 3 : 4); doubleBufferSurfaceWeakRef = new WeakReference(localDBSurface); } this.doubleBufferSurface = localDBSurface; StitchSurface window = localDBSurface.CreateWindow(0, 0, size.Width, size.Height); return window; } private class RenderContext { public StitchSurface[] windows; public Point[] offsets; public Rectangle[] rects; public DocumentStitchView owner; public WaitCallback waitCallback; public int TopIndex = 0; public void RenderThreadMethod1(object indexObject) { int index = (int)indexObject; this.owner.rendererList.topList[TopIndex].Render(windows[index], offsets[index]); //this.owner.rendererList.RenderTop(windows[index], offsets[index]); this.windows[index].Dispose(); this.windows[index] = null; } public void RenderThreadMethod(object indexObject) { int index = (int)indexObject; this.owner.rendererList.list[0].Render(windows[index], offsets[index]); this.windows[index].Dispose(); this.windows[index] = null; } } public unsafe void DrawArea(StitchRenderArgs ra, Point offset) { if (compositionSurface == null) { return; } if (renderContext == null || (renderContext.windows != null && renderContext.windows.Length != Processor.LogicalCpuCount)) { renderContext = new RenderContext(); //这里需要计算宽高 renderContext.owner = this; renderContext.waitCallback = new WaitCallback(renderContext.RenderThreadMethod); renderContext.windows = new StitchSurface[Processor.LogicalCpuCount]; renderContext.offsets = new Point[Processor.LogicalCpuCount]; renderContext.rects = new Rectangle[Processor.LogicalCpuCount]; //renderContext.owner = this; //renderContext.waitCallback = new WaitCallback(renderContext.RenderThreadMethod); //renderContext.windows = new StitchSurface[1];//Processor.LogicalCpuCount //renderContext.offsets = new Point[1]; //renderContext.rects = new Rectangle[1]; } Utility.SplitRectangle(ra.Bounds, renderContext.rects); for (int i = 0; i < renderContext.rects.Length; ++i) { if (renderContext.rects[i].Width > 0 && renderContext.rects[i].Height > 0) { renderContext.offsets[i] = new Point(renderContext.rects[i].X + offset.X, renderContext.rects[i].Y + offset.Y); renderContext.windows[i] = ra.Surface.CreateWindow(renderContext.rects[i]); } else { renderContext.windows[i] = null; } } for (int i = 0; i < renderContext.windows.Length; ++i) { if (renderContext.windows[i] != null) { this.threadPool.QueueUserWorkItem(renderContext.waitCallback, BoxedConstants.GetInt32(i)); } } try { this.threadPool.Drain(); } catch { } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.panel.Select(); } protected override void OnMouseWheel(MouseEventArgs e) { HandleMouseWheel(this, e); base.OnMouseWheel(e); } /// /// 鼠标滚轮事件 /// /// /// protected virtual void HandleMouseWheel(Control sender, MouseEventArgs e) { double docDelta = (double)e.Delta / this.ScaleFactor.Ratio; double oldX = this.DocumentScrollPositionF.X; double oldY = this.DocumentScrollPositionF.Y; double newX; double newY; if (Control.ModifierKeys == Keys.Shift) { this.panel.Response = false; // scroll horizontally newX = this.DocumentScrollPositionF.X - docDelta; newY = this.DocumentScrollPositionF.Y; } else if (Control.ModifierKeys == Keys.None) { this.panel.Response = true; // scroll vertically newX = this.DocumentScrollPositionF.X; newY = this.DocumentScrollPositionF.Y - docDelta; } else { this.panel.Response = false; // no change newX = this.DocumentScrollPositionF.X; newY = this.DocumentScrollPositionF.Y; } if (newX != oldX || newY != oldY) this.DocumentScrollPositionF = new PointF((float)newX, (float)newY); } /// /// Get or set upper left of scroll location in document coordinates. /// [Browsable(false)] public PointF DocumentScrollPositionF { get { if (this.panel == null) { return PointF.Empty; } else { return this.panel.ScrollPosition; //return VisibleDocumentRectangleF.Location; } } set { if (panel == null) { return; } else { this.panel.ScrollPosition = new Point((int)value.X, (int)value.Y); } } } public Point PanelScrollPosition { get { return this.panel.ScrollPosition; } set { this.panel.ScrollPosition = value; } } [Browsable(false)] public PointF DocumentCenterPointF { get { RectangleF vsb = VisibleDocumentRectangleF; PointF centerPt = new PointF((vsb.Left + vsb.Right) / 2, (vsb.Top + vsb.Bottom) / 2); return centerPt; } set { RectangleF vsb = VisibleDocumentRectangleF; PointF newCornerPt = new PointF(value.X - (vsb.Width / 2), value.Y - (vsb.Height / 2)); this.DocumentScrollPositionF = newCornerPt; } } /// /// Clean up any resources being used. /// protected override void Dispose(bool disposing) { if (disposing) { if (this.components != null) { this.components.Dispose(); this.components = null; } if (this.compositionSurface != null) { this.compositionSurface.Dispose(); this.compositionSurface = null; } } base.Dispose(disposing); } /// /// 缩放比例改变事件 /// public event EventHandler ScaleFactorChanged; protected virtual void OnScaleFactorChanged() { if (ScaleFactorChanged != null) { ScaleFactorChanged(this, EventArgs.Empty); } } private double GetZoomInFactorEpsilon() { double ratio = this.ScaleFactor.Ratio; return (ratio + 0.01) / ratio; } private double GetZoomOutFactorEpsilon() { double ratio = this.ScaleFactor.Ratio; return (ratio - 0.01) / ratio; } public virtual void ZoomIn(double factor) { Do.TryBool(() => ZoomInImpl(factor)); } private void ZoomInImpl(double factor) { PointF centerPt = this.DocumentCenterPointF; ScaleFactor oldSF = this.ScaleFactor; ScaleFactor newSF = this.ScaleFactor; int countdown = 3; // At a minimum we want to increase the size of visible document by 1 pixel // Figure out what the ratio of ourSize : ourSize+1 is, and start out with that double zoomInEps = GetZoomInFactorEpsilon(); double desiredFactor = Math.Max(factor, zoomInEps); double newFactor = desiredFactor; // Keep setting the ScaleFactor until it actually 'sticks' // Important for certain image sizes where not all zoom levels create distinct // screen sizes do { newSF = ScaleFactor.FromDouble(newSF.Ratio * newFactor); this.ScaleFactor = newSF; --countdown; newFactor *= 1.10; } while (this.ScaleFactor == oldSF && countdown > 0); this.DocumentCenterPointF = centerPt; } public virtual void ZoomIn() { Do.TryBool(ZoomInImpl); } private void ZoomInImpl() { PointF centerPt = this.DocumentCenterPointF; ScaleFactor oldSF = this.ScaleFactor; ScaleFactor newSF = this.ScaleFactor; int countdown = ScaleFactor.PresetValues.Length; // Keep setting the ScaleFactor until it actually 'sticks' // Important for certain image sizes where not all zoom levels create distinct // screen sizes do { newSF = newSF.GetNextLarger(); this.ScaleFactor = newSF; --countdown; } while (this.ScaleFactor == oldSF && countdown > 0); this.DocumentCenterPointF = centerPt; } public virtual void ZoomOut(double factor) { Do.TryBool(() => ZoomOutImpl(factor)); } private void ZoomOutImpl(double factor) { PointF centerPt = this.DocumentCenterPointF; ScaleFactor oldSF = this.ScaleFactor; ScaleFactor newSF = this.ScaleFactor; int countdown = 3; // At a minimum we want to decrease the size of visible document by 1 pixel (without dividing by zero of course) // Figure out what the ratio of ourSize : ourSize-1 is, and start out with that double zoomOutEps = GetZoomOutFactorEpsilon(); double factorRecip = 1.0 / factor; double desiredFactor = Math.Min(factorRecip, zoomOutEps); double newFactor = desiredFactor; // Keep setting the ScaleFactor until it actually 'sticks' // Important for certain image sizes where not all zoom levels create distinct // screen sizes do { newSF = ScaleFactor.FromDouble(newSF.Ratio * newFactor); this.ScaleFactor = newSF; --countdown; newFactor *= 0.9; } while (this.ScaleFactor == oldSF && countdown > 0); this.DocumentCenterPointF = centerPt; } public virtual void ZoomOut() { Do.TryBool(ZoomOutImpl); } private void ZoomOutImpl() { PointF centerPt = this.DocumentCenterPointF; ScaleFactor oldSF = this.ScaleFactor; ScaleFactor newSF = this.ScaleFactor; int countdown = ScaleFactor.PresetValues.Length; // Keep setting the ScaleFactor until it actually 'sticks' // Important for certain image sizes where not all zoom levels create distinct // screen sizes do { newSF = newSF.GetNextSmaller(); this.ScaleFactor = newSF; --countdown; } while (this.ScaleFactor == oldSF && countdown > 0); this.DocumentCenterPointF = centerPt; } [Browsable(false)] public ScaleFactor ScaleFactor { get { return this.scaleFactor; } set { UI.SuspendControlPainting(this); ScaleFactor newValue = ScaleFactor.Min(value, ScaleFactor.MaxValue); if (newValue == this.scaleFactor && this.scaleFactor == ScaleFactor.OneToOne) { // this space intentionally left blank } else { //RectangleF visibleRect = this.VisibleDocumentRectangleF; //ScaleFactor oldSF = scaleFactor; scaleFactor = newValue; //// This value is used later below to re-center the document on screen //PointF centerPt = new PointF(visibleRect.X + visibleRect.Width / 2, // visibleRect.Y + visibleRect.Height / 2); if (compositionSurface != null) { Rectangle rc = this.panel.ClientRectangle; int width = (int)(this.compositionSurface.Width * this.scaleFactor.Ratio); int height = (int)(this.compositionSurface.Height * this.scaleFactor.Ratio); if (rc.Width < width || rc.Height < height) this.panel.AutoScrollMinSize = new Size((int)((this.compositionSurface.StitchWidth) * scaleFactor.Ratio) + offsetW, (int)((this.compositionSurface.StitchHeight) * scaleFactor.Ratio) + offsetH); else this.panel.AutoScrollMinSize = new Size((int)((this.compositionSurface.StitchWidth) * scaleFactor.Ratio), (int)((this.compositionSurface.StitchHeight) * scaleFactor.Ratio)); this.panel.ScaleFactor = this.scaleFactor; } //// re center ourself //RectangleF visibleRect2 = this.VisibleDocumentRectangleF; //RecenterView(centerPt); } this.OnResize(EventArgs.Empty); this.OnScaleFactorChanged(); if (compositionSurface != null) this.rendererList.DestinationSize = this.scaleFactor.ScaleSize(compositionSurface.Size); UI.ResumeControlPainting(this); Invalidate(true); } } /// /// Returns a rectangle for the bounding rectangle of what is currently visible on screen, /// in document coordinates. /// [Browsable(false)] public RectangleF VisibleDocumentRectangleF { get { Rectangle panelRect = this.panel.RectangleToScreen(this.panel.ClientRectangle); // screen coords coords Rectangle docScreenRect = panelRect; // screen coords Rectangle docClientRect = RectangleToClient(docScreenRect); RectangleF docDocRectF = ClientToDocument(docClientRect); return docDocRectF; } } public Rectangle PanelClientRectangle { get { return panel.ClientRectangle; } } public int SurfaceScrollableWidth { get { return (int)(this.compositionSurface.Width * this.scaleFactor.Ratio); } } public int SurfaceScrollableHeight { get { return (int)(this.compositionSurface.Height * this.scaleFactor.Ratio); } } public double ScaleRatio { get { return this.scaleFactor.Ratio; } } /// /// Returns a rectangle in screen coordinates that represents the space taken up /// by the document that is visible on screen. /// [Browsable(false)] public Rectangle VisibleDocumentBounds { get { // convert coordinates: document -> client -> screen return RectangleToScreen(Utility.RoundRectangle(DocumentToClient(VisibleDocumentRectangleF))); } } public Rectangle ClientRectangleMax { get { return RectangleToClient(this.panel.RectangleToScreen(this.panel.Bounds)); } } /// /// Gets or sets the Document that is shown through this instance of DocumentStitchView. /// /// /// This property is thread safe and may be called from a non-UI thread. However, /// if the setter is called from a non-UI thread, then that thread will block as /// the call is marshaled to the UI thread. /// [Browsable(false)] public StitchDocument StitchDocument { get { return document; } set { if (InvokeRequired) { this.Invoke(new Procedure(DocumentSetImpl), new object[2] { value, true }); } else { DocumentSetImpl(value, true); } } } private void DocumentSetImpl(StitchDocument value, bool toedit) { this.DoubleBuffered = true; SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); PointF dspf = DocumentScrollPositionF; try { if (this.document != null) { this.document.Invalidated -= Document_Invalidated; } this.document = value; if (document != null) { if (this.compositionSurface != null && this.compositionSurface.Size != document.Size) { this.compositionSurface.Dispose(); this.compositionSurface = null; } //if (this.compositionSurface == null) //{ //this.compositionSurface = new StitchSurface(Document.Size); this.compositionSurface = document.surface;//((BitmapLayer)(document.Layers[0])).Surface; this.baseRenderer.Source = document.surface; //((BitmapLayer)(document.Layers[0])).Surface; if (this.compositionSurface != null) { // Maintain the scalefactor /*this.Size = this.scaleFactor.ScaleSize(compositionSurface.Size);*/ this.rendererList.SourceSize = this.compositionSurface.Size; this.rendererList.DestinationSize = this.Size; } this.document.Invalidated += Document_Invalidated; } Invalidate(true); this.OnResize(EventArgs.Empty); } finally { } DocumentScrollPositionF = dspf; } public bool PanelAutoScroll { get { return panel.AutoScroll; } set { if (panel.AutoScroll != value) { panel.AutoScroll = value; } } } public DrawToolType ActiveTool { get => _activeTool; set { if (!tools.ContainsKey(value)) return; tools[_activeTool].InvokeMember("beginWithNewObject", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[0] { }); _activeTool = value; } } public GraphicsList GraphicsList { get { return graphicsList; } set { graphicsList = value; if (this.GraphicsList != null) { this.Invalidate(); } } } public bool DrawRectangleFlag { get { return this.drawRectangle; } set { this.drawRectangle = value; } } public Rectangle DrawRectangle { get { return this.rectangle; } set { this.rectangle = value; } } public bool ViewMoveOnMouseLeftDoubleClickEnable { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public int ToolNumber { set => throw new NotImplementedException(); } public LabelStyleModel.DrawAnalysisModel AnalysisStyleModel { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } private void DoLayout() { this.UpdateImgLocation(); } private void Document_Invalidated(object sender, InvalidateEventArgs e) { if (this.ScaleFactor == ScaleFactor.OneToOne) { this.panel.Invalidate(e.InvalidRect); } else { Rectangle inflatedInvalidRect = Rectangle.Inflate(e.InvalidRect, 1, 1); Rectangle clientRect = this.panel.SurfaceToClient(inflatedInvalidRect); Rectangle inflatedClientRect = Rectangle.Inflate(clientRect, 1, 1); this.panel.Invalidate(inflatedClientRect); } } ///// ///// 重新设置中心点 ///// ///// //public void RecenterView(PointF newCenter) //{ // RectangleF visibleRect = VisibleDocumentRectangleF; // PointF cornerPt = new PointF( // newCenter.X - (visibleRect.Width / 2), // newCenter.Y - (visibleRect.Height / 2)); // this.DocumentScrollPositionF = cornerPt; //} #region DocimentView的子控件的事件 private void Panel_KeyDown(object sender, KeyEventArgs e) { if (!e.Handled) { PointF oldPt = this.DocumentScrollPositionF; PointF newPt = oldPt; RectangleF vdr = VisibleDocumentRectangleF; switch (e.KeyData) { case Keys.Next: newPt.Y += vdr.Height; break; case (Keys.Next | Keys.Shift): newPt.X += vdr.Width; break; case Keys.Prior: newPt.Y -= vdr.Height; break; case (Keys.Prior | Keys.Shift): newPt.X -= vdr.Width; break; case Keys.Home: if (oldPt.X == 0) { newPt.Y = 0; } else { newPt.X = 0; } break; case Keys.End: if (vdr.Right < this.document.Width - 1) { newPt.X = this.document.Width; } else { newPt.Y = this.document.Height; } break; default: break; } if (newPt != oldPt) { DocumentScrollPositionF = newPt; e.Handled = true; } } } private void Panel_Scroll(object sender, System.Windows.Forms.ScrollEventArgs e) { OnScroll(e); } /// /// 鼠标按下事件 /// /// /// protected virtual void MouseEvent_Down(object sender, MouseEventArgs e) { if (tools != null) { //tools[activeTool].OnMouseDown(this, e); tools[_activeTool].InvokeMember("OnMouseDown", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[2] { this, e }); } } public void MouseEvent_Del(object sender, MouseEventArgs e) { try { tools[_activeTool].InvokeMember("beginWithNewObject", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[0] { }); tools[0].InvokeMember("OnDelKeyDown", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[2] { this, e }); } catch { } } /// /// 鼠标移动事件 /// /// /// protected virtual void MouseEvent_Move(object sender, MouseEventArgs e) { // // 处理标注测量 // if (!initialized) return; if (e.Button == MouseButtons.Left || e.Button == MouseButtons.None) if (tools != null) { tools[_activeTool].InvokeMember("OnMouseMove", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[2] { this, e }); } else this.Cursor = Cursors.Default; } /// /// 鼠标抬起事件 /// /// /// private void MouseEvent_Up(object sender, MouseEventArgs e) { if (tools != null) { if (e.Button == MouseButtons.Left) tools[_activeTool].InvokeMember("OnMouseUp", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[2] { this, e }); } } /// /// 鼠标单击事件 /// /// /// private void MouseEvent_Click(object sender, MouseEventArgs e) { if (tools != null) { tools[_activeTool].InvokeMember("OnMouseClick", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[2] { this, e }); } } /// 绘制事件 /// /// /// private unsafe void panelPaint(object sender, PaintEventArgs e) { if (compositionSurface != null) { // 以下是计算绘制图片的位置和大小并绘制图片 Rectangle rc = this.panel.ClientRectangle; int width = (int)(this.compositionSurface.Width * this.scaleFactor.Ratio); int height = (int)(this.compositionSurface.Height * this.scaleFactor.Ratio); int x = (rc.Width < width) ? this.panel.AutoScrollPosition.X + offsetHalfW : (rc.Width - width) / 2; int y = (rc.Height < height) ? this.panel.AutoScrollPosition.Y + offsetHalfH : (rc.Height - height) / 2; //第四个版本,只绘制当前需要显示的大小的图片 //if (this.compositionSurface.Bitmap != null) if (this.compositionSurface.CreateAliasedBitmap() != null) { using (StitchSurface doubleBuffer = GetDoubleBuffer(new Size((rc.Width < width) ? rc.Width : width, (rc.Height < height) ? rc.Height : height))) { try { using (StitchRenderArgs renderArgs = new StitchRenderArgs(doubleBuffer)) { DrawArea(renderArgs, new Point((rc.Width < width) ? -x : 0, (rc.Height < height) ? -y : 0)); if (m_center) { e.Graphics.DrawImage(doubleBuffer.CreateAliasedBitmap(), (rc.Width < width) ? 0 : (rc.Width - width) / 2, (rc.Height < height) ? 0 : (rc.Height - height) / 2, (rc.Width < width) ? rc.Width : width, (rc.Height < height) ? rc.Height : height); } else { e.Graphics.DrawImage(doubleBuffer.CreateAliasedBitmap(), m_pLeft, m_pTop, (rc.Width < width) ? rc.Width : width, (rc.Height < height) ? rc.Height : height); } } } catch { } } } // // 以下是绘制网格、标注、测量、视场等开始 // e.Graphics.TranslateTransform(x, y); e.Graphics.ScaleTransform((float)this.scaleFactor.Ratio, (float)this.scaleFactor.Ratio); // // 以下是绘制标注、测量、视场 // if (graphicsList != null) { var drawObject = graphicsList[0]; if (!(drawObject is MeasureRectangle)) { }//graphicsList.Draw(e.Graphics); else//pen.DashStyle = DashStyle.Solid; e.Graphics.DrawRectangle(new Pen(Color.Green, 14), drawObject.Rectangle.X, drawObject.Rectangle.Y, drawObject.Rectangle.Width, drawObject.Rectangle.Height); } e.Graphics.ScaleTransform(1 / (float)this.scaleFactor.Ratio, 1 / (float)this.scaleFactor.Ratio); e.Graphics.TranslateTransform(-x, -y); } } #endregion ///// ///// 获取panel可见位置的图片 ///// ///// //public Bitmap GetClientRangePic() //{ #region DocumentStitchView的事件 protected override void OnLayout(LayoutEventArgs e) { DoLayout(); base.OnLayout(e); } /// /// 让画布获取焦点 /// public new void Focus() { this.panel.Focus(); } protected override void OnResize(EventArgs e) { // enable or disable timer: no sense drawing selection if we're minimized Form parentForm = ParentForm; if (parentForm != null) { if (parentForm.WindowState != this.oldWindowState) { PerformLayout(); } this.oldWindowState = parentForm.WindowState; } base.OnResize(e); DoLayout(); } #endregion #region 坐标转换相关方法 public Point MouseToDocument(Control sender, Point mouse) { Point screenPoint = sender.PointToScreen(mouse); Point sbClient = this.panel.PointToClient(screenPoint); Point docPoint = Point.Truncate(this.panel.ClientToSurface(sbClient)); return docPoint; } /// /// Converts a rectangle from the Windows Forms "client" coordinate space into the Document /// coordinate space. /// /// A Rectangle that is in client coordinates. /// A Rectangle that is in Document coordinates. public RectangleF ClientToDocument(Rectangle clientRect) { Rectangle screen = RectangleToScreen(clientRect); screen.X = screen.X + offsetW; screen.Y = screen.Y + offsetH; Rectangle sbClient = this.panel.RectangleToClient(screen); return this.panel.ClientToSurface((RectangleF)sbClient); } /// /// Converts a rectangle from Document coordinate space into the Windows Forms "client" /// coordinate space. /// /// A Rectangle that is in Document coordinates. /// A Rectangle that is in client coordinates. public RectangleF DocumentToClient(RectangleF documentRect) { RectangleF sbClient = this.panel.SurfaceToClient(documentRect); Rectangle screen = this.panel.RectangleToScreen(Utility.RoundRectangle(sbClient)); return RectangleToClient(screen); } public Rectangle SurfaceToClient(Rectangle surfaceRect) { return new Rectangle(SurfaceToClient(surfaceRect.Location), SurfaceToClient(surfaceRect.Size)); } public Point SurfaceToClient(Point surfacePt) { return ScaleFactor.ScalePoint(surfacePt); } public Size SurfaceToClient(Size surfaceSize) { return Size.Round(SurfaceToClient((SizeF)surfaceSize)); } public SizeF SurfaceToClient(SizeF surfaceSize) { return ScaleFactor.ScaleSize(surfaceSize); } #endregion #region 初始化控件 private void InitializeComponent() { this.components = new Container(); this.panel = new PanelEx(); this.panel.SuspendLayout(); this.SuspendLayout(); // // panel // this.panel.AutoScroll = true; this.panel.Dock = DockStyle.Fill; this.panel.HideHScroll = false; this.panel.HideVScroll = false; this.panel.Location = new Point(16, 16); this.panel.Name = "panel"; this.panel.ScrollPosition = new Point(0, 0); this.panel.Size = new Size(368, 304); this.panel.TabIndex = 5; this.panel.AllowDrop = false; this.panel.Scroll += new ScrollEventHandler(this.Panel_Scroll); this.panel.KeyDown += new KeyEventHandler(Panel_KeyDown); // // DocumentStitchView // this.Controls.Add(this.panel); this.Name = "DocumentStitchView"; this.Size = new System.Drawing.Size(384, 320); this.panel.ResumeLayout(false); this.ResumeLayout(false); } #endregion #region 设定图片位置 // add by maxb 20200716 /// /// 图片位置坐标 /// private bool m_center = true; private int m_pTop = 0; private int m_pLeft = 0; private int m_initTop = 0; private int m_initLeft = 0; private void UpdateImgLocation() { if (!m_center) { //Console.WriteLine("m_pLeft: " + m_initLeft + " Ratio:" + this.scaleFactor.Ratio); m_pLeft = 16 + (int)(m_initLeft * this.scaleFactor.Ratio); m_pTop = 16 + (int)(m_initTop * this.scaleFactor.Ratio); //Console.WriteLine("Location: " + m_pLeft + " " + m_pTop); } } public RectangleF GetVisibleDocumentRectangleF() { return this.VisibleDocumentRectangleF; //return this.AppWorkspaceTop.GetVisibleDocumentRectangleF(); } public SizeF GetDocumentSize() { if (this.document != null) return this.document.Size; else return new SizeF(0, 0); //return this.AppWorkspaceTop.GetDocumentSize(); } public void AddCommandToHistory(Command c) { throw new NotImplementedException(); } public void SetDirty() { throw new NotImplementedException(); } /// /// 获取未缩放的坐标点 /// /// /// public Point GetScalePoint(PointF point) { Rectangle rc = this.panel.ClientRectangle; int width = this.compositionSurface == null ? 800 : (int)(this.compositionSurface.Width * this.scaleFactor.Ratio); int height = this.compositionSurface == null ? 600 : (int)(this.compositionSurface.Height * this.scaleFactor.Ratio); int x = (rc.Width < width) ? this.panel.AutoScrollPosition.X + offsetHalfW : (rc.Width - width) / 2; int y = (rc.Height < height) ? this.panel.AutoScrollPosition.Y + offsetHalfH : (rc.Height - height) / 2; return new Point( (int)((point.X - x) / this.scaleFactor.Ratio), (int)((point.Y - y) / this.scaleFactor.Ratio) ); //return this.scaleFactor.UnscalePoint(location); } public Point GetCalcOriginPoint() { throw new NotImplementedException(); } public int UnscaleScalar(int deltaX) { throw new NotImplementedException(); } public PointF GetDocumentScrollPositionF() { return this.DocumentScrollPositionF; //return this.AppWorkspaceTop.GetDocumentScrollPositionF(); } public void SetDocumentScrollPositionF(PointF newScrollPos) { Point sbClient = Point.Round(newScrollPos); if (this.panel.AutoScrollPosition != new Point(-sbClient.X, -sbClient.Y)) { this.panel.AutoScrollPosition = sbClient; } } public PointF DocumentToClient(PointF pointF) { throw new NotImplementedException(); } public string[] GetPxPerUnit() { throw new NotImplementedException(); } public Dictionary GetUnitsDictionary() { throw new NotImplementedException(); } public Dictionary GetUnitSymbolsDictionary() { throw new NotImplementedException(); } public CombineMode GetCombineMode() { throw new NotImplementedException(); } public void SetMouseStatus(bool status) { throw new NotImplementedException(); } public bool GetMouseStatus() { throw new NotImplementedException(); } public Dictionary GetTools() { throw new NotImplementedException(); } public bool ContinuousDrawingLabel() { throw new NotImplementedException(); } public void SetContinuousDrawingLabel(bool v) { throw new NotImplementedException(); } public bool ContinuousDrawingMeasure() { throw new NotImplementedException(); } public void SetContinuousDrawingMeasure(bool v) { throw new NotImplementedException(); } public void ResetUndoManager() { throw new NotImplementedException(); } public LabelStyleModel GetLabelStyleModel() { throw new NotImplementedException(); } public MeasureStyleModel GetMeasureStyleModel() { return new MeasureStyleModel();// throw new NotImplementedException(); } public WatermarkModel GetWatermarkModel() { throw new NotImplementedException(); } public WorkTypeStyleModel GetWorkTypeStyleModel() { throw new NotImplementedException(); } public RulerModel GetRulerStyleModel() { throw new NotImplementedException(); } public Dictionary getMeasureInfo() { throw new NotImplementedException(); } public MeasurementUnit GetMeasurementUnit() { throw new NotImplementedException(); } public decimal GetGainMultiple() { throw new NotImplementedException(); } public decimal GetMic_Rulers() { throw new NotImplementedException(); } public void RefreshLabelListDialog() { throw new NotImplementedException(); } public void UpdateContinueNum() { throw new NotImplementedException(); } public bool ContinuousBinaryAction() { throw new NotImplementedException(); } public void BinaryActionExtract(PointF point) { throw new NotImplementedException(); } public void BinaryActionChoise(PointF point) { throw new NotImplementedException(); } public void BinaryActionChoiseRectangle(RectangleF rectangle) { throw new NotImplementedException(); } public void BinaryActionChoiseOval(RectangleF rectangle) { throw new NotImplementedException(); } public void BinaryActionChoisePolygon(List points) { throw new NotImplementedException(); } public int GetSegmentationWidth() { throw new NotImplementedException(); } public void BinaryActionSplitLine(PointF start, PointF end) { throw new NotImplementedException(); } public void BinaryActionSplitOval(RectangleF rect) { throw new NotImplementedException(); } public int GetConnectionWidth() { throw new NotImplementedException(); } public void BinaryActionConnectionLine(PointF start, PointF end) { throw new NotImplementedException(); } public void BinaryConnectionOval(RectangleF rect) { throw new NotImplementedException(); } public void BinaryActionDelete(PointF point) { throw new NotImplementedException(); } public void BinaryActionDelete(RectangleF rect) { throw new NotImplementedException(); } public void BinaryActionDelete(List points) { throw new NotImplementedException(); } public void BinaryActionDeleteOval(RectangleF rect) { throw new NotImplementedException(); } public void BinaryActionAddOval(RectangleF rect) { throw new NotImplementedException(); } public void BinaryActionAddRectangle(RectangleF rect) { throw new NotImplementedException(); } public void BinaryActionAddPolygon(List points) { throw new NotImplementedException(); } public void PPhaseActionRectangle(RectangleF rect) { throw new NotImplementedException(); } public void PPhaseActionPolygon(List points) { throw new NotImplementedException(); } public void PPhaseActionOval(RectangleF rect) { throw new NotImplementedException(); } public PointF GetRulerPointInPanel(PointF point) { throw new NotImplementedException(); } public PointF ScalePointToRulerPoint(PointF point) { throw new NotImplementedException(); } public bool ActualSize() { throw new NotImplementedException(); } public bool SuitableSize() { throw new NotImplementedException(); } public bool SuitableWidth() { throw new NotImplementedException(); } public bool SuitableHeight() { throw new NotImplementedException(); } public bool LockZoom() { throw new NotImplementedException(); } public bool FixedMultiple() { throw new NotImplementedException(); } public bool MergeFieldOfView() { throw new NotImplementedException(); } public bool DeleteFieldOfView() { throw new NotImplementedException(); } public Inclusion GetInclusion() { throw new NotImplementedException(); } #endregion } }