#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;
}
}
}
}