How does Circle() work? (make areas of image transparent)

Just starting out? Need help? Post your questions and find answers here.
Seymour Clufley
Addict
Addict
Posts: 1265
Joined: Wed Feb 28, 2007 9:13 am
Location: London

How does Circle() work? (make areas of image transparent)

Post by Seymour Clufley »

I'm looking for a way to make a circular area in an image transparent.

The way I've been doing it is to create a second image, draw the circle on that, then Point() through the whole image and record whether each pixel is black/white into an array. Then, when drawing the real image, I do it one pixel at a time and only draw each pixel if the corresponding pixel in the array is black (not had the circle drawn over it).

Obviously this method is slow!

It seems a faster way would be to set the alpha value of each pixel in the image itself. I know how to get the alpha value of each pixel thanks to Srod's code, but not how to set the value. I've requested a PlotAlpha() command but, in the meantime...?

Secondly, how to know which pixels to make transparent?! This is why I asked how the Circle() command works. Is each pixel changed individually or is there some quicker way?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

a quick circle algorithm draws 8 times an 8th part of a circle.
you need to calculate the Sin/Cos values only for 45° and repeat/mirror these values.
oh... and have a nice day.
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

quidquid Latine dictum sit altum videtur
cxAlex
User
User
Posts: 88
Joined: Fri Oct 24, 2008 11:29 pm
Location: Austria
Contact:

Post by cxAlex »

Try this Code:

Code: Select all

Procedure _Circle(x, y, rad, color = 0)
  Protected sPos.f, ePos.f, y2.d, rad2, oldx
  Protected cy1, cy2, cx1, cx2, ocy1, ocy2, ocx1, ocx2
  
  ocy1 = y-rad
  ocy2 = y + rad
  ocx1 = x
  ocx2 = x
  
  rad2 = rad*rad
  sPos = x
  ePos = x + rad
  
  For x = sPos To ePos
    oldx + 1
    y2 = Sqr(rad2-oldx*oldx)
    
    cy1 = y-y2
    cy2 = y + y2
    cx1 = x
    cx2 = sPos-oldx
    
    LineXY(ocx1, ocy1, cx1, cy1, color)
    LineXY(ocx1, ocy2, cx1, cy2, color)
    LineXY(ocx2, ocy1, cx2, cy1, color)
    LineXY(ocx2, ocy2, cx2, cy2, color)
    
    ocy1 = cy1
    ocy2 = cy2
    ocx1 = cx1
    ocx2 = cx2
    
  Next
  
EndProcedure

OpenWindow(0, 0, 0, 450, 450, "demo", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

If StartDrawing(WindowOutput(0))
    _Circle(225, 225, 200, $ff)
    DrawingMode(#PB_2DDrawing_Outlined)
    Circle(225, 225, 150)
  StopDrawing()
EndIf

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
SMartin
User
User
Posts: 19
Joined: Thu Aug 16, 2007 6:08 am
Location: Las Vegas

C translation

Post by SMartin »

In case you're interested.
Here's a PB translation of the c code linked to by Freak

Code: Select all


Procedure  RasterCircle(x0.i,y0.i,Radius.i)

	;{ Original C source code
	
			; void rasterCircle(int x0, int y0, int radius)
			;   {
			;     int f = 1 - radius;
			;     int ddF_x = 1;
			;     int ddF_y = -2 * radius;
			;     int x = 0;
			;     int y = radius;
			;  
			;     setPixel(x0, y0 + radius);
			;     setPixel(x0, y0 - radius);
			;     setPixel(x0 + radius, y0);
			;     setPixel(x0 - radius, y0);
			;  
			;     While(x < y)
			;     {
			;       assert(ddF_x == 2 * x + 1);
			;       assert(ddF_y == -2 * y);
			;       assert(f == x*x + y*y - radius*radius + 2*x - y + 1);
			;       If(f >= 0) 
			;       {
			;         y--;
			;         ddF_y += 2;
			;         f += ddF_y;
			;       }
			;       x++;
			;       ddF_x += 2;
			;       f += ddF_x;    
			;       setPixel(x0 + x, y0 + y);
			;       setPixel(x0 - x, y0 + y);
			;       setPixel(x0 + x, y0 - y);
			;       setPixel(x0 - x, y0 - y);
			;       setPixel(x0 + y, y0 + x);
			;       setPixel(x0 - y, y0 + x);
			;       setPixel(x0 + y, y0 - x);
			;       setPixel(x0 - y, y0 - x);
			;     }
			;   }
	
	;} End Original C source code
	
	Define f.i = 1 - Radius
	Define ddF_x = 1
	Define ddF_y = -2 * Radius
	Define x.i = 0
	Define y.i = Radius
	
	StartDrawing(WindowOutput(0))
		Plot(x0,y0 + Radius)
		Plot(x0,y0 - Radius)
		Plot(x0 + Radius,y0)
		Plot(x0 - Radius,y0)
	StopDrawing()
	
	While (x < y)
	
		If  ddF_x = ((2 * x) + 1) 		
			If ddF_y = (-2 * y) 			
				If f = (x * x + y * y - Radius * Radius + 2 * x - y + 1) 
					If f >= 0
						y - 1
						ddF_y + 2
						f + ddF_y
					EndIf					
					x + 1
					ddF_x + 2
					f + ddF_x					
					StartDrawing(WindowOutput(0))
						Plot(x0 + x,y0 + y)
						Plot(x0 - x,y0 + y)
						Plot(x0 + x,y0 - y)
						Plot(x0 - x,y0 - y)
						Plot(x0 + y,y0 + x)
						Plot(x0 - y,y0 + x)
						Plot(x0 + y,y0 - x)
						Plot(x0 - y,y0 - x)
					StopDrawing()				
				Else				
					ProcedureReturn 					
				EndIf							
			Else			
				ProcedureReturn 				
			EndIf					
		Else		
			ProcedureReturn 			
		EndIf
		
	Wend

EndProcedure


If OpenWindow(0, 0, 0, 200, 200, "Raster Circle", #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)

	RasterCircle(100,100,10)
	RasterCircle(100,100,20)
	RasterCircle(100,100,40)
	RasterCircle(100,100,80)
	
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  
EndIf

End

Steve Martin

He who waits too long to hesitate…hesitates last.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Just a bit of fun, you may find it helpful or not:

Code: Select all

; Image to start with, we'll just make it blue
CreateImage(0, 640,640,32)
StartDrawing(ImageOutput(0))
  Box(0,0,640,640,#Blue)
  
  ; Our transparent color will be pink, make a pink circle
  Circle(320,320,100,RGB(255,0,255))
  
  ; Now, make all the pink pixels transparent
  *ptr.RGBQUAD = DrawingBuffer()
  For j=0 To 639
    For i=0 To DrawingBufferPitch()-SizeOf(RGBQUAD) Step SizeOf(RGBQUAD)
      If *ptr\rgbRed&$FF=$FF And *ptr\rgbGreen&$FF=0 And *ptr\rgbBlue&$FF=$FF ; Found a pink one!
        *ptr\rgbReserved=0
      Else
        *ptr\rgbReserved=$FF
      EndIf
      *ptr+SizeOf(RGBQUAD)
    Next
  Next
  
  ; All done
StopDrawing()

; Let's see what we got...

OpenWindow(0,0,0,800,700,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)

Repeat
  ev=WaitWindowEvent()
  Select ev
    Case #PB_Event_Repaint
      StartDrawing(WindowOutput(0))
        DrawAlphaImage(ImageID(0),100,50)
      StopDrawing()
  EndSelect
Until ev=#PB_Event_CloseWindow
BERESHEIT
User avatar
Demivec
Addict
Addict
Posts: 4267
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

@netmaestro: I'm not seeing anything but a grey window with your example. XP sp3 x86
cxAlex
User
User
Posts: 88
Joined: Fri Oct 24, 2008 11:29 pm
Location: Austria
Contact:

Post by cxAlex »

Here is a very fast Circle Procedure, it's as fast as PB and sometimes faster:

(Tested on a Intel QuadCore @ 3.2 GHz & 4 GB Ram)

Code: Select all

Procedure _Circle(x0, y0, rad, color = 0)
  Static x, y, rad2, oldcolor
  
  oldcolor = FrontColor(color)
  rad2 = rad*rad
  x = 0
  
  Plot(x0, y0 + rad)
  Plot(x0, y0-rad)
  Plot(x0 + rad, y0)
  Plot(x0-rad, y0)
  
  Repeat
    
    x + 1
    y = Sqr(rad2-x*x)
    
    Plot(x0-x, y0-y)
    Plot(x0-x, y0 + y)
    Plot(x0 + x, y0-y)
    Plot(x0 + x, y0 + y)
    Plot(x0-y, y0-x)
    Plot(x0-y, y0 + x)
    Plot(x0 + y, y0-x)
    Plot(x0 + y, y0 + x)
    
  Until x=>y
  
  FrontColor(oldcolor)
  
EndProcedure
Post Reply