using UnityEngine; using System.Text.RegularExpressions; using UnityEngine.UI.Extensions; using System.Collections.Generic; using System; using System.Linq; using UnityEditor; using TMPro; using UnityEngine.EventSystems; using Unity.VisualScripting; public class WallCreationManager : MonoBehaviour { static public WallCreationManager _instance; [SerializeField] private WallPoint _prefabWallPoint; [SerializeField] private WallLine _prefabWallLine; [SerializeField] private RectTransform _parentWallPoints; [SerializeField] private RectTransform _parentWallLines; [SerializeField] private RectTransform _parentDeletionObjects; [SerializeField] private Canvas _canvas; private WallPoint _currentWallPoint; private WallLine _currentWallLine; public GameObject _InputKeyDimension; public TMP_InputField _InputKeyValue; static public bool _isAddingWall; // TODO : have proper state machine for wall deletion and other event triggers on objects private void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); return; } else { _instance = this; } } private void Update() { if (!_isAddingWall) { _InputKeyDimension.SetActive(false); return; } AddMeasure(); AddInputDimension(); if (Input.GetKeyDown(KeyCode.Return)) { CreatePointFromKeyInput(); } // TODO : update not used while inactive? if (!gameObject.activeInHierarchy) // TODO : use right click as cancel (for now)? { // TODO : undo actions EndCreation(); return; } // other point follows cursor and wall adjusts accordingly (TODO : update wall values with function on manipulation) bool isSnapped = WallSnap.TrySnap(GetMousePositionOnScreen(), _currentWallPoint.GetComponent(), out Vector2 toPosition, out RectTransform onSnapTransform); _currentWallPoint.SetAnchoredPosition(toPosition); if (_currentWallLine != null) { _currentWallLine.UpdateValuesFromPoints(); } //Debug.Log($"_currentWallPoint {_currentWallPoint?.name} && onSnapTransform {onSnapTransform?.name}"); // create other point and wall on 1st click in plan if (Input.GetMouseButtonDown(0)) { if (isSnapped && onSnapTransform != null) { if (onSnapTransform.TryGetComponent(out WallPoint snappedWallPoint)) { Debug.Log("Try merge with wall point"); _currentWallPoint.MergeWithPoint(snappedWallPoint); _currentWallPoint = snappedWallPoint; } else if (onSnapTransform.TryGetComponent(out WallLine snappedWallLine)) { //Debug.Log("Try merge with wall line"); _currentWallPoint.MergeWithWall(snappedWallLine); } } WallPoint pointStart = _currentWallPoint; _G.SelectedPoint2D=pointStart; #if false // TODO : temporary forced sequential wall building // stop other point from following mouse on 2nd click _currentWallPoint = CreatePoint(toPosition); WallPoint pointEnd = _currentWallPoint; if (_currentWallLine != null) { _currentWallLine.ValidateWall(); _currentWallLine = null; return; } _currentWallLine = CreateLine(pointStart, pointEnd); #else if (_parentWallLines.childCount > 0) { WallPoint firstPoint = _parentWallLines.GetChild(0).GetComponent()._pointStart; WallPoint lastPoint = _parentWallLines.GetChild(_parentWallLines.childCount - 1).GetComponent()._pointEnd; WallPoint lastPointStart = _parentWallLines.GetChild(_parentWallLines.childCount - 1).GetComponent()._pointStart; if (_currentWallPoint == firstPoint) { _currentWallPoint = CreatePoint(toPosition); ClosePlan(); EndCreation(); } else if (_currentWallPoint == lastPointStart) { _isAddingWall = false; EndCreation(); ClosePlan(); } else { _currentWallPoint = CreatePoint(toPosition); WallPoint pointEnd = _currentWallPoint; _currentWallLine = CreateLine(pointStart, pointEnd); } } else { _currentWallPoint = CreatePoint(toPosition); WallPoint pointEnd = _currentWallPoint; _currentWallLine = CreateLine(pointStart, pointEnd); } #endif } if (Input.GetMouseButtonDown(1)) { EndCreation(); ClosePlan(); ReorderNumberWalls(); HideMeasureInteriorWall(); } } public WallPoint GetCurrentWallPoint() { return _currentWallPoint; } private void OnDisable() { EndCreation(); } public bool IsAddingWallState() { return _isAddingWall; } public void AddFirstPointFreehandDraw() { print("---Click on Board---"); if (GetWallPointContainer().childCount == 0) { print("---First Click on Board---"); _G.isExteriorWall = true; _currentWallPoint = CreatePoint(GetMousePositionOnScreen()); _isAddingWall = true; AddWall(); _G.StartPoint2D=_currentWallPoint; } // if (!_G.isExteriorWall) // { // //print("Mouseposition----→ʼn------"); // float PointXmax = 0; // float PointXmin = 0; // float PointYmax = 0; // float PointYmin = 0; // foreach (Transform point in _parentWallPoints.transform) // { // Vector2 Position = point.gameObject.GetComponent().GetAnchoredPosition(); // if (Position.x > PointXmax) { PointXmax = Position.x; } // if (Position.x < PointXmin) { PointXmin = Position.x; } // if (Position.y > PointYmax) { PointYmax = Position.y; } // if (Position.y < PointXmin) { PointYmin = Position.y; } // } // Vector2 Mouseposition = GetMousePositionOnScreen(); // if (Mouseposition.x < PointXmax && Mouseposition.x > PointXmin && Mouseposition.y > PointYmin && Mouseposition.y < PointYmax) // { // _currentWallPoint = CreatePoint(GetMousePositionOnScreen()); // _isAddingWall = true; // AddWall(); // } // else // { // HideMeasureInteriorWall(); // print("Mouseposition----Out------"); // } // } } // create point on create button pressed public void AddWall() { if (_currentWallPoint != null) { return; } if (WallSelection.TryGetCurrentSelection(out IWallSelection selection)) { selection.InsertWall(); return; } #if true // TODO : temporary sequential wall creation mode if (_parentWallLines.childCount > 0) { WallPoint firstPoint = _parentWallLines.GetChild(0).GetComponent()._pointStart; WallPoint lastPoint = _parentWallLines.GetChild(_parentWallLines.childCount - 1).GetComponent()._pointEnd; if (firstPoint == lastPoint) { return; } } #endif _isAddingWall = true; _currentWallPoint = CreatePoint(GetMousePositionOnScreen()); #if true // TODO : temporary sequential wall creation mode RectTransform wallContainer = GetWallLineContainer(); if (wallContainer.childCount > 0) { WallPoint startPoint = wallContainer.GetChild(wallContainer.childCount - 1).GetComponent()._pointEnd; _currentWallLine = CreateLine(startPoint, _currentWallPoint); } #endif } static public Vector2 GetMousePositionOnScreen() { return ((Vector2)Input.mousePosition - new Vector2(Screen.width, Screen.height) / 2.0f) / _instance._canvas.scaleFactor; } static public WallPoint CreatePoint(Vector3 position) { WallPoint wallPoint = Instantiate(_instance._prefabWallPoint, _instance._parentWallPoints); wallPoint.name = $"WallPoint{ GetWallPointContainer().childCount}"; if (!wallPoint.HasAwaken) { wallPoint.Awake(); } wallPoint.SetAnchoredPosition(position); wallPoint._PointHeight = _G.HEIGHT; _G.SelectedPoint2D=wallPoint; // _G.StartPoint2D=wallPoint; return wallPoint; } static public WallPoint CreatePoint(WallPointData data) { WallPoint wallPoint = Instantiate(_instance._prefabWallPoint, _instance._parentWallPoints); wallPoint.name = $"WallPoint{GetWallPointContainer().childCount}"; //wallPoint.Copy(data); if (!wallPoint.HasAwaken) { wallPoint.Awake(); } wallPoint.SetAnchoredPosition(data._Position); wallPoint._PointHeight = data._PointHeight; _G.SelectedPoint2D=wallPoint; return wallPoint; } static public WallLine CreateLine(WallPoint pointStart, WallPoint pointEnd) { WallLine wallLine = Instantiate(_instance._prefabWallLine, _instance._parentWallLines); wallLine.gameObject.SetActive(true); wallLine.name = "WallLine"; if (!wallLine.HasAwaken) { wallLine.Awake(); } wallLine.InitPoints(pointStart, pointEnd); //Set Wall category creation Exterior or Interior if (_G.SelectedWall2D == null) { _G.SelectedWall2D = wallLine; } string WallCreation = "Exterior"; float Thickness = 6; if (!_G.isExteriorWall) { WallCreation = "Interior"; for (int i = 0; i < 5; i++) { wallLine.mat.Add(_G.WallsMaterial[0]); } Thickness = 6; } wallLine.gameObject.GetComponent().LineThickness = Thickness; wallLine.Thickness = Thickness; wallLine._category = WallCreation; //int.TryParse(wallLine.name[8..], out int index); //wallLine.interiorWallFacesNumber.Add(index.ToString()); ReorderNumberWalls(); return wallLine; } static public WallLine CreateLine(WallPoint pointStart, WallPoint pointEnd, WallLineData data) { WallLine wallLine = Instantiate(_instance._prefabWallLine, _instance._parentWallLines); wallLine.gameObject.SetActive(true); wallLine.name = "WallLine"; if (!wallLine.HasAwaken) { wallLine.Awake(); } wallLine.InitPoints(pointStart, pointEnd); //Set Wall category creation Exterior or Interior if (_G.SelectedWall2D == null) { _G.SelectedWall2D = wallLine; } string WallCreation = data.category; float Thickness = data.thickness; wallLine.gameObject.GetComponent().LineThickness = Thickness; wallLine.Thickness = Thickness; wallLine._category = WallCreation; wallLine.mat = data.matList; ReorderNumberWalls(); wallLine.interiorWallFacesNumber = data.interiorWallFacesNumber; return wallLine; } static public void EndCreation() { if (_isAddingWall) { if (_instance._currentWallPoint != null) { _instance._currentWallPoint.DestroyPoint(); _instance._currentWallPoint = null; } if (_instance._currentWallLine != null) { _instance._currentWallLine.DestroyWall(); _instance._currentWallLine = null; } _isAddingWall = false; } _G.EXTERIOR_WALL_PLAN_CLOSED=true; HideMeasureInteriorWall(); } public void HandleWallDeletion() { #if true // TODO : temporary wall deletion management, see if still necessary if (_isAddingWall) { EndCreation(); } else { RectTransform wallContainer = GetWallLineContainer(); if (wallContainer.childCount > 0) { wallContainer.GetChild(wallContainer.childCount - 1).GetComponent().DestroyWall(); } } #endif } public void ClosePlan() { if (_G.isExteriorWall) { int QtyPoint = _parentWallPoints.childCount; WallPoint firstPoint = _parentWallPoints.GetChild(0).GetComponent(); WallPoint LastPoint = _parentWallPoints.GetChild(QtyPoint - 2).GetComponent(); _currentWallLine = CreateLine(LastPoint, firstPoint); _currentWallLine.GetComponent().LineThickness = 2; _G.WALLS_HIDDEN_LIST.Add("w" + (QtyPoint - 1).ToString()); _G.EXTERIOR_WALL_PLAN_CLOSED = true; _G.isExteriorWall = false; //_G.NWInterior=_G.NW+=1; HideMeasureInteriorWall(); } } public static void ReorderNumberWalls() { int IndexPosition = 1; RectTransform wallContainer = GetWallLineContainer(); foreach (RectTransform Wall in wallContainer.transform) { string IsNumber = string.Join(null, Regex.Split(Wall.gameObject.name, "[^\\d]")); if (string.IsNullOrEmpty(IsNumber)) { Wall.gameObject.name += IndexPosition.ToString(); } else { Wall.gameObject.name = Wall.gameObject.name.Replace(IsNumber, IndexPosition.ToString()); } IndexPosition += 1; } } static public RectTransform GetWallPointContainer() { return _instance._parentWallPoints; } static public RectTransform GetWallLineContainer() { return _instance._parentWallLines; } static public RectTransform GetDeletionContainer() { return _instance._parentDeletionObjects; } public static WallLine GetWallLineWithWallIndex(int wallIndex) { Transform WallLineContainer = GetWallLineContainer(); var matchingElement = _G.WallAssociateWallLine.FirstOrDefault(a => a.Split("_")[0] == $"w{wallIndex + 1}"); if (matchingElement != null) // If a matching element is found { // Access the element directly //Debug.Log($"Matching element: {matchingElement}"); if (int.TryParse(matchingElement.Split("_")[1], out int wallLineIndex)) { if (wallLineIndex < WallLineContainer.childCount) { Transform t = WallLineContainer.GetChild(wallLineIndex); if (t.TryGetComponent(out WallLine wallLine)) { return wallLine; } } } } return null; } public static bool IsWallExterior(int wallIndex) { WallLine wallLine = GetWallLineWithWallIndex(wallIndex); if (wallLine == null) { return false; } return wallLine._category == "Exterior"; } //------------Key Dimension public void AddInputDimension(){ if(_InputKeyDimension.activeInHierarchy==false){ _InputKeyDimension.SetActive(true); } } public void CreatePointFromKeyInput(){ //Get input from KeyInput float Distance=DOIT.ConvertStringToNumber(_InputKeyValue.text)*WallLine.RatioWorldToScreen; Vector2 direction = (_currentWallLine._pointEnd.GetAnchoredPosition() - _currentWallLine._pointStart.GetAnchoredPosition()).normalized; Vector2 Position =_currentWallLine._pointStart.GetAnchoredPosition()+Distance*direction; _currentWallLine._pointEnd.SetAnchoredPosition(Position); _currentWallPoint.SetAnchoredPosition(Position); _currentWallLine.UpdateValuesFromPoints(); WallPoint wpmouse = CreatePoint(GetMousePositionOnScreen()); _currentWallPoint=wpmouse ; _currentWallLine=CreateLine(_currentWallLine._pointEnd ,wpmouse); _InputKeyValue.text=""; } private void OnPointerDown(PointerEventData data) { Debug.Log("Pointer Down Event Triggered on " + data.pointerPress); } //------------Quotes on Wallpoints public static void AddMeasure() { bool isShow=false; if(GetCategoryWallPoint(_G.SelectedPoint2D)=="Interior" )isShow=true; if(_G.SelectedPoint2D==null)isShow=false; if(isShow){ WallSelection.Quote1.SetActive(true); WallSelection.Quote2.SetActive(true); GameObject InputMeasure1 = WallSelection.Quote1.transform.Find("Measure1").gameObject; GameObject InputMeasure2 = WallSelection.Quote2.transform.Find("Measure2").gameObject; Vector2 CurrentPosition = _G.SelectedPoint2D.GetAnchoredPosition(); Vector2? intersection; Vector2 TouchPointY=new(0,0); Vector2 TouchPointX=new(0,0); Vector2 start,end; float DistanceY=500; float DistanceX=500; foreach(Transform wallline in WallCreationManager.GetWallLineContainer()) { WallLine Wall = wallline.GetComponent(); if(Wall._category=="Exterior") { start=Wall._pointStart.GetAnchoredPosition(); end=Wall._pointEnd.GetAnchoredPosition(); intersection = FindIntersectionOnYAxis(CurrentPosition.x,start,end); if (intersection.HasValue && DistanceY > Vector2.Distance((Vector2)intersection,CurrentPosition)){ DistanceY=Vector2.Distance((Vector2)intersection,CurrentPosition); TouchPointY = (Vector2)intersection; } intersection = FindIntersectionOnXAxis(CurrentPosition.y,start,end); if (intersection.HasValue && DistanceX > Vector2.Distance((Vector2)intersection,CurrentPosition)){ DistanceX=Vector2.Distance((Vector2)intersection,CurrentPosition); TouchPointX = (Vector2)intersection; } } } InputMeasure1.transform.localPosition=Vector2.Lerp(CurrentPosition,TouchPointY,0.5f); UILineRenderer line1= WallSelection.Quote1.transform.Find("Line").GetComponent(); line1.Points[0] = CurrentPosition; line1.Points[1] = TouchPointY; line1.LineThickness = 1.5f; line1.color = Color.grey; line1.SetVerticesDirty(); InputMeasure2.transform.localPosition=Vector2.Lerp(CurrentPosition,TouchPointX,0.5f); UILineRenderer line2= WallSelection.Quote2.transform.Find("Line").GetComponent(); line2.Points[0] = CurrentPosition; line2.Points[1] = TouchPointX; line2.LineThickness = 1.5f; line2.color = Color.grey; line2.SetVerticesDirty(); //Add measure float DisY=Vector2.Distance(CurrentPosition,TouchPointY)/WallLine.RatioWorldToScreen; float DisX=Vector2.Distance(CurrentPosition,TouchPointX)/WallLine.RatioWorldToScreen; InputMeasure1.transform.Find("Text").gameObject.GetComponent().text=DOIT.ConvertNumberToString(DisY); InputMeasure2.transform.Find("Text").GetComponent().text=DOIT.ConvertNumberToString(DisX); if(TouchPointY==Vector2.zero || TouchPointX==Vector2.zero)HideMeasureInteriorWall(); } else{HideMeasureInteriorWall();} } public static string GetCategoryWallPoint(WallPoint Point){ foreach(Transform wallline in WallCreationManager.GetWallLineContainer()){ WallLine Wall = wallline.GetComponent(); if(Wall._pointStart==Point || Wall._pointEnd==Point){return Wall._category;} } return "Interior"; } public static void HideMeasureInteriorWall(){ _G.SelectedPoint2D=null; if(WallSelection.Quote1!=null)WallSelection.Quote1.SetActive(false); if(WallSelection.Quote2!=null) WallSelection.Quote2.SetActive(false); } public static Vector2? FindIntersectionOnYAxis(float x0, Vector2 p1, Vector2 p2) { // Check if the line formed by p1 and p2 is vertical (same x value) if (Mathf.Approximately(p1.x, p2.x)) { //Debug.Log("Line is vertical, no intersection with another vertical line."); return null; // No intersection if the line formed by p1 and p2 is vertical } // Calculate the slope of the line (m = (y2 - y1) / (x2 - x1)) float slope =(p2.y - p1.y) / (p2.x - p1.x); // Calculate the y-intercept for the given x0 (y = mx + c) float yIntersection = slope * (x0 - p1.x) + p1.y; // Check if the intersection lies within the bounds of the line segment (p1 -> p2) if (x0 >= Mathf.Min(p1.x, p2.x) && x0 <= Mathf.Max(p1.x, p2.x)) { // Return the intersection point as a Vector2 return new Vector2(x0, yIntersection); } // No valid intersection within the segment return null; } public static Vector2? FindIntersectionOnXAxis(float y0, Vector2 p1, Vector2 p2) { // Check if the line formed by p1 and p2 is horizontal (same y value) if (Mathf.Approximately(p1.y, p2.y)) { //Debug.Log("Line is horizontal, no intersection with another horizontal line."); return null; // No intersection if the line formed by p1 and p2 is horizontal } // Calculate the slope of the line (m = (y2 - y1) / (x2 - x1)) float slope = (p2.y - p1.y) / (p2.x - p1.x); // Calculate the x-intercept for the given y0 (x = (y - c) / m) float xIntersection = (y0 - p1.y) / slope + p1.x; // Check if the intersection lies within the bounds of the line segment (p1 -> p2) if (y0 >= Mathf.Min(p1.y, p2.y) && y0 <= Mathf.Max(p1.y, p2.y)) { // Return the intersection point as a Vector2 return new Vector2(xIntersection, y0); } // No valid intersection within the segment return null; } }