123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- using UnityEngine;
- using UnityEngine.UI;
- using TMPro;
- using System.Linq;
-
- public class StairDiagramController : MonoBehaviour
- {
- [Header("元件綁定")]
- public RectTransform 繪圖區_panel;
- public RectTransform 對應資訊區_panel;
- public GameObject 階梯Prefab;
- public GameObject 資訊列Prefab; // 預設放一個 TMP Text 或含文字的UI列
- public GameObject 線段編號Prefab;
-
- [Header("參數設定")]
- [SerializeField] TMP_InputField 階梯階數_tb;
- [SerializeField] TextMeshProUGUI 總深_tb,總高_tb, 斜邊_tb, 長邊_tb, 推薦斜邊_tb, 推薦長邊_tb, 最小斜邊_tb, 最小長邊_tb;
- [SerializeField] TMP_InputField[] 高;
- [SerializeField] TMP_InputField[] 深;
-
- [SerializeField] Image 法規_bg,推薦_bg,最小_bg;
- [SerializeField] GameObject 簡易圖_pl,斜坡板參數_pl;
-
- int 線段編號 = 1;
- public void 返回參數(){
- 簡易圖_pl.SetActive(false);
- 斜坡板參數_pl.SetActive(true);
- }
- public void 生成法規圖(string 畫圖種類){
- 法規_bg.color=Color.white;推薦_bg.color=Color.white;最小_bg.color=Color.white;
- if (畫圖種類 == "法規"){
- 法規_bg.color = new Color32(253, 228, 151, 255);
- }
- else if (畫圖種類 == "推薦"){
- 推薦_bg.color = new Color32(253, 228, 151, 255);
- }
- else if (畫圖種類 == "最小"){
- 最小_bg.color = new Color32(253, 228, 151, 255);
- }
-
- int 階梯層數 = int.Parse(階梯階數_tb.text);
- float shortSide = float.Parse(總高_tb.text);
- float longSide = float.Parse(總深_tb.text);
- if (shortSide == 0f || longSide == 0f)
- return;
- 簡易圖_pl.SetActive(true);
- 斜坡板參數_pl.SetActive(false);
- foreach (Transform child in 繪圖區_panel)
- Destroy(child.gameObject);
- foreach (Transform child in 對應資訊區_panel)
- Destroy(child.gameObject);
-
- 線段編號 = 1;
- float[] stepWidths = GetStepWidths(1);
- float[] stepHeights = GetStepHeights(1);
- float lastStepWidth = stepWidths[階梯層數 - 1];
-
- double angle = 0;
- if (shortSide >= 20){
- angle = 4.78;
- }else if(shortSide >=5 && shortSide < 20){
- angle = 5.74;
- }else if(shortSide >=4 && shortSide < 5){
- angle = 11.54;
- }else if(shortSide >=0 && shortSide < 3){
- angle = 30;
- }
- 計算斜邊(angle, shortSide, longSide, stepWidths[階梯層數 - 1], 斜邊_tb, 長邊_tb);
- 計算斜邊(9.59, shortSide, longSide, stepWidths[階梯層數 - 1], 推薦斜邊_tb, 推薦長邊_tb);
- 計算斜邊(11.54, shortSide, longSide, stepWidths[階梯層數 - 1], 最小斜邊_tb, 最小長邊_tb);
-
- float hypotenuse = float.Parse(斜邊_tb.text);
- float hypotenuse2 = float.Parse(推薦斜邊_tb.text);
- float hypotenuse3 = float.Parse(最小斜邊_tb.text);
-
- float longuse = float.Parse(長邊_tb.text);
- float longuse2 = float.Parse(推薦長邊_tb.text);
- float longuse3 = float.Parse(最小長邊_tb.text);
-
- float otherSide = Mathf.Sqrt(hypotenuse * hypotenuse - shortSide * shortSide);
- float otherSide2 = Mathf.Sqrt(hypotenuse2 * hypotenuse2 - shortSide * shortSide);
- float otherSide3 = Mathf.Sqrt(hypotenuse3 * hypotenuse3 - shortSide * shortSide);
- float setWidthLast = GetStepWidths(1)[階梯層數 - 1];
- float 倍數 = Mathf.Round((繪圖區_panel.rect.width - 100f) / (otherSide + setWidthLast) * 100f) / 100f;
-
- float bottomY = 100f;
- float pointA_x = 10f;
- Vector2 pointA = new Vector2(pointA_x, bottomY);
- Vector2 pointB = new Vector2(pointA.x + otherSide * 倍數, bottomY);
- Vector2 pointC = new Vector2(pointB.x, bottomY + shortSide * 倍數);
- Vector2 pointD = new Vector2(pointB.x - otherSide2 * 倍數, bottomY);
- Vector2 pointE = new Vector2(pointB.x - otherSide3 * 倍數, bottomY);
-
- if(畫圖種類=="法規"){
- DrawLine(pointA, pointC, Color.blue, 畫圖種類+"斜坡板長度", hypotenuse);
- DrawLine(pointA, pointB, Color.black, "通道保留空間", longuse);
- }else if(畫圖種類=="推薦"){
- DrawLine(pointD, pointC, Color.black, 畫圖種類+"斜坡板長度", hypotenuse);
- DrawLine(pointD, pointB, Color.black, "通道保留空間", longuse2);
- }else{//最小
- DrawLine(pointE, pointC, Color.red, 畫圖種類+"斜坡板長度", hypotenuse);
- DrawLine(pointE, pointB, Color.black, "通道保留空間", longuse3);
- }
-
- float startX = pointA.x + otherSide * 倍數;
- for (int i = 0; i < 階梯層數 - 1; i++)
- startX -= stepWidths[i] * 倍數;
-
- float baseX;
- float baseOtherSide;
-
- if (畫圖種類 == "法規"){
- baseX = pointA.x;
- baseOtherSide = otherSide;
- }else if (畫圖種類 == "推薦"){
- baseX = pointD.x;
- baseOtherSide = otherSide2;
- }else{ // 最小
- baseX = pointE.x;
- baseOtherSide = otherSide3;
- }
-
- for (int i = 0; i < 階梯層數 - 1; i++)
- {
- float leftX = startX + stepWidths.Take(i).Sum() * 倍數;
- float stairTopY = bottomY + stepHeights.Take(i + 1).Sum() * 倍數;
- Vector2 stairTop = new Vector2(leftX, stairTopY);
-
- // 法規線在對應 X 的 Y 高度
- float slopeY = bottomY + (leftX - baseX) * (shortSide / baseOtherSide);
- Vector2 intersectPoint = new Vector2(leftX, slopeY);
-
- // ✅ 關鍵修改:統一與 VB 一樣公式
- float 垂直距離 = Mathf.Round((slopeY - stairTopY) / 倍數 * 10f) / 10f;
-
- Vector2 mid = (stairTop + intersectPoint) / 2 + Vector2.up * 10;
- DrawLine(stairTop, intersectPoint, Color.yellow, "間距", 垂直距離);
- }
-
-
- float stairX = startX;
- float stairY = bottomY;
-
- for (int i = 0; i < 階梯層數; i++){
- float w = stepWidths[i] * 倍數;
- float h = stepHeights[i] * 倍數;
- DrawStairBox(new Vector2(stairX, stairY), w, h);
- stairX += w;
- stairY += h;
- }
- }
- void DrawStairBox(Vector2 bottomLeft, float width, float height){
- GameObject box = Instantiate(階梯Prefab, 繪圖區_panel);
- RectTransform rt = box.GetComponent<RectTransform>();
-
- rt.anchorMin = rt.anchorMax = rt.pivot = new Vector2(0, 0); // 左下角錨點
- rt.anchoredPosition = bottomLeft;
- rt.sizeDelta = new Vector2(width, height);
- }
- void DrawLine(Vector2 start, Vector2 end, Color color, string 用途 = "", float 實際長度 = -1f){
- GameObject line = new GameObject("UILine", typeof(Image));
- line.transform.SetParent(繪圖區_panel, false);
-
- RectTransform rt = line.GetComponent<RectTransform>();
- Image image = line.GetComponent<Image>();
- image.color = color;
-
- Vector2 direction = end - start;
- float length = direction.magnitude;
- float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
-
- rt.sizeDelta = new Vector2(length, 10f);
- rt.pivot = new Vector2(0, 0.5f);
- rt.anchorMin = new Vector2(0, 0);
- rt.anchorMax = new Vector2(0, 0);
- rt.anchoredPosition = start;
- rt.localRotation = Quaternion.Euler(0, 0, angle);
-
- // 加線段編號(畫面旁邊)
- GameObject label = Instantiate(線段編號Prefab, 繪圖區_panel);
- TextMeshProUGUI text = label.GetComponent<TextMeshProUGUI>();
- text.text = $"L{線段編號}";
- RectTransform textRT = label.GetComponent<RectTransform>();
- textRT.anchorMin = textRT.anchorMax = new Vector2(0, 0);
- textRT.pivot = new Vector2(0.5f, 0.5f);
- // 計算文字偏移(避免被線擋住)
- Vector2 mid = (start + end) / 2;
- Vector2 offset = Vector2.Perpendicular((end - start).normalized) * 15f;
- textRT.anchoredPosition = mid + offset;
-
- label.transform.SetAsLastSibling();
- // 紀錄這條線的資訊到對應區域
- if (string.IsNullOrEmpty(用途))
- 用途 = "未指定";
-
- if (實際長度 < 0f)
- 實際長度 = Vector2.Distance(start, end); // fallback 值
-
- AddInfoRow($"L{線段編號}", 用途, 實際長度);
- 線段編號++;
- }
- void AddInfoRow(string 編號, string 用途, float 長度){
- GameObject row = Instantiate(資訊列Prefab, 對應資訊區_panel);
- TextMeshProUGUI[] labels = row.GetComponentsInChildren<TextMeshProUGUI>();
- labels[0].text = 編號 + " | ";
- labels[1].text = $"{用途} | {Mathf.Round(長度 * 10f) / 10f} cm";
- }
- public float[] GetStepWidths(float multiplier){
- float[] widths = new float[深.Length];
- for (int i = 0; i < 深.Length; i++){
- widths[i] = GetDepthValue(深[i], multiplier);
- }
- return widths;
- }
-
-
- public float[] GetStepHeights(float multiplier)
- {
- float[] heights = new float[高.Length];
- for (int i = 0; i < 高.Length; i++){
- heights[i] = GetHeightValue(高[i], multiplier);
- }
- return heights;
- }
-
-
- private float GetDepthValue(TMP_InputField inputField, float multiplier){
- if (!string.IsNullOrWhiteSpace(inputField.text) && float.TryParse(inputField.text, out float value)){
- return value * multiplier;
- }
- return 0f;
- }
-
-
- private float GetHeightValue(TMP_InputField inputField, float multiplier){
- if (!string.IsNullOrWhiteSpace(inputField.text) && float.TryParse(inputField.text, out float value)){
- return value * multiplier;
- }
- return 0f;
- }
- void 計算斜邊(double angle, double 短邊, double 長邊, double setWidth, TextMeshProUGUI 斜邊Text, TextMeshProUGUI 長邊Text){
- double angleInRadians = angle * Mathf.Deg2Rad;
- double hypotenuse = 短邊 / Mathf.Sin((float)angleInRadians);
- double longSide = hypotenuse * Mathf.Cos((float)angleInRadians) - 長邊 + setWidth;
-
- 斜邊Text.text = System.Math.Round(hypotenuse, 1, System.MidpointRounding.AwayFromZero).ToString();
- 長邊Text.text = System.Math.Round(longSide, 1, System.MidpointRounding.AwayFromZero).ToString();
- }
- }
|