Arpolygon

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 18

using UnityEngine;

using UnityEngine.EventSystems;
using EnhancedTouch = UnityEngine.InputSystem.EnhancedTouch;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using TMPro;

public class DotConnector : MonoBehaviour


{
[SerializeField] private ARPlaneManager planeManager;
[SerializeField] private ARRaycastManager raycastManager;
[SerializeField] private TileSelector tileSelector;
[SerializeField] private GameObject dotPrefab;
[SerializeField] private GameObject linePrefab;
[SerializeField] private Material polyMaterial;
[SerializeField] private Button createPolyButton;
[SerializeField] private Texture floorTexture;
[SerializeField] private TextMeshProUGUI resultText;
[SerializeField] private Slider rotateSlider;
[SerializeField] private Button resetButton;
[SerializeField] private Button undoButton;
[SerializeField] private Slider tileSizeSlider;
[SerializeField] private Text sizeLabel;
[SerializeField] private GameObject additionalDotPrefab;
[SerializeField] private Canvas canvas;
[SerializeField] private GameObject errorPrefabToast;
[SerializeField] private Transform cartPageContainer;
[SerializeField] private Button btnAddToCart;
[SerializeField] private Button btnCapturePhoto;
[SerializeField] private Button moveButton;
[SerializeField] private Button addButton;
[SerializeField] private GameObject tilePanel;
[SerializeField] private GameObject prefabAddToCart;
private ProductData selectedProduct;
private float[] snapValues = { 0f, 0.5f, 1f };
private string[] tileSizes = { "30x30", "40x40", "60x60" };
private float[] sizeValues = { 0.3f, 0.4f, 0.6f };
private float tileSizeInMeters = 0.4f;
private GameObject currentLine;
private LineRenderer lineRenderer;
private List<Vector3> points = new List<Vector3>();
private List<GameObject> dots = new List<GameObject>();
private GameObject currentPolygon;
private GameObject selectedDot;
private bool confirmAddDotResult;
private bool allowTouch = true;
private bool isDragging = false;
private float lineThreshold = 0.05f;
private GameObject currentDialog;
private TaskCompletionSource<bool> tcs;
private bool isDialogOpen = false;
private Vector3? savedTouchPosition = null;
private Vector3 originalDraggedDotPosition;
private float previousSliderValue;
private int currentTotalTilesNeeded = 0;
private cartManager cartManager;
private bool isMoveActive = false;
private float minimumAreaThreshold = 0.05f;

private void Start()


{
InitializeUIElements();
SetupListeners();
InitializeRaycastLine();
}

private void InitializeUIElements()


{
// Using coroutines to activate/deactivate UI elements in sequence,
reducing UI thread load.
StartCoroutine(DeactivateUIElements());
tileSizeSlider.minValue = 0f;
tileSizeSlider.maxValue = 1f;
tileSizeSlider.value = 0.5f;
UpdateTileSizeLabel(snapValues[1]);

// Initialize product data if available


if (ProductSelectionHandler.selectedProduct != null)
{
selectedProduct = ProductSelectionHandler.selectedProduct;
floorTexture = selectedProduct.texture;
}
}

private IEnumerator DeactivateUIElements()


{
yield return null; // Slight delay before deactivation to allow UI to
initialize

undoButton.gameObject.SetActive(false);
resetButton.gameObject.SetActive(false);
rotateSlider.gameObject.SetActive(false);
btnAddToCart.gameObject.SetActive(false);
btnCapturePhoto.gameObject.SetActive(false);
tilePanel.gameObject.SetActive(false);
addButton.gameObject.SetActive(false);
createPolyButton.gameObject.SetActive(false);
}

private void SetupListeners()


{
// Event listeners
moveButton.onClick.AddListener(OnMoveButtonClicked);
addButton.onClick.AddListener(OnAddButtonClicked);
createPolyButton.onClick.AddListener(CreatePolygon);
resetButton.onClick.AddListener(ResetPolygons);
undoButton.onClick.AddListener(UndoReset);
rotateSlider.onValueChanged.AddListener(RotateSliderUpdate);
tileSizeSlider.onValueChanged.AddListener(OnSizeSliderValueChanged);
btnAddToCart.onClick.AddListener(AddCalculatedToCart);

cartManager = FindObjectOfType<cartManager>();
if (cartManager == null)
{
Debug.LogError("cartManager not found!");
}
}

private void InitializeRaycastLine()


{
currentLine = Instantiate(linePrefab);
lineRenderer = currentLine.GetComponent<LineRenderer>();
}

private void OnEnable()


{
EnhancedTouch.TouchSimulation.Enable();
EnhancedTouch.Touch.onFingerDown += FingerDown;
EnhancedTouch.Touch.onFingerMove += FingerMove;
EnhancedTouch.Touch.onFingerUp += FingerUp;
}

private void OnDisable()


{
EnhancedTouch.TouchSimulation.Disable();
EnhancedTouch.Touch.onFingerDown -= FingerDown;
EnhancedTouch.Touch.onFingerMove -= FingerMove;
EnhancedTouch.Touch.onFingerUp -= FingerUp;
}

private void FingerDown(EnhancedTouch.Finger finger)


{
if (isDialogOpen || !allowTouch || IsPointerOverUI(finger) ||
finger.index != 0)
{
return;
}

RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(finger.currentTouch.screenPosition);
if (Physics.Raycast(ray, out hit) &&
dots.Contains(hit.transform.gameObject))
{
selectedDot = hit.transform.gameObject;
isDragging = true;
originalDraggedDotPosition = selectedDot.transform.position;
return;
}

if (isMoveActive) return;

// Start coroutine for raycasting to keep everything on the main thread

StartCoroutine(HandleFingerDownRaycast(finger.currentTouch.screenPosition));
}

private IEnumerator HandleFingerDownRaycast(Vector2 screenPosition)


{
List<ARRaycastHit> hits = new List<ARRaycastHit>();

// Perform AR Raycast on the main thread and yield control to allow frame
updates
if (raycastManager.Raycast(screenPosition, hits,
TrackableType.PlaneWithinPolygon))
{
Pose hitPose = hits[0].pose;
savedTouchPosition = hitPose.position;

if (dots.Count >= 4)
{
isDialogOpen = true;

// Start a coroutine for ConfirmAdditionalDot to wait


asynchronously
yield return StartCoroutine(ConfirmAdditionalDotCoroutine());

isDialogOpen = false;

if (!confirmAddDotResult)
{
savedTouchPosition = null;
yield break;
}
}

if (savedTouchPosition.HasValue)
{
Vector3 newDotPosition = savedTouchPosition.Value;

if (points.Count < 2)
{
SpawnDot(newDotPosition);
savedTouchPosition = null;
if (points.Count > 1) DrawLines();
yield break;
}

Vector3 lastDotPosition = points[points.Count - 1];


int closestSegmentIndex = -1;
Vector3 closestPointOnSegment = Vector3.zero;
float closestDistance = lineThreshold;

// Find closest segment in segments, yielding control every 100


iterations
for (int i = 0; i < points.Count; i++)
{
Vector3 point1 = points[i];
Vector3 point2 = points[(i + 1) % points.Count];

Vector3 pointOnLine = NearestPointOnLine(point1, point2,


newDotPosition);
float distance = Vector3.Distance(newDotPosition, pointOnLine);

if (distance < closestDistance)


{
closestDistance = distance;
closestSegmentIndex = i;
closestPointOnSegment = pointOnLine;
}

// Yield control periodically to prevent freezing


if (i % 100 == 0) yield return null;
}

if (closestSegmentIndex != -1)
{
InsertDotAtSegment(closestSegmentIndex, closestPointOnSegment);
}
else if (!IsIntersectingExistingLines(lastDotPosition,
newDotPosition))
{
SpawnDot(newDotPosition);
}
else
{
ShowError("New line would intersect an existing line. Dot not
added.");
}

savedTouchPosition = null;
if (points.Count > 1) DrawLines();
if (points.Count >= 3 && !createPolyButton.gameObject.activeSelf)
createPolyButton.gameObject.SetActive(true);
}
}
}

private void FindClosestSegment(Vector3 newDotPosition, out int


closestSegmentIndex, out Vector3 closestPointOnSegment, out float closestDistance)
{
closestSegmentIndex = -1;
closestPointOnSegment = Vector3.zero;
closestDistance = lineThreshold;

for (int i = 0; i < points.Count; i++)


{
Vector3 point1 = points[i];
Vector3 point2 = points[(i + 1) % points.Count];
Vector3 pointOnLine = NearestPointOnLine(point1, point2,
newDotPosition);
float distance = Vector3.Distance(newDotPosition, pointOnLine);

if (distance < closestDistance)


{
closestDistance = distance;
closestSegmentIndex = i;
closestPointOnSegment = pointOnLine;
}
}
}

private bool IsPointerOverUI(EnhancedTouch.Finger finger)


{
var pointerEventData = new PointerEventData(EventSystem.current)
{
position = finger.currentTouch.screenPosition
};

var results = new List<RaycastResult>();


EventSystem.current.RaycastAll(pointerEventData, results);
return results.Count > 0;
}

private Vector3 NearestPointOnLine(Vector3 a, Vector3 b, Vector3 point)


{
Vector3 aToPoint = point - a;
Vector3 aToB = b - a;
float sqrLenAB = aToB.sqrMagnitude;
float t = Mathf.Clamp01(Vector3.Dot(aToPoint, aToB) / sqrLenAB);
return a + t * aToB;
}

private void InsertDotAtSegment(int segmentIndex, Vector3 position)


{
GameObject dot = Instantiate(dotPrefab, position, Quaternion.identity);
dots.Insert(segmentIndex + 1, dot);
points.Insert(segmentIndex + 1, position);
}

private void FingerMove(EnhancedTouch.Finger finger)


{
if (isDragging && selectedDot != null && isMoveActive)
{
List<ARRaycastHit> hits = new List<ARRaycastHit>();
if (raycastManager.Raycast(finger.currentTouch.screenPosition, hits,
TrackableType.PlaneWithinPolygon))
{
// Temporarily update only the dot position without updating lines
Vector3 newPosition = hits[0].pose.position;
selectedDot.transform.position = newPosition;
UpdateDotPosition(selectedDot); // Update the points list with the
dragged position, without drawing lines
}
}
}

private void FingerUp(EnhancedTouch.Finger finger)


{
if (isDragging && selectedDot != null)
{
bool intersects = false;
int dotIndex = dots.IndexOf(selectedDot);

if (dotIndex >= 0)
{
Vector3 prevPoint = (dotIndex > 0) ? points[dotIndex - 1] :
points[points.Count - 1];
Vector3 nextPoint = (dotIndex < points.Count - 1) ? points[dotIndex
+ 1] : points[0];
Vector3 newPosition = selectedDot.transform.position;

// Check if the new position would cause an intersection


if (IsIntersectingExistingLines(prevPoint, newPosition) ||
IsIntersectingExistingLines(newPosition, nextPoint))
{
intersects = true;
}
}
if (intersects)
{
// Revert to the original position if there’s an intersection
selectedDot.transform.position = originalDraggedDotPosition;
UpdateDotPosition(selectedDot); // Update the points list with the
reverted position
Debug.Log("Dot position reverted due to line intersection.");
ShowError("Dot position reverted due to line intersection.");
}
else
{
// Calculate area to check if the final dragged position creates
too small of an area
float finalArea = CalculatePolygonArea(points);
if (finalArea < minimumAreaThreshold)
{
// Revert to original position if area is too small
selectedDot.transform.position = originalDraggedDotPosition;
UpdateDotPosition(selectedDot);
Debug.Log("Dot position reverted due to too small area on final
drag.");
ShowError("Area is too small, reverting to original
position.");
}
else
{
// Update the points list with the final position if there’s no
intersection and area is sufficient
UpdateDotPosition(selectedDot);
}
}

DrawLines(); // Re-draw lines to connect them to the final or reverted


dot position
isDragging = false;
selectedDot = null;
}
}

private bool IsIntersectingExistingLines(Vector3 newStart, Vector3 newEnd)


{
for (int i = 0; i < points.Count; i++)
{
Vector3 start = points[i];
Vector3 end = points[(i + 1) % points.Count];

if ((start == newStart && end == newEnd) || (start == newEnd && end ==


newStart)) continue;
if (DoLinesIntersect(newStart, newEnd, start, end)) return true;
}
return false;
}

private bool DoLinesIntersect(Vector3 p1, Vector3 p2, Vector3 q1, Vector3 q2)
{
return ArePointsOnOppositeSides(p1, p2, q1, q2) &&
ArePointsOnOppositeSides(q1, q2, p1, p2);
}
private bool ArePointsOnOppositeSides(Vector3 a, Vector3 b, Vector3 p, Vector3
q)
{
Vector3 ab = b - a;
Vector3 ap = p - a;
Vector3 aq = q - a;

float cross1 = Vector3.Cross(ab, ap).y;


float cross2 = Vector3.Cross(ab, aq).y;

return cross1 * cross2 < 0;


}

private float CalculatePolygonArea(List<Vector3> points)


{
float area = 0f;
int j = points.Count - 1;

for (int i = 0; i < points.Count; i++)


{
area += (points[j].x + points[i].x) * (points[j].z - points[i].z);
j = i; // j is previous vertex to i
}

return Mathf.Abs(area / 2f);


}

private void SpawnDot(Vector3 position)


{
GameObject dot = Instantiate(dotPrefab, position, Quaternion.identity);
dots.Add(dot);
points.Add(position);
}

private void UpdateDotPosition(GameObject dot)


{
int index = dots.IndexOf(dot);
if (index >= 0)
{
points[index] = dot.transform.position;
}
}

private IEnumerator ConfirmAdditionalDotCoroutine()


{
confirmAddDotResult = false;

currentDialog = Instantiate(additionalDotPrefab, canvas.transform);

// Ensure CanvasGroup component exists, add if necessary


CanvasGroup canvasGroup = currentDialog.GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
canvasGroup = currentDialog.AddComponent<CanvasGroup>();
Debug.LogWarning("CanvasGroup component was missing from
additionalDotPrefab. Added dynamically.");
}
canvasGroup.alpha = 0;
LeanTween.alphaCanvas(canvasGroup, 1,
0.5f).setEase(LeanTweenType.easeInOutQuad);

tcs = new TaskCompletionSource<bool>();

Button[] buttons = currentDialog.GetComponentsInChildren<Button>();


if (buttons.Length >= 2)
{
buttons[0].onClick.AddListener(() => OnDialogButtonClick(true));
buttons[1].onClick.AddListener(() => OnDialogButtonClick(false));
}
else
{
Debug.LogError("Expected buttons not found in the confirmation dialog
prefab.");
yield break;
}

// Wait until the dialog button click resolves


yield return new WaitUntil(() => tcs.Task.IsCompleted);

confirmAddDotResult = tcs.Task.Result;

// Fade out and destroy the dialog


LeanTween.alphaCanvas(canvasGroup, 0,
0.5f).setEase(LeanTweenType.easeInOutQuad)
.setOnComplete(() => Destroy(currentDialog));
}

private void OnDialogButtonClick(bool choice)


{
tcs?.SetResult(choice);
Debug.Log("User chose: " + choice);

// Fade out the dialog


CanvasGroup canvasGroup = currentDialog.GetComponent<CanvasGroup>();
if (canvasGroup != null)
{
LeanTween.alphaCanvas(canvasGroup, 0, 0.5f)
.setEase(LeanTweenType.easeInOutQuad)
.setOnComplete(() => Destroy(currentDialog));
}
}

private void DrawLines()


{
lineRenderer.positionCount = points.Count;
lineRenderer.SetPositions(points.ToArray());
lineRenderer.loop = points.Count > 2;
}

public void CreatePolygon()


{
if (points.Count < 3) return; // Need at least 3 points to form a polygon

// Confirmation Dialog Here for UX.

// Set UI and interaction states


createPolyButton.gameObject.SetActive(false);
tilePanel.gameObject.SetActive(true);
allowTouch = false;

// Destroy any existing polygon to free up memory


if (currentPolygon != null)
{
Destroy(currentPolygon);
Debug.Log("Object destroyed: " + currentPolygon.name);
}

// Start the polygon creation process as a coroutine to avoid blocking the


main thread
StartCoroutine(CreatePolygonAsync());
}

private IEnumerator CreatePolygonAsync()


{
// Step 1: Perform triangulation asynchronously
List<int> triangles = new List<int>();
yield return StartCoroutine(TriangulatePolygonAsync(points, triangles));

if (triangles == null || triangles.Count == 0)


{
Debug.LogError("Triangulation failed or resulted in an empty triangle
list.");
yield break;
}

// Step 2: Prepare vertices and UVs


Mesh polygonMesh = new Mesh();
Vector3[] vertices = new Vector3[points.Count];
Vector2[] uv = new Vector2[points.Count];

float minX = float.MaxValue, maxX = float.MinValue;


float minZ = float.MaxValue, maxZ = float.MinValue;

// Compute min and max for UV mapping in a single pass


foreach (var point in points)
{
if (point.x < minX) minX = point.x;
if (point.x > maxX) maxX = point.x;
if (point.z < minZ) minZ = point.z;
if (point.z > maxZ) maxZ = point.z;
}

float width = maxX - minX;


float height = maxZ - minZ;

CalculateTotalTilesNeeded(width, height);

// Generate vertices and UVs in batches


for (int i = 0; i < points.Count; i++)
{
vertices[i] = points[i];
uv[i] = new Vector2((points[i].x - minX) / width, (points[i].z -
minZ) / height);

// Yield control to avoid freezing if large number of points


if (i % 100 == 0)
{
yield return null;
}
}

// Step 3: Apply vertices and UVs to mesh


polygonMesh.vertices = vertices;
polygonMesh.triangles = triangles.ToArray();
polygonMesh.uv = uv;

// Recalculate normals for shading


polygonMesh.RecalculateNormals();

// Step 4: Create GameObject for the mesh


currentPolygon = new GameObject("Polygon");
MeshFilter meshFilter = currentPolygon.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = currentPolygon.AddComponent<MeshRenderer>();
meshFilter.mesh = polygonMesh;
polyMaterial.SetTexture("_BaseTexture", floorTexture);
meshRenderer.material = polyMaterial;

ResetDotPoints();
ActivateUIAfterCreation();
}

private void ActivateUIAfterCreation()


{
btnAddToCart.gameObject.SetActive(true);
rotateSlider.gameObject.SetActive(true);
btnCapturePhoto.gameObject.SetActive(true);
moveButton.gameObject.SetActive(true);
addButton.gameObject.SetActive(false);
}

// Async triangulation method using Coroutine


private IEnumerator TriangulatePolygonAsync(List<Vector3> vertices, List<int>
triangles)
{
List<Vector3> tempVertices = new List<Vector3>(vertices);
while (tempVertices.Count > 2)
{
bool earFound = false;
for (int i = 0; i < tempVertices.Count; i++)
{
Vector3 prev = tempVertices[(i - 1 + tempVertices.Count) %
tempVertices.Count];
Vector3 curr = tempVertices[i];
Vector3 next = tempVertices[(i + 1) % tempVertices.Count];

if (IsEar(prev, curr, next, tempVertices))


{
triangles.Add(vertices.IndexOf(prev));
triangles.Add(vertices.IndexOf(curr));
triangles.Add(vertices.IndexOf(next));

tempVertices.RemoveAt(i);
earFound = true;
break;
}

// Yield control every 100 iterations to avoid blocking main thread


if (i % 100 == 0)
{
yield return null;
}
}

if (!earFound)
{
Debug.LogWarning("Triangulation stopped - unable to find ear. Check
input polygon.");
break;
}
}
}

// Helper function to determine if a vertex is an "ear" in ear clipping


algorithm
private bool IsEar(Vector3 prev, Vector3 curr, Vector3 next, List<Vector3>
vertices)
{
if (Vector3.Cross(next - curr, prev - curr).y <= 0)
return false;

foreach (var vertex in vertices)


{
if (vertex == prev || vertex == curr || vertex == next) continue;

if (PointInTriangle(vertex, prev, curr, next))


return false;
}
return true;
}

// Helper function to check if a point is inside a triangle


private bool PointInTriangle(Vector3 point, Vector3 a, Vector3 b, Vector3 c)
{
var cross1 = Vector3.Cross(b - a, point - a);
var cross2 = Vector3.Cross(c - b, point - b);
var cross3 = Vector3.Cross(a - c, point - c);

return cross1.y >= 0 && cross2.y >= 0 && cross3.y >= 0;


}

private int CalculateTotalTilesNeeded(float width, float height)


{
// Define grout width and spacing based on tile size
float groutWidth = 0.005f; // default to 5 mm
string groutSpacing = "4-5mm";

if (tileSizeInMeters == 0.4f)
{
groutWidth = 0.005f;
groutSpacing = "4-5mm";
}
else if (tileSizeInMeters == 0.3f)
{
groutWidth = 0.004f;
groutSpacing = "3-4mm";
}
else if (tileSizeInMeters == 0.6f)
{
groutWidth = 0.003f;
groutSpacing = "2-3mm";
}

// Calculate the effective tile size by including grout width


float effectiveTileSize = tileSizeInMeters + groutWidth;

// Calculate the number of full tiles along each dimension


int fullTilesX = Mathf.FloorToInt(width / effectiveTileSize);
int fullTilesY = Mathf.FloorToInt(height / effectiveTileSize);

// Initialize total tiles needed with the full tiles count


int totalTilesNeeded = fullTilesX * fullTilesY;

// Calculate the areas for partial tiles


float partialWidth = width % effectiveTileSize;
float partialHeight = height % effectiveTileSize;
double partialTileArea = 0;

// Add extra tiles for partial tiles along edges


if (partialWidth > 0)
{
totalTilesNeeded += fullTilesY; // Add a column of partial tiles
partialTileArea += partialWidth * (fullTilesY * tileSizeInMeters);
}
if (partialHeight > 0)
{
totalTilesNeeded += fullTilesX; // Add a row of partial tiles
partialTileArea += partialHeight * (fullTilesX * tileSizeInMeters);
}

// Add one corner tile for any remaining space in both directions
if (partialWidth > 0 && partialHeight > 0)
{
totalTilesNeeded += 1; // Additional corner tile
partialTileArea += partialWidth * partialHeight;
}

// Calculate total area in square meters


double totalArea = width * height;

// Calculate grout and adhesive requirements based on total area


double groutRequiredKg = Math.Ceiling((totalArea / 5) * 2); // 2 kg per 5
sqm
double adhesiveRequiredKg = Math.Ceiling((totalArea / 6) * 25); // 25 kg
per 6 sqm

// Output results
Debug.Log($"Total Area: {totalArea} sqm");
Debug.Log($"Total Tiles Needed: {totalTilesNeeded}");
Debug.Log($"Partial Tile Area: {partialTileArea} sqm");
Debug.Log($"Recommended Grout Spacing: {groutSpacing}");
Debug.Log($"Grout Required (kg): {groutRequiredKg}");
Debug.Log($"Adhesive Required (kg): {adhesiveRequiredKg}");
// Display results
resultText.text = $"Number of Tiles: {totalTilesNeeded}\n";
resultText.text += $"Partial Tile Area: {partialTileArea:F2} sqm\n";
resultText.text += $"Recommended Grout Spacing: {groutSpacing}\n";
resultText.text += $"Grout Required: {groutRequiredKg} kg\n";
resultText.text += $"Adhesive Required: {adhesiveRequiredKg} kg";
resultText.gameObject.SetActive(true);

// Adjust tiling for the shader based on real-world dimensions, accounting


for grout spacing
float tileCountX = width / effectiveTileSize;
float tileCountY = height / effectiveTileSize;
polyMaterial.SetVector("_Tiling", new Vector4(tileCountX, tileCountY, 0,
0));

currentTotalTilesNeeded = totalTilesNeeded;

return totalTilesNeeded;
}

private void ResetDotPoints()


{
// Cleanup: Destroy dots and clear points
foreach (GameObject dot in dots)
{
Destroy(dot);
}

points.Clear();
dots.Clear();

// Destroy the line renderer


if (currentLine != null)
{
Destroy(currentLine);
}
currentLine = Instantiate(linePrefab);
lineRenderer = currentLine.GetComponent<LineRenderer>();
}

private void ResetPolygons()


{
allowTouch = true;
currentPolygon.SetActive(false);
tilePanel.gameObject.SetActive(false);
resultText.gameObject.SetActive(false);
rotateSlider.gameObject.SetActive(false);
btnAddToCart.gameObject.SetActive(false);
btnCapturePhoto.gameObject.SetActive(false);
moveButton.gameObject.SetActive(false);
addButton.gameObject.SetActive(false);
}

private void UndoReset()


{
allowTouch = false;

if (points.Count > 0)
{
ResetDotPoints();
}

currentPolygon.SetActive(true);
tilePanel.gameObject.SetActive(true);
resultText.gameObject.SetActive(true);
rotateSlider.gameObject.SetActive(true);
btnAddToCart.gameObject.SetActive(true);
btnCapturePhoto.gameObject.SetActive(true);
moveButton.gameObject.SetActive(true);
addButton.gameObject.SetActive(true);
}

private void RotateSliderUpdate(float value)


{
polyMaterial.SetFloat("_Rotation", value);
}

private void OnSizeSliderValueChanged(float value)


{
// Find the closest snap value
float closest = snapValues[0];
float minDifference = Mathf.Abs(value - snapValues[0]);

for (int i = 1; i < snapValues.Length; i++)


{
float difference = Mathf.Abs(value - snapValues[i]);
if (difference < minDifference)
{
closest = snapValues[i];
minDifference = difference;
}
}

// Snap the slider to the closest value


tileSizeSlider.value = closest;

if (tileSizeSlider.value == previousSliderValue)
{
return;
}

previousSliderValue = tileSizeSlider.value;

// Update the size label based on the snapped value


int sizeIndex = System.Array.IndexOf(snapValues, closest);
UpdateTileSizeLabel(closest);

tileSizeInMeters = sizeValues[sizeIndex];

if (currentPolygon != null)
{
Vector3 minBounds =
currentPolygon.GetComponent<MeshFilter>().mesh.bounds.min;
Vector3 maxBounds =
currentPolygon.GetComponent<MeshFilter>().mesh.bounds.max;
CalculateTotalTilesNeeded(maxBounds.x - minBounds.x, maxBounds.z -
minBounds.z);
}
}

private void UpdateTileSizeLabel(float snapValue)


{
int sizeIndex = System.Array.IndexOf(snapValues, snapValue);
sizeLabel.text = tileSizes[sizeIndex]; // Update the label with
corresponding tile size
}

private void AddCalculatedToCart()


{
// Ensure product data is available
ProductData productData;
ProductData selectorProduct = tileSelector.GetCurrentSelectedProduct();
if (selectorProduct == null)
{
productData = selectedProduct;
}
else
{
productData = selectorProduct;
}

// Get the size based on the slider's current value


int sizeIndex = System.Array.IndexOf(snapValues, tileSizeSlider.value);
if (sizeIndex < 0 || sizeIndex >= sizeValues.Length)
{
Debug.LogError("Invalid size index.");
return;
}

float tileSize = sizeValues[sizeIndex];


string tileSizeString = tileSizes[sizeIndex];

// Check if there is stock for the selected size


int availableStock = productData.GetStockForSize(tileSizeString);
if (availableStock <= 0)
{
Debug.LogError($"No stock available for size {tileSizeString}.");
ShowError($"No stock available for size {tileSizeString}. Please choose
a different size.");
return;
}

// Ensure the required tiles are in stock


if (currentTotalTilesNeeded > availableStock)
{
Debug.LogError($"Not enough stock available. Required:
{currentTotalTilesNeeded}, Available: {availableStock}");
ShowError("Not enough stock available for the selected size.");
return;
}

// Show confirmation dialog


ShowAddToCartConfirmation(() =>
{
// Callback when the user confirms the addition
float selectedSizePrice = productData.GetPriceForSize(tileSizeString);
// Create a productCartData object to store cart details
productCartData cartData = new productCartData(
productData.productCode,
productData.name,
productData.image,
tileSizeString,
selectedSizePrice,
currentTotalTilesNeeded
);

// Add to the cart


if (cartManager != null)
{
cartManager.AddToCart(cartData);
Debug.Log("Added Calculated to Cart.");
}
else
{
Debug.LogError("CartManager not found!");
}
});
}

private void ShowAddToCartConfirmation(Action onConfirm)


{
// Instantiate the confirmation dialog prefab
GameObject dialog = Instantiate(prefabAddToCart, canvas.transform);

// Get references to the dialog components


TextMeshProUGUI dialogText =
dialog.GetComponentInChildren<TextMeshProUGUI>();
dialogText.text = "Are you sure you want to add this item to your cart?";

Button confirmButton =
dialog.transform.Find("btnConfirm").GetComponent<Button>();
Button cancelButton =
dialog.transform.Find("btnCancel").GetComponent<Button>();

// Add listeners to the confirm and cancel buttons


confirmButton.onClick.AddListener(() =>
{
onConfirm.Invoke();
Destroy(dialog);
});

cancelButton.onClick.AddListener(() => Destroy(dialog));


}

private void ShowError(string message)


{
GameObject successPanel = Instantiate(errorPrefabToast, cartPageContainer);

TextMeshProUGUI panelText =
successPanel.GetComponentInChildren<TextMeshProUGUI>();
panelText.text = message;

successPanel.transform.localScale = Vector3.zero;
LeanTween.scale(successPanel, Vector3.one,
0.5f).setEase(LeanTweenType.easeOutBack);
LeanTween.delayedCall(2f, () =>
{
LeanTween.scale(successPanel, Vector3.zero,
0.5f).setEase(LeanTweenType.easeInBack)
.setOnComplete(() => Destroy(successPanel));
});
}

void OnMoveButtonClicked()
{
isMoveActive = true; // Set to true when Move button is clicked
moveButton.gameObject.SetActive(false);
addButton.gameObject.SetActive(true);
Debug.Log("Move Button Active: " + isMoveActive);

void OnAddButtonClicked()
{
isMoveActive = false; // Set to false when Add button is clicked
moveButton.gameObject.SetActive(true);
addButton.gameObject.SetActive(false);
Debug.Log("Move Button Active: " + isMoveActive);
}
}

You might also like