Placement of spheres - Math Problem

I’m trying to evenly space apart each set of spheres. No matter what the number of Masters(smiles) or SlavesPerMaster(frowney) is set to. The SlavesPerMaster(frowney)'s are spaced evenly apart, that part works.

Problem is evenly spacing the Masters(smiles) so that none of the frowney’s touch each other, I’m hoping a math wiz can help me? :unamused:

Here is my code:

from math import pi, sin, degrees, tan
from pandac.PandaModules import *
from direct.showbase.ShowBase import ShowBase


 
class MyApp(ShowBase):
	def __init__(self):
		ShowBase.__init__(self)
		base.setBackgroundColor(1,1,1)
		base.disableMouse()
		base.setFrameRateMeter(True)
		

		# Load the environment model.
		self.environ = NodePath("visCenter")
		# Reparent the model to render.
		self.environ.reparentTo(self.render)
		# Apply scale and position transforms on the model.
		#self.environ.setScale(2, 2, 2)
		#self.environ.setPos(0, 0, 0)

		def getDistance(r, numberOfMasters):
			'''
			angle = (360.0 / numberOfMasters) / 2.0
			print '--------------------------------'
			print '\t Number of slaves /2', r
			print "\tangle: ", angle
			print "\tr: ", r
			print "\t tan theta", abs(tan(angle))
			H = r / abs(tan(angle))
			print "\tH", H
			'''
			theta = 360/numberOfMasters
			D = 2*r
			
			return D
			
		Masters =20
		SlavesPerMaster = 20
		for i in range(0, Masters):
			smiley = self.loader.loadModel("smiley")
			smiley.reparentTo(self.environ)
			smiley.setH(i * (360 / Masters))
			#smiley.setY(smiley, -10)
			smiley.setY(smiley, -getDistance(SlavesPerMaster/2.0, Masters))
			
			for j in range(0, SlavesPerMaster):
				ls = LineSegs()
				ls.setThickness(1.0)
				ls.setColor(0, 0, 0, 1)
				
				
				slave = self.loader.loadModel("frowney")
				slave.reparentTo(smiley)
				slave.setScale(.5, .5, .5)
				slave.setZ(slave, -10)
				slave.setH(j * (360 / SlavesPerMaster))
				slave.setY(slave, -SlavesPerMaster/2)
				
				ls.moveTo(smiley.getPos(slave))
				ls.drawTo(slave.getPos(slave))
				slave.attachNewNode(ls.create())

			

		self.center = NodePath("envPoint")
		self.center.reparentTo(self.environ)

		self.camera.reparentTo(self.center)
		self.camera.setY(-50)



		#self.accept('arrow_left', self.leftSpin)
		#self.accept('arrow_right', self.rightSpin)
		
		#self.accept('arrow_left-repeat', self.leftSpin)
		#self.accept('arrow_right-repeat', self.rightSpin)
		self.accept('mouse3', self.setRightMouse, [True])
		self.accept('mouse3-up', self.setRightMouse, [False])


		self.setRightMouse(False)
		
		taskMgr.add(self.spin, "spin")

		alight = AmbientLight('alight')
		alight.setColor(VBase4(.9, .9, .9, 1))
		alnp = render.attachNewNode(alight)
		render.setLight(alnp)


	def setRightMouse(self, value):
		self.rightMouseClicked = value

	
	def spin(self, task):
		if base.mouseWatcherNode.hasMouse() and self.rightMouseClicked:
			mpos = base.mouseWatcherNode.getMouse()
			self.center.setH(self.center, mpos.getX()*globalClock.getDt()*-400)
		return task.cont



app = MyApp()
app.run()

I think you’re on the right track. I would just modify getDistance as follows:

         theta = 180/numberOfMasters 
         D = r / sin(theta)

So D is the hypotenuse of the triangle from the center to a master to a slave (in the x-z plane); theta is half the angle between adjacent masters; and the sin of that angle is the ratio of the small radius (horizontal distance of slave from master) to the large radius (horizontal distance of masters from the center). Theoretically that should work, except we haven’t added in the radius of the slaves.

Unfortunately it doesn’t work even that well: the circles of slaves overlap… :confused: