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."