REBOL [
title: "Generate a gauge with a needle"
]
;; [---------------------------------------------------------------------------]
;; [ This function uses the REBOL layout function to generate a png file ]
;; [ that is a "gauge" graphic to show the amount of free space on a ]
;; [ server disk. One calls the function with three items: ]
;; [ An integer giving the total capacity of the disk. ]
;; [ An integer giving the amount of space used. ]
;; [ A file name for the resulting graphic. ]
;; [ The gauge is a semicircular "fuel gauge" graphic on a black background. ]
;; [ It is in a 200x100 box. The center is at the middle of the bottom edge, ]
;; [ at pixel location 100x100 (from the top left corner). ]
;; [ Naturally, this could be modified for other uses. ]
;; [ The code for the function is a bit plodding, since this was a learning ]
;; [ exercise. ]
;; [---------------------------------------------------------------------------]
;; [---------------------------------------------------------------------------]
;; [ This function calculates the endpoint of an arrow on a gauge. ]
;; [ Then it draws the arrow on a generated gauge in a layout, converts ]
;; [ the image to a png file, and saves it. ]
;; [ The gauge is a semicircle in the middle of a 200x100 box. ]
;; [ The pixel grid in such a box starts at 0x0 in the upper left corner. ]
;; [ The semicircular gauge will be centered at 100x100 in the box, ]
;; [ in other words, along the bottom edge, at the center of the box. ]
;; [ The point we want to calculate is a point on the circumference of the ]
;; [ circle, to which a "needle" on the gauge will point. ]
;; [ THe gauge indicates the amount of free space, with all the way to ]
;; [ the left meaning "empty" or no free space, and all the way to the ]
;; [ right meaning "full" or all free space. ]
;; [ The data provided to this function is NOT the amount of space free, ]
;; [ but the amount of space used. Fortunately, by the nature of the ]
;; [ sine and cosine functions we will be using, if we make a gauge ]
;; [ "needle" showing the amount full, that needle will point all the way ]
;; [ to the right when the amount full is zero, and all the way to the ]
;; [ when the amount full is at its maximum. ]
;; [ Because of that happy coincidence, to get the result we want we ]
;; [ just have to make a needle using the input data we have showing the ]
;; [ amount used, because the needle indicating the amount used will move ]
;; [ from right to left as the amount used increases, which then will show ]
;; [ the amount of free space decreasing. As the amount used decreases, ]
;; [ the needle will move from left to right indicating that the amount ]
;; [ of free space is increaseing. This is the result we want. ]
;; [ Normally this function would be used as part of some automated job ]
;; [ that obtained the total capacity of a disk and the total amount in use. ]
;; [ If your automated procedure produces the amount free instead of the ]
;; [ amount used, you could revise this function, or else you could ]
;; [ subtract the amount free from the total capacity to get the amount ]
;; [ used, and then use this function as it is. Either way should be ]
;; [ a simple change. ]
;; [---------------------------------------------------------------------------]
GEN-GAUGE-FREESPACE: func [
;; Input items:
;; Because of the various scripts that will feed this function,
;; the input items are the total capacity and the amount used.
AMOUNT-FULL ;; From caller, value of full gauge
AMOUNT-USED ;; From caller, amount in use
GAUGE-FILENAME ;; Name of png file we will create
/local
;; Items we calculate:
PERCENT-FULL ;; Percent that amount used is of amount available
ANGLE-USED ;; Angle for percent full (180 * percent)
ENDPOINT-X ;; Endpoint X relative to gauge center
ENDPOINT-Y ;; Endpoint Y relative to gauge center
ARROW-END-X ;; Endpoint X relative to top left corner
ARROW-END-Y ;; Endpoint Y relative to top left corner
] [
;; Procedure:
;; -- What percent is full?
PERCENT-FULL: AMOUNT-USED / AMOUNT-FULL
;; -- Apply percentage to 180 degrees to find out where the needle
;; -- should point. This angle will be all the way to the right for
;; -- zeros, and moving left as the amount used increases.
;; -- This is good, because what we REALLY want the needle to show
;; -- is the amount of free space, with zero being all the way to the
;; -- left and maximum free space being all the way to the right.
ANGLE-USED: to-integer (PERCENT-FULL * 180)
;; -- Find out where the needle should hit the arc.
;; -- We should be able to use the sine and cosine functions because
;; -- we have an angle and a hypotenuse (100 pixels).
;; -- This will work even for an obtuse angle that is pointing to the
;; -- negative side of the Y axis because of the periodic nature of
;; -- the trigonometric function.
ENDPOINT-X: to-integer 100 * cosine ANGLE-USED
ENDPOINT-Y: to-integer 100 * sine ANGLE-USED
;; -- The above calculations are based on a coordinate system that is
;; -- centered at the center of the bottom edge of the box.
;; -- In REBOL, coordinates inside a face start at the top left corner.
;; -- Calculate the REBOL coordinates from the X-Y values we calculated
;; -- above.
;; -- The ENDPOINT-X value will be negative if the needle is pointing
;; -- to the left of the Y axis. Thus the calculation below works
;; -- when the needle is pointing to the left OR to the right of the
;; -- Y axis.
ARROW-END-Y: to-integer 100 - ENDPOINT-Y
ARROW-END-X: to-integer 100 + ENDPOINT-X
;; -- Now make a pair for the draw function.
ARROW-END: as-pair ARROW-END-X ARROW-END-Y
GAUGE-LAYOUT: layout [
across
GAUGE-PICTURE: box 200x100 black effect [
draw [
fill-pen red arc 100x100 100x100 180 20 closed
fill-pen yellow arc 100x100 100x100 200 20 closed
fill-pen green arc 100x100 100x100 220 140 closed
arrow 1x0
line-width 3
pen black
line 100x100 ARROW-END
]
]
]
save/png GAUGE-FILENAME to-image GAUGE-PICTURE
]
;; -- Uncomment to test
;GEN-GAUGE-FREESPACE 100 65 %GAUGE-65PERCENT.png
;GEN-GAUGE-FREESPACE 100 25 %GAUGE-25PERCENT.png
;alert "Done."