#region Disclaimer / License // Copyright (C) 2009, Kenneth Skovhede // http://www.hexad.dk, opensource@hexad.dk // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Data; using System.Windows.Forms; using OSGeo.MapGuide.MaestroAPI; using OSGeo.MapGuide.MaestroAPI.RuntimeClasses; namespace OSGeo.MapGuide.Maestro.RasterViewer { /// /// Summary description for RasterViewer. /// public class RasterViewer : System.Windows.Forms.UserControl { private const int SCREEN_DPI = 96; public enum Tools { ZoomIn, ZoomOut, Pan, Select } private class View { double m_minx; double m_miny; double m_maxx; double m_maxy; public View(double minx, double miny, double maxx, double maxy) { m_minx = Math.Min(minx, maxx); m_miny = Math.Min(miny, maxy); m_maxx = Math.Max(minx, maxx); m_maxy = Math.Max(miny, maxy); } public View(double x, double y, double scale, double unitsPerPixel, int w, int h) { double width = ((double)w * unitsPerPixel * scale) / 2; double height = ((double)h * unitsPerPixel * scale) / 2; m_minx = x - width; m_maxx = x + width; m_miny = y - height; m_maxy = y + height; } public double MinX { get { return m_minx; } set { m_minx = value; } } public double MinY { get { return m_miny; } set { m_miny = value; } } public double MaxX { get { return m_maxx; } set { m_maxx = value; } } public double MaxY { get { return m_maxy; } set { m_maxy = value; } } public double Width { get { return m_maxx - m_minx; } set { double diff = (this.Width - value) / 2; m_maxx += diff; m_minx -= diff; } } public double Height { get { return m_maxy - m_miny; } set { double diff = (this.Height - value) / 2; m_maxy -= diff; m_miny += diff; } } public double X { get { return (this.Width / 2) + m_minx; } set { double diff = this.X - value; m_maxx -= diff; m_minx -= diff; } } public double Y { get { return (this.Height / 2) + m_miny; } set { double diff = this.Y - value; m_maxy -= diff; m_miny -= diff; } } public PointF Center { get { return new PointF((float)this.X, (float)this.Y); } set { this.X = value.X; this.Y = value.Y; } } public double GetScale(int w, int h, double unitsPerPixel) { return Math.Max(1 / ((w * unitsPerPixel) / this.Width), 1 / ((h * unitsPerPixel) / this.Height)); } public PointF CalculatePosition(int x, int y, int w, int h) { return new PointF((float)(this.Width * (x/(double)w) + m_minx), (float)(this.Height * ((h-y)/(double)h) + m_miny)); } } public System.Windows.Forms.ImageList imageList; public System.Windows.Forms.ToolBar toolBar; public System.Windows.Forms.PictureBox picture; private System.Windows.Forms.Panel panel; private System.Windows.Forms.Splitter splitter1; private System.Windows.Forms.ToolBarButton ZoomInButton; private System.Windows.Forms.ToolBarButton ZoomOutButton; private System.Windows.Forms.ToolBarButton UnzoomButton; private System.Windows.Forms.StatusBar statusBar; private System.ComponentModel.IContainer components; private ServerConnectionI m_connection; private View m_current; private View m_initial; private System.Windows.Forms.ToolBarButton RefreshMapButton; private string m_currentmap; private Tools m_currentTool; private System.Windows.Forms.ToolBarButton PanButton; private double m_unitsPerPixel; private Point m_downPoint; public RasterViewer() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); // TODO: Add any initialization after the InitializeComponent call } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Component Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.imageList = new System.Windows.Forms.ImageList(this.components); this.toolBar = new System.Windows.Forms.ToolBar(); this.ZoomInButton = new System.Windows.Forms.ToolBarButton(); this.ZoomOutButton = new System.Windows.Forms.ToolBarButton(); this.UnzoomButton = new System.Windows.Forms.ToolBarButton(); this.RefreshMapButton = new System.Windows.Forms.ToolBarButton(); this.PanButton = new System.Windows.Forms.ToolBarButton(); this.picture = new System.Windows.Forms.PictureBox(); this.panel = new System.Windows.Forms.Panel(); this.splitter1 = new System.Windows.Forms.Splitter(); this.statusBar = new System.Windows.Forms.StatusBar(); this.SuspendLayout(); // // imageList // this.imageList.ImageSize = new System.Drawing.Size(16, 16); this.imageList.TransparentColor = System.Drawing.Color.Transparent; // // toolBar // this.toolBar.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] { this.ZoomInButton, this.ZoomOutButton, this.UnzoomButton, this.RefreshMapButton, this.PanButton}); this.toolBar.DropDownArrows = true; this.toolBar.ImageList = this.imageList; this.toolBar.Location = new System.Drawing.Point(0, 0); this.toolBar.Name = "toolBar"; this.toolBar.ShowToolTips = true; this.toolBar.Size = new System.Drawing.Size(616, 42); this.toolBar.TabIndex = 0; this.toolBar.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.toolBar_ButtonClick); // // ZoomInButton // this.ZoomInButton.Text = "Zoom in"; // // ZoomOutButton // this.ZoomOutButton.Text = "Zoom out"; // // UnzoomButton // this.UnzoomButton.Text = "Unzoom"; // // RefreshMapButton // this.RefreshMapButton.Text = "Refresh"; // // PanButton // this.PanButton.Text = "Recenter"; // // picture // this.picture.Dock = System.Windows.Forms.DockStyle.Fill; this.picture.Location = new System.Drawing.Point(96, 42); this.picture.Name = "picture"; this.picture.Size = new System.Drawing.Size(520, 288); this.picture.TabIndex = 1; this.picture.TabStop = false; this.picture.Click += new System.EventHandler(this.picture_Click); this.picture.Resize += new System.EventHandler(this.picture_Resize); this.picture.VisibleChanged += new System.EventHandler(this.picture_VisibleChanged); this.picture.Paint += new System.Windows.Forms.PaintEventHandler(this.picture_Paint); this.picture.MouseUp += new System.Windows.Forms.MouseEventHandler(this.picture_MouseUp); this.picture.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picture_MouseMove); this.picture.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picture_MouseDown); // // panel // this.panel.Dock = System.Windows.Forms.DockStyle.Left; this.panel.Location = new System.Drawing.Point(0, 42); this.panel.Name = "panel"; this.panel.Size = new System.Drawing.Size(88, 288); this.panel.TabIndex = 2; // // splitter1 // this.splitter1.Location = new System.Drawing.Point(88, 42); this.splitter1.Name = "splitter1"; this.splitter1.Size = new System.Drawing.Size(8, 288); this.splitter1.TabIndex = 3; this.splitter1.TabStop = false; // // statusBar // this.statusBar.Location = new System.Drawing.Point(0, 330); this.statusBar.Name = "statusBar"; this.statusBar.Size = new System.Drawing.Size(616, 22); this.statusBar.TabIndex = 4; // // RasterViewer // this.Controls.Add(this.picture); this.Controls.Add(this.splitter1); this.Controls.Add(this.panel); this.Controls.Add(this.toolBar); this.Controls.Add(this.statusBar); this.Name = "RasterViewer"; this.Size = new System.Drawing.Size(616, 352); this.ResumeLayout(false); } #endregion public void SetCurrentMap(ServerConnectionI connection, string resourceId) { m_connection = connection; RuntimeMap r; if (resourceId.EndsWith(".MapDefinition")) { m_currentmap = new ResourceIdentifier(Guid.NewGuid().ToString(), ResourceTypes.RuntimeMap, m_connection.SessionID); MapDefinition m = m_connection.GetMapDefinition(resourceId); r = new RuntimeMap(m); m_connection.CreateRuntimeMap(m_currentmap, r); } else { m_currentmap = resourceId; r = m_connection.GetRuntimeMap(m_currentmap); } m_initial = new View(r.Extents.MinX, r.Extents.MinY, r.Extents.MaxX, r.Extents.MaxY); m_current = new View(r.Extents.MinX, r.Extents.MinY, r.Extents.MaxX, r.Extents.MaxY); //Scaling code from server... m_unitsPerPixel = 0.0254 / (double)SCREEN_DPI / r.MetersPerUnit; /*double mapWidth2 = 0.5 * (double)width * unitsPerPixel * scale; double mapHeight2 = 0.5 * (double)height * unitsPerPixel * scale;*/ this.Visible = true; this.Enabled = true; GoToScale(m_initial.X, m_initial.Y, m_initial.GetScale(picture.Width, picture.Height, m_unitsPerPixel)); } public double CurrentScale { get { if (m_current == null) return 0; else return m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel); } set { if (m_current != null) m_current = new View(m_current.X, m_current.Y, value, m_unitsPerPixel, picture.Width, picture.Height); } } public PointF CurrentCenter { get { return m_current.Center; } set { m_current.Center = value; } } public void GoToScale(double x, double y, double scale) { if (!this.Enabled || !this.Visible || m_connection == null) return; if (m_imageFetcher != null && m_imageFetcher.IsAlive) { try { m_imageFetcher.Abort(); } catch { } //Don't care if we can't cancel, but at least try m_imageFetcher.Join(500); } m_current = new View(x, y, scale, m_unitsPerPixel, picture.Width, picture.Height); m_imageFetcherParams = new FetchImageParameters(); m_imageFetcherParams.x = m_current.X; m_imageFetcherParams.y = m_current.Y; m_imageFetcherParams.scale = m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel); m_imageFetcherParams.w = picture.Width; m_imageFetcherParams.h = picture.Height; m_imageFetcherParams.resid = m_currentmap; m_imageFetcherParams.evt = new System.Threading.ManualResetEvent(false); m_imageFetcher = new System.Threading.Thread(new System.Threading.ThreadStart(FetchImage)); m_imageFetcher.IsBackground = true; m_imageFetcher.Start(); m_imageFetcherParams.evt.WaitOne(); m_imageFetcherParams = null; } System.Threading.Thread m_imageFetcher; FetchImageParameters m_imageFetcherParams; private class FetchImageParameters { public double x; public double y; public double scale; public string resid; public int w; public int h; public System.Threading.ManualResetEvent evt; } private void FetchImage() { //Copy pointer and release FetchImageParameters p = m_imageFetcherParams; p.evt.Set(); Bitmap bmp = new Bitmap(m_connection.RenderRuntimeMap(p.resid, p.x, p.y, p.scale, p.w, p.h, SCREEN_DPI)); this.Invoke(new SetImageDelegate(SetImage), new object[] { bmp } ); } private delegate void SetImageDelegate(Bitmap bmp); private void SetImage(Bitmap bmp) { picture.Image = bmp; } private void toolBar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e) { if (e.Button == RefreshMapButton) GoToScale(m_current.X, m_current.Y, m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel)); else if (e.Button == UnzoomButton) GoToScale(m_initial.X, m_initial.Y, m_initial.GetScale(picture.Width, picture.Height, m_unitsPerPixel)); else if (e.Button == ZoomInButton) SetTool(Tools.ZoomIn); else if (e.Button == ZoomOutButton) SetTool(Tools.ZoomOut); else if (e.Button == PanButton) SetTool(Tools.Pan); /*else if (e.Button == SelectButton) SetTool(Tools.Select);*/ } private void SetTool(Tools tool) { m_currentTool = tool; } private void picture_Click(object sender, System.EventArgs e) { Point p = picture.PointToClient(Cursor.Position); PointF m = m_current.CalculatePosition(p.X, p.Y, picture.Width, picture.Height); double mapCoordX = m.X; //Cursor.Position.X * (picture.Width); double mapCoordY = m.Y; //Cursor.Position.Y * (picture.Height); double scale = m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel); switch (m_currentTool) { case Tools.ZoomIn: GoToScale(mapCoordX, mapCoordY, scale / 1.5); break; case Tools.ZoomOut: GoToScale(mapCoordX, mapCoordY, scale * 1.5); break; case Tools.Pan: GoToScale(mapCoordX, mapCoordY, scale); break; case Tools.Select: //TODO: Select break; } } private void picture_Resize(object sender, System.EventArgs e) { if (picture.Visible && picture.Enabled && m_current != null) GoToScale(m_current.X, m_current.Y, m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel)); } private void picture_VisibleChanged(object sender, System.EventArgs e) { if (picture.Visible && picture.Enabled && m_current != null) GoToScale(m_current.X, m_current.Y, m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel)); } private void picture_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { Point p = picture.PointToClient(Cursor.Position); PointF m = m_current.CalculatePosition(p.X, p.Y, picture.Width, picture.Height); statusBar.Text = "(" + m.X.ToString("0.0000") + ", " + m.Y.ToString("0.0000") + ")\t 1:" + m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel).ToString("0.0") + "\t (" + m_current.MinX.ToString("0.00") + ", " + m_current.MinY.ToString("0.00") + ") - (" + m_current.MaxX.ToString("0.00") + ", " + m_current.MaxY.ToString("0.00") + ")"; if (e.Button == MouseButtons.Left) { if (m_currentTool == Tools.ZoomIn || m_currentTool == Tools.Select) { } } } private void picture_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { //Code for visually displaying the center, used for debugging /*using(Pen p = new Pen(Color.Black)) { e.Graphics.DrawLine(p, 0, picture.Height / 2, picture.Width, picture.Height / 2); e.Graphics.DrawLine(p, picture.Width / 2, 0, picture.Width / 2, picture.Height); e.Graphics.DrawRectangle(p, 0, 0, picture.Width - 1, picture.Height - 1); }*/ } private void picture_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { if (e.Button == MouseButtons.Left) m_downPoint = picture.PointToClient(Cursor.Position); } private void picture_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { Point p = picture.PointToClient(Cursor.Position); PointF m = m_current.CalculatePosition(p.X, p.Y, picture.Width, picture.Height); double scale = m_current.GetScale(picture.Width, picture.Height, m_unitsPerPixel); bool boxType = Math.Abs(p.X - m_downPoint.X) > 2 || Math.Abs(p.Y - m_downPoint.Y) > 2; PointF m2 = m_current.CalculatePosition(m_downPoint.X, m_downPoint.Y, picture.Width, picture.Height); switch (m_currentTool) { case Tools.ZoomIn: /*if (boxType) { View v = new View(m.X, m.Y, m2.X, m2.Y); GoToScale(v.X, v.Y, v.GetScale(picture.Width, picture.Height, m_unitsPerPixel)); } else*/ GoToScale(m.X, m.Y, scale / 1.5); break; case Tools.ZoomOut: GoToScale(m.X, m.Y, scale * 1.5); break; case Tools.Pan: GoToScale(m.X, m.Y, scale); break; case Tools.Select: //TODO: Select break; } } } }