Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Visualization/HeuristicLab.Visualization/3.3/Chart.cs @ 13753

Last change on this file since 13753 was 13753, checked in by jkarder, 8 years ago

#1265: worked on visualization

  • brought back support for SnapToGrid methods
  • updated license headers
File size: 9.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.Windows.Forms;
26
27namespace HeuristicLab.Visualization {
28  public class Chart : IChart {
29    private PointD originalLowerLeft;
30    private PointD originalUpperRight;
31    protected List<Offset> zoomHistory;
32    protected List<RenderStage> renderStages;
33
34    private bool enabled;
35    public bool Enabled {
36      get { return enabled; }
37      set {
38        if (enabled == value) return;
39        enabled = value;
40        OnRedrawRequired();
41      }
42    }
43
44    private Color backgroundColor;
45    public Color BackgroundColor {
46      get { return backgroundColor; }
47      set {
48        if (backgroundColor == value) return;
49        backgroundColor = value;
50        OnRedrawRequired();
51      }
52    }
53
54    protected bool SuppressRedraw { get; set; }
55
56    public bool SuppressEvents { get; set; }
57
58    private PointD myLowerLeft;
59    public virtual PointD LowerLeft {
60      get { return myLowerLeft; }
61    }
62    private PointD myUpperRight;
63    public virtual PointD UpperRight {
64      get { return myUpperRight; }
65    }
66    public virtual SizeD Size {
67      get { return new SizeD(UpperRight.X - LowerLeft.X, UpperRight.Y - LowerLeft.Y); }
68    }
69    private Size mySizeInPixels;
70
71    public Size SizeInPixels {
72      get { return mySizeInPixels; }
73    }
74    public SizeD PixelToWorldRatio {
75      get { return new SizeD(Size.Width / SizeInPixels.Width, Size.Height / SizeInPixels.Height); }
76    }
77    public SizeD WorldToPixelRatio {
78      get { return new SizeD(SizeInPixels.Width / Size.Width, SizeInPixels.Height / Size.Height); }
79    }
80    public double Scale { get; set; }
81    public double MinimumZoomDistance { get; set; }
82    public IGroup Group { get; protected set; }
83    public IGrid Grid { get; protected set; }
84
85    public Chart(PointD lowerLeft, PointD upperRight) {
86      zoomHistory = new List<Offset>();
87      SetPosition(lowerLeft, upperRight);
88      mySizeInPixels = new Size((int)Size.Width, (int)Size.Height);
89      backgroundColor = Color.White;
90      Scale = 1.0;
91      Group = new Group(this);
92      Grid = new Grid(this);
93      renderStages = new List<RenderStage> {
94        new BackgroundColorRenderStage(this),
95        new GridRenderStage(this),
96        new GroupRenderStage(this),
97        new EnabledRenderStage(this)
98      };
99      Group.RedrawRequired += GroupOnRedrawRequired;
100      MinimumZoomDistance = 0.01;
101    }
102
103    public Chart(double x1, double y1, double x2, double y2)
104      : this(new PointD(x1, y1), new PointD(x2, y2)) { }
105
106    public PointD TransformPixelToWorld(Point point) {
107      var x = LowerLeft.X + point.X * PixelToWorldRatio.Width;
108      var y = LowerLeft.Y + (SizeInPixels.Height - point.Y) * PixelToWorldRatio.Height;
109      return new PointD(x, y);
110    }
111
112    public SizeD TransformPixelToWorld(Size size) {
113      var width = size.Width * PixelToWorldRatio.Width;
114      var height = size.Height * PixelToWorldRatio.Height;
115      return new SizeD(width, height);
116    }
117
118    public Point TransformWorldToPixel(PointD point) {
119      var x = (int)((point.X - LowerLeft.X) * WorldToPixelRatio.Width);
120      var y = (int)((UpperRight.Y - point.Y) * WorldToPixelRatio.Height);
121      return new Point(x, y);
122    }
123
124    public Size TransformWorldToPixel(SizeD size) {
125      var width = (int)(size.Width * WorldToPixelRatio.Width);
126      var height = (int)(size.Height * WorldToPixelRatio.Height);
127      return new Size(width, height);
128    }
129
130    public virtual void SetPosition(PointD lowerLeft, PointD upperRight) {
131      if ((lowerLeft.X >= upperRight.X) || (lowerLeft.Y >= upperRight.Y))
132        throw new ArgumentException("Lower left point is greater or equal than upper right point");
133
134      originalLowerLeft = lowerLeft;
135      originalUpperRight = upperRight;
136      if (zoomHistory != null) zoomHistory.Clear();
137      myLowerLeft = lowerLeft;
138      myUpperRight = upperRight;
139      OnRedrawRequired();
140    }
141
142    public virtual void Move(Offset delta) {
143      myLowerLeft += delta;
144      myUpperRight += delta;
145      OnRedrawRequired();
146    }
147
148    public virtual void Zoom(Point mousePosition, double delta) {
149      var cursor = TransformPixelToWorld(mousePosition);
150
151      double zoomLevel = (100 + delta) / 100;
152      double width = this.UpperRight.X - this.LowerLeft.X;
153      double height = this.UpperRight.Y - this.LowerLeft.Y;
154      double newWidth = width * zoomLevel;
155      double newHeight = height * zoomLevel;
156      double xAdaption = (UpperRight.X - cursor.X) / width;
157      double yAdaption = (UpperRight.Y - cursor.Y) / height;
158
159      ZoomIn(new PointD(cursor.X - newWidth * (1 - xAdaption), cursor.Y - newHeight * (1 - yAdaption)), new PointD(cursor.X + newWidth * xAdaption, cursor.Y + newHeight * yAdaption));
160      OnRedrawRequired();
161    }
162
163    public virtual void ZoomIn(Point mousePosition) {
164      Zoom(mousePosition, -10);
165    }
166
167    public virtual void ZoomIn(PointD lowerLeft, PointD upperRight) {
168      // maintain a 1:1 ratio between x and y axis
169      var pixels = SizeInPixels;
170      var diagonal = upperRight - lowerLeft;
171      var windowRatio = pixels.Height / (double)pixels.Width;
172      var viewRatio = diagonal.DY / diagonal.DX;
173      if (viewRatio < windowRatio) {
174        var neededHeight = windowRatio * diagonal.DX;
175        var diff = (neededHeight - diagonal.DY) / 2.0;
176        lowerLeft.Y -= diff;
177        upperRight.Y += diff;
178      } else {
179        var neededWidth = diagonal.DY / windowRatio;
180        var diff = (neededWidth - diagonal.DX) / 2.0;
181        lowerLeft.X -= diff;
182        upperRight.X += diff;
183      }
184      if ((lowerLeft - upperRight).Length < MinimumZoomDistance) return;
185      zoomHistory.Insert(0, LowerLeft - lowerLeft);
186      zoomHistory.Insert(0, UpperRight - upperRight);
187      myLowerLeft = lowerLeft;
188      myUpperRight = upperRight;
189      OnRedrawRequired();
190    }
191
192    public virtual void ZoomIn(Point lowerLeft, Point upperRight) {
193      ZoomIn(TransformPixelToWorld(lowerLeft), TransformPixelToWorld(upperRight));
194    }
195
196    public virtual void ZoomOut() {
197      if (zoomHistory.Count > 0) {
198        Offset upperRight = zoomHistory[0];
199        zoomHistory.RemoveAt(0);
200        Offset lowerLeft = zoomHistory[0];
201        zoomHistory.RemoveAt(0);
202        myLowerLeft = LowerLeft + lowerLeft;
203        myUpperRight = UpperRight + upperRight;
204        OnRedrawRequired();
205      } else {
206        var lowerLeft = new PointD(myLowerLeft.X - Size.Width / 4, myLowerLeft.Y - Size.Height / 4);
207        var upperRight = new PointD(myUpperRight.X + Size.Width / 4, myUpperRight.Y + Size.Height / 4);
208        ZoomIn(lowerLeft, upperRight);
209        if (zoomHistory.Count >= 2) {
210          zoomHistory.RemoveRange(0, 2);
211        }
212      }
213    }
214
215    public virtual void Unzoom() {
216      SetPosition(originalLowerLeft, originalUpperRight);
217    }
218
219    public virtual void IntoForeground(IPrimitive primitive) {
220      Group.IntoForeground(primitive);
221    }
222    public virtual void IntoBackground(IPrimitive primitive) {
223      Group.IntoBackground(primitive);
224    }
225    public virtual void OneLayerUp(IPrimitive primitive) {
226      Group.OneLayerUp(primitive);
227    }
228    public virtual void OneLayerDown(IPrimitive primitive) {
229      Group.OneLayerDown(primitive);
230    }
231
232    public virtual Cursor GetCursor(Point point) {
233      return Group.GetCursor(TransformPixelToWorld(point)) ?? Cursors.Default;
234    }
235
236    public virtual string GetToolTipText(Point point) {
237      return Group.GetToolTipText(TransformPixelToWorld(point));
238    }
239
240    public virtual IPrimitive GetPrimitive(Point point) {
241      return Group.GetPrimitive(TransformPixelToWorld(point));
242    }
243
244    public virtual IEnumerable<IPrimitive> GetAllPrimitives(Point point) {
245      return Group.GetAllPrimitives(TransformPixelToWorld(point));
246    }
247
248    public virtual void Render(Graphics graphics, int width, int height) {
249      mySizeInPixels = new Size(width, height);
250      foreach (var renderStage in renderStages)
251        renderStage.Render(graphics);
252    }
253
254    public event EventHandler RedrawRequired;
255    protected virtual void OnRedrawRequired() {
256      if (SuppressRedraw) return;
257      var handler = RedrawRequired;
258      if (handler != null) handler(this, EventArgs.Empty);
259    }
260
261    public void RaiseRedrawRequired() {
262      var handler = RedrawRequired;
263      if (handler != null) handler(this, EventArgs.Empty);
264    }
265
266    private void GroupOnRedrawRequired(object sender, EventArgs e) {
267      OnRedrawRequired();
268    }
269  }
270}
Note: See TracBrowser for help on using the repository browser.