Page 1 of 2

Draw arcs, polygons, pies, thick lines, no API calls

Posted: Sun Mar 31, 2013 4:52 pm
by BasicallyPure
I needed a procedure to draw arcs. As a bonus I made one that would also draw regular polygons.

BP

Code: Select all

   Procedure Arc(x, y, start.f, finish.f, radius.f, color = 0, mode = 0)
      ; BasicallyPure 4.2.2013
      ; purpose: draw an arc or regular polygon
      ; this procedure must be used inside a StartDrawing() StopDrawing() block.
      ;
      ; Syntax: Arc(x, y, start, finish, radius, [color], [mode])
      ;
      ; x, y    |  the center location of the arc or polygon.
      ; start   |  the starting angle in degrees.
      ; finish  |  a dual purpose parameter, depends on mode.
      ;         |  if mode = #Arc_Mode_Arc then finish is the arc end point in degrees.
      ;         |  if mode = #Arc_Mode_Polygon then finish is the number of polygon sides.
      ; color   |  optional, sets the line color (default is black).
      ; mode    |  optional, draws arc or polygon (default is Arc).
      
   #Arc_Mode_Arc = 0
   #Arc_Mode_Polygon = 1
   
   Protected xx, yy, px, py, inc.f, ang.f, fin.f
   
   Select mode
      Case #Arc_Mode_Arc
         If start > finish : Swap start, finish : EndIf
         If finish - start > 360 : finish = start + 360 : EndIf
         inc = 0.1 ; arc smoothness
      Case #Arc_Mode_Polygon
         If finish < 3 : finish = 3 : EndIf
         If finish > 64 : finish = 64 : EndIf
         inc = Radian(360 / finish)
         finish = start + 360
      Default
         ProcedureReturn 0
   EndSelect
   
   ang = Radian(start)
   fin = Radian(finish)
   px = x + Cos(ang) * radius
   py = y + Sin(ang) * radius
   
   Repeat
      ang + inc
      If ang > fin : ang = fin : EndIf
      xx = x + Cos(ang) * radius
      yy = y + Sin(ang) * radius
      LineXY(px, py, xx, yy, color)
      px = xx
      py = yy
   Until ang = fin
   
EndProcedure

; <><><><><><><><><> and now a demonstration <><><><><><><><><>

Procedure  InitGUI()
   Global  s = 0, f = 180, r = 150
   
   If Not OpenWindow(0, 200, 100, 800, 800, "ARC & POLYGON DEMO") : End : EndIf
   
   CanvasGadget(0, 0, 0, 800, 650)
   TrackBarGadget(1, 60, 700, 600, 25, 0, 300) : SetGadgetState(1, r) ; radius
   TrackBarGadget(2, 60, 730, 600, 25, 0, 720) : SetGadgetState(2, s+360) ; start
   TrackBarGadget(3, 60, 760, 600, 25, 0, 720) : SetGadgetState(3, f+360) ; finish
   
   TextGadget(#PB_Any,10, 670, 45, 25, "Mode")
   TextGadget(#PB_Any,10, 700, 45, 25, "Radius")
   TextGadget(#PB_Any,10, 730, 45, 25, "Start")
   TextGadget(#PB_Any,10, 760, 45, 25, "Finish")
   
   StringGadget(4, 670, 700, 45, 25, Str(r))
   StringGadget(5, 670, 730, 45, 25, Str(s))
   StringGadget(6, 670, 760, 45, 25, Str(f))
   
   OptionGadget(7, 060, 670, 45, 25, "Arc") : SetGadgetState(7,1)
   OptionGadget(8, 115, 670, 55, 25, "Polygon")
   
EndProcedure


Procedure DrawObject()
   StartDrawing(CanvasOutput(0))
      Box(0,0,800,650, $0B94CB)
      ;Circle(400, 330, 2, 0) ; optional
      If GetGadgetState(7)
         arc(400, 325, s, f, r, 0, #Arc_Mode_Arc)
      Else
         arc(400, 325, s, f, r, 0, #Arc_Mode_Polygon)
      EndIf
   StopDrawing()
EndProcedure


Procedure EventLoop()
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_Gadget
            Select EventGadget()
               Case 1 ; radius
                  r = GetGadgetState(1)
                  SetGadgetText(4, Str(r))
                  DrawObject()
               Case 2 ; start
                  s = GetGadgetState(2) - 360
                  SetGadgetText(5, Str(s))
                  DrawObject()
               Case 3 ; finish
                  f = GetGadgetState(3) - 360
                  If GetGadgetState(8)
                     f = Abs(f) / 36
                  EndIf
                  SetGadgetText(6, Str(f))
                  DrawObject()
               Case 7 ; Arc mode
                  f = GetGadgetState(3) - 360
                  SetGadgetText(6, Str(f))
                  DrawObject()
               Case 8 ; polygon mode
                  f = Abs(f) / 36
                  SetGadgetText(6, Str(f))
                  DrawObject()
            EndSelect
         Case #PB_Event_CloseWindow
            Break
      EndSelect
   ForEver
EndProcedure

InitGUI()
DrawObject()
EventLoop()

End

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Sun Mar 31, 2013 5:46 pm
by Demivec
Thanks, the code to draw arcs is great! :)

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Sun Mar 31, 2013 10:22 pm
by falsam
Yes the code is great. Adopted in the code box. :)

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Sun Mar 31, 2013 10:36 pm
by luis
Nice and pretty demo :)

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Sun Mar 31, 2013 10:59 pm
by idle
nice

added orientation and major and minor axis
to orientate and create elliptic arcs

Code: Select all


  

Procedure Arc(x, y, start.f, finish.f,majoraxis.f,minoraxis.f=0,orient.f=0,color = 0, mode = 0)
      ; BasicallyPure 3.31.2013
      ; Idle added eliptic function
      ; purpose: draw an arc or regular polygon
      ; this procedure must be used inside a StartDrawing() StopDrawing() block.
      ;
      ; Syntax: Arc(x, y, start, finish, MajorAxis, MinorAxis, [Orient], [color], [mode])
      ;
      ; x, y      |  the center location of the arc or polygon.
      ; start     |  the starting angle of arc in degrees.
      ; finish    |  a dual purpose parameter, depends on mode.
      ;           |  if mode = #Arc_Mode_Arc then finish is the arc end point in degrees.
      ;           |  if mode = #Arc_Mode_Polygon then finish is the number of polygon sides.
      ; MajorAxis |  width of elliptic
      ; MinorAxis |  Height of elliptic
      ; Orient    |  Orientation of 0 to 360 
      ; color   |  optional, sets the line color (default is black).
      ; mode    |  optional, draws arc or polygon (default is Arc).
      
   #Arc_Mode_Arc = 0
   #Arc_Mode_Polygon = 1
   
   Protected xx, yy, px, py, inc.f, ang.f, fin.f
   Protected ndx.f,ndy.f,dy.f,dx.f,dx1,dy1,cosOrient.f,SinOrient.f
   
   Select mode
      Case #Arc_Mode_Arc
         If start > finish : Swap start, finish : EndIf
         If finish - start > 360 : finish = start + 360 : EndIf
         inc = 0.1 ; arc smoothness
      Case #Arc_Mode_Polygon
         If finish < 3 : finish = 3 : EndIf
         If finish > 64 : finish = 64 : EndIf
         inc = Radian(360 / finish)
         finish = start + 360
      Default
         ProcedureReturn 0
   EndSelect
         
   
   ang = Radian(start)
   fin = Radian(finish)
   cosOrient = Sin(Radian(orient-180)) ;0 To 360
   sinOrient = Cos(Radian(orient-180))  
   dx = x + (Cos(ang) * majoraxis) 
   dy = y + (Sin(ang) * minoraxis) 
   dx1 = dx - x 
   dy1 = dy - y
   px = x + (dx1 * sinOrient - dy1 * cosOrient) ;rotate elipse
   py = y + (dx1 * cosOrient + dy1 * sinOrient)
   
    ;draw elipse 
   Repeat 
     ang + inc  
     dx = x + (Cos(ang) * majoraxis) 
     dy = y + (Sin(ang) * minoraxis) 
     dx1 = dx - x 
     dy1 = dy - y
     ndx = x + (dx1 * sinOrient - dy1 * cosorient) ;rotate elipse
     ndy = y + (dx1 * cosOrient + dy1 * sinorient)
     LineXY(px, py, ndx, ndy, color)
     px = ndx
     py = ndy
   Until ang >= fin
      
EndProcedure

; <><><><><><><><><> and now a demonstration <><><><><><><><><>
Enumeration 1 
  #Orient 
  #MajorAxis
  #MinorAxis 
  #Start
  #Finish
  #Arc
  #Poly
  #SOrient
  #SMajor
  #SMinor
  #sStart
  #SFinish 
EndEnumeration  
  
Procedure  InitGUI()
   Global  s = 0, f = 180, majoraxis = 150, minoraxis=150, orient=0
   
   If Not OpenWindow(0, 200, 100, 800, 660, "ARC & POLYGON DEMO") : End : EndIf
   
   TrackBarGadget(#Orient, 60, 500, 600, 25, 0, 360) : SetGadgetState(#Orient, orient) ; orient
   TrackBarGadget(#MajorAxis, 60,530, 600, 25, 0, 300) : SetGadgetState(#MajorAxis, majoraxis) ; majoraxis
   TrackBarGadget(#MinorAxis, 60, 560, 600, 25, 0, 300) : SetGadgetState(#MinorAxis, minoraxis) ; minoraxis  
   TrackBarGadget(#Start, 60, 590, 600, 25, 0, 720) : SetGadgetState(#start, s+360) ; start
   TrackBarGadget(#Finish, 60, 620, 600, 25, 0, 720) : SetGadgetState(#finish, f+360) ; finish
   
   TextGadget(#PB_Any,10, 470, 45, 25, "Mode")
   TextGadget(#PB_Any,10, 500, 45, 25, "Orient")
   TextGadget(#PB_Any,10, 530, 45, 25, "MajorAxis")
   TextGadget(#PB_Any,10, 560, 45, 25, "MinorAxis")
   
   TextGadget(#PB_Any,10, 590, 45, 25, "Start")
   TextGadget(#PB_Any,10, 620, 45, 25, "Finish")
   
   StringGadget(#SOrient, 670, 500, 45, 25, Str(orient))
   StringGadget(#SMajor, 670, 530, 45, 25, Str(majoraxis))
   StringGadget(#SMinor, 670, 560, 45, 25, Str(minoraxis))
   StringGadget(#sStart, 670, 590, 45, 25, Str(s))
   StringGadget(#SFinish, 670, 620, 45, 25, Str(f))
   
   OptionGadget(#arc, 60, 470, 45, 25, "Arc") : SetGadgetState(#arc,1)
   OptionGadget(#poly, 115, 470, 65, 25, "Polygon")
  
   
   
EndProcedure


Procedure DrawObject()
   StartDrawing(WindowOutput(0))
      Box(0,0,800,450, $0B94CB)
      ;Circle(400, 330, 2, 0) ; optional
      If GetGadgetState(#Arc)
         arc(400, 225, s, f, majoraxis,minoraxis,orient,0, #Arc_Mode_Arc)
      Else
         arc(400, 225, s, f, majoraxis,minoraxis,orient,0,#Arc_Mode_Polygon)
      EndIf
   StopDrawing()
EndProcedure


Procedure EventLoop()
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_Gadget
            Select EventGadget()
               Case #Orient 
                  orient = GetGadgetState(#Orient)
                  SetGadgetText(#SOrient,Str(orient))
                  DrawObject()
               Case #MajorAxis ; radius
                  majoraxis = GetGadgetState(#MajorAxis)
                  SetGadgetText(#SMajor, Str(majoraxis))
                  DrawObject()
               Case #MinorAxis ; minor
                  minoraxis = GetGadgetState(#MinorAxis)
                  SetGadgetText(#SMinor, Str(minoraxis))
                  DrawObject()   
               Case #Start ; start
                  s = GetGadgetState(#Start) - 360
                  SetGadgetText(#sStart, Str(s))
                  DrawObject()
               Case #Finish ; finish
                  f = GetGadgetState(#Finish) - 360
                  If GetGadgetState(#Poly)
                     f = Abs(f) / 36
                  EndIf
                  SetGadgetText(#SFinish, Str(f))
                  DrawObject()
               Case #Arc ; Arc mode
                  f = GetGadgetState(#Finish) - 360
                  SetGadgetText(#SFinish, Str(f))
                  DrawObject()
               Case #poly ; polygon mode
                  f = Abs(f) / 36
                  SetGadgetText(#SFinish, Str(f))
                  DrawObject()
               EndSelect
         Case #PB_Event_CloseWindow
            Break
      EndSelect
   ForEver
EndProcedure

InitGUI()
DrawObject()
EventLoop()

End

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Mon Apr 01, 2013 1:02 am
by BasicallyPure
Very good idle, I like the upgrade.

I notice one problem with your code, if start and finish are the same then there is a small line, not a point as it should be.
If you change the drawing loop like this then it will work.
What do you think?

BP

Code: Select all

    ;draw elipse 
   Repeat 
     ang + inc
     If ang > fin : ang = fin : EndIf ; <----- added this line
     dx = x + (Cos(ang) * majoraxis) 
     dy = y + (Sin(ang) * minoraxis) 
     dx1 = dx - x 
     dy1 = dy - y
     ndx = x + (dx1 * sinOrient - dy1 * cosorient) ;rotate elipse
     ndy = y + (dx1 * cosOrient + dy1 * sinorient)
     LineXY(px, py, ndx, ndy, color)
     px = ndx
     py = ndy
   Until ang = fin ; <----- removed >

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Mon Apr 01, 2013 4:55 am
by idle
thanks for the fix BP

Added line thickness routine

Code: Select all


Macro mPlot(x,y,color,thickness)
  If thickness  
    Circle(x,y,thickness/2,color)
  EndIf  
EndMacro 

Procedure BresenhamLine(x0 ,y0 ,x1 ,y1,color=0,thickness=1)
     If Abs(y1 - y0) > Abs(x1 - x0);
        steep =#True 
        Swap x0, y0
        Swap x1, y1
     EndIf    
     If x0 > x1 
         Swap x0, x1
         Swap y0, y1
     EndIf 
     deltax = x1 - x0
     deltay = Abs(y1 - y0)
     error = deltax / 2
     y = y0
     If y0 < y1  
        ystep = 1
     Else
        ystep = -1 
     EndIf 
     For x = x0 To x1
         If steep 
           mPlot(y,x,color,thickness)
         Else 
           mPlot(x,y,color,thickness)
         EndIf
         error - deltay
         If error < 0 
             y + ystep
             error + deltax
         EndIf
     Next        
EndProcedure
  

Procedure Arc(x, y, start.f, finish.f,majoraxis.f,minoraxis.f=0,orient.f=0,color = 0,thickness=1,mode = 0)
      ; BasicallyPure 3.31.2013
      ; Idle added eliptic function
      ; purpose: draw an arc or regular polygon
      ; this procedure must be used inside a StartDrawing() StopDrawing() block.
      ;
      ; Syntax: Arc(x, y, start, finish, MajorAxis, MinorAxis, [Orient], [color], [mode])
      ;
      ; x, y      |  the center location of the arc or polygon.
      ; start     |  the starting angle of arc in degrees.
      ; finish    |  a dual purpose parameter, depends on mode.
      ;           |  if mode = #Arc_Mode_Arc then finish is the arc end point in degrees.
      ;           |  if mode = #Arc_Mode_Polygon then finish is the number of polygon sides.
      ; MajorAxis |  width of elliptic
      ; MinorAxis |  Height of elliptic
      ; Orient    |  Orientation of 0 to 360 
      ; color     |  optional, sets the line color (default is black).
      ; thickness |  Line thickness
      ; mode      |  optional, draws arc or polygon (default is Arc).
      
   #Arc_Mode_Arc = 0
   #Arc_Mode_Polygon = 1
   
   Protected xx, yy, px, py, inc.f, ang.f, fin.f
   Protected ndx.f,ndy.f,dy.f,dx.f,dx1,dy1,cosOrient.f,SinOrient.f
   
   Select mode
      Case #Arc_Mode_Arc
         If start > finish : Swap start, finish : EndIf
         If finish - start > 360 : finish = start + 360 : EndIf
         inc = 0.1 ; arc smoothness
      Case #Arc_Mode_Polygon
         If finish < 3 : finish = 3 : EndIf
         If finish > 64 : finish = 64 : EndIf
         inc = Radian(360 / finish)
         finish = start + 360
      Default
         ProcedureReturn 0
   EndSelect
         
   
   ang = Radian(start)
   fin = Radian(finish)
   cosOrient = Sin(Radian(orient-180)) ;0 To 360
   sinOrient = Cos(Radian(orient-180))  
   dx = x + (Cos(ang) * majoraxis) 
   dy = y + (Sin(ang) * minoraxis) 
   dx1 = dx - x 
   dy1 = dy - y
   px = x + (dx1 * sinOrient - dy1 * cosOrient) ;rotate elipse
   py = y + (dx1 * cosOrient + dy1 * sinOrient)
   
    ;draw elipse 
   Repeat 
     ang + inc  
     If ang > fin : ang = fin : EndIf
     dx = x + (Cos(ang) * majoraxis) 
     dy = y + (Sin(ang) * minoraxis) 
     dx1 = dx - x 
     dy1 = dy - y
     ndx = x + (dx1 * sinOrient - dy1 * cosorient) ;rotate elipse
     ndy = y + (dx1 * cosOrient + dy1 * sinorient)
     
     BresenhamLine(px,py,ndx,ndy,0,thickness)
    
     px = ndx
     py = ndy
   Until ang = fin
      
EndProcedure

; <><><><><><><><><> and now a demonstration <><><><><><><><><>
Enumeration 1 
  #image 
  #Orient 
  #MajorAxis
  #MinorAxis 
  #Start
  #Finish
  #Arc
  #Poly
  #thick
  #SOrient
  #SMajor
  #SMinor
  #sStart
  #SFinish
  
EndEnumeration  
  
Procedure  InitGUI()
   Global  s = 0, f = 180, majoraxis = 150, minoraxis=150, orient=0,thickness=1
   
   If Not OpenWindow(0, 200, 100, 800, 660, "ARC & POLYGON DEMO") : End : EndIf
   
   ImageGadget(#image,0,0,800,450,0)
   TrackBarGadget(#Orient, 60, 500, 600, 25, 0, 360) : SetGadgetState(#Orient, orient) ; orient
   TrackBarGadget(#MajorAxis, 60,530, 600, 25, 0, 300) : SetGadgetState(#MajorAxis, majoraxis) ; majoraxis
   TrackBarGadget(#MinorAxis, 60, 560, 600, 25, 0, 300) : SetGadgetState(#MinorAxis, minoraxis) ; minoraxis  
   TrackBarGadget(#Start, 60, 590, 600, 25, 0, 720) : SetGadgetState(#start, s+360) ; start
   TrackBarGadget(#Finish, 60, 620, 600, 25, 0, 720) : SetGadgetState(#finish, f+360) ; finish
   
   TextGadget(#PB_Any,10, 470, 45, 25, "Mode")
   TextGadget(#PB_Any,10, 500, 45, 25, "Orient")
   TextGadget(#PB_Any,10, 530, 45, 25, "MajorAxis")
   TextGadget(#PB_Any,10, 560, 45, 25, "MinorAxis")
   
   TextGadget(#PB_Any,10, 590, 45, 25, "Start")
   TextGadget(#PB_Any,10, 620, 45, 25, "Finish")
   
   StringGadget(#SOrient, 670, 500, 45, 25, Str(orient))
   StringGadget(#SMajor, 670, 530, 45, 25, Str(majoraxis))
   StringGadget(#SMinor, 670, 560, 45, 25, Str(minoraxis))
   StringGadget(#sStart, 670, 590, 45, 25, Str(s))
   StringGadget(#SFinish, 670, 620, 45, 25, Str(f))
   
   OptionGadget(#arc, 60, 470, 45, 25, "Arc") : SetGadgetState(#arc,1)
   OptionGadget(#poly, 115, 470, 65, 25, "Polygon")
   TextGadget(#PB_Any,190,470,65,25,"Thickness")
   SpinGadget(#thick,256,470,60,25,1,30,#PB_Spin_Numeric) : SetGadgetState(#thick,1)
   
   
EndProcedure


Procedure DrawObject()
   Static img 
   If Not img 
      img = CreateImage(#PB_Any,800,450)
   EndIf    
   StartDrawing(ImageOutput(img))
   Box(0,0,800,450, $0B94CB)
   If GetGadgetState(#Arc)
      arc(400, 225, s, f, majoraxis,minoraxis,orient,0,thickness,#Arc_Mode_Arc)
   Else
      arc(400, 225, s, f, majoraxis,minoraxis,orient,0,thickness,#Arc_Mode_Polygon)
   EndIf
   StopDrawing()
   SetGadgetState(#image,ImageID(img))
EndProcedure


Procedure EventLoop()
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_Gadget
            Select EventGadget()
               Case #Orient 
                  orient = GetGadgetState(#Orient)
                  SetGadgetText(#SOrient,Str(orient))
                  DrawObject()
               Case #MajorAxis ; radius
                  majoraxis = GetGadgetState(#MajorAxis)
                  SetGadgetText(#SMajor, Str(majoraxis))
                  DrawObject()
               Case #MinorAxis ; minor
                  minoraxis = GetGadgetState(#MinorAxis)
                  SetGadgetText(#SMinor, Str(minoraxis))
                  DrawObject()   
               Case #Start ; start
                  s = GetGadgetState(#Start) - 360
                  SetGadgetText(#sStart, Str(s))
                  DrawObject()
               Case #Finish ; finish
                  f = GetGadgetState(#Finish) - 360
                  If GetGadgetState(#Poly)
                     f = Abs(f) / 36
                  EndIf
                  SetGadgetText(#SFinish, Str(f))
                  DrawObject()
               Case #Arc ; Arc mode
                  f = GetGadgetState(#Finish) - 360
                  SetGadgetText(#SFinish, Str(f))
                  DrawObject()
               Case #poly ; polygon mode
                  f = Abs(f) / 36
                  SetGadgetText(#SFinish, Str(f))
                  DrawObject()
               Case #thick 
                  thickness = GetGadgetState(#thick) 
                  DrawObject()
            EndSelect
         Case #PB_Event_CloseWindow
            Break
      EndSelect
   ForEver
EndProcedure

InitGUI()
DrawObject()
EventLoop()

End


Re: Procedure to draw arc or regular polygon, no API calls

Posted: Mon Apr 01, 2013 5:17 pm
by BasicallyPure
Excellent!
Teamwork gets it done.

I noticed if the line goes outside the drawing area it will crash because of 'Plot(x,y,color).
A possible solution?

Code: Select all

;Macro mPlot(x,y,color,thickness,AA) ; <---- 'AA' not used
Macro mPlot(x,y,color,thickness)
  If thickness = 1 
     ;Plot(x,y,color) ; <---- will crash if line goes outside drawing area
     Circle(x,y,0,color) ; <---- this seems to work
  Else 
    Circle(x,y,thickness/2,color)
  EndIf
EndMacro

Code: Select all

If steep
   ;mPlot(y,x,color,thickness,1) ; don't need the ',1'
   mPlot(y,x,color,thickness)
Else 
   ;mPlot(x,y,color,thickness,1) ; don't need the ',1'
   mPlot(x,y,color,thickness)
EndIf

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Mon Apr 01, 2013 7:47 pm
by idle
edited the code in the previous post

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Tue Apr 02, 2013 12:56 pm
by Golfy
I would to know if it's possible to have a filled arc.
Something like having 3/4 of a circle would show a kind of circle minus a box...

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Tue Apr 02, 2013 7:58 pm
by BasicallyPure
Golfy wrote:I would to know if it's possible to have a filled arc.
Something like having 3/4 of a circle would show a kind of circle minus a box...

Code: Select all

Procedure Pie(x, y, start.f, finish.f, radius.f, color = 0)
   ; BasicallyPure 4.2.2013
   ; purpose: draw a filled Pie chart
   ; this procedure must be used inside a StartDrawing() StopDrawing() block.
   
   Protected x0, y0, x1, y1, xf, yf
   
   If start > finish : start - 360 : EndIf
   If finish - start > 360 : finish = start + 360 : EndIf
   
   DrawingMode(#PB_2DDrawing_Outlined)
   Circle(x, y, radius, color)
   
   x0 = x + Cos(Radian(start)) * radius
   y0 = y + Sin(Radian(start)) * radius
   x1 = x + Cos(Radian(finish)) * radius
   y1 = y + Sin(Radian(finish)) * radius
   
   LineXY(x0, y0, x, y, color)
   LineXY(x, y, x1, y1, color)
   
   xf = radius/2 * (Cos(Radian((start+finish)/2))) + x
   yf = radius/2 * (Sin(Radian((start+finish)/2))) + y
   FillArea(xf, yf, color, color ! 1)
EndProcedure


Procedure DrawPie()
   Shared x, y, start.f, finish.f, radius, color
   
   StartDrawing(CanvasOutput(0))
      Box(0, 0, 800, 600, $0A94CB)
      Pie(x, y, start, finish, radius, color)
   StopDrawing()

EndProcedure


If OpenWindow(0, 200, 100, 800, 650, "Filled Pie Demo")
   
   CanvasGadget(0,0, 0, 800, 600)
   TrackBarGadget(1,10, 615, 600, 25, 0, 360)
   SetGadgetState(1,270)
   
   x = 400
   y = 300
   start.f = 0
   finish.f = 270
   radius = 200
   color = $FF0000
   
   DrawPie()
   
   Repeat 
      Select WaitWindowEvent()
         Case #PB_Event_CloseWindow
            Break
         Case #PB_Event_Gadget
            If EventGadget() = 1
               finish = GetGadgetState(1)
               DrawPie()
            EndIf
      EndSelect
   ForEver
   
EndIf

Re: Procedure to draw arc or regular polygon, no API calls

Posted: Tue Apr 02, 2013 9:20 pm
by idle
abstracted it a little added Pie fill and helper functions

Code: Select all

;Arcs Polygons Pies
;BasicallyPure, Idle 
;3/4/13

EnableExplicit 

Procedure _Line(x1, y1, x2, y2,color=0,width=1)
   Protected dx,dy,e2,err,sx,sy
   width = width * 2 - 2
   dx = Abs(x2-x1) : dy = Abs(y2-y1) : err = dx - dy
   
   If x1 < x2 : sx = 1 : Else : sx = -1 : EndIf
   If y1 < y2 : sy = 1 : Else : sy = -1 : EndIf
   
   Repeat
      Circle(x1, y1, width, color)
      If x1 = x2 And y1 = y2 : Break : EndIf
      e2 = err << 1
      If e2 > -dy : err - dy : x1 + sx : EndIf
      If e2 <  dx : err + dx : y1 + sy : EndIf
   ForEver
   
EndProcedure

CompilerIf Not Defined(point,#PB_Structure) 
 Structure Point
   x.i
   y.i
 EndStructure   
CompilerEndIf 

Structure ArcData
  astart.point
  aend.point
EndStructure

#Arc_Mode_Arc = 0
#Arc_Mode_Polygon = 1


Procedure _Arc(x,y,degrees.i,majoraxis.i,minoraxis.i=0,orient.i=0,color=0,thickness=1,mode=#Arc_Mode_Arc,*arc.ArcData=0,Fill=0,FillColor=$FFFFFF)
   ; BasicallyPure 3.31.2013
   ; Idle added eliptic,orientation,bresenham,thickness
   ; purpose: draw an arc or regular polygon
   ; this procedure must be used inside a StartDrawing() StopDrawing() block.
   ;
   ; Syntax: Arc(x,y,degrees,MajorAxis, MinorAxis, [Orient], [color],[thickness],[mode],[*arc])
   ;
   ; x, y      |  the center location of the arc or polygon.
   ; Degrees   |  degree of arc or the number of sides of a polygon 
   ;           |   if mode = #Arc_Mode_Arc: how many degrees of the arc.
   ;           |   if mode = #Arc_Mode_Polygon: number of polygon sides.
   ; MajorAxis |  width of elliptic
   ; MinorAxis |  Height of elliptic
   ; Orient    |  Orientation of 0 to 360 
   ; color     |  optional, sets the line color (default is black).
   ; thickness |  optional, Line thickness
   ; mode      |  optional, draws arc or polygon (default is Arc).
   ; *arc      |  optional, pointer to arcdata structure to store start and end points
   
   Protected xx, yy, px, py, inc.f, ang.f, fin.f
   Protected ndx.f,ndy.f,dy.f,dx.f,dx1,dy1,cosOrient.f,SinOrient.f
   Protected start.i,finish.i
   start = 0 : finish=degrees 
   
   Select mode
      Case #Arc_Mode_Arc
         If start > finish : Swap start, finish : EndIf
         If finish - start > 360 : finish = start + 360 : EndIf
         inc = 0.1 ; arc smoothness
      Case #Arc_Mode_Polygon
         If finish < 3 : finish = 3 : EndIf
         If finish > 64 : finish = 64 : EndIf
         inc = Radian(360 / finish)
         finish = start + 360
      Default
         ProcedureReturn 0
   EndSelect
         
   
   ang = Radian(start)
   fin = Radian(finish)
   cosOrient = Sin(Radian(orient-180)) ;0 To 360
   sinOrient = Cos(Radian(orient-180))  
   dx = x + (Cos(ang) * majoraxis) 
   dy = y + (Sin(ang) * minoraxis) 
   dx1 = dx - x 
   dy1 = dy - y
   px = x + (dx1 * sinOrient - dy1 * cosOrient) ;rotate elipse
   py = y + (dx1 * cosOrient + dy1 * sinOrient)
   
   If *arc 
      *arc\astart\x = px
      *arc\astart\y = py
   EndIf  
    ;draw elipse 
   Repeat 
     ang + inc  
     If ang > fin : ang = fin : EndIf
     dx = x + (Cos(ang) * majoraxis) 
     dy = y + (Sin(ang) * minoraxis) 
     dx1 = dx - x 
     dy1 = dy - y
     ndx = x + (dx1 * sinOrient - dy1 * cosorient) ;rotate elipse
     ndy = y + (dx1 * cosOrient + dy1 * sinorient)
     
     _Line(px,py,ndx,ndy,0,thickness)
    
     px = ndx
     py = ndy
   Until ang = fin
   
   If *arc
      *arc\aend\x = px
      *arc\aend\y = py 
   EndIf    
   
   If Fill 
     If mode = #Arc_Mode_Polygon
        FillArea(x,y,color,FillColor)
     EndIf 
   EndIf   
   
EndProcedure
;-Public Helper functions  
Procedure Arc(x,y,degrees.i,majoraxis.i,minoraxis.i,orient.i,color=0,thickness=1) 
  _arc(x,y,degrees,majoraxis,minoraxis,orient,color,thickness) 
EndProcedure 

Procedure Polygon(x,y,sides.i,majoraxis.i,minoraxis.i=0,orient.i=0,color=0,thickness=1,Fill=0,FillColor=$FFFFFF)
   _arc(x,y,sides,majoraxis,minoraxis,orient,color,thickness,#Arc_Mode_Polygon,0,Fill,FillColor) 
EndProcedure    

Procedure Pie(x,y,degrees.i,radius.i,orient.i=0,color=0,thickness=1,Fill=0,FillColor=$FFFFFF)  
   Protected pts.ArcData,ang.f,dx.f,dy.f,dx1.f,dy1.f,px,py,cosOrient.f,sinOrient.f 
   _arc(x,y,degrees,radius,radius,orient,color,thickness,#Arc_Mode_Arc,@pts) 
   _Line(x,y,pts\astart\x,pts\astart\y,color,thickness)
   _Line(x,y,pts\aend\x,pts\aend\y,color,thickness)
   If Fill 
      ang = Radian(degrees/2) 
      cosOrient = Sin(Radian(orient-180)) ;0 To 360
      sinOrient = Cos(Radian(orient-180))  
      dx = x + (Cos(ang) * radius/2) 
      dy = y + (Sin(ang) * radius/2) 
      dx1 = dx - x 
      dy1 = dy - y
      px = x + (dx1 * sinOrient - dy1 * cosOrient) ;rotate elipse
      py = y + (dx1 * cosOrient + dy1 * sinOrient)
      FillArea(px,py,color,FillColor)
   EndIf 
EndProcedure    

Procedure BLine(x1,y1,x2,y2,color=0,thickness=1)
   _Line(x1,y1,x2,y2,color,thickness)
EndProcedure    


;-<><><> and now a demonstration <><><>
Enumeration 1 
  #image 
  #Orient 
  #MajorAxis
  #MinorAxis 
  #Degrees
  #Arc
  #Poly
  #Pie
  #thick
  #SOrient
  #SMajor
  #SMinor
  #sDegrees
  #SFinish
  
EndEnumeration  
  
Procedure  InitGUI()
   Global  degrees = 180, f = 180, majoraxis = 150, minoraxis=150, orient=0, thickness=1
   
   If Not OpenWindow(0, 200, 100, 800, 630, "ARC & POLYGON DEMO") : End : EndIf
   
   ImageGadget(#image,0,0,800,450,0)
   TrackBarGadget(#Orient, 60, 500, 600, 25, 0, 360) : SetGadgetState(#Orient, orient) ; orient
   TrackBarGadget(#MajorAxis, 60,530, 600, 25, 0, 300) : SetGadgetState(#MajorAxis, majoraxis) ; majoraxis
   TrackBarGadget(#MinorAxis, 60, 560, 600, 25, 0, 300) : SetGadgetState(#MinorAxis, minoraxis) ; minoraxis  
   TrackBarGadget(#Degrees, 60, 590, 600, 25, 0, 720) : SetGadgetState(#Degrees, degrees+360) ; start
  
   
   TextGadget(#PB_Any,10, 470, 45, 25, "Mode")
   TextGadget(#PB_Any,10, 500, 45, 25, "Orient")
   TextGadget(#PB_Any,10, 530, 45, 25, "MajorAxis")
   TextGadget(#PB_Any,10, 560, 45, 25, "MinorAxis")
   
   TextGadget(#PB_Any,10, 590, 45, 25, "Degrees")
  
   
   StringGadget(#SOrient, 670, 500, 45, 25, Str(orient))
   StringGadget(#SMajor, 670, 530, 45, 25, Str(majoraxis))
   StringGadget(#SMinor, 670, 560, 45, 25, Str(minoraxis))
   StringGadget(#sDegrees, 670, 590, 45, 25, Str(degrees))
  
   
   OptionGadget(#arc, 60, 470, 45, 25, "Arc") : SetGadgetState(#arc,1)
   OptionGadget(#poly, 115, 470, 65, 25, "Polygon")
   OptionGadget(#pie, 190, 470, 65, 25, "Pie")
   TextGadget(#PB_Any,256,470,65,25,"Thickness")
   SpinGadget(#thick,336,470,60,25,1,100,#PB_Spin_Numeric) : SetGadgetState(#thick,1)
   
   
EndProcedure


Procedure DrawObject()
   Static img 
   If Not img 
      img = CreateImage(#PB_Any,800,450)
   EndIf    
   StartDrawing(ImageOutput(img))
   Box(0,0,800,450, $0B94CB)
   If GetGadgetState(#Arc)
      arc(400, 225,degrees,majoraxis,minoraxis,orient,0,thickness)
   ElseIf GetGadgetState(#Poly)
      Polygon(400,225,degrees,majoraxis,minoraxis,orient,0,thickness,1)
   Else 
      pie(400, 225,degrees,majoraxis,orient,0,thickness,1) 
   EndIf
   StopDrawing()
   SetGadgetState(#image,ImageID(img))
EndProcedure


Procedure EventLoop()
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_Gadget
            Select EventGadget()
               Case #Orient 
                  orient = GetGadgetState(#Orient)
                  SetGadgetText(#SOrient,Str(orient))
                  DrawObject()
               Case #MajorAxis ; radius
                  majoraxis = GetGadgetState(#MajorAxis)
                  SetGadgetText(#SMajor, Str(majoraxis))
                  DrawObject()
               Case #MinorAxis ; minor
                  minoraxis = GetGadgetState(#MinorAxis)
                  SetGadgetText(#SMinor, Str(minoraxis))
                  DrawObject()   
               Case #Degrees ; start
                  degrees = GetGadgetState(#Degrees) - 360
                  If GetGadgetState(#Poly)
                     degrees = Abs(degrees) / 12
                  EndIf
                  SetGadgetText(#sDegrees, Str(degrees))
                  DrawObject()
              Case #Arc ; Arc mode
                  degrees = GetGadgetState(#Degrees) - 360
                  SetGadgetText(#SDegrees, Str(degrees))
                  DrawObject()
               Case #poly ; polygon mode
                  degrees = Abs(degrees) / 12
                  SetGadgetText(#sDegrees, Str(degrees))
                  DrawObject()
               Case #Pie
                  degrees = GetGadgetState(#Degrees) - 360
                  SetGadgetText(#SDegrees, Str(degrees))
                  DrawObject()
               Case #thick 
                  thickness = GetGadgetState(#thick) 
                  DrawObject()
            EndSelect
         Case #PB_Event_CloseWindow
            Break
      EndSelect
   ForEver
EndProcedure

InitGUI()
DrawObject()
EventLoop()

End



Re: Procedure to draw arc or regular polygon, no API calls

Posted: Wed Apr 03, 2013 12:25 am
by BasicallyPure
Nice idle.

If all you need is to draw some thick lines you can use this short procedure.
A simplified version of the Bresenham line algorithm.

Code: Select all

Procedure ThickLine(x1, y1, x2, y2, width, color)
   Protected dx, dy, e2, err, sx, sy
   
   If width < 1 : width = 1 : EndIf
   
   width - 1
   dx = Abs(x2-x1) : dy = Abs(y2-y1) : err = dx - dy
   
   If x1 < x2 : sx = 1 : Else : sx = -1 : EndIf
   If y1 < y2 : sy = 1 : Else : sy = -1 : EndIf
   
   Repeat
      Circle(x1, y1, width, color)
      If x1 = x2 And y1 = y2 : Break : EndIf
      e2 = err << 1
      If e2 > -dy : err - dy : x1 + sx : EndIf
      If e2 <  dx : err + dx : y1 + sy : EndIf
   ForEver
EndProcedure

Procedure RndLines()
   Protected w = 800 : h = 600
   StartDrawing(CanvasOutput(0))
      Box(0,0,w,h,0)
      For n = 1 To Random(20) + 5
         ThickLine(Random(w),Random(h),Random(w),Random(h),Random(6),Random($FFFFFF))
      Next n
   StopDrawing()
EndProcedure

If OpenWindow(0, 0, 0, 800, 600, "ThickLine Demo")
   CanvasGadget(0, 0, 0, 800, 600)
   RndLines()
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_CloseWindow
            Break
         Case #WM_MOUSEMOVE
            cd -1
            If cd < 1
               cd = 20
               RndLines()
            EndIf
      EndSelect
   ForEver
EndIf
BP

Re: Draw arcs, polygons, pies, thick lines, no API calls

Posted: Wed Apr 03, 2013 1:32 am
by idle
Thats much better BP, updated the code in my previous post

Re: Draw arcs, polygons, pies, thick lines, no API calls

Posted: Fri Oct 11, 2013 9:34 pm
by [blendman]
Hi

The procedure thickline is really great !!

I would to know I could add a sort of "pass" like in photoshop ?
The pass = the space between two circle
if the pass = 50, the line is made by dot with distance between dots = 50 pixels for example.