Drawing Circles within Circles Evenly (Derma Geometry)

Hello, I am trying to draw circles inside a larger circle (equidistant from eachother) in a DFrame. (Might sound confusing I know.)

Right now, I’m basically drawing a large circle (400 radius) using the function found on the wiki here: https://wiki.garrysmod.com/page/surface/DrawPoly

EXAMPLE:

(scaleX and scaleH are just custom functions used to properly scale across 16:9 aspect ratios.)



concommand.Add("_lol", function()
  if b then b:Remove() end

  b = vgui.Create("DFrame")
  b:SetSize(scaleX(1500), scaleH(900))
  b:MakePopup()
  b:Center()
  b.Paint = function()

    surface.SetDrawColor( 255, 255, 255, 50 )
    draw.NoTexture()
    draw.Circle( b:GetWide() / 2, b:GetTall() / 2, 400, 360 )
  end

  local RadioA = vgui.Create( "DButton", b )
  RadioA:SetPos( scaleX(b:GetWide() / 2 - 50), scaleH(b:GetTall() / 2 + 300) )
  RadioA:SetText( "" )
  RadioA:SetSize( 100, 100 )
  RadioA.Paint = function()
    surface.SetDrawColor( 0, 0, 0, 200 )
    draw.NoTexture()
    draw.Circle( scaleX(RadioA:GetWide() - 50), scaleH(RadioA:GetTall() - 50), 50, 360 )
    
    --using this to draw the origins, easy way to find distance.

    surface.SetDrawColor( 255, 0, 0, 200 )
    draw.Circle( scaleX(RadioA:GetWide() - 50), scaleH(RadioA:GetTall() - 50), 3, 360)
  end


Obviously, the way I’m drawing them apart from each other is not at all equidistant, which is what I’m looking to do.
I want to have the circles ~100 units away from each other following the WHOLE perimeter of the circle similar in this test image (my way of just ‘eye balling’ the circles positions):

Does anyone happen to know an easier way of doing this? Sadly my Geometry skills aren’t that great.
Thanks. :slight_smile:

use cosine? I’m confused as to what 100 units is meant to be

Ah, should have explained that better. 100 units meaning 100 from the origin of the circle. (not sure if I can technically call that pixels)

Same units used in SetPos(x, y)

I snooped around and found this site which does exactly ( I think ) what you want:

I couldn’t find if it said how it did it, but looking at the source code, you could just translate it into Lua or understand the math behind it.

http://pastebin.com/UhpMXDuH

The units are arbitrary, so just keep them consistent, for example, 400 for the red field, 50 for the blue field.

This thread should be of some use:

http://forum.facepunch.com/showthread.php?t=1450530

This bit:


function PointOnCircle( ang, radius, offX, offY )
    ang =  math.rad( ang )
    local x = math.cos( ang ) * radius + offX
    local y = math.sin( ang ) * radius + offY
    return x, y
end




local numSquares = 12 --How many squares do we want to draw?
local interval = 360 / numSquares
local centerX, centerY = 200, 500
local radius = 120


hook.Add("HUDPaint","Draw a circle of boxes!", function()


    for degrees = 1, 360, interval do --Start at 1, go to 360, and skip forward at even intervals.
        
        local x, y = PointOnCircle( degrees, radius, centerX, centerY )
        
        draw.RoundedBox( 4, x, y, 30, 30, Color(255,255,0) )
        
    end
    
end)


Helped me do this:

https://dl.dropboxusercontent.com/u/10892189/Half-Life 2 03.15.2016 - 18.09.58.05.webm

Ah yes, this actually helped me a bunch! Thanks dude.

Now, the only problem I have is drawing them into DButtons.
Using this code shown on the post:



hook.Add( "HUDPaint", "Draw a circle of boxes!", function()

	for degrees = 1, 360, interval do --Start at 1, go to 360, and skip forward at even intervals.

		local x, y = PointOnCircle( degrees, radius, centerX, centerY )

		draw.RoundedBox( 4, x, y, 30, 30, Color( 255, 255, 0 ) )

	end

end )


Theoretically should allow me to do something along the lines of (obviously calling calling the DButton interval is a terrible idea, but that’s one of the only changing vars in the loop):



    for degrees = 1, 360, interval do --Start at 1, go to 360, and skip forward at even intervals.

      local x, y = PointOnCircle( degrees, radius, centerX, centerY )
      --default code from thread.

      --draw.RoundedBox( 4, x, y, 30, 30, Color( 255, 255, 0 ) )
      surface.SetDrawColor( 0, 0, 0, 255 )
      draw.NoTexture()
      draw.Circle(x + 140, y - 140, 50, 360)

      local interval = vgui.Create( "DButton", b )
      interval:SetPos( scaleX(x), scaleH(y) )
      interval:SetText( "" )
      interval:SetSize( 100, 100 )
      interval.Paint = function()
        surface.SetDrawColor( 0, 0, 0, 200 )
        draw.NoTexture()
        draw.Circle( scaleX(interval:GetWide() - 50), scaleH(interval:GetTall() - 50), 50, 360 )
      end
    end


Since the paint functions are think hooks, this seems to create huge amounts of lag (just infinitely creates circles I assume)

If that is the case, should I just have it run the loop once?

I came up with my own proprietary button system rather than vgui stuff. But yeah, just run it once if you’re just trying to get coords for button placement. Store them in a table is what I’d do.