|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Object common:Generic common:Transform common:UtilityTransform common:Handles
class
Handles utility transform class.
This is a utility transform used to display "handles". Handles are visual aids that show where important points that influence a formula are located within an image. Provided you have defined the handle data, it will return a solid flag for each transformed point. It is up to your code to decide what to do with that information. As an example, in a transform you might toggle the state of the #solid flag based on the handle rendering result; in a coloring formula, you might use #solid or you might use a specific color.
This class provides three types of visual aids. First are the handles themselves; these are located at a specific point, and can be a box, a circle, a diamond, an X, a point with an arrow, or a point with a double arrow. Each handle may also be labeled with a number (integer), a combination of letters and numbers (up to five), or an 8x8 pixel icon. Handles may also be rotated to arbitrary angles (especially useful for arrows). See SetHandlePoint() for more information.
The second type of visual aid are lines. Often these lines are used to connect handle points together, but there is absolutely no requirement that this be done; handle lines can be constructed anywhere a formula needs. Lines may be solid, dotted, short dashed, or long dashed. See SetHandleLine() for more information.
The third type of visual aid are circles. Circles may be placed anywhere and be of any size; as with lines, they may be solid, dotted, short dashed, or long dashed. Note that circles will always be circles, even if the aspect ratio of the fractal image is not 1:1.
Handles are intended as visual aids for the creation of fractal images, not as part of the final created image. For this reason, the default settings for the Handles class will automatically disable handle rendering for any rendered image. Also, handle sizes are always measured in pixels, which means when the image size shrinks (as it does for previews) the handles do not shrink. This makes them too large for most uses of the preview window, so the default settings for Handles disables them on preview images as well. The user can override these settings if they choose to.
To use the Handles class, create a Handles parameter for
your formula. (You probably do not want it to be selectable.)
Then, call SetHandleCount() to indicate the number of points,
lines, and circles you will use. Call SetHandlePoint(),
SetHandleLine(), and SetHandleCircle() for each element.
Then, while processing, use Init() to set up each pixel and
Iterate() to compute the handle solid flag value. Use
IsSolid() to test the result of the handle rendering.
class Handles(UtilityTransform) { ; Handles utility transform class. ; <p> ; This is a utility transform used to display "handles". ; Handles are visual aids that show where important points ; that influence a formula are located within an image. ; Provided you have defined the handle data, it will return a ; solid flag for each transformed point. It is up to your ; code to decide what to do with that information. As an ; example, in a transform you might toggle the state of the ; #solid flag based on the handle rendering result; in a ; coloring formula, you might use #solid or you might use ; a specific color. ; <p> ; This class provides three types of visual aids. First are ; the handles themselves; these are located at a specific ; point, and can be a box, a circle, a diamond, an X, a ; point with an arrow, or a point with a double arrow. Each ; handle may also be labeled with a number (integer), a ; combination of letters and numbers (up to five), or an ; 8x8 pixel icon. Handles may also be rotated to arbitrary ; angles (especially useful for arrows). See SetHandlePoint() ; for more information. ; <p> ; The second type of visual aid are lines. Often these lines ; are used to connect handle points together, but there is ; absolutely no requirement that this be done; handle lines ; can be constructed anywhere a formula needs. Lines may ; be solid, dotted, short dashed, or long dashed. See ; SetHandleLine() for more information. ; <p> ; The third type of visual aid are circles. Circles may be ; placed anywhere and be of any size; as with lines, they ; may be solid, dotted, short dashed, or long dashed. Note ; that circles will always be circles, even if the aspect ; ratio of the fractal image is not 1:1. ; <p> ; Handles are intended as visual aids for the creation of ; fractal images, not as part of the final created image. ; For this reason, the default settings for the Handles ; class will automatically disable handle rendering for ; any rendered image. Also, handle sizes are always measured ; in pixels, which means when the image size shrinks (as it ; does for previews) the handles do not shrink. This makes ; them too large for most uses of the preview window, so ; the default settings for Handles disables them on preview ; images as well. The user can override these settings if ; they choose to. ; <p> ; To use the Handles class, create a Handles parameter for ; your formula. (You probably do not want it to be selectable.) ; Then, call SetHandleCount() to indicate the number of points, ; lines, and circles you will use. Call SetHandlePoint(), ; SetHandleLine(), and SetHandleCircle() for each element. ; Then, while processing, use Init() to set up each pixel and ; Iterate() to compute the handle solid flag value. Use ; IsSolid() to test the result of the handle rendering. public: ; Constructor ; ; @param pparent a reference to the object creating the new object; typically, 'this' func Handles(Generic pparent) UtilityTransform.UtilityTransform(pparent) ; pixel coordinate transform m_PixelCoordinate = new PixelCoordinate(pparent) ; digit/letter bitmaps m_DigitsDetail[0] = (409387979.0,3552798232.0) ; 0 m_DigitsDetail[1] = (406329368.0,404232252.0) ; 1 m_DigitsDetail[2] = (1011221251.0,102261247.0) ; 2 m_DigitsDetail[3] = (1011221262.0,50546236.0) ; 3 m_DigitsDetail[4] = (271605860.0,3439266828.0) ; 4 m_DigitsDetail[5] = (2126576646.0,50562684.0) ; 5 m_DigitsDetail[6] = (476110054.0,3284362812.0) ; 6 m_DigitsDetail[7] = (4270197772.0,202905624.0) ; 7 m_DigitsDetail[8] = (1013335612.0,1656972860.0) ; 8 m_DigitsDetail[9] = (1013367747.0,1731921464.0) ; 9 m_DigitsDetail[10] = (0.0,0.0) ; blank m_DigitsDetail[11] = (404237356.0,1182696323.0) ; A m_DigitsDetail[12] = (4240885500.0,3334719228.0) ; B m_DigitsDetail[13] = (1013170368.0,3233833788.0) ; C m_DigitsDetail[14] = (4173775811.0,3284387576.0) ; D m_DigitsDetail[15] = (4274045176.0,3233857791.0) ; E m_DigitsDetail[16] = (4290822392.0,3233857728.0) ; F m_DigitsDetail[17] = (1013170383.0,3284362044.0) ; G m_DigitsDetail[18] = (3284386815.0,3284386755.0) ; H m_DigitsDetail[19] = (1008211992.0,404232252.0) ; I m_DigitsDetail[20] = (252052998.0,101092472.0) ; J m_DigitsDetail[21] = (3335313648.0,3637298883.0) ; K m_DigitsDetail[22] = (3233857728.0,3233858047.0) ; L m_DigitsDetail[23] = (2177099775.0,3687039939.0) ; M m_DigitsDetail[24] = (2210653171.0,3687827395.0) ; N m_DigitsDetail[25] = (1013367747.0,3284362812.0) ; O m_DigitsDetail[26] = (4240884678.0,4240490688.0) ; P m_DigitsDetail[27] = (1013367747.0,3553322555.0) ; Q m_DigitsDetail[28] = (4240884678.0,4241278659.0) ; R m_DigitsDetail[29] = (1013080124.0,100894332.0) ; S m_DigitsDetail[30] = (4279769112.0,404232252.0) ; T m_DigitsDetail[31] = (3284386755.0,3284362812.0) ; U m_DigitsDetail[32] = (2206418502.0,741087256.0) ; V m_DigitsDetail[33] = (2206434118.0,1448487980.0) ; W m_DigitsDetail[34] = (2210819128.0,946652867.0) ; X m_DigitsDetail[35] = (3284362812.0,404232216.0) ; Y m_DigitsDetail[36] = (4286975000.0,405823999.0) ; Z m_DigitsDetail[37] = (417038043.0,402653184.0) ; * m_DigitsDetail[38] = (101059596.0,404238384.0) ; / m_DigitsDetail[39] = (0.0,6168.0) ; . endfunc ; Compute handle state for a single point within a sequence ; <p> ; Handles is a Transform, so to test the handle state for ; a particular point, the standard approach is to Init(), ; Iterate() (just once), and then test IsSolid(). ; ; @param pz the complex value to test ; @return the same complex value (Handles is a transform but the value is in the solid test; the complex value is not transformed) complex func Iterate(complex pz) UtilityTransform.Iterate(pz) float sx float sy float vx float vy float dx float dy bool nolines = false ; note that we completely ignore pz; handles are NOT transformed along with ; the underlying image ; if handles are turned off, stop now if (!@p_showhandles || \ (#calculationPurpose == 1 && @p_handlesnopreview) || \ (#calculationPurpose == 3 && @p_handlesnopreview) || \ (#calculationPurpose == 2 && @p_handlesnorender)) return pz endif $ifdef debug int testx = 400 int testy = 600 $endif ; see if any handle points apply int j = 0 int k = 0 int l = length(m_HandleTypes) int label = 0 int base = 0 int digit = 0 float n = 0 while (j < l) if (m_HandleTypes[j] > 0 || m_HandleLabels[j] > 0) sx = real(m_HandleCenters[j]) sy = imag(m_HandleCenters[j]) vx = #x-sx vy = #y-sy if (m_HandleRotations[j] != 0) complex v = (vx + flip(vy)) * m_HandleRotations[j] vx = real(v) vy = imag(v) endif dx = abs(vx) dy = abs(vy) ; if we're inside any handle area, flag that no lines be drawn if ((m_HandleTypes[j] < 5 && dx < @p_handlesize+@p_handlewidth*2 && dy < @p_handlesize+@p_handlewidth*2) || \ (m_HandleTypes[j] >= 5 && dx < @p_handlewidth*2.5 && dy < @p_handlewidth*2.5)) nolines = true endif ; handle if ((m_HandleTypes[j] == 1 && \ (dx >= @p_handlesize || dy >= @p_handlesize) && \ (dx < @p_handlesize+@p_handlewidth && dy < @p_handlesize+@p_handlewidth)) || \ (m_HandleTypes[j] == 2 && \ dx*dx+dy*dy >= @p_handlesize*@p_handlesize && dx*dx+dy*dy < sqr(@p_handlesize+@p_handlewidth)) || \ (m_HandleTypes[j] == 3 && \ dx+dy >= @p_handlesize && dx+dy < @p_handlesize+@p_handlewidth) || \ (m_HandleTypes[j] == 4 && \ 2*abs(dx+0.5-dy) < @p_handlewidth && (dx < @p_handlesize+@p_handlewidth && dy < @p_handlesize+@p_handlewidth)) || \ (m_HandleTypes[j] == 5 && \ ((dy < @p_handlewidth*0.5 && vx >= 0 && vx < @p_handlesize+@p_handlewidth) || \ (vx >= @p_handlesize*0.75 && dx+dy >= @p_handlesize && dx+dy < @p_handlesize+@p_handlewidth) || \ (dx*dx+dy*dy <= 1.5*@p_handlewidth*@p_handlewidth))) || \ (m_HandleTypes[j] == 6 && \ ((dy < @p_handlewidth*0.5 && dx < @p_handlesize+@p_handlewidth) || \ (dx >= @p_handlesize*0.75 && dx+dy >= @p_handlesize && dx+dy < @p_handlesize+@p_handlewidth) || \ (dx*dx+dy*dy <= 1.5*@p_handlewidth*@p_handlewidth))) \ ) m_Solid = !m_Solid endif ; number if (@p_handleswithnumbers && \ m_HandleLabelSizes[j] > 0 && \ #x >= sx+@p_handlesize+@p_handlewidth && #x < sx+@p_handlesize+@p_handlewidth*(1+5*m_HandleLabelSizes[j]) && \ #y >= sy+@p_handlesize+@p_handlewidth && #y < sy+@p_handlesize+@p_handlewidth*5) nolines = true ; no lines through number dx = floor((#x-sx-@p_handlesize-@p_handlewidth)/@p_handlewidth*2) ; pixel coordinate within label area dy = floor((#y-sy-@p_handlesize-@p_handlewidth)/@p_handlewidth*2) label = m_HandleLabels[j] if (label > 0) base = 10 else base = 40 endif digit = m_HandleLabelSizes[j]-floor(dx/10)-1 ; digit position within label dx = dx % 10 ; pixel coordinate within digit k = floor(abs(label) / base^digit + 0.00001) % base ; actual glyph number (includes a bit of round-off fudge) if (dx > 0 && dx < 9) ; pixel lies within glyph boundary if (dy < 4) ; top half of glyph n = real(m_DigitsDetail[k]) ; bit values dx = (8-dx) + 8*(3-dy) ; bit number else ; bottom half of glyph n = imag(m_DigitsDetail[k]) ; bit values dx = (8-dx) + 8*(7-dy) ; bit number endif dy = 2^dx ; mask bit if (floor(n / dy) % 2 > 0) ; test bit m_Solid = !m_Solid endif endif endif ; icon ; note the same flag that controls number rendering controls icons if (@p_handleswithnumbers && \ (real(m_HandleIcons[j]) > 0 || imag(m_HandleIcons[j]) > 0) && \ #x >= sx+@p_handlesize+@p_handlewidth && #x < sx+@p_handlesize+@p_handlewidth*5 && \ #y >= sy+@p_handlesize+@p_handlewidth && #y < sy+@p_handlesize+@p_handlewidth*5) nolines = true ; no lines through number dx = floor((#x-sx-@p_handlesize-@p_handlewidth)/@p_handlewidth*2) ; pixel coordinate within icon area dy = floor((#y-sy-@p_handlesize-@p_handlewidth)/@p_handlewidth*2) if (dx >= 0 && dx < 8) ; pixel lies within glyph boundary if (dy < 4) ; top half of glyph n = real(m_HandleIcons[j]) ; bit values dx = (7-dx) + 8*(3-dy) ; bit number else ; bottom half of glyph n = imag(m_HandleIcons[j]) ; bit values dx = (7-dx) + 8*(7-dy) ; bit number endif dy = 2^dx ; mask bit if (floor(n / dy) % 2 > 0) ; test bit m_Solid = !m_Solid endif endif endif endif j = j + 1 endwhile ; see if any handle lines apply float linelength = 0 j = 0 l = length(m_LineTypes) while (j < l && !nolines && @p_handleswithlines) if (!m_LineConnects[j]) ; this line does not connect to the previous line linelength = 0 ; reset the accumulated line length (helps line up dashes/dots) endif if (m_LineTypes[j] > 0) dx = ((real(m_LineEnds[j]) - real(m_LineStarts[j])) * (#y - imag(m_LineStarts[j])) - (#x - real(m_LineStarts[j])) * (imag(m_LineEnds[j]) - imag(m_LineStarts[j]))) / m_LineDistances[j] dy = ((imag(m_LineEnds[j]) - imag(m_LineStarts[j])) * (#y - imag(m_LineStarts[j])) - (#x - real(m_LineStarts[j])) * (real(m_LineStarts[j]) - real(m_LineEnds[j]))) / m_LineDistances[j] if (abs(dx) < @p_handlewidth*0.5 && dy > 0 && dy < m_LineDistances[j]) if (m_LineTypes[j] == 1) m_Solid = !m_Solid elseif (m_LineTypes[j] == 2) if (dy % (@p_handlewidth*2) > @p_handlewidth) m_Solid = !m_Solid endif elseif (m_LineTypes[j] == 3) if (dy % (@p_handlesize) > @p_handlesize*0.5) m_Solid = !m_Solid endif elseif (m_LineTypes[j] == 4) if (dy % (@p_handlesize*2) > @p_handlesize) m_Solid = !m_Solid endif endif endif endif j = j + 1 endwhile linelength = linelength + 1 ; **** silences compiler warning ; see if any handle circles apply j = 0 l = length(m_CircleTypes) while (j < l && !nolines && @p_handleswithlines) if (m_CircleTypes[j] > 0) dx = cabs((#x + flip(#y)) - m_CircleCenters[j]) - m_CircleRadii[j] dy = atan2((#x + flip(#y)) - m_CircleCenters[j]) if (dy < 0) dy = dy + 2*#pi endif dy = dy * m_CircleRadii[j] $ifdef debug if (#x == testx && #y == testy) print("test: ", #x, ",", #y) print("circle ", j, " center: ", m_CircleCenters[j], " radius: ", m_CircleRadii[j]) print("dx: ", dx, " dy: ", dy) endif $endif if (abs(dx) < @p_handlewidth*0.5) if (m_CircleTypes[j] == 1) m_Solid = !m_Solid elseif (m_CircleTypes[j] == 2) if (dy % (@p_handlewidth*2) > @p_handlewidth) m_Solid = !m_Solid endif elseif (m_CircleTypes[j] == 3) if (dy % (@p_handlesize) > @p_handlesize*0.5) m_Solid = !m_Solid endif elseif (m_CircleTypes[j] == 4) if (dy % (@p_handlesize*2) > @p_handlesize) m_Solid = !m_Solid endif endif endif endif j = j + 1 endwhile return pz endfunc ; Set the number of handles to render ; <p> ; You must call this function before you can define any handles. ; Specify the maximum number of each type of visual aid you ; will use. Any handles not defined will not be rendered, but ; defining more than you need will slow down rendering slightly. ; ; @param phandles number of handle points ; @param plines number of handle lines ; @param pcircles number of handle circles ; @param pcurves number of special handles; this is being reserved for future use, so you should always use 0 func SetHandleCount(int phandles, int plines, int pcircles, int pcurves) if (phandles >= 0) setLength(m_HandleTypes, phandles) setLength(m_HandleLabels, phandles) setLength(m_HandleLabelSizes, phandles) setLength(m_HandleIcons, phandles) setLength(m_HandleCenters, phandles) setLength(m_HandleRotations, phandles) endif if (plines >= 0) setLength(m_LineTypes, plines) setLength(m_LineConnects, plines) setLength(m_LineDistances, plines) setLength(m_LineStarts, plines) setLength(m_LineEnds, plines) endif if (pcircles >= 0) setLength(m_CircleTypes, pcircles) setLength(m_CircleCenters, pcircles) setLength(m_CircleRadii, pcircles) endif endfunc ; Define a handle point ; <p> ; This function defines all the information about a handle ; point. You will call this once for each handle point. ; <p> ; Handles can be one of several pre-defined shapes. You may ; specify a blank handle, which is useful if you simply want ; to place a label within your image. Squares are, by ; convention, used to indicate points that are on an edge ; that the user can directly select. Circles are used to ; indicate points that are NOT on an edge that the user may ; select. Diamonds are used to indicate interior or center ; points; the user may or may not be allowed to directly ; select this point. X should be used for an implied or ; computed point that the user CANNOT select. Arrows should ; be used for points where a particular direction needs to ; be indicated (specify the angle as something other than ; zero). Double-arrows should be used for points where the ; location along the line perpendicular to the arrows is ; irrelevant, and only the location in the direction the ; arrows show is relevant; they may also be used to mark ; points on a handle circle. A single triangle is used to ; mark a point on a line that the user may set indirectly. ; A double triangle should be used to indicate a point on ; a line where the line is set automatically but the ; position along the line is under the user's control ; (different from the double-arrow, where the user sets the ; line position; here they are setting the position of a ; point along a line). ; <p> ; Any handle shape may be rotated, but rotation is primarily ; intended for arrows. Rotation does not affect labels or ; icons, only the handle shape. ; <p> ; Labels can be numbers or short letter/number combinations. ; For positive integers, simply provide the number. For ; words, the process is a bit more complicated. Words may ; be five characters or less (including spaces). Each character ; is encoded in a base-40 encoding scheme: ; <p> ; 0 to 9: digits 0 to 9<br> ; 10: space<br> ; 11 to 36: letters A to Z<br> ; 37: asterisk (*)<br> ; 38: slash (/)<br> ; 39: period (.)<br> ; <p> ; As an example, to encode the word "TEST", convert each letter ; to its number: 30 15 29 30 ; <p> ; Next, treat these as base 40 values: ; (((30*40+15)*40+29)*40+30) = 1945190 ; <p> ; Then, pass in the value as a negative integer to indicate it ; should be interpreted as characters rather than just a number: ; -1945190 ; <p> ; Icons may be used in place of letters. (If you place an icon ; and characters on the same handle point, they will overlap.) ; Icons are 8x8 pixel bitmaps encoded as a single complex value: ; <p> ; row 1: real(icon) bits 31 to 24<br> ; row 2: real(icon) bits 23 to 16<br> ; row 3: real(icon) bits 15 to 8<br> ; row 4: real(icon) bits 7 to 0<br> ; row 5: imag(icon) bits 31 to 24<br> ; row 6: imag(icon) bits 23 to 16<br> ; row 7: imag(icon) bits 15 to 8<br> ; row 8: imag(icon) bits 7 to 0 ; <p> ; Because 32 bits are used for each icon, you must specify the ; values as explicitly real (include .0 on the end). Note that ; internally, the letters, numbers, and symbols are specified ; with this same format. ; ; @param phandle slot number, starting at 0; if you indicate -1, the next slot will be used automatically ; @param ptype handle type: 0 = blank (just number), 1 = square, 2 = circle, 3 = diamond, 4 = X, 5 = single arrow, 6 = double arrow, 7 = single triangle, 8 = double triangle ; @param plabel label number: 0 = blank, >0 = number, <0 = number/letter ; @param picon icon (use 0 for blank) ; @param pz location of handle ; @param pr rotation of handle in degrees func SetHandlePoint(int phandle, int ptype, int plabel, complex picon, complex pz, float pr) float logbase = 10.0 ; work-around for log(10.0) optimization introducing round-off errors if (phandle == -1) phandle = m_HandleNext m_HandleNext = m_HandleNext + 1 endif ; save point metadata m_HandleTypes[phandle] = ptype m_HandleLabels[phandle] = plabel m_HandleIcons[phandle] = picon m_HandleRotations[phandle] = (0,1)^(pr/90.0) ; convert point to pixel coordinates now m_PixelCoordinate.Init(pz) m_HandleCenters[phandle] = m_PixelCoordinate.Iterate(pz) ; determine label length now if (plabel > 0) m_HandleLabelSizes[phandle] = floor(log(plabel)/log(logbase))+1 elseif (plabel < 0) logbase = 40.0 m_HandleLabelSizes[phandle] = floor(log(-plabel)/log(logbase))+1 else m_HandleLabelSizes[phandle] = 0 endif endfunc ; Define a handle line segment ; <p> ; Handle lines can be used to complement handle points and ; show relationships between them. They can also be used by ; themselves (there is no requirement that they be used to ; connect handle points). ; <p> ; Lines are automatically hidden in the area around handle ; points and labels/icons. This is so that the lines can ; never obscure the more important parts of the handle ; system. ; <p> ; Lines may be drawn in one of four styles. Solid lines ; should be used only for shapes or elements that are ; otherwise completely invisible. Dotted lines should be ; used to indicate constraining or boundary lines. ; Short dashed lines should be used for a shape boundary ; that is drawn some distance from a visible edge. ; <p> ; When lines are being drawn end-to-end without handles ; at the connecting points, you may wish to indicate that ; the lines are connected. This allows the handle system ; to automatically adjust the pattern on the lines to be ; continuous. If handles are rendered at the connecting ; points they will obscure the join, making this setting ; irrelevant. ; ; @param phandle slot number, starting at 0; if you indicate -1, the next slot will be used automatically ; @param pconnect whether segment connects to previous line segment ; @param ptype line type: 0 = blank, 1 = solid, 2 = dotted, 3 = short dashed, 4 = long dashed ; @param pstart starting point of line segment ; @param pend ending point of line segment func SetHandleLine(int phandle, int ptype, bool pconnect, complex pstart, complex pend) if (phandle == -1) phandle = m_LineNext m_LineNext = m_LineNext + 1 endif ; save line metadata m_LineTypes[phandle] = ptype m_LineConnects[phandle] = pconnect ; convert points to pixel coordinates now ; we include a bit of fudge so that lines don't precisely ; fall on pixel boundaries; this guarantees that lines ; will not be an extra pixel thick due to each side being ; exactly the right number of pixels from the center m_PixelCoordinate.Init(pstart) m_LineStarts[phandle] = m_PixelCoordinate.Iterate(pstart) - (0.001, 0.001) m_PixelCoordinate.Init(pend) m_LineEnds[phandle] = m_PixelCoordinate.Iterate(pend) - (0.001, 0.001) ; compute line length in pixel coordinates now m_LineDistances[phandle] = cabs(m_LineEnds[phandle] - m_LineStarts[phandle]) endfunc ; Define a handle circle ; <p> ; Circles are similar to lines in that they have different ; styles. In the current implementation, circles will always ; appear circular regardless of the image aspect ratio. ; ; @param phandle slot number, starting at 0; if you indicate -1, the next slot will be used automatically ; @param ptype circle type: 0 = blank, 1 = solid, 2 = dotted, 3 = short dashed, 4 = long dashed ; @param pcenter center point of the circle ; @param pradius radius of the circle func SetHandleCircle(int phandle, int ptype, complex pcenter, float pradius) if (phandle == -1) phandle = m_CircleNext m_CircleNext = m_CircleNext + 1 endif ; save circle metadata m_CircleTypes[phandle] = ptype ; convert points to pixel coordinates now m_PixelCoordinate.Init(pcenter) m_CircleCenters[phandle] = m_PixelCoordinate.Iterate(pcenter) m_PixelCoordinate.Init(pcenter+pradius) m_CircleRadii[phandle] = cabs(m_CircleCenters[phandle]-m_PixelCoordinate.Iterate(pcenter+pradius)) endfunc ; use this function to set the screen-relative coordinate style ; if you don't do this, and you allow screen-relative coordinates, ; your handles will appear in the wrong place func SetScreenRelative(int ptype) m_PixelCoordinate.SetScreenRelative(ptype) endfunc protected: PixelCoordinate m_PixelCoordinate complex m_DigitsDetail[40] int m_HandleNext int m_HandleTypes[] int m_HandleLabels[] int m_HandleLabelSizes[] complex m_HandleIcons[] complex m_HandleCenters[] complex m_HandleRotations[] int m_LineNext int m_LineTypes[] bool m_LineConnects[] float m_LineDistances[] complex m_LineStarts[] complex m_LineEnds[] int m_CircleNext int m_CircleTypes[] complex m_CircleCenters[] float m_CircleRadii[] default: title = "Handles utility class" int param v_handles caption = "Version (Handles)" default = 100 hint = "This version parameter is used to detect when a change has been made to the formula that is incompatible with the previous version. When that happens, this field will reflect the old version number to alert you to the fact that an alternate rendering is being used." visible = @v_handles < 100 endparam bool param p_showhandles caption = "Show Handles" default = true hint = "If enabled, shows 'handles' in the image to mark where the control points of the shape are located. This is very useful while you are creating your image, but you will probably not want handles in your final image render. By default, handles should not render in your final image if the render is large, but if you do a small final render you may need to use this master switch to disable handles." endparam bool param p_handlesnopreview caption = "Not on previews" default = true visible = (@p_showhandles) hint = "If checked, handles will not be shown on previews. Handles don't scale with window size, so they appear disproportionately large in the preview window." endparam bool param p_handlesnorender caption = "Not on renders" default = true visible = (@p_showhandles) hint = "If checked, handles will be disabled for any image above a certain size. This is useful for automatically disabling handles on disk renders." endparam bool param p_handleswithnumbers caption = "Show Numbers" default = true visible = (@p_showhandles) hint = "If checked, handles will be numbered." endparam bool param p_handleswithlines caption = "Show Lines" default = true visible = (@p_showhandles) hint = "If checked, lines may also appear." endparam int param p_handlesize caption = "Handle Size" default = 8 visible = (@p_showhandles) hint = "Sets the size of the inside area of the handle. You may need to adjust this to make the handles more visible on some fractals." endparam int param p_handlewidth caption = "Handle Thickness" default = 2 visible = (@p_showhandles) hint = "Sets the thickness of the handles. You may need to adjust this to make the handles more visible on some fractals." endparam }
Constructor Summary | |
---|---|
Handles()
|
|
Handles(Generic pparent)
Constructor |
Method Summary | |
---|---|
complex |
Iterate(complex pz)
Compute handle state for a single point within a sequence |
void |
SetHandleCircle(int phandle,
int ptype,
complex pcenter,
float pradius)
Define a handle circle |
void |
SetHandleCount(int phandles,
int plines,
int pcircles,
int pcurves)
Set the number of handles to render |
void |
SetHandleLine(int phandle,
int ptype,
boolean pconnect,
complex pstart,
complex pend)
Define a handle line segment |
void |
SetHandlePoint(int phandle,
int ptype,
int plabel,
complex picon,
complex pz,
float pr)
Define a handle point |
void |
SetScreenRelative(int ptype)
use this function to set the screen-relative coordinate style if you don't do this, and you allow screen-relative coordinates, your handles will appear in the wrong place |
Methods inherited from class common:Transform |
---|
Init, IsSolid, IterateSilent |
Methods inherited from class common:Generic |
---|
GetParent |
Methods inherited from class Object |
---|
|
Constructor Detail |
---|
public Handles(Generic pparent)
pparent
- a reference to the object creating the new object; typically, 'this'public Handles()
Method Detail |
---|
public complex Iterate(complex pz)
Handles is a Transform, so to test the handle state for a particular point, the standard approach is to Init(), Iterate() (just once), and then test IsSolid().
Iterate
in class Transform
pz
- the complex value to test
public void SetHandleCount(int phandles, int plines, int pcircles, int pcurves)
You must call this function before you can define any handles. Specify the maximum number of each type of visual aid you will use. Any handles not defined will not be rendered, but defining more than you need will slow down rendering slightly.
phandles
- number of handle pointsplines
- number of handle linespcircles
- number of handle circlespcurves
- number of special handles; this is being reserved for future use, so you should always use 0public void SetHandlePoint(int phandle, int ptype, int plabel, complex picon, complex pz, float pr)
This function defines all the information about a handle point. You will call this once for each handle point.
Handles can be one of several pre-defined shapes. You may specify a blank handle, which is useful if you simply want to place a label within your image. Squares are, by convention, used to indicate points that are on an edge that the user can directly select. Circles are used to indicate points that are NOT on an edge that the user may select. Diamonds are used to indicate interior or center points; the user may or may not be allowed to directly select this point. X should be used for an implied or computed point that the user CANNOT select. Arrows should be used for points where a particular direction needs to be indicated (specify the angle as something other than zero). Double-arrows should be used for points where the location along the line perpendicular to the arrows is irrelevant, and only the location in the direction the arrows show is relevant; they may also be used to mark points on a handle circle. A single triangle is used to mark a point on a line that the user may set indirectly. A double triangle should be used to indicate a point on a line where the line is set automatically but the position along the line is under the user's control (different from the double-arrow, where the user sets the line position; here they are setting the position of a point along a line).
Any handle shape may be rotated, but rotation is primarily intended for arrows. Rotation does not affect labels or icons, only the handle shape.
Labels can be numbers or short letter/number combinations. For positive integers, simply provide the number. For words, the process is a bit more complicated. Words may be five characters or less (including spaces). Each character is encoded in a base-40 encoding scheme:
0 to 9: digits 0 to 9
10: space
11 to 36: letters A to Z
37: asterisk (*)
38: slash (/)
39: period (.)
As an example, to encode the word "TEST", convert each letter to its number: 30 15 29 30
Next, treat these as base 40 values: (((30*40+15)*40+29)*40+30) = 1945190
Then, pass in the value as a negative integer to indicate it should be interpreted as characters rather than just a number: -1945190
Icons may be used in place of letters. (If you place an icon and characters on the same handle point, they will overlap.) Icons are 8x8 pixel bitmaps encoded as a single complex value:
row 1: real(icon) bits 31 to 24
row 2: real(icon) bits 23 to 16
row 3: real(icon) bits 15 to 8
row 4: real(icon) bits 7 to 0
row 5: imag(icon) bits 31 to 24
row 6: imag(icon) bits 23 to 16
row 7: imag(icon) bits 15 to 8
row 8: imag(icon) bits 7 to 0
Because 32 bits are used for each icon, you must specify the values as explicitly real (include .0 on the end). Note that internally, the letters, numbers, and symbols are specified with this same format.
phandle
- slot number, starting at 0; if you indicate -1, the next slot will be used automaticallyptype
- handle type: 0 = blank (just number), 1 = square, 2 = circle, 3 = diamond, 4 = X, 5 = single arrow, 6 = double arrow, 7 = single triangle, 8 = double triangleplabel
- label number: 0 = blank, >0 = number, <0 = number/letterpicon
- icon (use 0 for blank)pz
- location of handlepr
- rotation of handle in degreespublic void SetHandleLine(int phandle, int ptype, boolean pconnect, complex pstart, complex pend)
Handle lines can be used to complement handle points and show relationships between them. They can also be used by themselves (there is no requirement that they be used to connect handle points).
Lines are automatically hidden in the area around handle points and labels/icons. This is so that the lines can never obscure the more important parts of the handle system.
Lines may be drawn in one of four styles. Solid lines should be used only for shapes or elements that are otherwise completely invisible. Dotted lines should be used to indicate constraining or boundary lines. Short dashed lines should be used for a shape boundary that is drawn some distance from a visible edge.
When lines are being drawn end-to-end without handles at the connecting points, you may wish to indicate that the lines are connected. This allows the handle system to automatically adjust the pattern on the lines to be continuous. If handles are rendered at the connecting points they will obscure the join, making this setting irrelevant.
phandle
- slot number, starting at 0; if you indicate -1, the next slot will be used automaticallypconnect
- whether segment connects to previous line segmentptype
- line type: 0 = blank, 1 = solid, 2 = dotted, 3 = short dashed, 4 = long dashedpstart
- starting point of line segmentpend
- ending point of line segmentpublic void SetHandleCircle(int phandle, int ptype, complex pcenter, float pradius)
Circles are similar to lines in that they have different styles. In the current implementation, circles will always appear circular regardless of the image aspect ratio.
phandle
- slot number, starting at 0; if you indicate -1, the next slot will be used automaticallyptype
- circle type: 0 = blank, 1 = solid, 2 = dotted, 3 = short dashed, 4 = long dashedpcenter
- center point of the circlepradius
- radius of the circlepublic void SetScreenRelative(int ptype)
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |