Average overlapping colours
The following code uses regions to separate the overlapping and non-overlapping parts of the circles, and unsigned arithmetic to get an average RGB colour for the overlapping region.
COMPILE ,_dimmedvarsOnly LOCAL FN RGBAverage(src1RGBPtr&,src2RGBPtr&,destRGBPtr&) DIM red1&,green1&,blue1&,red2&,green2&,blue2& red1&=src1RGBPtr&.0% green1&=src1RGBPtr&.2% blue1&=src1RGBPtr&.4% red2&=src2RGBPtr&.0% green2&=src2RGBPtr&.2% blue2&=src2RGBPtr&.4% IF red1&<0 THEN red1&=red1&+65536' unsigned IF green1&<0 THEN green1&=green1&+65536 IF blue1&<0 THEN blue1&=blue1&+65536 IF red2&<0 THEN red2&=red2&+65536 IF green2&<0 THEN green2&=green2&+65536 IF blue2&<0 THEN blue2&=blue2&+65536 destRGBPtr&.0%=(red1&+red2&)>>1' average destRGBPtr&.2%=(green1&+green2&)>>1 destRGBPtr&.4%=(blue1&+blue2&)>>1 END FN LOCAL FN OverlapOvals(rect1Ptr&,rgb1Ptr&,rect2Ptr&,rgb2Ptr&) DIM rgn1&,rgn2&,olapRgn&,avgRGB.6 rgn1&=FN NEWRGN rgn2&=FN NEWRGN olapRgn&=FN NEWRGN CALL OPENRGN CALL FRAMEOVAL(#rect1Ptr&) ' oval 1 CALL CLOSERGN(rgn1&) CALL OPENRGN CALL FRAMEOVAL(#rect2Ptr&) ' oval 2 CALL CLOSERGN(rgn2&) CALL SECTRGN(rgn1&,rgn2&,olapRgn&)' the overlap CALL DIFFRGN(rgn1&,olapRgn&,rgn1&)' remove overlap CALL DIFFRGN(rgn2&,olapRgn&,rgn2&)' remove overlap CALL RGBFORECOLOR(#rgb1Ptr&) CALL PAINTRGN(rgn1&) ' oval 1 CALL RGBFORECOLOR(#rgb2Ptr&) CALL PAINTRGN(rgn2&) ' oval 2 FN RGBAverage(rgb1Ptr&,rgb2Ptr&,@avgRGB) CALL RGBFORECOLOR(avgRGB) CALL PAINTRGN(olapRgn&) ' overlap CALL DISPOSERGN(rgn1&) CALL DISPOSERGN(rgn2&) CALL DISPOSERGN(olapRgn&) END FN LOCAL FN RandomRGB(destRGBPtr&) destRGBPtr&.red%=RND(255)*256 destRGBPtr&.green%=RND(255)*256 destRGBPtr&.blue%=RND(255)*256 END FN DIM rect1.8, rect2.8, myRGB1.6, myRGB2.6, x,y RANDOMIZE TIMER WINDOW 1,"Overlap",(0,0)-(630,430) CALL SETRECT(rect1,10,10,90,90) CALL SETRECT(rect2,50,10,130,90) FOR x=0 TO 450 STEP 150 FOR y=0 TO 300 STEP 150 FN RandomRGB(@myRGB1) FN RandomRGB(@myRGB2) CALL SETORIGIN(-x,-y) FN OverlapOvals(@rect1,@myRGB1,@rect2,@myRGB2) NEXT NEXT CALL SETORIGIN(0,0) ' restore QuickDraw origin DO HANDLEEVENTS UNTIL FN BUTTON
Don't know if this is what you're looking for, but...
'================ CLEAR LOCAL FN drawCircles DIM cirColor.rgbColor cirColor.Red = 65535 cirColor.Green = 40000 cirColor.Blue = 40000 ' PEN ,,,_adMin 'Note that there are other pen settings 'that will effect how the colors turn out, 'here's a couple... '_subPin '_subOver CALL RGBFORECOLOR(#@cirColor) CIRCLE FILL 100,100,50 cirColor.Red = 40000 cirColor.Green = 40000 cirColor.Blue = 65535 CALL RGBFORECOLOR(#@cirColor) CIRCLE FILL 150,150,50 CALL PENNORMAL END FN WINDOW 1 FN drawCircles DO HANDLEEVENTS UNTIL 0 '================
These are 2 routines from one of my programs that blends 2 colo(u)rs where 2 colo(u)red regions overlap.
CLEAR LOCAL LOCAL FN AvgRGB(red&, green&, blue&, rgbRed&, rgbGreen&, rgbBlue&) DIM redRGB, greenRGB, blueRGB redRGB = red& greenRGB = green& blueRGB = blue& LONG IF redRGB + greenRGB + blueRGB = 0 %rgbRed&,13500 %rgbGreen&,13500 %rgbBlue&,13500 XELSE %rgbRed&,redRGB %rgbGreen&,greenRGB %rgbBlue&,blueRGB END IF END FN CLEAR LOCAL LOCAL FN AvgPaintRgn(face1, rgn1H&, face2, rgn2H&) DIM red&, green&, blue&, rgbRed, rgbGreen, rgbBlue, rgnH& DIM red1&, red2&, green1&, green2&, blue1&, blue2& rgnH& = FN NEWRGN CALL SECTRGN(rgn1H&, rgn2H&, rgnH&) red1& = VAL(UNS$(gColor.red%(face1))) : red2& = VAL(UNS$(gColor.red%(face2))) red& = (red1& + red2&) / 2& green1& = VAL(UNS$(gColor.green%(face1))) : green2& VAL(UNS$(gColor.green%(face2))) green& = (green1& + green2&) / 2& blue1& = VAL(UNS$(gColor.blue%(face1))) : blue2& VAL(UNS$(gColor.blue%(face2))) blue& = (blue1& + blue2&) / 2& FN AvgRGB(red&, green&, blue&, @rgbRed, @rgbGreen, @rgbBlue) LONG COLOR rgbBlue, rgbGreen, rgbRed CALL PAINTRGN(rgnH&) DEF DISPOSEH(rgnH&) END FN
Here is my slow attempt to mix the colours:
DIM color1.RGBColor DIM color2.RGBColor END GLOBALS CLEAR LOCAL LOCAL FN initColors color1.red% = 65535 : color1.green% = 0 : color1.blue% = 0 color2.red% = 65535 : color2.green% = 65535 : color2.blue% = 0 END FN CLEAR LOCAL LOCAL FN drawRects dim h,v DIM togglingflag,thecolor DIM myRect1.8 DIM myRect2.8 DIM myRect3.8 CALL SETRECT(myRect1,20,20,100,100) CALL SETRECT(myRect2,50,20,130,100) CALL SETRECT(myRect3,50,20,100,100) CALL RGBFORECOLOR(#@color1) : CALL PAINTRECT(myRect1) CALL RGBFORECOLOR(#@color2) : CALL PAINTRECT(myRect2) FOR h = myRect3.left% TO myRect3.right% togglingflag = NOT(togglingflag) FOR v = myRect3.top% TO myRect3.bottom% LONG IF v MOD 2 IF togglingflag THEN thecolor = 1 ELSE thecolor = 2 XELSE IF togglingflag THEN thecolor = 2 ELSE thecolor = 1 END IF IF thecolor = 1 THEN CALL SETCPIXEL(h,v,#@color1) ELSE CALL SETCPIXEL(h,v,#@color2) NEXT NEXT END FN WINDOW 1 FN initColors FN drawRects DO UNTIL FN BUTTON OR LEN(INKEY$)
Phil Yates asked how to colour the overlapping area of two circles. The suggestion to use: PEN ,,,_adMin or other constants seems to change the orginal colours too as it combines the existing colour with the new one.
Here's an short example of a function to draw a circle and create a region for it. Then the region handles can be used to calculate the interseting area and simple averaging can determine the colour used to paint the overlapping region. See pages 297-299 in the FBII Handbook for more info re regions and their commands. - Powerful stuff.
'================== LOCAL FN drawCircle( h,v, r ) DIM rect;8 CALL SETRECT( rect, h-r,v-r, h+r,v+r ) rgn& = FN NEWRGN LONG IF rgn& CALL OPENRGN CALL FRAMEOVAL( rect ) CALL CLOSERGN( rgn& ) END IF CALL PAINTRGN( rgn& ) END FN = rgn& '================== WINDOW 1 DIM c1&, c2&, overlap& ' use your own colours red1=64000: green1=00000: blue1=00000 ' pure red red2=00000: green2=00000: blue2=64000 ' pure blue red3 = (red1+red2)/2 ' calc the average colour green3 = (green1+green2)/2 blue3 = (blue1+blue2)/2 LONG COLOR blue1,green1,red1 c1& = FN drawCircle( 100,150, 50 ) DELAY 1000 LONG COLOR blue2,green2,red2 c2& = FN drawCircle( 90,100, 70 ) DELAY 1000 overlap& = FN NEWRGN ' note - need to create a region for next instruction. CALL SECTRGN( c1&, c2&, overlap& ) LONG COLOR blue3,green3,red3 CALL PAINTRGN( overlap& ) DELAY 1000 DO HANDLEEVENTS UNTIL 0 '==================
It's been a long time since I did this but here goes: There are other color modes in the Mac than just RGB, HSB for example. There are also easy toolbox calls to convert to and from!
In a similar situation i converted to HSB (Hue, Saturation, Brilliance) and averaged only the hue value, keeping Saturation and brilliance at the same levels, then converted back to RGB for display. It gave satisfactory effects.
I've recently started lurking on the FB listserve. I'm not much of a programmer so I'm not likely to contribute much. As a graduate student in cognitive psychology I do know a little bit about color perception.
Color averaging is a little bit tricky. Before you can figure out the algorithm for averaging, you need to decide what the result should look like. If one circle were fully saturated bright red and the other fully saturated bright green do you want the overlap to be dark brown or yellow. Brown (red = 32767, green = 32767, blue = 0) is what you would get if you mixed paints. Yellow (red = 65535, green = 65535, blue = 0) is what you would get if you shown a red and a green spot light together on a white surface.
Leaving aside the matter of mixing light for the moment, think about a standard color wheel which has the full range of bright, saturated hues around the edge with those hues becoming less saturated ("muddier") toward the center of the circle. Gray is at the center. Suppose you wanted to mix two colors on the rim of the color wheel. They are both bright and saturated. Do you want to find the mid-point between those two colors by moving to the mid-point on the rim of the circle (averaging the hues and retaining brightness and saturation) or do you want to find the midpoint of the straight line that connects the two points (averaging hue, reducing saturation, and leaving brightness unchanged). Averaging RGB values will give you a third result: average hues, reduced brightness, and saturation unchanged.
Averaging RGB values may give you exactly what you want. However, I suggest you test the results with the range of mixtures you are likely to use and make sure you are satisfied. You may be looking for a different effect such as averaging hue, saturation, and brightness (which are the dimensions of psychological "color space").