Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1265: implemented new render stage concept

File size: 9.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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
84    public Chart(PointD lowerLeft, PointD upperRight) {
85      zoomHistory = new List<Offset>();
86      SetPosition(lowerLeft, upperRight);
87      mySizeInPixels = new Size((int)Size.Width, (int)Size.Height);
88      backgroundColor = Color.White;
89      Scale = 1.0;
90      Group = new Group(this);
91      renderStages = new List<RenderStage> {
92        new BackgroundColorRenderStage(this),
93        new GridRenderStage(this),
94        new GroupRenderStage(this),
95        new EnabledRenderStage(this)
96      };
97      Group.RedrawRequired += GroupOnRedrawRequired;
98      MinimumZoomDistance = 0.01;
99    }
100
101    public Chart(double x1, double y1, double x2, double y2)
102      : this(new PointD(x1, y1), new PointD(x2, y2)) { }
103
104    public PointD TransformPixelToWorld(Point point) {
105      var x = LowerLeft.X + point.X * PixelToWorldRatio.Width;
106      var y = LowerLeft.Y + (SizeInPixels.Height - point.Y) * PixelToWorldRatio.Height;
107      return new PointD(x, y);
108    }
109
110    public SizeD TransformPixelToWorld(Size size) {
111      var width = size.Width * PixelToWorldRatio.Width;
112      var height = size.Height * PixelToWorldRatio.Height;
113      return new SizeD(width, height);
114    }
115
116    public Point TransformWorldToPixel(PointD point) {
117      var x = (int)((point.X - LowerLeft.X) * WorldToPixelRatio.Width);
118      var y = (int)((UpperRight.Y - point.Y) * WorldToPixelRatio.Height);
119      return new Point(x, y);
120    }
121
122    public Size TransformWorldToPixel(SizeD size) {
123      var width = (int)(size.Width * WorldToPixelRatio.Width);
124      var height = (int)(size.Height * WorldToPixelRatio.Height);
125      return new Size(width, height);
126    }
127
128    public virtual void SetPosition(PointD lowerLeft, PointD upperRight) {
129      if ((lowerLeft.X >= upperRight.X) || (lowerLeft.Y >= upperRight.Y))
130        throw new ArgumentException("Lower left point is greater or equal than upper right point");
131
132      originalLowerLeft = lowerLeft;
133      originalUpperRight = upperRight;
134      if (zoomHistory != null) zoomHistory.Clear();
135      myLowerLeft = lowerLeft;
136      myUpperRight = upperRight;
137      OnRedrawRequired();
138    }
139
140    public virtual void Move(Offset delta) {
141      myLowerLeft += delta;
142      myUpperRight += delta;
143      OnRedrawRequired();
144    }
145
146    public virtual void Zoom(Point mousePosition, double delta) {
147      var cursor = TransformPixelToWorld(mousePosition);
148
149      double zoomLevel = (100 + delta) / 100;
150      double width = this.UpperRight.X - this.LowerLeft.X;
151      double height = this.UpperRight.Y - this.LowerLeft.Y;
152      double newWidth = width * zoomLevel;
153      double newHeight = height * zoomLevel;
154      double xAdaption = (UpperRight.X - cursor.X) / width;
155      double yAdaption = (UpperRight.Y - cursor.Y) / height;
156
157      ZoomIn(new PointD(cursor.X - newWidth * (1 - xAdaption), cursor.Y - newHeight * (1 - yAdaption)), new PointD(cursor.X + newWidth * xAdaption, cursor.Y + newHeight * yAdaption));
158      OnRedrawRequired();
159    }
160
161    public virtual void ZoomIn(Point mousePosition) {
162      Zoom(mousePosition, -10);
163    }
164
165    public virtual void ZoomIn(PointD lowerLeft, PointD upperRight) {
166      // maintain a 1:1 ratio between x and y axis
167      var pixels = SizeInPixels;
168      var diagonal = upperRight - lowerLeft;
169      var windowRatio = pixels.Height / (double)pixels.Width;
170      var viewRatio = diagonal.DY / diagonal.DX;
171      if (viewRatio < windowRatio) {
172        var neededHeight = windowRatio * diagonal.DX;
173        var diff = (neededHeight - diagonal.DY) / 2.0;
174        lowerLeft.Y -= diff;
175        upperRight.Y += diff;
176      } else {
177        var neededWidth = diagonal.DY / windowRatio;
178        var diff = (neededWidth - diagonal.DX) / 2.0;
179        lowerLeft.X -= diff;
180        upperRight.X += diff;
181      }
182      if ((lowerLeft - upperRight).Length < MinimumZoomDistance) return;
183      zoomHistory.Insert(0, LowerLeft - lowerLeft);
184      zoomHistory.Insert(0, UpperRight - upperRight);
185      myLowerLeft = lowerLeft;
186      myUpperRight = upperRight;
187      OnRedrawRequired();
188    }
189
190    public virtual void ZoomIn(Point lowerLeft, Point upperRight) {
191      ZoomIn(TransformPixelToWorld(lowerLeft), TransformPixelToWorld(upperRight));
192    }
193
194    public virtual void ZoomOut() {
195      if (zoomHistory.Count > 0) {
196        Offset upperRight = zoomHistory[0];
197        zoomHistory.RemoveAt(0);
198        Offset lowerLeft = zoomHistory[0];
199        zoomHistory.RemoveAt(0);
200        myLowerLeft = LowerLeft + lowerLeft;
201        myUpperRight = UpperRight + upperRight;
202        OnRedrawRequired();
203      } else {
204        var lowerLeft = new PointD(myLowerLeft.X - Size.Width / 4, myLowerLeft.Y - Size.Height / 4);
205        var upperRight = new PointD(myUpperRight.X + Size.Width / 4, myUpperRight.Y + Size.Height / 4);
206        ZoomIn(lowerLeft, upperRight);
207        if (zoomHistory.Count >= 2) {
208          zoomHistory.RemoveRange(0, 2);
209        }
210      }
211    }
212
213    public virtual void Unzoom() {
214      SetPosition(originalLowerLeft, originalUpperRight);
215    }
216
217    public virtual void IntoForeground(IPrimitive primitive) {
218      Group.IntoForeground(primitive);
219    }
220    public virtual void IntoBackground(IPrimitive primitive) {
221      Group.IntoBackground(primitive);
222    }
223    public virtual void OneLayerUp(IPrimitive primitive) {
224      Group.OneLayerUp(primitive);
225    }
226    public virtual void OneLayerDown(IPrimitive primitive) {
227      Group.OneLayerDown(primitive);
228    }
229
230    public virtual Cursor GetCursor(Point point) {
231      return Group.GetCursor(TransformPixelToWorld(point)) ?? Cursors.Default;
232    }
233
234    public virtual string GetToolTipText(Point point) {
235      return Group.GetToolTipText(TransformPixelToWorld(point));
236    }
237
238    public virtual IPrimitive GetPrimitive(Point point) {
239      return Group.GetPrimitive(TransformPixelToWorld(point));
240    }
241
242    public virtual IEnumerable<IPrimitive> GetAllPrimitives(Point point) {
243      return Group.GetAllPrimitives(TransformPixelToWorld(point));
244    }
245
246    public virtual void Render(Graphics graphics, int width, int height) {
247      mySizeInPixels = new Size(width, height);
248      foreach (var renderStage in renderStages)
249        renderStage.Render(graphics);
250    }
251
252    public event EventHandler RedrawRequired;
253    protected virtual void OnRedrawRequired() {
254      if (SuppressRedraw) return;
255      var handler = RedrawRequired;
256      if (handler != null) handler(this, EventArgs.Empty);
257    }
258
259    public void RaiseRedrawRequired() {
260      var handler = RedrawRequired;
261      if (handler != null) handler(this, EventArgs.Empty);
262    }
263
264    private void GroupOnRedrawRequired(object sender, EventArgs e) {
265      OnRedrawRequired();
266    }
267  }
268}
Note: See TracBrowser for help on using the repository browser.