1 /** This file is part of Shapes.
3 ** Shapes is free software: you can redistribute it and/or modify
4 ** it under the terms of the GNU General Public License as published by
5 ** the Free Software Foundation, either version 3 of the License, or
8 ** Shapes is distributed in the hope that it will be useful,
9 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ** GNU General Public License for more details.
13 ** You should have received a copy of the GNU General Public License
14 ** along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 ** Copyright 2015 Henrik Tidefelt
19 ##needs ..Shapes..Layout / shiftoff
22 ##lookin ..Shapes..Traits
23 ##lookin ..Shapes..Geometry
24 ##lookin ..Shapes..Graphics
25 ##lookin ..Shapes..Numeric..Math
33 intMark: [Graphics..fill [circle 3bp]]
34 holeMark: Traits..@width:0.1bp & Traits..@nonstroking:BW..WHITE | [Graphics..fillstroke [circle 2bp]]
36 axisHead: [ShapesArrow width:5bp ...]
38 xAxis: \ dataMin dataMax →
44 [Graphics..stroke (dataMin,0u)--(dataMax,0u) head:axisHead]
46 [[Data..range begin:[Numeric..Math..ceil dataMin/1u] end:[Numeric..Math..floor dataMax/1u]].foldl
52 [if e ≠ '0 and [modulo e den] = '0
53 [Graphics..stroke (x,0)--(x,~5bp)] & [[shift (x,~5bp)] [Layout..shiftoff_wlm (Text..newText << (String..newString << x/1u)) Layout..to_bot]]
54 [Graphics..stroke (x,0)--(x,~3bp)]
64 yAxis: \ dataMin dataMax →
70 [Graphics..stroke (0u,dataMin)--(0u,dataMax) head:axisHead]
72 [[Data..range begin:[Numeric..Math..ceil dataMin/1u] end:[Numeric..Math..floor dataMax/1u]].foldl
78 [if e ≠ '0 and [modulo e den] = '0
79 [Graphics..stroke (0,y)--(~5bp,y)] & [[shift (~5bp,y)] [Layout..shiftoff_wlm (Text..newText << (String..newString << y/1u)) Layout..to_lft]]
80 [Graphics..stroke (0,y)--(~3bp,y)]
90 remainderPlot: \ fun den →
97 [[Data..range begin:(xMin/aden - '1) end:(xMax/aden)].foldl
101 x2: (e + '1) * aden * 1u
102 /** To get the corrent limit in all cases, we use the fact that the limit will always be an integer,
103 ** so an approximation is first computed in the interior of the segment, and then rounded.
105 y1: [Numeric..Math..round [fun (x1/1u + 0.1) den*1.0]] * 1u
106 y2: [Numeric..Math..round [fun (x2/1u - 0.1) den*1.0]] * 1u
107 p & [Graphics..stroke (x1,y1)--(x2,y2)]
112 intMarks: [[Data..range begin:xMin end:(xMax + '1)].foldl
117 p & [[shift (x*1u,y*1u)] intMark]
121 holeMarks: [[Data..range begin:xMin end:(xMax + '1)].foldl
125 /** Using rounding to get the left and right limits, and also rounding the value at x,
126 ** the logic is simplified since we can use integer equality testing.
128 y0: [Numeric..Math..round [fun x den*1.0]]
129 y1: [Numeric..Math..round [fun (x + 0.1) den*1.0]]
130 y2: [Numeric..Math..round [fun (x - 0.1) den*1.0]]
132 [Data..cons y1 ≠ y0 p & [[shift (x*1u,y1*1u)] holeMark]]
133 [Data..cons y2 ≠ y0 p & [[shift (x*1u,y2*1u)] holeMark]]
139 viewXMin: (xMin*1.0-0.7)*1u
140 viewXMax: (xMax*1.0+0.7)*1u
141 viewYMin: ~(aden*1.0+1.7)*1u
142 viewYMax: (aden*1.0+1.7)*1u
144 •plot << [xAxis viewXMin viewXMax]
145 •plot << [yAxis viewYMin viewYMax]
146 data: floatPath & intMarks & holeMarks
147 •plot << [Graphics..clip data [Geometry..rectangle (viewXMin,viewYMin) (viewXMax,viewYMax)]]
148 Text..@font:Text..Font..COURIER
151 •plot << [[shift (0,viewYMax)] [Layout..shiftoff_wlm (Text..newText << (String..newString << [Debug..sourceof fun] << ` ´ << den*1.0)) Layout..to_top]]
154 [Layout..enlarge_bleedbox plot (2mm,2mm)]
158 remainderPlotPair: \ fun →
159 [[shift (~10u,0)] [remainderPlot fun den]]
161 [[shift (10u,0)] [remainderPlot fun ~den]]
164 IO..•page << [remainderPlotPair [Debug..locate modulo]] >> [shift (0,~0*yPlotStep)]
165 IO..•page << [remainderPlotPair [Debug..locate mod]] >> [shift (0,~1*yPlotStep)]
166 IO..•page << [remainderPlotPair [Debug..locate rem]] >> [shift (0,~2*yPlotStep)]