# How do I get the boundaries of a plane I spawned a gameobject on?

**URL:** https://community.nianticspatial.com/t/how-do-i-get-the-boundaries-of-a-plane-i-spawned-a-gameobject-on/3869
**Category:** I'm Stuck
**Created:** [September 23, 2023, 9:37pm UTC](https://community.nianticspatial.com/t/how-do-i-get-the-boundaries-of-a-plane-i-spawned-a-gameobject-on/3869 "2023-09-23T21:37:29Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![CUCUMBER](https://avatars.discourse-cdn.com/v4/letter/c/53a042/32.png) [@CUCUMBER](https://community.nianticspatial.com/u/CUCUMBER)
#### Post date: [September 23, 2023, 9:37pm UTC](https://community.nianticspatial.com/t/how-do-i-get-the-boundaries-of-a-plane-i-spawned-a-gameobject-on/3869/1 "2023-09-23T21:37:29Z")

</div>

Hi guys!

I am new here 🙂

I am spawning a vehicle on a plane, and trying to figure out on what plane it was spawned and saving its boundaries. e.g. lowest and highest x,y and z coordinates of the plane the vehicle was spawned on.

I am attaching my code. I will appreciate your help very much!

P.S. I am also including my code achieving the behavior I am looking for with AR Foundation and ARCore (Commented out).

using System.Collections.Generic;

using Niantic.ARDK.AR;  
using Niantic.ARDK.AR.ARSessionEventArgs;  
using Niantic.ARDK.AR.HitTest;  
using Niantic.ARDK.External;  
using Niantic.ARDK.Utilities;  
using Niantic.ARDK.Utilities.Input.Legacy;

using UnityEngine;  
using UniRx;  
using TMPro;

///

#  
/// Responsible for placing the object on a plane  
///   
public class PlacementOnPlane : MonoBehaviour  
{  
/// #  
/// The camera used to render the scene. Used to get the center of the screen.  
///   
public Camera Camera = null;

```
/// The types of hit test results to filter against when performing a hit test.
[EnumFlagAttribute]
public ARHitTestResultType HitTestType = ARHitTestResultType.ExistingPlane;

/// Internal reference to the session, used to get the current frame to hit test against.
private IARSession _session;

/// <summary>
/// Minimum boundary of the spawned plane
/// </summary>
public Vector3 MinBounds { get; private set; }

/// <summary>
/// Maximum boundary of the spawned plane
/// </summary>
public Vector3 MaxBounds { get; private set; }

/// <summary>
/// Bool reactive property that checks if we would like to place the object
/// todo: Change to false
/// </summary>
public ReactiveProperty<bool> IsReadyToPlace { get; private set; } =
    new ReactiveProperty<bool>(true);

/// <summary>
/// The object we will spawn
/// </summary>
[SerializeField] private AffectedObject _objectToSpawn;

/// <summary>
/// Prints values to the canvas.
/// </summary>
public TextMeshProUGUI DebugText = null;

private void Start()
{
    ARSessionFactory.SessionInitialized += OnAnyARSessionDidInitialize;
}

private void OnAnyARSessionDidInitialize(AnyARSessionInitializedArgs args)
{
    _session = args.Session;
}

private void Update()
{
    if (_session == null)
    {
        return;
    }

    if (PlatformAgnosticInput.touchCount <= 0)
    {
        return;
    }

    var touch = PlatformAgnosticInput.GetTouch(0);
    if (touch.phase == TouchPhase.Began)
    {
        TouchBegan(touch);
    }
}

private void TouchBegan(Touch touch)
{
    var currentFrame = _session.CurrentFrame;

    if (currentFrame == null)
    {
        return;
    }

    if (touch.IsTouchOverUIObject())
    {
        Debug.Log("Pressed on UI");
        return;
    }
        
    var results = currentFrame.HitTest
    (
      Camera.pixelWidth,
      Camera.pixelHeight,
      touch.position,
      HitTestType
    );

    int count = results.Count;
    Debug.Log("Hit test results: " + count);

    if (count <= 0)
    {
        Debug.LogWarning("Non-Positive hits");
        return;
    }
        

    // Get the closest result
    var result = results[0];

    Debug.Log($"{result.GetType()}");

    var hitPosition = result.WorldTransform.ToPosition();

    if (!_objectToSpawn.gameObject.activeSelf)
    {
        _objectToSpawn.Spawn();

        //todo: Find the plane on which the raycast was hit, to set _spawnedPlane
        /**
        // Set _spawnedPlane to the plane that was hit
                        _spawnedPlane = _hits[0].trackable as ARPlane;

                        // Calculate and set _minBounds and _maxBounds based on the boundaries of the spawned plane
                        CalculatePlaneBounds(_spawnedPlane);
         */

        _objectToSpawn.transform.position = hitPosition;

        ObjectPositionPrinter();

        SetObjectPlacingMode();
    }

    /**
    // Raycast hit a plane, spawn the object at the hit position
                Pose hitPose = _hits[0].pose;

                if (!_objectToSpawn.gameObject.activeSelf)
                {
                    _objectToSpawn.Spawn();

                    // Set _spawnedPlane to the plane that was hit
                    _spawnedPlane = _hits[0].trackable as ARPlane;

                    // Calculate and set _minBounds and _maxBounds based on the boundaries of the spawned plane
                    CalculatePlaneBounds(_spawnedPlane);

                    _objectToSpawn.transform.position = hitPose.position;

                    ObjectPositionPrinter();

                    SetObjectPlacingMode();
                }
     */
}

/// <summary>
/// Responsible for determining if we can place an object
/// </summary>
public void SetObjectPlacingMode()
{
    if (IsReadyToPlace.Value)
    {
        IsReadyToPlace.Value = false;
    }
    else
    {
        if (_objectToSpawn.gameObject.activeSelf)
        {
            _objectToSpawn.Dispose();
        }

        IsReadyToPlace.Value = true;
    }
}

/// <summary>
/// Printing the position of the object.
/// </summary>
private void ObjectPositionPrinter()
{
    if (_objectToSpawn.gameObject.activeSelf)
    {
        DebugText.text = $"{_objectToSpawn.transform.position}";
    }
    else
    {
        DebugText.text = $"Still null.";
    }

    DebugText.text = $"Object position: {_objectToSpawn.transform.position}\n " +
        $"Min X:{MinBounds.x}. Max X:{MaxBounds.x} MinZ:{MinBounds.z} MaxZ:{MaxBounds.z}";
}

/// <summary>
/// Calculate the boundaries of the spawned plane
/// </summary>
//private void CalculatePlaneBounds(ARPlane plane)
//{
// // Get the center of the plane
// Vector3 center = plane.center;

// // Get the extents of the plane (half of its size in each dimension)
// Vector2 extents = plane.extents;

// // Calculate the minimum and maximum bounds of the plane
// MinBounds = center - new Vector3(extents.x, 0, extents.y);
// MaxBounds = center + new Vector3(extents.x, 0, extents.y);

//}

```

}

/\*\*  
using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using UnityEngine.XR.ARFoundation;  
using UnityEngine.XR.ARSubsystems;  
using TMPro;  
using UniRx;

///

#  
/// Responsible for placing the object on a plane  
///   
public class PlacementOnPlane : MonoBehaviour  
{  
/// #  
/// The object we will spawn  
///   
[SerializeField] private AffectedObject \_objectToSpawn;

```
/// <summary>
/// Reference to the raycast manager
/// </summary>
private ARRaycastManager _raycastManager;

/// <summary>
/// Data Structure of the AR Raycast Hits
/// </summary>
private List<ARRaycastHit> _hits = new List<ARRaycastHit>();

/// <summary>
/// Bool reactive property that checks if we would like to place the object
/// </summary>
public ReactiveProperty<bool> IsReadyToPlace { get; private set; } =
    new ReactiveProperty<bool>(false);

/// <summary>
/// Prints values to the canvas.
/// </summary>
public TextMeshProUGUI DebugText = null;

/// <summary>
/// Store the reference to the plane where the vehicle was spawned
/// </summary>
private ARPlane _spawnedPlane;

/// <summary>
/// Minimum boundary of the spawned plane
/// </summary>
public Vector3 MinBounds { get; private set; }

/// <summary>
/// Maximum boundary of the spawned plane
/// </summary>
public Vector3 MaxBounds { get; private set; }

private void Awake()
{
    _raycastManager = GetComponent<ARRaycastManager>();
}

/// <summary>
/// Implementing the main AR logic
/// </summary>
void Update()
{
    if ((Input.touchCount > 0) && (IsReadyToPlace.Value))
    {
        Touch touch = Input.GetTouch(0);

        if (touch.phase == TouchPhase.Began)
        {
            if (_raycastManager.Raycast(touch.position, _hits, TrackableType.PlaneWithinPolygon))
            {
                // Raycast hit a plane, spawn the object at the hit position
                Pose hitPose = _hits[0].pose;

                if (!_objectToSpawn.gameObject.activeSelf)
                {
                    _objectToSpawn.Spawn();

                    // Set _spawnedPlane to the plane that was hit
                    _spawnedPlane = _hits[0].trackable as ARPlane;

                    // Calculate and set _minBounds and _maxBounds based on the boundaries of the spawned plane
                    CalculatePlaneBounds(_spawnedPlane);

                    _objectToSpawn.transform.position = hitPose.position;

                    ObjectPositionPrinter();

                    SetObjectPlacingMode();
                }
            }
        }
    }
}

/// <summary>
/// Calculate the boundaries of the spawned plane
/// </summary>
private void CalculatePlaneBounds(ARPlane plane)
{
    // Get the center of the plane
    Vector3 center = plane.center;

    // Get the extents of the plane (half of its size in each dimension)
    Vector2 extents = plane.extents;

    // Calculate the minimum and maximum bounds of the plane
    MinBounds = center - new Vector3(extents.x, 0, extents.y);
    MaxBounds = center + new Vector3(extents.x, 0, extents.y);

}

/// <summary>
/// Printing the position of the object.
/// </summary>
private void ObjectPositionPrinter()
{
    if (_objectToSpawn.gameObject.activeSelf)
    {
        DebugText.text = $"{_objectToSpawn.transform.position}";
    }
    else
    {
        DebugText.text = $"Still null.";
    }

    DebugText.text = $"Object position: {_objectToSpawn.transform.position}\n " +
        $"Min X:{MinBounds.x}. Max X:{MaxBounds.x} MinZ:{MinBounds.z} MaxZ:{MaxBounds.z}";
}

/// <summary>
/// Responsible for determining if we can place an object
/// </summary>
public void SetObjectPlacingMode()
{
    if (IsReadyToPlace.Value)
    {
        IsReadyToPlace.Value = false;
    }
    else
    {
        if (_objectToSpawn.gameObject.activeSelf)
        {
            _objectToSpawn.Dispose();
        }

        IsReadyToPlace.Value = true;
    }
}

```

}  
\*/

---

<div class="post-metadata">

### Author: ![Maverick\_Niantic](https://avatars.discourse-cdn.com/v4/letter/m/8edcca/32.png) [@Maverick\_Niantic](https://community.nianticspatial.com/u/Maverick_Niantic)
#### Post date: [March 5, 2026, 11:44pm UTC](https://community.nianticspatial.com/t/how-do-i-get-the-boundaries-of-a-plane-i-spawned-a-gameobject-on/3869/2 "2026-03-05T23:44:39Z")

</div>

Age
