How do I snap an object to a circular grid

This is how I generate the grid,
I would like to know how to find nearest point on the grid to the mouse click position

for (int layer = 1; layer < Layers; layer++)
  {
    for (int slice = 0; slice < Slices; slice++)
    {
     float angle = slice * Mathf.PI * 2 / Slices;
     Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * (gridRadius * layer);

     currentPos = transform.position;
     desiredPos = new Vector3(currentPos.x + pos.x, currentPos.y + pos.y, currentPos.z + pos.z);

     Gizmos.DrawSphere(desiredPos, 1.0f);
    }
}

This is how my Grid looks like after I generate it:

What I want is that where ever I click my mouse, lets say to place a simple cube object, I want it to find the nearest point on the grid and place the object there, something like that:

private Grid grid;

    private void Awake()
    {
        grid = FindObjectOfType<Grid>();
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hitInfo;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(ray, out hitInfo))
            {
                PlaceCubeNear(hitInfo.point);
            }
        }
    }

    private void PlaceCubeNear(Vector3 clickPoint)
    {
//get closest point on grid and CreatePrimitive(PrimitiveType.Cube) at that location
    }

First, fill a kd-tree (or similar) with all your points for a quicker lookup. Then, make a Plane and do a Plane.Raycast to find the place on the plane (the ground, or a wall) that you clicked, and pass that point into the kd-tree’s find nearest function to get your result.

Alternatively (maybe faster and easier), using the same plane raycast, check how far the point is from the center and snap that distance to the nearest ring. Then find the nearest snap-angle from there and calculate where the point is on that angle. Or loop through all the points in that ring to find the nearest (slower).

If your desired gridpoints follow a simple formula you can simply convert your incoming point on the plane into polar coordinates (angle + distance), clamp both to your desired grid and just convert them back to cartesian coordinates.

The first thing you might want to do is reduce the 3d points to 2d points. The easiest way to do this is to convert them from worldspace into localspace coordinate of an empty gameobject. This gameobject should represent the center of your plane. Just use InverseTransformPoint to get a given worldspace point in local coordinates. Now we can just ignore the y component and only use x and z.

With Mathf.Atan2 you can calculate the angle (in radians) of the given local point in relation to the x axis. The magnitude of your local vector is your distance. Now just clamp those two values as you like. In your picture you splitted the 360° (2PI) into 20 steps. So you would want to make the angle be a multiple of 360/20== 18 degree (2PI / 20 == PI/10 radians). Your distance may be clamped to a multiple of 1 or whatever spacing you want.

When done you can use Sin and Cos to get back an actual local space vector and if you need the position in worldspace just use TransformPoint on it.

public static Vector3 ClampCircle(Vector3 aLocalPoint, int aAngleSubDiv, float aDistance)
{
    float segment = Mathf.PI*2f / aAngleSubDiv;
    float angle = Mathf.Atan2(aLocalPoint.z, aLocalPoint.x);
    float dist = aLocalPoint.magnitude;
    // clamp
    angle = Mathf.Round(angle / segment) * segment;
    dist = Mathf.Round(dist / aDistance) * aDistance;

    return new Vector3(Mathf.Cos(angle) * dist, 0, Mathf.Sin(angle) * dist);
}

To get the closest point on a plane “attached” to the gameobject depending on where the user clicks, just do this:

private void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        Plane p = new Plane(transform.up, transform.position);
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float dist;
        if (p.Raycast(ray, out dist))
        {
            var v = transform.InverseTransformPoint(ray.GetPoint(dist));
            v = ClampCircle(v, 20, 1f);
            v = transform.TransformPoint(v);
            // v is the clamped worldspace point
        }
    }
}