433 lines
16 KiB
C#
433 lines
16 KiB
C#
using System.Collections.Generic;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
using UnityEngine.XR.ARFoundation;
|
||
using UnityEngine.XR.Interaction.Toolkit.AR;
|
||
|
||
public class LineManager : MonoBehaviour
|
||
{
|
||
//Creamos una referencia de 'LineaObjeto'
|
||
public LineRenderer lineRenderer;
|
||
//Creamos una referencia a nuestro AR Placement Interactable
|
||
public ARPlacementInteractable aRPlacementInteractable;
|
||
//Creamos una referencia al TextoDistancia
|
||
public TextMeshPro mText;
|
||
//Creamos unbooleano para delimitar al usuario cuando cierre la forma de los poligonos
|
||
private bool isPolygonClosed = false;
|
||
|
||
// Listas para los objetos y textos colocados
|
||
private List<GameObject> placedObjects = new List<GameObject>();
|
||
private List<TextMeshPro> distanceTexts = new List<TextMeshPro>();
|
||
|
||
//Referencias a los botones
|
||
public GameObject cleanButton; // Bot<6F>n de Limpiar
|
||
public GameObject undoButton; // Bot<6F>n de Deshacer
|
||
public GameObject confirmButton; // Bot<6F>n de confirmaci<63>n
|
||
|
||
//Referencia
|
||
public ObjectPlacementManager objectPlacementManager; // Referencia al script ObjectPlacementManager.cs
|
||
|
||
[SerializeField] private ARPlaneManager arPlaneManager; // Referencia al ARPlaneManager
|
||
[SerializeField] private Material fillMaterial; // Material con la textura
|
||
private MeshFilter meshFilter;
|
||
private MeshRenderer meshRenderer;
|
||
|
||
|
||
public ARRaycastManager arRaycastManager; // Aseg<65>rate de asignar esto en el Inspector
|
||
|
||
// Start is called before the first frame update
|
||
void Start()
|
||
{
|
||
//aRPlacementInteractable.objectPlaced.AddListener(DrawLine);
|
||
|
||
// Configurar MeshFilter y MeshRenderer din<69>micamente
|
||
// meshFilter = gameObject.AddComponent<MeshFilter>();
|
||
// meshRenderer = gameObject.AddComponent<MeshRenderer>();
|
||
// meshRenderer.material = fillMaterial; // Asignar el material en el Inspector
|
||
// meshRenderer.enabled = false; // Ocultar el MeshRenderer hasta que se confirme
|
||
SceneManager.LoadScene("ARScreen", LoadSceneMode.Additive);
|
||
StartCoroutine(AssignManagersToARScreen());
|
||
}
|
||
void DrawLine(ARObjectPlacementEventArgs args)
|
||
{
|
||
//Si esta cerrado el poligono entonces dejamos de dibujar lineas
|
||
if (isPolygonClosed) return; // Detenemos si el pol<6F>gono est<73> cerrado
|
||
|
||
// Colocar punto
|
||
placedObjects.Add(args.placementObject); // Registrar el objeto colocado
|
||
|
||
|
||
//increase point count
|
||
lineRenderer.positionCount++;
|
||
|
||
//2. let the points location in the line renderer
|
||
lineRenderer.SetPosition(
|
||
index: lineRenderer.positionCount - 1,//La linea se crea desde el objeto colocado anteriormente
|
||
args.placementObject.transform.position//Hasta el nuevo objeto colocado
|
||
);
|
||
//Mientras tengamos una linea o mas de un punto, entonces se puede crear el texto de medicion
|
||
if (lineRenderer.positionCount > 1)
|
||
{
|
||
//Distancia del ultimo punto colocado
|
||
Vector3 pointA = lineRenderer.GetPosition(index: lineRenderer.positionCount - 1);
|
||
//Distancia del punto anterior al ultimo colocado (penultimo punto)
|
||
Vector3 pointB = lineRenderer.GetPosition(index: lineRenderer.positionCount - 2);
|
||
//Objtenem,os la distancia entre los dos puntos
|
||
float distancia = Vector3.Distance(pointA, pointB);
|
||
//Colocamos el texto de la distancia en TextoDistancia se mostrara en cm ejemplo de salida: 10.009 cm
|
||
//mText.text = (distancia * 100).ToString("0.000") + " cm";
|
||
//crearemos un TextoDistancia en cada linea cada vez que se genere una.
|
||
TextMeshPro textoDistanciaTemp = Instantiate(mText);
|
||
textoDistanciaTemp.text = (distancia * 100).ToString("0.000") + " cm";
|
||
//aplicamos un formato al texto para que se coloque encima de la linea
|
||
Vector3 directionVector = (pointB - pointA);
|
||
Vector3 normal = args.placementObject.transform.up;
|
||
|
||
Vector3 upd = Vector3.Cross(
|
||
lhs: directionVector,
|
||
rhs: normal).normalized;
|
||
//calculamos la rotacion del texto
|
||
Quaternion rotation = Quaternion.LookRotation(forward: -normal, upwards: upd);
|
||
//aplicamos la posicion y rotacion al texto
|
||
textoDistanciaTemp.transform.position = (pointA + directionVector * 0.5f) + upd * 0.05f;
|
||
textoDistanciaTemp.transform.rotation = rotation;
|
||
|
||
distanceTexts.Add(textoDistanciaTemp); // Registrar el texto de distancia
|
||
}
|
||
//Si los botones de limpiar y deshacer estan desactivados alcolocar una linea u objeto, entonces los activamos
|
||
if (!cleanButton.activeSelf && !undoButton.activeSelf)
|
||
{
|
||
//Agregamos los botones a la pantalla al agregar un punto
|
||
cleanButton.SetActive(true);
|
||
undoButton.SetActive(true);
|
||
}
|
||
//Verificamos si es posiblie cerrar el poligono
|
||
CheckPolygonClosure();
|
||
}
|
||
|
||
//Este metodo determina si se pueden continuar insertando o no mas lineas
|
||
private void CheckPolygonClosure()
|
||
{
|
||
if (lineRenderer.positionCount > 2)
|
||
{
|
||
Vector3 firstPoint = lineRenderer.GetPosition(0);
|
||
Vector3 lastPoint = lineRenderer.GetPosition(lineRenderer.positionCount - 1);
|
||
|
||
float distanceToFirst = Vector3.Distance(lastPoint, firstPoint);
|
||
|
||
if (distanceToFirst < 0.03f) // Define el margen de cierre en 3 cm
|
||
{
|
||
isPolygonClosed = true;//En caso de que la proxima linea este cerca de la primera entonces volvemos true
|
||
|
||
// Cambiar color del pol<6F>gono para indicar cierre
|
||
lineRenderer.material.color = Color.green;
|
||
|
||
// Deshabilitar el ARPlacementInteractable para evitar m<>s colocaciones
|
||
aRPlacementInteractable.enabled = false;
|
||
|
||
// Activar el bot<6F>n de confirmaci<63>n
|
||
confirmButton.SetActive(true);
|
||
|
||
|
||
// Mostrar mensaje al usuario
|
||
Debug.Log("Pol<6F>gono cerrado. No se pueden agregar m<>s puntos.");
|
||
//FindObjectOfType<DebugLoggerUI>().AddMessage("Pol<6F>gono cerrado. No se pueden agregar m<>s puntos.");
|
||
}
|
||
}
|
||
}
|
||
|
||
//Este metodo limpia los poligonos de la camara
|
||
public void ResetPolygon()
|
||
{
|
||
if (isPolygonClosed)
|
||
{
|
||
//Quitamos de pantalla boton confirmar
|
||
confirmButton.SetActive(false);
|
||
}
|
||
// Reiniciar la l<>gica del pol<6F>gono
|
||
isPolygonClosed = false;
|
||
aRPlacementInteractable.enabled = true;
|
||
|
||
// Limpiar las l<>neas
|
||
lineRenderer.positionCount = 0;
|
||
lineRenderer.material.color = Color.red;
|
||
|
||
// Destruir objetos colocados
|
||
foreach (GameObject obj in placedObjects)
|
||
{
|
||
Destroy(obj);
|
||
}
|
||
placedObjects.Clear();
|
||
|
||
// Destruir textos de distancia
|
||
foreach (TextMeshPro text in distanceTexts)
|
||
{
|
||
Destroy(text.gameObject);
|
||
}
|
||
distanceTexts.Clear();
|
||
//Quitamos los botones de limpiar y deshacer de la pantalla
|
||
cleanButton.SetActive(false);
|
||
undoButton.SetActive(false);
|
||
|
||
Debug.Log("Pol<6F>gono reiniciado.");
|
||
}
|
||
|
||
//Este metodo se encarga de deshacer los cambios del usuario
|
||
public void UndoLastAction()
|
||
{
|
||
// Verificar que haya puntos para deshacer
|
||
if (placedObjects.Count > 0)
|
||
{
|
||
// Eliminar el <20>ltimo punto colocado
|
||
GameObject lastObject = placedObjects[placedObjects.Count - 1];
|
||
Destroy(lastObject);
|
||
placedObjects.RemoveAt(placedObjects.Count - 1);
|
||
|
||
// Eliminar el <20>ltimo texto de distancia, si existe
|
||
if (distanceTexts.Count > 0)
|
||
{
|
||
TextMeshPro lastText = distanceTexts[distanceTexts.Count - 1];
|
||
Destroy(lastText.gameObject);
|
||
distanceTexts.RemoveAt(distanceTexts.Count - 1);
|
||
}
|
||
|
||
// Actualizar el LineRenderer
|
||
if (lineRenderer.positionCount > 0)
|
||
{
|
||
lineRenderer.positionCount--; // Reduce el conteo de puntos
|
||
|
||
// Si el poligono ya estaba cerrado lo volvemos a habilitar
|
||
if (isPolygonClosed)
|
||
{
|
||
isPolygonClosed = false;
|
||
aRPlacementInteractable.enabled = true;
|
||
lineRenderer.material.color = Color.red;// Cambiar color del pol<6F>gono
|
||
//Quitamos de pantalla boton confirmar
|
||
confirmButton.SetActive(false);
|
||
}
|
||
|
||
}
|
||
//Si no tenemos ningun objeto entonces quitamos los botones de limpiar
|
||
if (placedObjects.Count == 0)
|
||
{
|
||
//Agregamos los botones a la pantalla al agregar un punto
|
||
cleanButton.SetActive(false);
|
||
undoButton.SetActive(false);
|
||
}
|
||
Debug.Log("<22>ltima acci<63>n deshecha.");
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("No hay acciones para deshacer.");
|
||
}
|
||
}
|
||
|
||
//Confirmar el seteo de objetos
|
||
public void ConfirmPlacement()
|
||
{
|
||
if (!isPolygonClosed)
|
||
{
|
||
Debug.Log("No se puede confirmar: el pol<6F>gono no est<73> cerrado.");
|
||
return;
|
||
}
|
||
|
||
Debug.Log("Confirmaci<63>n completada: Solo se pueden colocar objetos dentro del <20>rea seleccionada.");
|
||
|
||
// Generar el Mesh del pol<6F>gono
|
||
GeneratePolygonMesh(GetPolygonPoints());
|
||
|
||
// Cambiar la l<>gica del ARPlacementInteractable
|
||
aRPlacementInteractable.objectPlaced.RemoveListener(DrawLine); // Quitar la l<>gica de dibujo
|
||
aRPlacementInteractable.objectPlaced.AddListener(ValidatePlacement); // Agregar la validaci<63>n
|
||
//aRPlacementInteractable.enabled = true;
|
||
|
||
// Detener la detecci<63>n de planos y ocultar los existentes
|
||
if (arPlaneManager != null)
|
||
{
|
||
arPlaneManager.enabled = false;
|
||
|
||
foreach (var plane in arPlaneManager.trackables)
|
||
{
|
||
plane.gameObject.SetActive(false);
|
||
}
|
||
Debug.Log("Detecci<63>n de planos detenida y planos ocultos.");
|
||
}
|
||
|
||
//Quitamos los botones de la pantalla
|
||
cleanButton.SetActive(false);
|
||
undoButton.SetActive(false);
|
||
confirmButton.SetActive(false);
|
||
|
||
// Cargar ARScreen en modo aditivo
|
||
SceneManager.LoadScene("ARScreen", LoadSceneMode.Additive);
|
||
Debug.Log("ARScreen cargado en modo aditivo.");
|
||
//FindObjectOfType<DebugLoggerUI>().AddMessage("ARScreen cargado en modo aditivo.");
|
||
|
||
// Asignar la c<>mara y el ARRaycastManager a los scripts en ARScreen
|
||
StartCoroutine(AssignManagersToARScreen());
|
||
}
|
||
|
||
private System.Collections.IEnumerator AssignManagersToARScreen()
|
||
{
|
||
yield return null; // Esperar un frame para que ARScreen se cargue
|
||
|
||
Camera measuringCamera = Camera.main;
|
||
|
||
if (measuringCamera == null)
|
||
{
|
||
Debug.LogError("C<>mara principal no encontrada en la nueva escena.");
|
||
yield break;
|
||
}
|
||
|
||
ARRaycastManager raycastManager = FindObjectOfType<ARRaycastManager>();
|
||
if (raycastManager == null)
|
||
{
|
||
Debug.LogError("ARRaycastManager no encontrado en la nueva escena.");
|
||
yield break;
|
||
}
|
||
|
||
foreach (var dragManager in FindObjectsOfType<DragAndDropManager>())
|
||
{
|
||
dragManager.SetCamera(measuringCamera);
|
||
dragManager.SetARRaycastManager(raycastManager);
|
||
}
|
||
|
||
foreach (var objectSelector in FindObjectsOfType<ObjectSelector>())
|
||
{
|
||
objectSelector.SetCamera(measuringCamera);
|
||
objectSelector.SetARRaycastManager(raycastManager);
|
||
}
|
||
|
||
Debug.Log("C<>mara y ARRaycastManager asignados a ARScreen.");
|
||
//FindObjectOfType<DebugLoggerUI>().AddMessage("C<>mara y ARRaycastManager asignados a ARScreen.");
|
||
}
|
||
|
||
|
||
|
||
#region Limitar area de seto de objetos
|
||
void ValidatePlacement(ARObjectPlacementEventArgs args)
|
||
{
|
||
Debug.Log($"Intentando colocar objeto en: {args.placementObject.transform.position}");
|
||
// Validar la posici<63>n del objeto antes de colocarlo
|
||
objectPlacementManager.PlaceObject(args.placementObject.transform.position);
|
||
Destroy(args.placementObject); // Eliminar el objeto temporal si est<73> fuera del <20>rea
|
||
}
|
||
/**
|
||
*
|
||
* Metodos publicos para compartir datos a otros scripts
|
||
*
|
||
* **/
|
||
public bool IsPolygonClosed()
|
||
{
|
||
return isPolygonClosed;
|
||
}
|
||
|
||
public List<Vector3> GetPolygonPoints()
|
||
{
|
||
List<Vector3> points = new List<Vector3>();
|
||
for (int i = 0; i < lineRenderer.positionCount; i++)
|
||
{
|
||
points.Add(lineRenderer.GetPosition(i));
|
||
}
|
||
return points;
|
||
}
|
||
|
||
public bool IsPointInPolygon(Vector2 point, List<Vector3> polygon)
|
||
{
|
||
int intersections = 0;
|
||
for (int i = 0; i < polygon.Count; i++)
|
||
{
|
||
Vector3 vertex1 = polygon[i];
|
||
Vector3 vertex2 = polygon[(i + 1) % polygon.Count];
|
||
|
||
if (RayIntersectsSegment(point, new Vector2(vertex1.x, vertex1.z), new Vector2(vertex2.x, vertex2.z)))
|
||
{
|
||
intersections++;
|
||
}
|
||
}
|
||
Debug.DrawLine(new Vector3(point.x, 0, point.y), new Vector3(point.x, 1, point.y), Color.red, 5f);
|
||
|
||
return (intersections % 2) != 0; // Punto est<73> dentro si intersecciones es impar
|
||
}
|
||
|
||
private bool RayIntersectsSegment(Vector2 point, Vector2 vertex1, Vector2 vertex2)
|
||
{
|
||
// Checa si el rayo desde el punto cruza el segmento
|
||
if (vertex1.y > vertex2.y)
|
||
{
|
||
Vector2 temp = vertex1;
|
||
vertex1 = vertex2;
|
||
vertex2 = temp;
|
||
}
|
||
|
||
if (point.y == vertex1.y || point.y == vertex2.y)
|
||
{
|
||
//point.y += 0.0001f; // Evita bordes exactos
|
||
point.y += 0.001f; // Ajusta este valor para evitar problemas en bordes
|
||
}
|
||
|
||
if (point.y < vertex1.y || point.y > vertex2.y || point.x > Mathf.Max(vertex1.x, vertex2.x))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (point.x < Mathf.Min(vertex1.x, vertex2.x))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
float red = (point.y - vertex1.y) / (vertex2.y - vertex1.y);
|
||
float blue = (point.x - vertex1.x) / (vertex2.x - vertex1.x);
|
||
return red >= blue;
|
||
}
|
||
#endregion
|
||
|
||
#region pintar poligono
|
||
private void GeneratePolygonMesh(List<Vector3> polygonPoints)
|
||
{
|
||
if (polygonPoints.Count < 3)
|
||
{
|
||
Debug.LogError("El pol<6F>gono debe tener al menos 3 puntos.");
|
||
return;
|
||
}
|
||
|
||
// Crear un nuevo Mesh
|
||
Mesh mesh = new Mesh();
|
||
|
||
// Convertir los puntos del pol<6F>gono a un array de Vector3
|
||
Vector3[] vertices = polygonPoints.ToArray();
|
||
|
||
// Generar <20>ndices para triangulaci<63>n (simple para pol<6F>gonos convexos)
|
||
List<int> indices = new List<int>();
|
||
for (int i = 1; i < polygonPoints.Count - 1; i++)
|
||
{
|
||
indices.Add(0);
|
||
indices.Add(i);
|
||
indices.Add(i + 1);
|
||
}
|
||
|
||
// Asignar los v<>rtices y tri<72>ngulos al Mesh
|
||
mesh.vertices = vertices;
|
||
mesh.triangles = indices.ToArray();
|
||
|
||
// Generar UVs para aplicar la textura
|
||
Vector2[] uvs = new Vector2[vertices.Length];
|
||
for (int i = 0; i < vertices.Length; i++)
|
||
{
|
||
uvs[i] = new Vector2(vertices[i].x, vertices[i].z); // UV mapping en XZ
|
||
}
|
||
mesh.uv = uvs;
|
||
|
||
// Asignar el Mesh al MeshFilter
|
||
mesh.RecalculateNormals();
|
||
mesh.RecalculateBounds();
|
||
meshFilter.mesh = mesh;
|
||
|
||
// Activar el MeshRenderer para mostrar la textura
|
||
meshRenderer.enabled = true;
|
||
}
|
||
#endregion
|
||
|
||
}
|