#region License Information /* HeuristicLab * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Drawing; namespace HeuristicLab.Visualization { public class Grid : PrimitiveBase, IGrid { protected const int CellSpacing = 10; public virtual PointD Origin { get; set; } public virtual double XPrecision { get; set; } public virtual double YPrecision { get; set; } public virtual PointD GetBottomLeftGridPoint(PointD point) { var nx = (int)Math.Floor((point.X - Origin.X) / XPrecision); var ny = (int)Math.Floor((point.Y - Origin.Y) / YPrecision); return new PointD(Origin.X + nx * XPrecision, Origin.Y + ny * YPrecision); } public virtual PointD GetUpperRightGridPoint(PointD point) { var nx = (int)Math.Ceiling((point.X - Origin.X) / XPrecision); var ny = (int)Math.Ceiling((point.Y - Origin.Y) / YPrecision); return new PointD(Origin.X + nx * XPrecision, Origin.Y + ny * YPrecision); } public virtual PointD GetNearestGridPoint(PointD point) { var bl = GetBottomLeftGridPoint(point); var ur = GetUpperRightGridPoint(point); return new PointD( Math.Abs(bl.X - point.X) <= Math.Abs(ur.X - point.X) ? bl.X : ur.X, Math.Abs(bl.Y - point.Y) <= Math.Abs(ur.Y - point.Y) ? bl.Y : ur.Y); } public Grid(IChart chart) : this(chart, 1.0) { } public Grid(IChart chart, double precision) : base(chart) { Origin = new PointD(0, 0); XPrecision = precision; YPrecision = precision; } public override bool ContainsPoint(PointD point) { return false; } public override void Move(Offset delta) { } public override void Move(PointD point, Offset delta) { } public override void SnapToGrid(IGrid grid) { } public override void SnapToGrid(PointD point, IGrid grid) { } public override void Draw(Graphics graphics) { if (!(Chart.Size.Width > 0) || !(Chart.Size.Height > 0)) return; graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; var pen = new Pen(Color.LightGray, 1.0f); var pixelSize = Chart.TransformWorldToPixel(Chart.Size); // size of the drawing area in pixel coordinates var numberOfXParallelLines = (int)Math.Floor(pixelSize.Height / (double)CellSpacing); // how many x parallel lines can be drawn var numberOfYParallelLines = (int)Math.Floor(pixelSize.Width / (double)CellSpacing); // how many y parallel lines can be drawn if (numberOfXParallelLines <= 0 || numberOfYParallelLines <= 0) return; var cellWorldSize = new SizeD(Chart.Size.Width / numberOfYParallelLines, Chart.Size.Height / numberOfXParallelLines); // the cellSize in world coordinates cellWorldSize.Width = Math.Pow(10, Math.Floor(Math.Log10(cellWorldSize.Width))); cellWorldSize.Height = Math.Pow(10, Math.Floor(Math.Log10(cellWorldSize.Width))); var cellPixelSize = Chart.TransformWorldToPixel(cellWorldSize); while (cellPixelSize.Width < 25 || cellPixelSize.Height < 25) { if (cellPixelSize.Width < 25) cellWorldSize.Width *= 2; if (cellPixelSize.Height < 25) cellWorldSize.Height *= 2; cellPixelSize = Chart.TransformWorldToPixel(cellWorldSize); if (cellPixelSize.Width < 25) cellWorldSize.Width *= 2.5; if (cellPixelSize.Height < 25) cellWorldSize.Height *= 2.5; cellPixelSize = Chart.TransformWorldToPixel(cellWorldSize); } var firstX = Math.Floor(Chart.LowerLeft.X / cellWorldSize.Width) * cellWorldSize.Width; var firstY = Math.Floor(Chart.LowerLeft.Y / cellWorldSize.Height) * cellWorldSize.Height; double x = firstX, y = firstY; var axisyLabel = new Font(FontFamily.GenericMonospace, 7.0f, FontStyle.Regular, GraphicsUnit.Point, 0); var axisxLabel = new Font(FontFamily.GenericMonospace, 7.0f, FontStyle.Regular, GraphicsUnit.Point, 0, true); var axisDrawing = new SolidBrush(Color.DarkGray); try { var bottom = Chart.TransformWorldToPixel(Chart.Size).Height; while (x <= Chart.LowerLeft.X + Chart.Size.Width) { var start = Chart.TransformWorldToPixel(new PointD(x, firstY)); var end = Chart.TransformWorldToPixel(new PointD(x, Chart.LowerLeft.Y + Chart.Size.Height)); graphics.DrawLine(pen, start, end); var axis = x.ToString("0.##"); double stringwidth = graphics.MeasureString(axis, axisyLabel).Width; graphics.DrawString(axis, axisyLabel, axisDrawing, end.X - (int)(stringwidth / 2.0), bottom - 15); x += cellWorldSize.Width; } while (y <= Chart.LowerLeft.Y + Chart.Size.Height) { var start = Chart.TransformWorldToPixel(new PointD(firstX, y)); var end = Chart.TransformWorldToPixel(new PointD(Chart.LowerLeft.X + Chart.Size.Width, y)); graphics.DrawLine(pen, start, end); graphics.DrawString(y.ToString("0.##"), axisxLabel, axisDrawing, 0, start.Y); y += cellWorldSize.Height; } } finally { axisDrawing.Dispose(); axisxLabel.Dispose(); axisyLabel.Dispose(); } } } }