Annotation of Examples/AppKit/UnderPressure/Brush.m, revision 1.1

1.1     ! root        1: /*
        !             2: 
        !             3:   Brush.m -- Pressure sensitive paint brush
        !             4: 
        !             5:   by Peter Graffagnino, NeXT Computer Inc.
        !             6: 
        !             7:   Brush's responsibilities are
        !             8: 
        !             9:   - implement brushMoveTo:... and brushLineTo:... painting protocol.
        !            10:   - provide target/action methods to tweak brush parameters
        !            11: 
        !            12:   You may freely copy, distribute, and reuse the code in this example.
        !            13:   NeXT disclaims any warranty of any kind, expressed or  implied, as to its
        !            14:   fitness for any particular use.
        !            15: 
        !            16: */
        !            17: 
        !            18: 
        !            19: #import <appkit/appkit.h>
        !            20: #import <math.h>
        !            21: #import "Brush.h"
        !            22: 
        !            23: @implementation Brush
        !            24: 
        !            25: 
        !            26: 
        !            27: /*
        !            28:  * fill_tangent_trapezoid:  takes two circles of radius r1 and r2 whose centers
        !            29:  * are separated by (dx,dy) and draws the trapezoid formed by the common
        !            30:  * tangents of the two circles, and parallel chords of the two circles.  This
        !            31:  * is essentially that shape of a belt around two different sized pullies.  The
        !            32:  * code assumes that the current point is at the center of the first circle
        !            33:  */ 
        !            34: 
        !            35: void fill_tangent_trapezoid(double r1, double r2, double dx, double dy)
        !            36: {
        !            37:     double d, eta, nu, x1, y1, x1m, y1m, x2, y2, x2m, y2m;
        !            38:     double xeta, yeta, xnu, ynu;
        !            39: 
        !            40:     d = sqrt(dx * dx + dy * dy);
        !            41: 
        !            42:     /*
        !            43:      * protect against the degenerate case (one circle contained in the other)
        !            44:      */
        !            45:     if ((r1 - r2) >= d || (r1 - r2) <= -d)
        !            46:        return;
        !            47: 
        !            48:     eta = (r1 - r2)/d;
        !            49:     nu = sqrt(1 - eta*eta);
        !            50:     
        !            51:     nu /= d;     xnu = dx*nu;      ynu = dy*nu;
        !            52:     eta /= d;    xeta = dx*eta;    yeta = dy*eta;
        !            53:     
        !            54:     x1  = xeta - ynu;    x2 = dx + r2*x1;      x1 *= r1;
        !            55:     y1  = yeta + xnu;    y2 = dy + r2*y1;      y1 *= r1;
        !            56:     
        !            57:     x1m = xeta + ynu;   x2m = dx + r2*x1m;    x1m *= r1;
        !            58:     y1m = yeta - xnu;   y2m = dy + r2*y1m;    y1m *= r1;
        !            59:     
        !            60:     PSrmoveto(x1,y1);
        !            61:     PSrlineto(x1m - x1, y1m - y1);
        !            62:     PSrlineto(x2m - x1m, y2m - y1m);
        !            63:     PSrlineto(x2 - x2m, y2 - y2m);
        !            64:     PSclosepath();
        !            65:     PSfill();
        !            66: }
        !            67: 
        !            68: 
        !            69: /*
        !            70:  * brushMoveTo:... and brushLineTo:... are the basic painting protocol.  The
        !            71:  * assumption is that we are currently lockFocused: appropriately.  Our
        !            72:  * only job is to emit postscript to draw the brush stroke, and return a dirty
        !            73:  * rectangle in which we drew.
        !            74:  */
        !            75: 
        !            76: 
        !            77: - brushMoveTo:(float)x :(float)y withPressure:(float) pressure
        !            78:  dirtyRect: (NXRect *) dirty
        !            79: {
        !            80:     /*
        !            81:      * latch the current point as the last point.  lastsize is immaterial
        !            82:      * since the line will be zero length.  This allows us to use lineto
        !            83:      * to plot a single point.
        !            84:      */
        !            85:     lastx = x; lasty = y; lastsize = 1.0;
        !            86:     return [self brushLineTo: x : y withPressure: pressure dirtyRect: dirty];
        !            87: }
        !            88:     
        !            89: 
        !            90: - brushLineTo:(float)x :(float)y withPressure:(float) pressure
        !            91:  dirtyRect: (NXRect *) dirty
        !            92: {
        !            93:     float size;
        !            94: 
        !            95:     NXSetColor(brushColor);    
        !            96: 
        !            97:     size = pressureCoefficient*pow(pressure,pressureExponent) + minSize;
        !            98: 
        !            99:     /* Do the endpoint first */
        !           100:     PSsetlinewidth(size);
        !           101:     PSsetlinecap(1);
        !           102:     
        !           103:     PSmoveto(x,y); PSclosepath(); PSstroke();
        !           104: 
        !           105:     /* Connect the last circle to this one with bimodular tangents (honest) */
        !           106:     PSmoveto(lastx,lasty);
        !           107:     fill_tangent_trapezoid(lastsize/2, size/2, x - lastx, y - lasty);
        !           108: 
        !           109:     /* calculate dirty rect for flush */
        !           110:     if(lastx > x) {
        !           111:        dirty->origin.x = x;
        !           112:        dirty->size.width = lastx - x;
        !           113:     } else {
        !           114:        dirty->origin.x = lastx;
        !           115:        dirty->size.width = x - lastx;
        !           116:     }
        !           117:     if (lasty > y) {
        !           118:        dirty->origin.y = y;
        !           119:        dirty->size.height = lasty - y;
        !           120:     } else {
        !           121:        dirty->origin.y = lasty;
        !           122:        dirty->size.height = y - lasty;
        !           123:     }
        !           124:     NXInsetRect(dirty, -(size + lastsize + 2.0)/2.0,
        !           125:                -(size + lastsize + 2.0)/2.0);
        !           126:     lastx = x; lasty = y; lastsize = size;
        !           127:     return self;
        !           128: }
        !           129: 
        !           130: 
        !           131: /*
        !           132:  * Target/action parameter methods.  We implement a number of action methods
        !           133:  * to allow control over our various parameters.  We also use these methods
        !           134:  * to latch initial values from nibified controls, by declaring appropriately
        !           135:  * named phantom outlets in nib.
        !           136:  */
        !           137: 
        !           138: - setMinSize: sender
        !           139: {
        !           140:     minSize = [sender floatValue];
        !           141:     return self;
        !           142: }
        !           143: 
        !           144: - setPressureExponent: sender
        !           145: {
        !           146:     pressureExponent = [sender floatValue];
        !           147:     return self;
        !           148: }
        !           149: 
        !           150: - setPressureCoefficient: sender
        !           151: {
        !           152:     pressureCoefficient = [sender floatValue];
        !           153:     return self;
        !           154: }
        !           155: 
        !           156: - setBrushColor: sender
        !           157: {
        !           158: 
        !           159:     brushColor = [sender color];
        !           160:     return self;
        !           161: }
        !           162: 
        !           163: /*
        !           164:  * init -- give some reasonable default values.  Note that the above
        !           165:  * methods are called by the outlet-setting pass of nib loading, making
        !           166:  * the real defaults come from the nib itself
        !           167:  */
        !           168: 
        !           169: - init
        !           170: {
        !           171:     self = [super init];
        !           172:     brushColor = NX_COLORBLACK;
        !           173:     pressureExponent = 2.0;
        !           174:     minSize = 0.0;
        !           175:     pressureCoefficient = 12.0;
        !           176: 
        !           177:     return self;
        !           178: }
        !           179:     

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.