]> gitweb.factorcode.org Git - factor.git/blob - extra/ui/gadgets/charts/lines/lines-docs.factor
bde78cc9ee9e16ce603fc629bb1fd9d0a53bddd8
[factor.git] / extra / ui / gadgets / charts / lines / lines-docs.factor
1 ! Copyright (C) 2017 Alexander Ilin.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: binary-search colors help.markup help.syntax kernel
4 sequences splitting.monotonic ui.gadgets ui.gadgets.charts
5 ui.gadgets.charts.lines.private ui.render ;
6 IN: ui.gadgets.charts.lines
7
8 ABOUT: { "ui.gadgets.charts.lines" "about" }
9
10 ARTICLE: { "ui.gadgets.charts.lines" "about" } "Lines"
11 " The " { $vocab-link "ui.gadgets.charts.lines" } " vocab implements the " { $link line } " gadget. See the " { $link { "charts.lines" "implementation" } } "." ;
12
13 ARTICLE: { "charts.lines" "implementation" } "Implementation details"
14 "The " { $slot "data" } " in a " { $link line } " gadget should be sorted by non-descending " { $snippet "x" } " coordinate. In a large data set this allows to quickly find the left and right intersection points with the viewport using binary " { $link search } " and remove the irrelevant data from further processing: " { $link clip-by-x } ". If the resulting sequence is empty (i.e. the entire data set is completely to the left or to the right of the viewport), nothing is drawn (" { $link x-in-bounds? } ")."
15 $nl
16 "If there are several points with the same " { $snippet "x" } " coordinate matching " { $snippet "xmin" } ", the leftmost of those is found and included in the resulting set (" { $link adjusted-head-slice } "). The same adjustment is done for the right point if it matches " { $snippet "xmax" } ", only this time the rightmost is searched for (" { $link adjusted-tail-slice } ")."
17 $nl
18 "If there are no points with either the " { $snippet "xmin" } " or the " { $snippet "xmax" } " coordinate, and the line spans beyond the viewport in either of those directions, the corresponding points are calculated and added to the data set (" { $link min-max-cut } ")."
19 $nl
20 "After we've got a subset of data that's completely within the " { $snippet "[xmin,xmax]" } " bounds, we check if the resulting data are completely above or completely below the viewport (" { $link y-in-bounds? } "), and if so, nothing is drawn. This involves finding the minimum and maximum " { $snippet "y" } " values by traversing the remaining data, which is why it's important to cut away the irrelevant data first and to make sure the " { $snippet "y" } " coordinates for the points at " { $snippet "xmin" } " and " { $snippet "xmax" } " are in the data set. All of the above is done by " { $link clip-data } "."
21 $nl
22 "At this point either the data set is empty, or there is at least some intersection between the data and the viewport. The task of the next step is to produce a sequence of lines that can be drawn on the viewport. The " { $link drawable-chunks } " word cuts away all the data outside the viewport, adding the intersection points where necessary. It does so by first grouping the data points into subsequences (chunks), in which all points are either above, below or within the " { $snippet "[ymin,ymax]" } " limits (" { $link monotonic-split-slice } " using " { $link between<=> } ")."
23 $nl
24 "Those chunks are then examined pairwise by " { $link (drawable-chunks) } " and edge points are calculated and added where necessary by " { $link (make-pair) } ". For example, if a chunk is within the viewport, and the next one is above the viewport, then a point should be added to the end of the first chunk, connecting its last point to the point of the viewport boundary intersection (" { $link fix-left-chunk } ", and " { $link fix-right-chunk } " for the opposite case). If a chunk is below the viewport, and the next one is above the viewport (or vice versa), then a new 2-point chunk should be created so that the intersecting line would be drawn within the viewport boundaries (" { $link 2-point-chunk } ")."
25 $nl
26 "The data are now filtered down to contain only the subset that is relevant to the currently chosen visible range, and is split into chunks that can each be drawn in a single contuguous stroke."
27 $nl
28 "Since the display uses inverted coordinate system, with " { $snippet "y" } " = 0 at the top of the screen, and growing downwards, we need to flip the data along the horizontal center line (" { $link flip-y-axis } ")."
29 $nl
30 "Finally, the data needs to be scaled so that its coordinates are mapped to the screen coordinates (" { $link scale-chunks } "). This last step could probably be combined with flipping the " { $snippet "y" } " coordinate for extra performance."
31 $nl
32 "The resulting chunks are displayed with a call to " { $link draw-line } " each."
33 ;
34
35 HELP: clip-data
36 { $values
37     { "bounds" "{ { xmin xmax } { ymin ymax } }" }
38     { "data" { $link sequence } " of { x y } pairs sorted by non-descending x" }
39     { "data'" "possibly empty subsequence of " { $snippet "data" } }
40 }
41 { $description "Filter the " { $snippet "data" } " by first removing all points outside the " { $snippet "[xmin,xmax]" } " range, and then making sure that the remaining " { $snippet "y" } " values are not entirely above or below the " { $snippet "[ymin,ymax]" } " range." } ;
42
43 HELP: draw-line
44 { $values
45     { "seq" { $link sequence } " of { x y } pairs, in pixels" }
46 }
47 { $description "Draw a sequence of straight line segments connecting all consecutive points with a single OpenGL call. Intended to be called by a " { $link draw-gadget* } " implementation." } ;
48
49 HELP: line
50 { $class-description "This is a " { $link gadget } " which, when added as a child to the " { $link chart } ", will display its data as straight line segments. The implementation is oriented towards speed to allow large data sets to be displayed as quickly as possible."
51 $nl
52 "Slots:"
53 { $list
54     { { $slot "data" } " - a " { $link sequence } " of { x y } pairs sorted by non-descending x;" }
55     { { $slot "data" } " - a " { $link color } " to draw the line with." }
56 } } ;
57
58 HELP: y-at
59 { $description "Given two points on a straight line and an " { $snippet "x" } " coordinate, calculate the " { $snippet "y" } " coordinate at " { $snippet "x" } " on that line." }
60 { $values
61     { "x" object }
62     { "point1" object }
63     { "point2" object }
64     { "y" object }
65 }
66 { $examples
67     { $example
68         "USING: ui.gadgets.charts.lines.private prettyprint ;"
69         "0 { 1 1 } { 5 5 } y-at ."
70         "0"
71     }
72     { $example
73         "USING: ui.gadgets.charts.lines.private prettyprint ;"
74         "3 { 0 5 } { 5 5 } y-at ."
75         "5"
76     }
77     { $example
78         "USING: ui.gadgets.charts.lines.private prettyprint ;"
79         "12 { 12 50 } { 15 15 } y-at ."
80         "50"
81     }
82 } ;
83
84 HELP: calc-x
85 { $description "Given the " { $snippet "slope" } " of a line and a random " { $snippet "point" } " belonging to that line, calculate the " { $snippet "x" } " coordinate corresponding to the given " { $snippet "y" } "." }
86 { $values
87     { "slope" object }
88     { "y" object }
89     { "point" object }
90     { "x" object }
91 }
92 { $examples
93     { $example
94         "USING: ui.gadgets.charts.lines.private prettyprint ;"
95         "1 5 { 1 1 } calc-x ."
96         "5"
97     }
98     { $example
99         "USING: ui.gadgets.charts.lines.private prettyprint ;"
100         "0.5 10 { 0 0 } calc-x ."
101         "20.0"
102     }
103 } ;
104
105 HELP: calc-y
106 { $description "Given the " { $snippet "slope" } " of a line and a random " { $snippet "point" } " belonging to that line, calculate the " { $snippet "y" } " coordinate corresponding to the given " { $snippet "x" } "." }
107 { $values
108     { "slope" object }
109     { "x" object }
110     { "point" object }
111     { "y" object }
112 }
113 { $examples
114     { $example
115         "USING: ui.gadgets.charts.lines.private prettyprint ;"
116         "1 5 { 1 1 } calc-y ."
117         "5"
118     }
119     { $example
120         "USING: ui.gadgets.charts.lines.private prettyprint ;"
121         "0.5 20 { 0 0 } calc-y ."
122         "10.0"
123     }
124 } ;
125
126 HELP: calc-line-slope
127 { $description "Given the two points belonging to a straight line, calculate the " { $snippet "slope" } " of the line, assuming the line equation is " { $snippet "y(x) = slope * x + b" } "."
128 { $values
129     { "point1" object }
130     { "point2" object }
131     { "slope" object }
132 }
133 $nl
134 "The formula for the calculation is " { $snippet "slope = (y1-y2) / (x1-x2)" } ", therefore it'll throw a division by zero error if both points have the same " { $snippet "x" } " coordinate." }
135 { $examples
136     { $example
137         "USING: ui.gadgets.charts.lines.private prettyprint ;"
138         "{ 1 1 } { 10 10 } calc-line-slope ."
139         "1"
140     }
141     { $example
142         "USING: ui.gadgets.charts.lines.private prettyprint ;"
143         "{ 0 0 } { 10 20 } calc-line-slope ."
144         "2"
145     }
146 } ;
147
148 { calc-line-slope y-at calc-x calc-y } related-words