Ammend merge: Fix examples and tests
[shapes.git] / examples / doc / remainders.shape
blob394a6928f3d620d8db9ef157d90dd3a670e02d24
1 /** This file is part of Shapes.
2  **
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
6  ** any later version.
7  **
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.
12  **
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/>.
15  **
16  ** Copyright 2015 Henrik Tidefelt
17  **/
19 ##needs ..Shapes..Layout / shiftoff
21 ##lookin ..Shapes
22 ##lookin ..Shapes..Traits
23 ##lookin ..Shapes..Geometry
24 ##lookin ..Shapes..Graphics
25 ##lookin ..Shapes..Numeric..Math
27 ##unit u = 5mm
29 den: '3
30 xMin: '~8
31 xMax: '8
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 →
40     Traits..@width:0.3bp
41   & Text..@size:8bp
42   |
43   {
44     [Graphics..stroke (dataMin,0u)--(dataMax,0u) head:axisHead]
45     &
46     [[Data..range begin:[Numeric..Math..ceil dataMin/1u] end:[Numeric..Math..floor dataMax/1u]].foldl
47         \ p e →
48         {
49           x: e * 1u
50           p
51           &
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)]
55           ]
56         }
57         null
58       ]
60   }
64 yAxis: \ dataMin dataMax →
66     Traits..@width:0.3bp
67   & Text..@size:8bp
68   |
69   {
70     [Graphics..stroke (0u,dataMin)--(0u,dataMax) head:axisHead]
71     &
72     [[Data..range begin:[Numeric..Math..ceil dataMin/1u] end:[Numeric..Math..floor dataMax/1u]].foldl
73         \ p e →
74         {
75           y: e * 1u
76           p
77           &
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)]
81           ]
82         }
83         null
84       ]
86   }
90 remainderPlot: \ fun den →
92   aden: [abs den]
93   floatPath:
94     Traits..@width:0.5bp
95     |
96     {
97       [[Data..range begin:(xMin/aden - '1) end:(xMax/aden)].foldl
98         \ p e →
99         {
100           x1: e * aden * 1u
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.
104            **/
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)]
108         }
109         null
110       ]
111     }
112   intMarks: [[Data..range begin:xMin end:(xMax + '1)].foldl
113     \ p e →
114     {
115       x: e
116       y: [fun x den]
117       p & [[shift (x*1u,y*1u)] intMark]
118     }
119     null
120   ]
121   holeMarks: [[Data..range begin:xMin end:(xMax + '1)].foldl
122     \ p e →
123     {
124       x: e * 1.0
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.
127        **/
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]]
131       [Control..cond
132         [Data..cons y1 ≠ y0 p & [[shift (x*1u,y1*1u)] holeMark]]
133         [Data..cons y2 ≠ y0 p & [[shift (x*1u,y2*1u)] holeMark]]
134         [Data..cons true p]
135       ]
136     }
137     null
138   ]
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
143   •plot: newGroup
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
149   |
150   {
151     •plot << [[shift (0,viewYMax)] [Layout..shiftoff_wlm (Text..newText << (String..newString << [Debug..sourceof fun] << ` ´ << den*1.0)) Layout..to_top]]
152   }
153   plot: freeze •plot
154   [Layout..enlarge_bleedbox plot (2mm,2mm)]
158 remainderPlotPair: \ fun →
159   [[shift (~10u,0)] [remainderPlot fun den]]
160   &
161   [[shift (10u,0)] [remainderPlot fun ~den]]
163 yPlotStep: 12u
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)]