ChartHelper.cs 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. /************************************************/
  2. /* */
  3. /* Copyright (c) 2018 - 2021 monitor1394 */
  4. /* https://github.com/monitor1394 */
  5. /* */
  6. /************************************************/
  7. using System.Text;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Text.RegularExpressions;
  11. using UnityEngine;
  12. using UnityEngine.EventSystems;
  13. using UnityEngine.UI;
  14. #if dUI_TextMeshPro
  15. using TMPro;
  16. #endif
  17. #if UNITY_EDITOR
  18. using UnityEditor;
  19. #endif
  20. namespace XCharts
  21. {
  22. public static class ChartHelper
  23. {
  24. private static StringBuilder s_Builder = new StringBuilder();
  25. private static Vector3 s_DefaultIngoreDataVector3 = Vector3.zero;
  26. public static StringBuilder sb { get { return s_Builder; } }
  27. public static Vector3 ignoreVector3 { get { return s_DefaultIngoreDataVector3; } }
  28. public static bool IsIngore(Vector3 pos)
  29. {
  30. return pos == s_DefaultIngoreDataVector3;
  31. }
  32. public static string Cancat(string str1, string str2)
  33. {
  34. s_Builder.Length = 0;
  35. s_Builder.Append(str1).Append(str2);
  36. return s_Builder.ToString();
  37. }
  38. public static string Cancat(string str1, int i)
  39. {
  40. s_Builder.Length = 0;
  41. s_Builder.Append(str1).Append(ChartCached.IntToStr(i));
  42. return s_Builder.ToString();
  43. }
  44. public static void SetActive(GameObject gameObject, bool active)
  45. {
  46. SetActive(gameObject.transform, active);
  47. }
  48. public static void SetActive(Image image, bool active)
  49. {
  50. if (image == null) return;
  51. SetActive(image.gameObject, active);
  52. }
  53. public static void SetActive(Text text, bool active)
  54. {
  55. if (text == null) return;
  56. SetActive(text.gameObject, active);
  57. }
  58. /// <summary>
  59. /// 通过设置scale实现是否显示,优化性能,减少GC
  60. /// </summary>
  61. /// <param name="transform"></param>
  62. /// <param name="active"></param>
  63. public static void SetActive(Transform transform, bool active)
  64. {
  65. if (active) transform.localScale = Vector3.one;
  66. else transform.localScale = Vector3.zero;
  67. }
  68. public static void HideAllObject(GameObject obj, string match = null)
  69. {
  70. HideAllObject(obj.transform, match);
  71. }
  72. public static void HideAllObject(Transform parent, string match = null)
  73. {
  74. ActiveAllObject(parent, false, match);
  75. }
  76. public static void ActiveAllObject(Transform parent, bool active, string match = null)
  77. {
  78. for (int i = 0; i < parent.childCount; i++)
  79. {
  80. if (match == null)
  81. SetActive(parent.GetChild(i), active);
  82. else
  83. {
  84. var go = parent.GetChild(i);
  85. if (go.name.StartsWith(match))
  86. {
  87. SetActive(go, active);
  88. }
  89. }
  90. }
  91. }
  92. public static void DestroyAllChildren(Transform parent)
  93. {
  94. if (parent == null) return;
  95. var childCount = parent.childCount;
  96. for (int i = childCount - 1; i >= 0; i--)
  97. {
  98. var go = parent.GetChild(i);
  99. if (go != null)
  100. {
  101. GameObject.DestroyImmediate(go.gameObject);
  102. }
  103. }
  104. }
  105. public static void DestoryGameObject(Transform parent, string childName)
  106. {
  107. if (parent == null) return;
  108. var go = parent.Find(childName);
  109. if (go != null)
  110. {
  111. GameObject.DestroyImmediate(go.gameObject);
  112. }
  113. }
  114. public static void DestoryGameObjectByMatch(Transform parent, string match)
  115. {
  116. if (parent == null) return;
  117. var childCount = parent.childCount;
  118. for (int i = childCount - 1; i >= 0; i--)
  119. {
  120. var go = parent.GetChild(i);
  121. if (go != null && go.name.StartsWith(match))
  122. {
  123. GameObject.DestroyImmediate(go.gameObject);
  124. }
  125. }
  126. }
  127. public static void DestoryGameObject(GameObject go)
  128. {
  129. if (go != null) GameObject.DestroyImmediate(go);
  130. }
  131. public static string GetFullName(Transform transform)
  132. {
  133. string name = transform.name;
  134. Transform obj = transform;
  135. while (obj.transform.parent)
  136. {
  137. name = obj.transform.parent.name + "/" + name;
  138. obj = obj.transform.parent;
  139. }
  140. return name;
  141. }
  142. public static void RemoveComponent<T>(GameObject gameObject)
  143. {
  144. var component = gameObject.GetComponent<T>();
  145. if (component != null)
  146. {
  147. #if UNITY_EDITOR
  148. if (!Application.isPlaying)
  149. GameObject.DestroyImmediate(component as GameObject);
  150. else
  151. GameObject.Destroy(component as GameObject);
  152. #else
  153. GameObject.Destroy(component as GameObject);
  154. #endif
  155. }
  156. }
  157. public static T GetOrAddComponent<T>(Transform transform) where T : Component
  158. {
  159. return GetOrAddComponent<T>(transform.gameObject);
  160. }
  161. public static T GetOrAddComponent<T>(GameObject gameObject) where T : Component
  162. {
  163. if (gameObject.GetComponent<T>() == null)
  164. {
  165. return gameObject.AddComponent<T>();
  166. }
  167. else
  168. {
  169. return gameObject.GetComponent<T>();
  170. }
  171. }
  172. public static GameObject AddObject(string name, Transform parent, Vector2 anchorMin,
  173. Vector2 anchorMax, Vector2 pivot, Vector2 sizeDelta, int replaceIndex = -1)
  174. {
  175. GameObject obj;
  176. if (parent.Find(name))
  177. {
  178. obj = parent.Find(name).gameObject;
  179. SetActive(obj, true);
  180. obj.transform.localPosition = Vector3.zero;
  181. obj.transform.localScale = Vector3.one;
  182. }
  183. else if (replaceIndex >= 0 && replaceIndex < parent.childCount)
  184. {
  185. obj = parent.GetChild(replaceIndex).gameObject;
  186. if (!obj.name.Equals(name)) obj.name = name;
  187. SetActive(obj, true);
  188. }
  189. else
  190. {
  191. obj = new GameObject();
  192. obj.name = name;
  193. obj.transform.SetParent(parent);
  194. obj.transform.localScale = Vector3.one;
  195. obj.transform.localPosition = Vector3.zero;
  196. }
  197. RectTransform rect = GetOrAddComponent<RectTransform>(obj);
  198. rect.localPosition = Vector3.zero;
  199. rect.sizeDelta = sizeDelta;
  200. rect.anchorMin = anchorMin;
  201. rect.anchorMax = anchorMax;
  202. rect.pivot = pivot;
  203. rect.anchoredPosition3D = Vector3.zero;
  204. return obj;
  205. }
  206. public static void UpdateRectTransform(GameObject obj, Vector2 anchorMin,
  207. Vector2 anchorMax, Vector2 pivot, Vector2 sizeDelta)
  208. {
  209. if (obj == null) return;
  210. RectTransform rect = GetOrAddComponent<RectTransform>(obj);
  211. rect.sizeDelta = sizeDelta;
  212. rect.anchorMin = anchorMin;
  213. rect.anchorMax = anchorMax;
  214. rect.pivot = pivot;
  215. }
  216. public static ChartText AddTextObject(string name, Transform parent, Vector2 anchorMin, Vector2 anchorMax,
  217. Vector2 pivot, Vector2 sizeDelta, TextStyle textStyle, ComponentTheme theme)
  218. {
  219. GameObject txtObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  220. txtObj.transform.localEulerAngles = new Vector3(0, 0, textStyle.rotate);
  221. var chartText = new ChartText();
  222. #if dUI_TextMeshPro
  223. RemoveComponent<Text>(txtObj);
  224. chartText.tmpText = GetOrAddComponent<TextMeshProUGUI>(txtObj);
  225. chartText.tmpText.font = textStyle.tmpFont == null ? theme.tmpFont : textStyle.tmpFont;
  226. chartText.tmpText.fontStyle = textStyle.tmpFontStyle;
  227. chartText.tmpText.alignment = textStyle.tmpAlignment;
  228. chartText.tmpText.richText = true;
  229. chartText.tmpText.raycastTarget = false;
  230. chartText.tmpText.enableWordWrapping = textStyle.autoWrap;
  231. #else
  232. chartText.text = GetOrAddComponent<Text>(txtObj);
  233. chartText.text.font = textStyle.font == null ? theme.font : textStyle.font;
  234. chartText.text.fontStyle = textStyle.fontStyle;
  235. chartText.text.alignment = textStyle.alignment;
  236. chartText.text.horizontalOverflow = textStyle.autoWrap ? HorizontalWrapMode.Wrap : HorizontalWrapMode.Overflow;
  237. chartText.text.verticalOverflow = VerticalWrapMode.Overflow;
  238. chartText.text.supportRichText = true;
  239. chartText.text.raycastTarget = false;
  240. #endif
  241. chartText.SetColor(textStyle.GetColor(theme.textColor));
  242. chartText.SetFontSize(textStyle.GetFontSize(theme));
  243. chartText.SetText("Text");
  244. chartText.SetLineSpacing(textStyle.lineSpacing);
  245. RectTransform rect = GetOrAddComponent<RectTransform>(txtObj);
  246. rect.localPosition = Vector3.zero;
  247. rect.sizeDelta = sizeDelta;
  248. rect.anchorMin = anchorMin;
  249. rect.anchorMax = anchorMax;
  250. rect.pivot = pivot;
  251. return chartText;
  252. }
  253. public static Text AddTextObject(string name, Transform parent, Font font, Color color,
  254. TextAnchor anchor, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 sizeDelta,
  255. int fontSize = 14, float rotate = 0, FontStyle fontStyle = FontStyle.Normal, float lineSpacing = 1)
  256. {
  257. GameObject txtObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  258. var txt = GetOrAddComponent<Text>(txtObj);
  259. txt.font = font;
  260. txt.fontSize = fontSize;
  261. txt.fontStyle = fontStyle;
  262. txt.text = "Text";
  263. txt.alignment = anchor;
  264. txt.horizontalOverflow = HorizontalWrapMode.Overflow;
  265. txt.verticalOverflow = VerticalWrapMode.Overflow;
  266. txt.color = color;
  267. txt.lineSpacing = lineSpacing;
  268. txt.raycastTarget = false;
  269. txtObj.transform.localEulerAngles = new Vector3(0, 0, rotate);
  270. RectTransform rect = GetOrAddComponent<RectTransform>(txtObj);
  271. rect.localPosition = Vector3.zero;
  272. rect.sizeDelta = sizeDelta;
  273. rect.anchorMin = anchorMin;
  274. rect.anchorMax = anchorMax;
  275. rect.pivot = pivot;
  276. return txt;
  277. }
  278. #if dUI_TextMeshPro
  279. public static TextMeshProUGUI AddTMPTextObject(string name, Transform parent, TMP_FontAsset font, Color color,
  280. TextAlignmentOptions anchor, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 sizeDelta,
  281. int fontSize = 14, float rotate = 0, FontStyles fontStyle = FontStyles.Normal, float lineSpacing = 1)
  282. {
  283. GameObject txtObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  284. var txt = GetOrAddComponent<TextMeshProUGUI>(txtObj);
  285. txt.font = font;
  286. txt.fontSize = fontSize;
  287. txt.fontStyle = fontStyle;
  288. txt.text = "Text";
  289. txt.alignment = anchor;
  290. txt.color = color;
  291. txt.lineSpacing = lineSpacing;
  292. txt.raycastTarget = false;
  293. txt.enableWordWrapping = false;
  294. txtObj.transform.localEulerAngles = new Vector3(0, 0, rotate);
  295. RectTransform rect = GetOrAddComponent<RectTransform>(txtObj);
  296. rect.localPosition = Vector3.zero;
  297. rect.sizeDelta = sizeDelta;
  298. rect.anchorMin = anchorMin;
  299. rect.anchorMax = anchorMax;
  300. rect.pivot = pivot;
  301. return txt;
  302. }
  303. #endif
  304. public static Button AddButtonObject(string name, Transform parent, Font font, int fontSize,
  305. Color color, TextAnchor anchor, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot,
  306. Vector2 sizeDelta, float lineSpacing)
  307. {
  308. GameObject btnObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  309. GetOrAddComponent<Image>(btnObj);
  310. GetOrAddComponent<Button>(btnObj);
  311. Text txt = AddTextObject("Text", btnObj.transform, font, color, TextAnchor.MiddleCenter,
  312. new Vector2(0, 0), new Vector2(1, 1), new Vector2(0.5f, 0.5f),
  313. sizeDelta, fontSize, lineSpacing);
  314. txt.rectTransform.offsetMin = Vector2.zero;
  315. txt.rectTransform.offsetMax = Vector2.zero;
  316. return btnObj.GetComponent<Button>();
  317. }
  318. #if dUI_TextMeshPro
  319. public static Button AddTMPButtonObject(string name, Transform parent, TMP_FontAsset font, int fontSize,
  320. Color color, TextAlignmentOptions anchor, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot,
  321. Vector2 sizeDelta, float lineSpacing)
  322. {
  323. GameObject btnObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  324. GetOrAddComponent<Image>(btnObj);
  325. GetOrAddComponent<Button>(btnObj);
  326. var txt = AddTMPTextObject("Text", btnObj.transform, font, color, anchor,
  327. new Vector2(0, 0), new Vector2(1, 1), new Vector2(0.5f, 0.5f),
  328. sizeDelta, fontSize, lineSpacing);
  329. txt.rectTransform.offsetMin = Vector2.zero;
  330. txt.rectTransform.offsetMax = Vector2.zero;
  331. return btnObj.GetComponent<Button>();
  332. }
  333. #endif
  334. internal static GameObject AddTooltipContent(string name, Transform parent, TextStyle textStyle,
  335. ChartTheme theme)
  336. {
  337. var anchorMax = new Vector2(0, 1);
  338. var anchorMin = new Vector2(0, 1);
  339. var pivot = new Vector2(0, 1);
  340. var sizeDelta = new Vector2(100, 100);
  341. GameObject tooltipObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  342. var img = GetOrAddComponent<Image>(tooltipObj);
  343. img.color = Color.black;
  344. var txt = AddTextObject("Text", tooltipObj.transform, anchorMin, anchorMax, pivot, sizeDelta,
  345. textStyle, theme.tooltip);
  346. txt.SetAlignment(textStyle.GetAlignment(TextAnchor.UpperLeft));
  347. txt.SetText("Text");
  348. txt.SetLocalPosition(new Vector2(3, -3));
  349. tooltipObj.transform.localPosition = Vector3.zero;
  350. return tooltipObj;
  351. }
  352. internal static Painter AddPainterObject(string name, Transform parent, Vector2 anchorMin, Vector2 anchorMax,
  353. Vector2 pivot, Vector2 sizeDelta, HideFlags hideFlags, int siblingIndex)
  354. {
  355. var painterObj = ChartHelper.AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  356. painterObj.hideFlags = hideFlags;
  357. painterObj.transform.SetSiblingIndex(siblingIndex);
  358. return ChartHelper.GetOrAddComponent<Painter>(painterObj);
  359. }
  360. public static Image AddIcon(string name, Transform parent, float width, float height, Sprite sprite = null,
  361. Image.Type type = Image.Type.Simple)
  362. {
  363. var anchorMax = new Vector2(0.5f, 0.5f);
  364. var anchorMin = new Vector2(0.5f, 0.5f);
  365. var pivot = new Vector2(0.5f, 0.5f);
  366. var sizeDelta = new Vector2(width, height);
  367. GameObject iconObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  368. var img = GetOrAddComponent<Image>(iconObj);
  369. img.raycastTarget = false;
  370. img.type = type;
  371. if (sprite != null)
  372. {
  373. img.sprite = sprite;
  374. if (width == 0 || height == 0)
  375. {
  376. img.SetNativeSize();
  377. }
  378. }
  379. return img;
  380. }
  381. public static ChartLabel AddAxisLabelObject(int total, int index, string name, Transform parent,
  382. Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 sizeDelta, Axis axis, ComponentTheme theme,
  383. string content)
  384. {
  385. var textStyle = axis.axisLabel.textStyle;
  386. var iconStyle = axis.iconStyle;
  387. var label = new ChartLabel();
  388. label.gameObject = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  389. // TODO: 为了兼容旧版本,这里后面版本可以去掉
  390. var oldText = label.gameObject.GetComponent<Text>();
  391. if (oldText != null)
  392. {
  393. GameObject.DestroyImmediate(oldText);
  394. }
  395. var labelShow = axis.axisLabel.show && (axis.axisLabel.interval == 0 || index % (axis.axisLabel.interval + 1) == 0);
  396. if (labelShow)
  397. {
  398. if (!axis.axisLabel.showStartLabel && index == 0) labelShow = false;
  399. else if (!axis.axisLabel.showEndLabel && index == total - 1) labelShow = false;
  400. }
  401. label.label = AddTextObject("Text", label.gameObject.transform, anchorMin, anchorMax, pivot, sizeDelta, textStyle, theme);
  402. label.icon = ChartHelper.AddIcon("Icon", label.gameObject.transform, iconStyle.width, iconStyle.height);
  403. label.SetAutoSize(false);
  404. label.UpdateIcon(iconStyle, axis.GetIcon(index));
  405. label.label.SetActive(labelShow);
  406. label.SetText(content);
  407. return label;
  408. }
  409. internal static GameObject AddSerieLabel(string name, Transform parent, float width, float height,
  410. Color color, TextStyle textStyle, ChartTheme theme)
  411. {
  412. var anchorMin = new Vector2(0.5f, 0.5f);
  413. var anchorMax = new Vector2(0.5f, 0.5f);
  414. var pivot = new Vector2(0.5f, 0.5f);
  415. var sizeDelta = (width != 0 && height != 0)
  416. ? new Vector2(width, height)
  417. : new Vector2(50, textStyle.GetFontSize(theme.common) + 2);
  418. var labelObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  419. var txt = AddTextObject("Text", labelObj.transform, anchorMin, anchorMax, pivot, sizeDelta, textStyle,
  420. theme.common);
  421. txt.SetColor(color);
  422. txt.SetAlignment(textStyle.alignment);
  423. txt.SetText("Text");
  424. txt.SetLocalPosition(new Vector2(0, 0));
  425. txt.SetLocalEulerAngles(Vector3.zero);
  426. labelObj.transform.localPosition = Vector3.zero;
  427. labelObj.transform.localEulerAngles = new Vector3(0, 0, textStyle.rotate);
  428. return labelObj;
  429. }
  430. internal static GameObject AddTooltipLabel(string name, Transform parent, ChartTheme theme, Vector2 pivot)
  431. {
  432. var anchorMax = new Vector2(0, 0);
  433. var anchorMin = new Vector2(0, 0);
  434. var sizeDelta = new Vector2(100, 50);
  435. return AddTooltipLabel(name, parent, theme, pivot, anchorMin, anchorMax, sizeDelta);
  436. }
  437. internal static GameObject AddTooltipLabel(string name, Transform parent, ChartTheme theme, Vector2 pivot,
  438. Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta)
  439. {
  440. GameObject labelObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
  441. labelObj.transform.localPosition = Vector3.zero;
  442. var img = GetOrAddComponent<Image>(labelObj);
  443. img.color = Color.black;
  444. #if dUI_TextMeshPro
  445. var alignment = TextAlignmentOptions.Center;
  446. var txt = AddTMPTextObject("Text", labelObj.transform, theme.tmpFont, Color.white, alignment,
  447. new Vector2(0, 0), new Vector2(1, 1), new Vector2(1, 1), sizeDelta, 16);
  448. #else
  449. var txt = AddTextObject("Text", labelObj.transform, theme.font, Color.white, TextAnchor.MiddleCenter,
  450. new Vector2(0, 0), new Vector2(1, 1), new Vector2(1, 1), sizeDelta, 16);
  451. #endif
  452. txt.GetComponent<RectTransform>().offsetMin = Vector2.zero;
  453. txt.GetComponent<RectTransform>().offsetMax = Vector2.zero;
  454. return labelObj;
  455. }
  456. public static void GetPointList(ref List<Vector3> posList, Vector3 sp, Vector3 ep, float k = 30f)
  457. {
  458. Vector3 dir = (ep - sp).normalized;
  459. float dist = Vector3.Distance(sp, ep);
  460. int segment = (int)(dist / k);
  461. posList.Clear();
  462. posList.Add(sp);
  463. for (int i = 1; i < segment; i++)
  464. {
  465. posList.Add(sp + dir * dist * i / segment);
  466. }
  467. posList.Add(ep);
  468. }
  469. public static void GetBezierList(ref List<Vector3> posList, Vector3 sp, Vector3 ep,
  470. Vector3 lsp, Vector3 nep, float smoothness = 2f, float k = 2.0f)
  471. {
  472. float dist = Mathf.Abs(sp.x - ep.x);
  473. Vector3 cp1, cp2;
  474. var dir = (ep - sp).normalized;
  475. var diff = dist / k;
  476. if (lsp == sp)
  477. {
  478. cp1 = sp + dist / k * dir * 1;
  479. cp1.y = sp.y;
  480. cp1 = sp;
  481. }
  482. else
  483. {
  484. cp1 = sp + (ep - lsp).normalized * diff;
  485. }
  486. if (nep == ep) cp2 = ep;
  487. else cp2 = ep - (nep - sp).normalized * diff;
  488. dist = Vector3.Distance(sp, ep);
  489. int segment = (int)(dist / (smoothness <= 0 ? 2f : smoothness));
  490. if (segment < 1) segment = (int)(dist / 0.5f);
  491. if (segment < 4) segment = 4;
  492. GetBezierList2(ref posList, sp, ep, segment, cp1, cp2);
  493. if (posList.Count < 2)
  494. {
  495. posList.Clear();
  496. posList.Add(sp);
  497. posList.Add(ep);
  498. }
  499. }
  500. public static void GetBezierListVertical(ref List<Vector3> posList, Vector3 sp, Vector3 ep,
  501. float smoothness = 2f, float k = 2.0f)
  502. {
  503. Vector3 dir = (ep - sp).normalized;
  504. float dist = Vector3.Distance(sp, ep);
  505. Vector3 cp1 = sp + dist / k * dir * 1;
  506. Vector3 cp2 = sp + dist / k * dir * (k - 1);
  507. cp1.x = sp.x;
  508. cp2.x = ep.x;
  509. int segment = (int)(dist / (smoothness <= 0 ? 2f : smoothness));
  510. GetBezierList2(ref posList, sp, ep, segment, cp1, cp2);
  511. if (posList.Count < 2)
  512. {
  513. posList.Clear();
  514. posList.Add(sp);
  515. posList.Add(ep);
  516. }
  517. }
  518. public static List<Vector3> GetBezierList(Vector3 sp, Vector3 ep, int segment, Vector3 cp)
  519. {
  520. List<Vector3> list = new List<Vector3>();
  521. for (int i = 0; i < segment; i++)
  522. {
  523. list.Add(GetBezier(i / (float)segment, sp, cp, ep));
  524. }
  525. list.Add(ep);
  526. return list;
  527. }
  528. public static void GetBezierList2(ref List<Vector3> posList, Vector3 sp, Vector3 ep, int segment, Vector3 cp,
  529. Vector3 cp2)
  530. {
  531. posList.Clear();
  532. if (posList.Capacity < segment + 1)
  533. {
  534. posList.Capacity = segment + 1;
  535. }
  536. for (int i = 0; i < segment; i++)
  537. {
  538. posList.Add((GetBezier2(i / (float)segment, sp, cp, cp2, ep)));
  539. }
  540. posList.Add(ep);
  541. }
  542. public static Vector3 GetBezier(float t, Vector3 sp, Vector3 cp, Vector3 ep)
  543. {
  544. Vector3 aa = sp + (cp - sp) * t;
  545. Vector3 bb = cp + (ep - cp) * t;
  546. return aa + (bb - aa) * t;
  547. }
  548. public static Vector3 GetBezier2(float t, Vector3 sp, Vector3 p1, Vector3 p2, Vector3 ep)
  549. {
  550. t = Mathf.Clamp01(t);
  551. var oneMinusT = 1f - t;
  552. return oneMinusT * oneMinusT * oneMinusT * sp +
  553. 3f * oneMinusT * oneMinusT * t * p1 +
  554. 3f * oneMinusT * t * t * p2 +
  555. t * t * t * ep;
  556. }
  557. public static bool IsValueEqualsColor(Color32 color1, Color32 color2)
  558. {
  559. return color1.a == color2.a &&
  560. color1.b == color2.b &&
  561. color1.g == color2.g &&
  562. color1.r == color2.r;
  563. }
  564. public static bool IsValueEqualsColor(Color color1, Color color2)
  565. {
  566. return color1.a == color2.a &&
  567. color1.b == color2.b &&
  568. color1.g == color2.g &&
  569. color1.r == color2.r;
  570. }
  571. public static bool IsValueEqualsString(string str1, string str2)
  572. {
  573. if (str1 == null && str2 == null) return true;
  574. else if (str1 != null && str2 != null) return str1.Equals(str2);
  575. else return false;
  576. }
  577. public static bool IsValueEqualsVector2(Vector2 v1, Vector2 v2)
  578. {
  579. return v1.x == v2.x && v1.y == v2.y;
  580. }
  581. public static bool IsValueEqualsVector3(Vector3 v1, Vector3 v2)
  582. {
  583. return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
  584. }
  585. public static bool IsValueEqualsList<T>(List<T> list1, List<T> list2)
  586. {
  587. if (list1 == null || list2 == null) return false;
  588. if (list1.Count != list2.Count) return false;
  589. for (int i = 0; i < list1.Count; i++)
  590. {
  591. if (list1[i] == null && list2[i] == null) { }
  592. else
  593. {
  594. if (list1[i] != null)
  595. {
  596. if (!list1[i].Equals(list2[i])) return false;
  597. }
  598. else
  599. {
  600. if (!list2[i].Equals(list1[i])) return false;
  601. }
  602. }
  603. }
  604. return true;
  605. }
  606. public static bool IsClearColor(Color32 color)
  607. {
  608. return color.a == 0 && color.b == 0 && color.g == 0 && color.r == 0;
  609. }
  610. public static bool IsClearColor(Color color)
  611. {
  612. return color.a == 0 && color.b == 0 && color.g == 0 && color.r == 0;
  613. }
  614. public static bool IsZeroVector(Vector3 pos)
  615. {
  616. return pos.x == 0 && pos.y == 0 && pos.z == 0;
  617. }
  618. public static bool CopyList<T>(List<T> toList, List<T> fromList)
  619. {
  620. if (toList == null || fromList == null) return false;
  621. toList.Clear();
  622. foreach (var item in fromList) toList.Add(item);
  623. return true;
  624. }
  625. public static bool CopyArray<T>(T[] toList, T[] fromList)
  626. {
  627. if (toList == null || fromList == null) return false;
  628. if (toList.Length != fromList.Length)
  629. {
  630. toList = new T[fromList.Length];
  631. }
  632. for (int i = 0; i < fromList.Length; i++) toList[i] = fromList[i];
  633. return true;
  634. }
  635. public static List<float> ParseFloatFromString(string jsonData)
  636. {
  637. List<float> list = new List<float>();
  638. if (string.IsNullOrEmpty(jsonData)) return list;
  639. int startIndex = jsonData.IndexOf("[");
  640. int endIndex = jsonData.IndexOf("]");
  641. string temp = jsonData.Substring(startIndex + 1, endIndex - startIndex - 1);
  642. if (temp.IndexOf("],") > -1 || temp.IndexOf("] ,") > -1)
  643. {
  644. string[] datas = temp.Split(new string[] { "],", "] ," }, StringSplitOptions.RemoveEmptyEntries);
  645. for (int i = 0; i < datas.Length; i++)
  646. {
  647. temp = datas[i];
  648. }
  649. return list;
  650. }
  651. else
  652. {
  653. string[] datas = temp.Split(',');
  654. for (int i = 0; i < datas.Length; i++)
  655. {
  656. list.Add(float.Parse(datas[i].Trim()));
  657. }
  658. return list;
  659. }
  660. }
  661. public static List<string> ParseStringFromString(string jsonData)
  662. {
  663. List<string> list = new List<string>();
  664. if (string.IsNullOrEmpty(jsonData)) return list;
  665. string pattern = "[\"'](.*?)[\"']";
  666. if (Regex.IsMatch(jsonData, pattern))
  667. {
  668. MatchCollection m = Regex.Matches(jsonData, pattern);
  669. foreach (Match match in m)
  670. {
  671. list.Add(match.Groups[1].Value);
  672. }
  673. }
  674. return list;
  675. }
  676. public static Color32 GetColor(string hexColorStr)
  677. {
  678. Color color;
  679. ColorUtility.TryParseHtmlString(hexColorStr, out color);
  680. return (Color32)color;
  681. }
  682. public static double GetMaxDivisibleValue(double max, int ceilRate)
  683. {
  684. if (max == 0) return 0;
  685. if (max > -1 && max < 1)
  686. {
  687. int count = 1;
  688. int intvalue = (int)(max * Mathf.Pow(10, count));
  689. while (intvalue == 0 && count < 12)
  690. {
  691. count++;
  692. intvalue = (int)(max * Mathf.Pow(10, count));
  693. }
  694. if (max > 0) return 1 / Mathf.Pow(10, count - 1);
  695. else return -1 / Mathf.Pow(10, count);
  696. }
  697. if (ceilRate == 0)
  698. {
  699. var bigger = Math.Ceiling(Math.Abs(max));
  700. int n = 1;
  701. while (bigger / (Mathf.Pow(10, n)) > 10)
  702. {
  703. n++;
  704. }
  705. double mm = bigger;
  706. if (mm > 10 && n < 38)
  707. {
  708. mm = bigger - bigger % (Mathf.Pow(10, n));
  709. mm += max > 0 ? Mathf.Pow(10, n) : -Mathf.Pow(10, n);
  710. }
  711. if (max < 0) return -Math.Ceiling(mm);
  712. else return Math.Ceiling(mm);
  713. }
  714. else
  715. {
  716. var mod = max % ceilRate;
  717. int rate = (int)(max / ceilRate);
  718. return mod == 0 ? max : (max < 0 ? rate : rate + 1) * ceilRate;
  719. }
  720. }
  721. public static double GetMinDivisibleValue(double min, int ceilRate)
  722. {
  723. if (min == 0) return 0;
  724. if (min > -1 && min < 1)
  725. {
  726. int count = 1;
  727. int intvalue = (int)(min * Mathf.Pow(10, count));
  728. while (intvalue == 0 && count < 12)
  729. {
  730. count++;
  731. intvalue = (int)(min * Mathf.Pow(10, count));
  732. }
  733. if (min > 0) return 1 / Mathf.Pow(10, count);
  734. else return -1 / Mathf.Pow(10, count - 1);
  735. }
  736. if (ceilRate == 0)
  737. {
  738. var bigger = Math.Floor(Math.Abs(min));
  739. int n = 1;
  740. while (bigger / (Mathf.Pow(10, n)) > 10)
  741. {
  742. n++;
  743. }
  744. double mm = bigger;
  745. if (mm > 10 && n < 38)
  746. {
  747. mm = bigger - bigger % (Mathf.Pow(10, n));
  748. mm += min < 0 ? Mathf.Pow(10, n) : -Mathf.Pow(10, n);
  749. }
  750. if (min < 0) return -Math.Floor(mm);
  751. else return Math.Floor(mm);
  752. }
  753. else
  754. {
  755. var mod = min % ceilRate;
  756. int rate = (int)(min / ceilRate);
  757. return mod == 0 ? min : (min < 0 ? rate - 1 : rate) * ceilRate;
  758. }
  759. }
  760. public static double GetMaxLogValue(double value, float logBase, bool isLogBaseE, out int splitNumber)
  761. {
  762. splitNumber = 0;
  763. if (value <= 0) return 0;
  764. double max = 0;
  765. while (max < value)
  766. {
  767. if (isLogBaseE)
  768. {
  769. max = Mathf.Exp(splitNumber);
  770. }
  771. else
  772. {
  773. max = Mathf.Pow(logBase, splitNumber);
  774. }
  775. splitNumber++;
  776. }
  777. return max;
  778. }
  779. public static float GetMinLogValue(double value, float logBase, bool isLogBaseE, out int splitNumber)
  780. {
  781. splitNumber = 0;
  782. if (value > 1) return 1;
  783. float min = 1;
  784. while (min > value)
  785. {
  786. if (isLogBaseE)
  787. {
  788. min = Mathf.Exp(-splitNumber);
  789. }
  790. else
  791. {
  792. min = Mathf.Pow(logBase, -splitNumber);
  793. }
  794. splitNumber++;
  795. }
  796. return min;
  797. }
  798. public static int GetFloatAccuracy(double value)
  799. {
  800. if (value > 1 || value < -1) return 0;
  801. int count = 1;
  802. int intvalue = (int)(value * Mathf.Pow(10, count));
  803. while (intvalue == 0 && count < 38)
  804. {
  805. count++;
  806. intvalue = (int)(value * Mathf.Pow(10, count));
  807. }
  808. if (count == 38 && (value == 0 || value == 1)) return 1;
  809. else return count;
  810. }
  811. public static void AddEventListener(GameObject obj, EventTriggerType type,
  812. UnityEngine.Events.UnityAction<BaseEventData> call)
  813. {
  814. EventTrigger trigger = GetOrAddComponent<EventTrigger>(obj.gameObject);
  815. EventTrigger.Entry entry = new EventTrigger.Entry();
  816. entry.eventID = type;
  817. entry.callback = new EventTrigger.TriggerEvent();
  818. entry.callback.AddListener(call);
  819. trigger.triggers.Add(entry);
  820. }
  821. public static void ClearEventListener(GameObject obj)
  822. {
  823. EventTrigger trigger = obj.GetComponent<EventTrigger>();
  824. if (trigger != null)
  825. {
  826. trigger.triggers.Clear();
  827. }
  828. }
  829. //获取两直线交点
  830. public static Vector3 GetIntersection(Vector3 lineAStart, Vector3 lineAEnd, Vector3 lineBStart,
  831. Vector3 lineBEnd)
  832. {
  833. float x1 = lineAStart.x, y1 = lineAStart.y;
  834. float x2 = lineAEnd.x, y2 = lineAEnd.y;
  835. float x3 = lineBStart.x, y3 = lineBStart.y;
  836. float x4 = lineBEnd.x, y4 = lineBEnd.y;
  837. if (x1 == x2 && x3 == x4 && x1 == x3)
  838. {
  839. return Vector3.zero;
  840. }
  841. if (y1 == y2 && y3 == y4 && y1 == y3)
  842. {
  843. return Vector3.zero;
  844. }
  845. if (x1 == x2 && x3 == x4)
  846. {
  847. return Vector3.zero;
  848. }
  849. if (y1 == y2 && y3 == y4)
  850. {
  851. return Vector3.zero;
  852. }
  853. float x, y;
  854. if (x1 == x2)
  855. {
  856. float m2 = (y4 - y3) / (x4 - x3);
  857. float c2 = -m2 * x3 + y3;
  858. x = x1;
  859. y = c2 + m2 * x1;
  860. }
  861. else if (x3 == x4)
  862. {
  863. float m1 = (y2 - y1) / (x2 - x1);
  864. float c1 = -m1 * x1 + y1;
  865. x = x3;
  866. y = c1 + m1 * x3;
  867. }
  868. else
  869. {
  870. float m1 = (y2 - y1) / (x2 - x1);
  871. float c1 = -m1 * x1 + y1;
  872. float m2 = (y4 - y3) / (x4 - x3);
  873. float c2 = -m2 * x3 + y3;
  874. x = (c1 - c2) / (m2 - m1);
  875. y = c2 + m2 * x;
  876. }
  877. if (IsInsideLine(lineAStart, lineAEnd, x, y) &&
  878. IsInsideLine(lineBStart, lineBEnd, x, y))
  879. {
  880. return new Vector3(x, y, 0);
  881. }
  882. return Vector3.zero;
  883. }
  884. private static bool IsInsideLine(Vector3 start, Vector3 end, float x, float y)
  885. {
  886. return ((x >= start.x && x <= end.x)
  887. || (x >= end.x && x <= start.x))
  888. && ((y >= start.y && y <= end.y)
  889. || (y >= end.y && y <= start.y));
  890. }
  891. public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
  892. {
  893. Vector3 point = Quaternion.AngleAxis(angle, axis) * (position - center);
  894. Vector3 resultVec3 = center + point;
  895. return resultVec3;
  896. }
  897. public static Vector3 GetPosition(Vector3 center, float angle, float radius)
  898. {
  899. var rad = angle * Mathf.Deg2Rad;
  900. var px = Mathf.Sin(rad) * radius;
  901. var py = Mathf.Cos(rad) * radius;
  902. return center + new Vector3(px, py);
  903. }
  904. /// <summary>
  905. /// 获得0-360的角度(12点钟方向为0度)
  906. /// </summary>
  907. /// <param name="from"></param>
  908. /// <param name="to"></param>
  909. /// <returns></returns>
  910. public static float GetAngle360(Vector2 from, Vector2 to)
  911. {
  912. float angle;
  913. Vector3 cross = Vector3.Cross(from, to);
  914. angle = Vector2.Angle(from, to);
  915. angle = cross.z > 0 ? -angle : angle;
  916. angle = (angle + 360) % 360;
  917. return angle;
  918. }
  919. public static Vector3 GetPos(Vector3 center, float radius, float angle, bool isDegree = false)
  920. {
  921. angle = isDegree ? angle * Mathf.Deg2Rad : angle;
  922. return new Vector3(center.x + radius * Mathf.Sin(angle), center.y + radius * Mathf.Cos(angle));
  923. }
  924. public static Vector3 GetDire(float angle, bool isDegree = false)
  925. {
  926. angle = isDegree ? angle * Mathf.Deg2Rad : angle;
  927. return new Vector3(Mathf.Sin(angle), Mathf.Cos(angle));
  928. }
  929. public static Vector3 GetVertialDire(Vector3 dire)
  930. {
  931. if (dire.x == 0)
  932. {
  933. return new Vector3(-1, 0, 0);
  934. }
  935. if (dire.y == 0)
  936. {
  937. return new Vector3(0, -1, 0);
  938. }
  939. else
  940. {
  941. return new Vector3(-dire.y / dire.x, 1, 0).normalized;
  942. }
  943. }
  944. public static float GetRuntimeRelativeOrAbsoluteValue(float check, float total)
  945. {
  946. if (check <= 0)
  947. {
  948. return 0;
  949. }
  950. else if (check <= 1)
  951. {
  952. return total * check;
  953. }
  954. else
  955. {
  956. return check;
  957. }
  958. }
  959. public static Vector3 GetLastPoint(List<Vector3> list)
  960. {
  961. if (list.Count <= 0) return Vector3.zero;
  962. else return list[list.Count - 1];
  963. }
  964. public static void SetColorOpacity(ref Color32 color, float opacity)
  965. {
  966. if (color.a != 0 && opacity != 1)
  967. {
  968. color.a = (byte)(color.a * opacity);
  969. }
  970. }
  971. public static Color32 GetHighlightColor(Color32 color, float rate = 0.8f)
  972. {
  973. var newColor = color;
  974. newColor.r = (byte)(color.r * rate);
  975. newColor.g = (byte)(color.g * rate);
  976. newColor.b = (byte)(color.b * rate);
  977. return newColor;
  978. }
  979. public static bool IsPointInQuadrilateral(Vector3 P, Vector3 A, Vector3 B, Vector3 C, Vector3 D)
  980. {
  981. Vector3 v0 = Vector3.Cross(A - D, P - D);
  982. Vector3 v1 = Vector3.Cross(B - A, P - A);
  983. Vector3 v2 = Vector3.Cross(C - B, P - B);
  984. Vector3 v3 = Vector3.Cross(D - C, P - C);
  985. if (Vector3.Dot(v0, v1) < 0 || Vector3.Dot(v0, v2) < 0 || Vector3.Dot(v0, v3) < 0)
  986. {
  987. return false;
  988. }
  989. else
  990. {
  991. return true;
  992. }
  993. }
  994. public static bool IsInRect(Vector3 pos, float xMin, float xMax, float yMin, float yMax)
  995. {
  996. return pos.x >= xMin && pos.x <= xMax && pos.y <= yMax && pos.y >= yMin;
  997. }
  998. }
  999. }