Finding random position in torus?

Hello,

I am trying to finding a random position in torus.

Actually I found a method that finding torus iteratively. But it includes while loop and I don’t want to use while loop in a method while it slows down update duration.

Are there any algorithm for my purpose.

Here is the code that I wrote

Vector3 GetARandomPositionInTorus(Vector3 center)
{

    Vector3 dest = transform.position;

    while (Vector3.Distance(dest, transform.position) < newCirclePositionMinDistance)
    {
        Vector3 randomPosition = Random.insideUnitSphere * newCirclePositionMaxDistance;
        randomPosition = new Vector3(randomPosition.x, transform.position.y, randomPosition.z);
        dest = randomPosition + center;
    }

    return dest;

}

This is more of a math problem than a Unity problem.

Imagine the torus as a necklace; a bunch of spheres connected with a string through their centers, and aligned in a ring.

Get a random angle around that ring.

Find the position of the string.

Imagine a sphere there.

Get a random point in that sphere.

Now you have a point that lies within the torus \o/

Here’s some code to demonstrate. I have not factored in the position and orientation of the torus, this is just to show the above steps in practice. Attach to an empty gameObject in a new scene. Hit Play. Left-click in the scene view and change the inspector values while playing.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class RandomPosInTorus : MonoBehaviour 
{
	public float innerRadius = 2f;
	public float outerRadius = 5f;
	[Space(20)]
	public int iterations = 1000;
	public GameObject markerObject;
	
	private List< GameObject > markerList; // object pool. for testing purposes


    void Start()
    {
		markerList = new List< GameObject >();
		Generate();
	}


    void Update()
    {
		if ( Input.GetKeyDown( KeyCode.Mouse0 ) )
			Generate();
    }


    void Generate()
    {
		// object pool. for testing purposes. remove old markers each time Generate is called
		if ( markerList.Count > 0 )
			foreach ( GameObject marker in markerList )
				Destroy( marker );
		
		markerList = new List< GameObject >();
		
		
		float wallRadius = ( outerRadius - innerRadius ) * 0.5f;
		float ringRadius = wallRadius + innerRadius; // ( ( max - min ) / 2 ) + min
		
		for ( int i = 0; i < iterations; i ++ )
		{
			// create marker object
			GameObject go;
			if ( !markerObject )
			{
				go = GameObject.CreatePrimitive( PrimitiveType.Sphere );
				go.transform.localScale = Vector3.one * 0.05f;
			}
			else
				go = (GameObject)Instantiate( markerObject );
			go.name = "Sphere_" + i.ToString();
			markerList.Add( go );
			
			// position marker object
			Transform tx = go.transform;
			tx.position = GetRandomPositionInTorus( ringRadius, wallRadius );
			tx.parent = transform;
		}
    }
    

    Vector3 GetRandomPositionInTorus( float ringRadius, float wallRadius )
    {
		// get a random angle around the ring
		float rndAngle = Random.value * 6.28f; // use radians, saves converting degrees to radians
		
		// determine position
		float cX = Mathf.Sin( rndAngle );
		float cZ = Mathf.Cos( rndAngle );
		
		Vector3 ringPos = new Vector3( cX, 0, cZ );
		ringPos *= ringRadius;
		
		// At any point around the center of the ring
		// a sphere of radius the same as the wallRadius will fit exactly into the torus.
		// Simply get a random point in a sphere of radius wallRadius,
		// then add that to the random center point
		Vector3 sPos = Random.insideUnitSphere * wallRadius;
		
		return ( ringPos + sPos );
    }
}