1 /* 2 ------------------------------------------------------------------- 3 4 Copyright (C) 2014, Edwin van Leeuwen 5 6 This file is part of plotd plotting library. 7 8 Plotd is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 Plotd is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Plotd. If not, see <http://www.gnu.org/licenses/>. 20 21 ------------------------------------------------------------------- 22 */ 23 24 /** 25 High level interface to the plotting library 26 */ 27 module plotd.plot; 28 29 import std.conv; 30 import std.range; 31 32 import plotd.drawing; 33 import plotd.primitives; 34 35 version (assert) { 36 import std.stdio : writeln; 37 } 38 39 /// Draw function on our plot 40 CONTEXT drawFunction(CONTEXT)( double delegate(double) func, 41 Bounds bounds, CONTEXT context ) { 42 auto points = iota( bounds.min_x, bounds.max_x, 43 bounds.width/100.0 ) 44 .map!( a => Point( a, func( a ) ) ); 45 46 auto from = points[0]; 47 foreach( to; points[1..$] ) { 48 context = drawLine( from, to, context ); 49 from = to; 50 } 51 return context; 52 } 53 54 /// Class that holds all state to do with one figure 55 class PlotState { 56 Bounds plotBounds = Bounds( 0, 1, 0, 1 ); 57 Bounds marginBounds = Bounds( 70, 400, 70, 400 ); 58 59 cairo.Surface surface; 60 cairo.Context axesContext; 61 cairo.Context plotContext; 62 } 63 64 /// Instantiate a new plot 65 PlotState createPlotState( Bounds plotBounds, Bounds marginBounds ) { 66 auto plot = new PlotState; 67 plot.plotBounds = plotBounds; 68 plot.marginBounds = marginBounds; 69 70 plot.surface = createPlotSurface( plot.marginBounds.max_x.to!int, 71 plot.marginBounds.max_y.to!int ); 72 73 // setup axes 74 plot.axesContext = axesContextFromSurface( plot.surface, 75 plot.plotBounds, plot.marginBounds ); 76 77 plot.axesContext = drawAxes( plot.plotBounds, plot.axesContext ); 78 79 plot.plotContext = plotContextFromSurface( plot.surface, 80 plot.plotBounds, plot.marginBounds ); 81 82 return plot; 83 } 84 85 /// Draw a range of points as a line 86 void drawRange(RANGE)( RANGE range, PlotState plot ) { 87 if (!range.empty) { 88 auto firstPoint = range.front; 89 range.popFront; 90 while (!range.empty) { 91 auto nextPoint = range.front; 92 range.popFront; 93 plot.plotContext = 94 drawLine( firstPoint, nextPoint, plot.plotContext ); 95 firstPoint = nextPoint; 96 } 97 } 98 } 99 100 /// Draw function on our plot 101 void drawFunction(CONTEXT)( double delegate(double) func, 102 PlotState plot ) { 103 iota( plot.plotBounds.min_x, plot.plotBounds.max_x, 104 plot.plotBounds.width/100.0 ) 105 .map!( a => Point( a, func( a ) ) ).drawRange( plot ); 106 } 107 108 /// Draw point on the plot 109 void draw( Point point, PlotState plot ) { 110 plot.plotContext = drawPoint( point, plot.plotContext ); 111 } 112 113 /// Save plot to a file 114 void save( PlotState plot, string name = "example.png" ) { 115 (cast(cairo.ImageSurface)( plot.surface )).writeToPNG( name ); 116 }