Page 1 of 2

Draw an antialiased circle?

Posted: Fri Feb 20, 2015 1:54 pm
by Dude
I'm using Circle() on an image but it's jaggy. Is there a way (or trick) to do it anti-aliased, so it's got a smooth edge?

Re: Draw an antialiased circle?

Posted: Fri Feb 20, 2015 3:41 pm
by heartbone
As it exists is in this snippet, this method is pretty much unusable in actual applications, but yields the smooth circle that you seek.
After running, a file is in your temp folder for inspection.

Code: Select all

UsePNGImageEncoder()
InitSprite()
OpenWindow(0,0,0,600,600,"SOFTWARE",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,800,600,#True,0,0)
CreateImage(0,1200,1200,32)
StartDrawing(ImageOutput(0))
Circle(600,600,550,$00DDDD)
Circle(600,600,545,$000000)
StopDrawing()
ResizeImage(0,555,555,#PB_Image_Smooth)
StartDrawing(ScreenOutput())
DrawImage(ImageID(0),25,25)
StopDrawing()
FlipBuffers()
SaveImage(0,GetTemporaryDirectory()+"/smoothercircle.png")
Delay(2000)
Depending on the background imagery, if you transform the circle image into a transparent sprite, then you may have a solution.

Re: Draw an antialiased circle?

Posted: Fri Feb 20, 2015 4:02 pm
by IdeasVacuum

Re: Draw an antialiased circle?

Posted: Fri Feb 20, 2015 4:09 pm
by TI-994A
Dude wrote:...Is there a way (or trick) to do it anti-aliased, so it's got a smooth edge?
Hello Dude. The jagged edges are caused by the low screen resolution. The trick would be to draw the circle on a high resolution context, and then transpose it onto the screen, like so:

Code: Select all

wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(0, 0, 0, 500, 500, "Smooth Circle", wFlags)
If CreateImage(0, 2000, 2000, 32, #Red) And StartDrawing(ImageOutput(0))
  Circle(1000, 1000, 900, #Yellow)
  StopDrawing() 
  ResizeImage(0, 500, 500)
  ImageGadget(0, 0, 0, 500, 500, ImageID(0))
EndIf
While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend

Re: Draw an antialiased circle?

Posted: Fri Feb 20, 2015 10:13 pm
by Samuel
You can also use gradients to create anti aliased circles.

Code: Select all

Enumeration
  #Window
  #Canvas
EndEnumeration

Declare AntialiasedCircle(StartX.d, StartY.d, Radius.d, AntiLength.d, Color.i)

Global.i WindowW = 800
Global.i WindowH = 600

If OpenWindow(#Window, 0, 0, WindowW, WindowH, "Antialiased Circle", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

  CanvasGadget(#Canvas, 0, 0, WindowW, WindowH)
  
  StartDrawing(CanvasOutput(#Canvas))
    Box(0, 0, WindowW, WindowH, RGB(30,30,30))
    AntialiasedCircle(WindowW*0.5, WindowH*0.5, 200, 2, RGB(255,0,0))
    AntialiasedCircle(        100,         100,  80, 2, RGB(0,0,255))
    AntialiasedCircle(WindowW-100,         100,  50, 2, RGB(0,255,0))
    AntialiasedCircle(        100, WindowH-100,  50, 2, RGB(0,255,0))
    AntialiasedCircle(WindowW-100, WindowH-100,  80, 2, RGB(0,0,255))
  StopDrawing()
  
  Repeat
    
    Event = WaitWindowEvent()
    
  Until Event = #PB_Event_CloseWindow
  
EndIf
End

Procedure AntialiasedCircle(StartX.d, StartY.d, Radius.d, AntiLength.d, Color.i)
  
  Define.i R,G,B
  Define.d Normal, Value
  
  If Radius <= 0
    Radius = 0.00001
  EndIf
  
  If AntiLength <= 0
    AntiLength = 0.00001
  EndIf
  
  DrawingMode(#PB_2DDrawing_AlphaBlend | #PB_2DDrawing_Gradient)
  
  ResetGradientColors()
  
  R = Red(Color)
  G = Green(Color)
  B = Blue(Color)
  
  Normal = 1 / Radius
  Value  = 1.0 - AntiLength * Normal
  
  GradientColor(  0.0, RGBA(R,G,B,255))
  GradientColor(Value, RGBA(R,G,B,255))
  GradientColor(  1.0, RGBA(R,G,B,0))
  
  CircularGradient(StartX, StartY, Radius)
  Circle(StartX, StartY, Radius)
  
EndProcedure

Re: Draw an antialiased circle?

Posted: Fri Feb 20, 2015 11:41 pm
by luis
Nice idea Samuel.

Re: Draw an antialiased circle?

Posted: Sat Feb 21, 2015 12:08 am
by Little John
luis wrote:Nice idea Samuel.
Yes, indeed! Thanks for sharing, Samuel.

Re: Draw an antialiased circle?

Posted: Sat Feb 21, 2015 3:01 am
by glomph
Wonderful idea Samuel.

I took your example to get also outlined circles.
It does not work for overlapping ones.

Code: Select all

Enumeration
  #Window
  #Canvas
EndEnumeration

Declare AntialiasedCircle(StartX.d, StartY.d, Radius.d,dick.d,AntiLength.d, front,back,art=0)
Global.i WindowW = 800
Global.i WindowH = 600

If OpenWindow(#Window, 0, 0, WindowW, WindowH, "Antialiased Circle", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

  CanvasGadget(#Canvas, 0, 0, WindowW, WindowH)
 
  StartDrawing(CanvasOutput(#Canvas))
    Box(0, 0, WindowW, WindowH, #White ); RGB(30,30,30))
    AntialiasedCircle(WindowW*0.5, WindowH*0.5, 200,7.1, 1, #Red,#White)
    AntialiasedCircle(WindowW*0.5, WindowH*0.5, 100,2, 2, #Blue,#Red,#PB_2DDrawing_Outlined)
    AntialiasedCircle(100,100, 80,2, 3, RGB(0,0,255),#White,#PB_2DDrawing_Outlined)
    AntialiasedCircle(WindowW-100,100, 50, 1.1, 1, RGB(0,255,0), #White, #PB_2DDrawing_Default)
    AntialiasedCircle(100, WindowH-100, 50, 1.1, 1, RGB(0,255,0), #White, #PB_2DDrawing_Outlined)
    AntialiasedCircle(WindowW-100, WindowH-100,  80,1.1,1, #Black,#White, #PB_2DDrawing_Outlined)
  StopDrawing()
 
  Repeat
   
    Event = WaitWindowEvent()
   
  Until Event = #PB_Event_CloseWindow
 
EndIf
End

Procedure AntialiasedCircle(StartX.d, StartY.d, Radius.d,dick.d, AntiLength.d, front,back,art=0)
  Define.i R,G,B
  Define.d Normal, Value
  If art=#PB_2DDrawing_Outlined
    radius+dick/2 ; to get the line in middle off the radius
  EndIf  
  If Radius <= 0
    Radius = 0.00001
  EndIf
 
  If AntiLength <= 0
    AntiLength = 0.00001
  EndIf
 
  DrawingMode(#PB_2DDrawing_AlphaBlend | #PB_2DDrawing_Gradient) ; |#PB_2DDrawing_Transparent)
 
  ResetGradientColors()
 
  R = Red(front)
  G = Green(front)
  B = Blue(front)
 
  Normal = 1 / Radius
  Value  = 1.0 - AntiLength * Normal
 
  GradientColor(  0.0, RGBA(R,G,B,255))
  GradientColor(Value, RGBA(R,G,B,255))
  GradientColor(  1.0, RGBA(R,G,B,0))
 
  CircularGradient(StartX, StartY, Radius)
  Circle(StartX, StartY, Radius)
  If art=#PB_2DDrawing_Outlined
    R = Red(back)
    G = Green(back)
    B = Blue(back)
    radius-dick
    GradientColor(  0.0, RGBA(R,G,B,255))
    GradientColor(Value, RGBA(R,G,B,255))
    GradientColor(  1.0, RGBA(R,G,B,0))
    CircularGradient(StartX, StartY, Radius)
    Circle(StartX, StartY, Radius)
  EndIf
  
EndProcedure

Re: Draw an antialiased circle?

Posted: Sat Feb 21, 2015 3:39 am
by heartbone
That's a nice new trick for an old dog Samuel.
It certainly goes into the bag.
Thanks.

Re: Draw an antialiased circle?

Posted: Sat Feb 21, 2015 3:47 am
by Dude
Thanks for all the awesome responses to my question! :D

Re: Draw an antialiased circle?

Posted: Sat Feb 21, 2015 8:14 pm
by davido
Always wanted smooth circles. Thanks for asking, Dude.

@Samuel
Brilliant. Thank you for sharing.

Re: Draw an antialiased circle?

Posted: Sun Feb 22, 2015 12:42 am
by Michael Vogel
Not bad :lol:

Code: Select all

Enumeration
	#Window
	#Canvas
EndEnumeration

Procedure MyCircle(x,y,radius,color,width=0,mode=0)

	Global MyCircleSmooth=2

	Protected d.d,s.d
	Protected fillcolor
	Protected xxcolor

	width-MyCircleSmooth>>1
	Debug width
	If width
		radius+width>>1
	EndIf

	If radius>0
		s=MyCircleSmooth
		If s<=0
			s=0.0001
		EndIf

		d=1/(radius+s)
		fillcolor=color|$FF000000
		xxcolor=color|$40000000

		DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Gradient)
		ResetGradientColors()

		GradientColor(0,fillcolor)
		If mode=#PB_2DDrawing_Outlined
			GradientColor(0,color)
			GradientColor(d*(radius-width-s),color)
			GradientColor(d*(radius-width-s/2),xxcolor)
			GradientColor(d*(radius-width),fillcolor)
		EndIf
		GradientColor(d*radius,fillcolor)
		GradientColor(d*(radius+s/2),xxcolor)
		GradientColor(1,color)
		CircularGradient(x,y,radius)
		Circle(x,y,radius)

	EndIf

EndProcedure

Global.i WindowW = 800
Global.i WindowH = 600

If OpenWindow(#Window, 0, 0, WindowW, WindowH, "Antialiased Circle", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	CanvasGadget(#Canvas, 0, 0, WindowW, WindowH)
	StartDrawing(CanvasOutput(#Canvas))
	Box(0, 0, WindowW, WindowH, #White ); RGB(30,30,30))
	For i=1 To 15
		MyCircle(50+i*20,50+i*20,50+i*10,Random(#White),i,#PB_2DDrawing_Outlined)
		MyCircle(WindowW-50-i*20,50+i*20,50+i*10,Random(#White),16-i,#PB_2DDrawing_Outlined)
	Next i
	StopDrawing()
	Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf

Re: Draw an antialiased circle?

Posted: Mon Feb 23, 2015 8:45 am
by dige
:shock: Wow! - well done :-)

Re: Draw an antialiased circle?

Posted: Mon Feb 23, 2015 10:59 am
by Dude
I came with some anti-aliasing wrapping macros here: http://www.purebasic.fr/english/viewtop ... 12&t=61721

Re: Draw an antialiased circle?

Posted: Sun May 17, 2015 1:34 pm
by firace
Any simple cross-platform way to have the below circle antialiased AND with no visible surrounding box? Basically I want to see the default window color ($F0F0F0 by default on windows 8, but XP, for instance, has a different shade of gray) around the circle.

Code: Select all

OpenWindow(0, 0, 0, 600, 600, "Smooth Circle")
CreateImage(0, 1000, 1000, 32, $000000)            ;  would like to make this transparent
  StartDrawing(ImageOutput(0))
  Circle(500, 500, 300, $0000FF)
  StopDrawing() 
ResizeImage(0, 500, 500)
ImageGadget(0, 0, 0, 500, 500, ImageID(0))

While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend