diff --git a/CHANGELOG.md b/CHANGELOG.md index 16083a67..9d29e6e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 更新日志 +* (2020.04.08) 增加`PieChart`通过`ItemStyle`设置边框的支持 * (2020.03.29) 增加`Axis`的`ceilRate`设置最大最小值的取整倍率 * (2020.03.29) 增加`BarChart`可通过`itemStyle`的`cornerRadius`设置`圆角柱图` * (2020.03.29) 增加`itemStyle`的`cornerRadius`支持圆角矩形 diff --git a/Editor/PropertyDrawers/SerieDrawer.cs b/Editor/PropertyDrawers/SerieDrawer.cs index 9b7f7e1f..b3cef122 100644 --- a/Editor/PropertyDrawers/SerieDrawer.cs +++ b/Editor/PropertyDrawers/SerieDrawer.cs @@ -194,6 +194,8 @@ namespace XCharts ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Radius, "Radius"); EditorGUI.PropertyField(drawRect, m_RoundCap); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, m_ItemStyle); + drawRect.y += EditorGUI.GetPropertyHeight(m_ItemStyle); EditorGUI.PropertyField(drawRect, m_Label); drawRect.y += EditorGUI.GetPropertyHeight(m_Label); EditorGUI.PropertyField(drawRect, m_Emphasis); @@ -507,6 +509,7 @@ namespace XCharts break; case SerieType.Pie: height += 9 * EditorGUIUtility.singleLineHeight + 8 * EditorGUIUtility.standardVerticalSpacing; + height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_ItemStyle")); height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Label")); height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Emphasis")); height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Animation")); diff --git a/Runtime/Component/Main/Tooltip.cs b/Runtime/Component/Main/Tooltip.cs index b19f0e65..f2447cda 100644 --- a/Runtime/Component/Main/Tooltip.cs +++ b/Runtime/Component/Main/Tooltip.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System.Linq; +using System.Collections.ObjectModel; /******************************************/ /* */ /* Copyright (c) 2018 monitor1394 */ @@ -365,9 +366,9 @@ namespace XCharts /// internal void ClearValue() { - runtimeDataIndex[0] = runtimeDataIndex[1] = -1; - runtimeXValues[0] = runtimeXValues[1] = -1; - runtimeYValues[0] = runtimeYValues[1] = -1; + for (int i = 0; i < runtimeDataIndex.Count; i++) runtimeDataIndex[i] = -1; + for (int i = 0; i < runtimeXValues.Length; i++) runtimeXValues[i] = -1; + for (int i = 0; i < runtimeYValues.Length; i++) runtimeYValues[i] = -1; } /// diff --git a/Runtime/Helper/SerieHelper.cs b/Runtime/Helper/SerieHelper.cs index f18c81cd..ba1f320e 100644 --- a/Runtime/Helper/SerieHelper.cs +++ b/Runtime/Helper/SerieHelper.cs @@ -142,7 +142,7 @@ namespace XCharts if (style == null) return GetItemStyle(serie, serieData, false); else return style; } - else if (serieData.enableItemStyle) return serieData.itemStyle; + else if (serieData != null && serieData.enableItemStyle) return serieData.itemStyle; else return serie.itemStyle; } @@ -226,18 +226,18 @@ namespace XCharts return color; } - public static float GetSymbolBorder(Serie serie, SerieData serieData, bool highlight) + public static float GetSymbolBorder(Serie serie, SerieData serieData, bool highlight, bool useLineWidth = true) { var itemStyle = GetItemStyle(serie, serieData, highlight); if (itemStyle != null && itemStyle.borderWidth != 0) return itemStyle.borderWidth; - else if (serie.lineStyle.width != 0) return serie.lineStyle.width; - else return 1; + else if (serie.lineStyle.width != 0 && useLineWidth) return serie.lineStyle.width; + else return 0; } public static float[] GetSymbolCornerRadius(Serie serie, SerieData serieData, bool highlight) { var itemStyle = GetItemStyle(serie, serieData, highlight); - if(itemStyle != null) return itemStyle.cornerRadius; + if (itemStyle != null) return itemStyle.cornerRadius; else return null; } } diff --git a/Runtime/Helper/TooltipHelper.cs b/Runtime/Helper/TooltipHelper.cs index c7a73614..f68afbf2 100644 --- a/Runtime/Helper/TooltipHelper.cs +++ b/Runtime/Helper/TooltipHelper.cs @@ -145,6 +145,7 @@ namespace XCharts var serie = series.GetSerie(i); if (!serie.show) continue; var serieData = serie.GetSerieData(dataIndex, dataZoom); + if (serieData == null) continue; var itemFormatter = GetItemFormatter(tooltip, serie, serieData); var percent = serieData.GetData(1) / serie.yTotal * 100; needCategory = needCategory || (serie.type == SerieType.Line || serie.type == SerieType.Bar); diff --git a/Runtime/PieChart.cs b/Runtime/PieChart.cs index 55454129..a83be3cf 100644 --- a/Runtime/PieChart.cs +++ b/Runtime/PieChart.cs @@ -82,13 +82,16 @@ namespace XCharts for (int n = 0; n < data.Count; n++) { var serieData = data[n]; - var itemStyle = SerieHelper.GetItemStyle(serie, serieData); + var itemStyle = SerieHelper.GetItemStyle(serie, serieData, serieData.highlighted); serieData.index = n; float value = serieData.GetCurrData(1, dataChangeDuration); if (serieData.IsDataChanged()) dataChanging = true; serieNameCount = m_LegendRealShowName.IndexOf(serieData.legendName); var color = SerieHelper.GetItemColor(serie, serieData, m_ThemeInfo, serieNameCount, serieData.highlighted); var toColor = SerieHelper.GetItemToColor(serie, serieData, m_ThemeInfo, serieNameCount, serieData.highlighted); + var borderWidth = itemStyle.borderWidth; + var borderColor = itemStyle.borderColor; + serieData.runtimePieStartAngle = startDegree; serieData.runtimePieToAngle = startDegree; serieData.runtimePieHalfAngle = startDegree; @@ -109,7 +112,7 @@ namespace XCharts isDataHighlight = true; serieData.runtimePieOutsideRadius += m_Settings.pieTooltipExtraRadius; } - var offset = serie.pieSpace; + var offset = 0f; if (serie.pieClickOffset && serieData.selected) { offset += m_Settings.pieSelectedOffset; @@ -131,7 +134,7 @@ namespace XCharts } if (offset > 0) { - serieData.runtimePieOffsetRadius = serie.pieSpace / Mathf.Sin(halfDegree * Mathf.Deg2Rad); + serieData.runtimePieOffsetRadius = 0; serieData.runtimePieInsideRadius -= serieData.runtimePieOffsetRadius; serieData.runtimePieOutsideRadius -= serieData.runtimePieOffsetRadius; if (serie.pieClickOffset && serieData.selected) @@ -143,19 +146,19 @@ namespace XCharts serieData.runtiemPieOffsetCenter = new Vector3(center.x + serieData.runtimePieOffsetRadius * currSin, center.y + serieData.runtimePieOffsetRadius * currCos); - var drawStartDegree = startDegree + serie.pieSpace; - var drawEndDegree = serieData.runtimePieCurrAngle - serie.pieSpace; - DrawRoundCap(vh, serie, serieData, serieData.runtiemPieOffsetCenter, color, ref drawStartDegree, ref drawEndDegree); - ChartDrawer.DrawDoughnut(vh, serieData.runtiemPieOffsetCenter, serieData.runtimePieInsideRadius, serieData.runtimePieOutsideRadius, - color, toColor, m_ThemeInfo.backgroundColor, m_Settings.cicleSmoothness, drawStartDegree, drawEndDegree); + var drawEndDegree = serieData.runtimePieCurrAngle; + var needRoundCap = serie.roundCap && serieData.runtimePieInsideRadius > 0; + ChartDrawer.DrawDoughnut(vh, serieData.runtiemPieOffsetCenter, serieData.runtimePieInsideRadius, + serieData.runtimePieOutsideRadius, color, toColor, Color.clear, startDegree, drawEndDegree, + borderWidth, borderColor, serie.pieSpace / 2, m_Settings.cicleSmoothness, needRoundCap, serie.clockwise); } - else + else //if(n==0) { - var drawStartDegree = startDegree + serie.pieSpace; - var drawEndDegree = serieData.runtimePieCurrAngle - serie.pieSpace; - DrawRoundCap(vh, serie, serieData, center, color, ref drawStartDegree, ref drawEndDegree); + var drawEndDegree = serieData.runtimePieCurrAngle; + var needRoundCap = serie.roundCap && serieData.runtimePieInsideRadius > 0; ChartDrawer.DrawDoughnut(vh, center, serieData.runtimePieInsideRadius, serieData.runtimePieOutsideRadius, - color, toColor, Color.clear, m_Settings.cicleSmoothness, drawStartDegree, drawEndDegree); + color, toColor, Color.clear, startDegree, drawEndDegree, borderWidth, borderColor, serie.pieSpace / 2, + m_Settings.cicleSmoothness, needRoundCap, serie.clockwise); DrawCenter(vh, serie, itemStyle, serieData.runtimePieInsideRadius); } serieData.canShowLabel = serieData.runtimePieCurrAngle >= serieData.runtimePieHalfAngle; @@ -189,22 +192,6 @@ namespace XCharts } } - private void DrawRoundCap(VertexHelper vh, Serie serie, SerieData serieData, Vector3 centerPos, - Color color, ref float drawStartDegree, ref float drawEndDegree) - { - if (serie.roundCap && serieData.runtimePieInsideRadius > 0) - { - var width = (serieData.runtimePieOutsideRadius - serieData.runtimePieInsideRadius) / 2; - var radius = serieData.runtimePieInsideRadius + width; - var diffDegree = Mathf.Asin(width / radius) * Mathf.Rad2Deg; - drawStartDegree += diffDegree; - drawEndDegree -= diffDegree; - - ChartDrawer.DrawRoundCap(vh, centerPos, width, radius, drawStartDegree, serie.clockwise, color, false); - ChartDrawer.DrawRoundCap(vh, centerPos, width, radius, drawEndDegree, serie.clockwise, color, true); - } - } - private void DrawLabelLine(VertexHelper vh) { foreach (var serie in m_Series.list) diff --git a/Runtime/RingChart.cs b/Runtime/RingChart.cs index 38cc2c1d..9e00cb2d 100644 --- a/Runtime/RingChart.cs +++ b/Runtime/RingChart.cs @@ -89,23 +89,22 @@ namespace XCharts var degree = 360 * value / max; var startDegree = GetStartAngle(serie); var toDegree = GetToAngle(serie, degree); + var itemStyle = SerieHelper.GetItemStyle(serie, serieData, serieData.highlighted); var itemColor = SerieHelper.GetItemColor(serie, serieData, m_ThemeInfo, j, serieData.highlighted); var outsideRadius = serie.runtimeOutsideRadius - j * (ringWidth + serie.ringGap); var insideRadius = outsideRadius - ringWidth; var centerRadius = (outsideRadius + insideRadius) / 2; + var borderWidth = itemStyle.borderWidth; + var borderColor = itemStyle.borderColor; + var roundCap = serie.roundCap && insideRadius > 0; serieData.runtimePieStartAngle = serie.clockwise ? startDegree : toDegree; serieData.runtimePieToAngle = serie.clockwise ? toDegree : startDegree; serieData.runtimePieInsideRadius = insideRadius; serieData.runtimePieOutsideRadius = outsideRadius; - - DrawBackground(vh, serie, serieData, j, insideRadius, outsideRadius); - DrawRoundCap(vh, serie, serie.runtimeCenterPos, itemColor, insideRadius, outsideRadius, - ref startDegree, ref toDegree); - ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, insideRadius, - outsideRadius, itemColor, Color.clear, m_Settings.cicleSmoothness, - startDegree, toDegree); - DrawBorder(vh, serie, serieData, insideRadius, outsideRadius); + ChartDrawer.DrawDoughnut(vh, serie.runtimeCenterPos, insideRadius, outsideRadius, itemColor, itemColor, + Color.clear, startDegree, toDegree, borderWidth, borderColor, 0, m_Settings.cicleSmoothness, + roundCap, serie.clockwise); DrawCenter(vh, serie, serieData, insideRadius, j == data.Count - 1); UpateLabelPosition(serie, serieData, j, startDegree, toDegree, centerRadius); } @@ -132,7 +131,7 @@ namespace XCharts var toAngle = angle + serie.startAngle; if (!serie.clockwise) { - toAngle = 360 - toAngle - serie.startAngle; + toAngle = 360 - angle - serie.startAngle; } if (!serie.animation.IsFinish()) { diff --git a/Runtime/Utility/ChartDrawer.cs b/Runtime/Utility/ChartDrawer.cs index 6a777a5b..d6d0a4ac 100644 --- a/Runtime/Utility/ChartDrawer.cs +++ b/Runtime/Utility/ChartDrawer.cs @@ -434,7 +434,7 @@ namespace XCharts if (brLt > 0) { tempCenter = new Vector3(center.x - halfWid + brLt, center.y + halfHig - brLt); - DrawDoughnut(vh, tempCenter, brLt, brLt + borderWidth, color, Color.clear, 2, 270, 360); + DrawDoughnut(vh, tempCenter, brLt, brLt + borderWidth, color, Color.clear, 270, 360); ltIn = tempCenter + brLt * Vector3.left; ltOt = tempCenter + (brLt + borderWidth) * Vector3.left; ltIn2 = tempCenter + brLt * Vector3.up; @@ -443,7 +443,7 @@ namespace XCharts if (brRt > 0) { tempCenter = new Vector3(center.x + halfWid - brRt, center.y + halfHig - brRt); - DrawDoughnut(vh, tempCenter, brRt, brRt + borderWidth, color, Color.clear, 2, 0, 90); + DrawDoughnut(vh, tempCenter, brRt, brRt + borderWidth, color, Color.clear, 0, 90); rtIn = tempCenter + brRt * Vector3.up; rtOt = tempCenter + (brRt + borderWidth) * Vector3.up; rtIn2 = tempCenter + brRt * Vector3.right; @@ -452,7 +452,7 @@ namespace XCharts if (brRb > 0) { tempCenter = new Vector3(center.x + halfWid - brRb, center.y - halfHig + brRb); - DrawDoughnut(vh, tempCenter, brRb, brRb + borderWidth, color, Color.clear, 2, 90, 180); + DrawDoughnut(vh, tempCenter, brRb, brRb + borderWidth, color, Color.clear, 90, 180); rbIn = tempCenter + brRb * Vector3.right; rbOt = tempCenter + (brRb + borderWidth) * Vector3.right; rbIn2 = tempCenter + brRb * Vector3.down; @@ -461,7 +461,7 @@ namespace XCharts if (brLb > 0) { tempCenter = new Vector3(center.x - halfWid + brLb, center.y - halfHig + brLb); - DrawDoughnut(vh, tempCenter, brLb, brLb + borderWidth, color, Color.clear, 2, 180, 270); + DrawDoughnut(vh, tempCenter, brLb, brLb + borderWidth, color, Color.clear, 180, 270); lbIn = tempCenter + brLb * Vector3.left; lbOt = tempCenter + (brLb + borderWidth) * Vector3.left; lbIn2 = tempCenter + brLb * Vector3.down; @@ -536,51 +536,166 @@ namespace XCharts } public static void DrawCricle(VertexHelper vh, Vector3 p, float radius, Color32 color, - Color32 toColor, float smoothness = 2f) + float smoothness = 2f) { - DrawSector(vh, p, radius, color, toColor, 0, 360, smoothness); + DrawCricle(vh, p, radius, color, color, 0, Color.clear, smoothness); } public static void DrawCricle(VertexHelper vh, Vector3 p, float radius, Color32 color, + Color32 toColor, float smoothness = 2f) + { + DrawSector(vh, p, radius, color, toColor, 0, 360, 0, Color.clear, smoothness); + } + + public static void DrawCricle(VertexHelper vh, Vector3 p, float radius, Color32 color, + Color32 toColor, float borderWidth, Color32 borderColor, float smoothness = 2f) + { + DrawSector(vh, p, radius, color, toColor, 0, 360, borderWidth, borderColor, smoothness); + } + + public static void DrawCricle(VertexHelper vh, Vector3 p, float radius, Color32 color, + float borderWidth, Color32 borderColor, float smoothness = 2f) + { + DrawCricle(vh, p, radius, color, color, borderWidth, borderColor, smoothness); + } + + public static void DrawEmptyCricle(VertexHelper vh, Vector3 p, float radius, float tickness, + Color32 color, Color32 emptyColor, float smoothness = 2f) + { + DrawDoughnut(vh, p, radius - tickness, radius, color, color, emptyColor, 0, 360, 0, Color.clear, 0, smoothness); + } + + public static void DrawEmptyCricle(VertexHelper vh, Vector3 p, float radius, float tickness, + Color32 color, Color32 emptyColor, float borderWidth, Color32 borderColor, float smoothness = 2f) + { + DrawDoughnut(vh, p, radius - tickness, radius, color, color, emptyColor, 0, 360, borderWidth, + borderColor, 0, smoothness); + } + + public static void DrawEmptyCricle(VertexHelper vh, Vector3 p, float radius, float tickness, + Color32 color, Color32 toColor, Color32 emptyColor, float smoothness = 2f) + { + DrawDoughnut(vh, p, radius - tickness, radius, color, toColor, emptyColor, 0, 360, 0, + Color.clear, 0, smoothness); + } + + public static void DrawEmptyCricle(VertexHelper vh, Vector3 p, float radius, float tickness, + Color32 color, Color32 toColor, Color32 emptyColor, float borderWidth, Color32 borderColor, float smoothness = 2f) { - DrawCricle(vh, p, radius, color, color, smoothness); - } - - public static void DrawEmptyCricle(VertexHelper vh, Vector3 p, float radius, float tickness, - Color32 color, Color emptyColor, float smoothness = 2f) - { - DrawDoughnut(vh, p, radius - tickness, radius, color, color, emptyColor, smoothness); - } - - public static void DrawEmptyCricle(VertexHelper vh, Vector3 p, float radius, float tickness, - Color32 color, Color32 toColor, Color emptyColor, float smoothness = 2f) - { - DrawDoughnut(vh, p, radius - tickness, radius, color, toColor, emptyColor, smoothness); + DrawDoughnut(vh, p, radius - tickness, radius, color, toColor, emptyColor, 0, 360, borderWidth, + borderColor, 0, smoothness); } public static void DrawSector(VertexHelper vh, Vector3 p, float radius, Color32 color, - float startDegree, float toDegree, float smoothness = 2f) + float startDegree, float toDegree, float smoothness = 2f) { - DrawSector(vh, p, radius, color, color, startDegree, toDegree, smoothness); + DrawSector(vh, p, radius, color, color, startDegree, toDegree, 0, Color.clear, smoothness); + } + + public static void DrawSector(VertexHelper vh, Vector3 p, float radius, Color32 color, Color32 toColor, + float startDegree, float toDegree, float smoothness = 2f) + { + DrawSector(vh, p, radius, color, toColor, startDegree, toDegree, 0, Color.clear, smoothness); } public static void DrawSector(VertexHelper vh, Vector3 p, float radius, Color32 color, - Color32 toColor, float startDegree, float toDegree, float smoothness = 2f) + float startDegree, float toDegree, float borderWidth, Color32 borderColor, float smoothness = 2f) { - int segments = (int)((2 * Mathf.PI * radius) / (smoothness < 0 ? 2f : smoothness)); - Vector3 p2, p3; + DrawSector(vh, p, radius, color, color, startDegree, toDegree, borderWidth, borderColor, smoothness); + } + + public static void DrawSector(VertexHelper vh, Vector3 p, float radius, Color32 color, Color32 toColor, + float startDegree, float toDegree, float borderWidth, Color32 borderColor, float smoothness = 2f) + { + DrawSector(vh, p, radius, color, toColor, startDegree, toDegree, borderWidth, borderColor, 0, smoothness); + } + + public static void DrawSector(VertexHelper vh, Vector3 p, float radius, Color32 color, Color32 toColor, + float startDegree, float toDegree, float borderWidth, Color32 borderColor, float space, + float smoothness = 2f) + { + radius -= borderWidth; + smoothness = (smoothness < 0 ? 2f : smoothness); + int segments = (int)((2 * Mathf.PI * radius) * (Mathf.Abs(toDegree - startDegree) / 360) / smoothness); float startAngle = startDegree * Mathf.Deg2Rad; - float angle = (toDegree - startDegree) * Mathf.Deg2Rad / segments; - p2 = new Vector3(p.x + radius * Mathf.Sin(startAngle), p.y + radius * Mathf.Cos(startAngle)); + float toAngle = toDegree * Mathf.Deg2Rad; + float realStartAngle = startAngle; + float realToAngle = toAngle; + float halfAngle = (toAngle - startAngle) / 2; + float borderAngle = 0; + float spaceAngle = 0; + + var p2 = p + radius * GetDire(startAngle); + var p3 = Vector3.zero; + var spaceCenter = p; + var realCenter = p; + var needBorder = borderWidth != 0; + var needSpace = space != 0; + var lastPos = Vector3.zero; + var middleDire = GetDire(startAngle + halfAngle); + if (needBorder || needSpace) + { + float spaceDiff = 0f; + float borderDiff = 0f; + if (needSpace) + { + spaceDiff = space / Mathf.Sin(halfAngle); + spaceCenter = p + spaceDiff * middleDire; + realCenter = spaceCenter; + spaceAngle = 2 * Mathf.Asin(space / (2 * radius)); + realStartAngle = startAngle + spaceAngle; + realToAngle = toAngle - spaceAngle; + p2 = GetPos(p, radius, realStartAngle); + } + if (needBorder) + { + borderDiff = borderWidth / Mathf.Sin(halfAngle); + realCenter += borderDiff * middleDire; + borderAngle = 2 * Mathf.Asin(borderWidth / (2 * radius)); + realStartAngle = realStartAngle + borderAngle; + var borderX1 = GetPos(p, radius, realStartAngle); + DrawPolygon(vh, realCenter, spaceCenter, p2, borderX1, borderColor); + p2 = borderX1; + + realToAngle = realToAngle - borderAngle; + var borderX2 = GetPos(p, radius, realToAngle); + var pEnd = GetPos(p, radius, toAngle - spaceAngle); + DrawPolygon(vh, realCenter, borderX2, pEnd, spaceCenter, borderColor); + } + } + float segmentAngle = (realToAngle - realStartAngle) / segments; for (int i = 0; i <= segments; i++) { - float currAngle = startAngle + i * angle; - p3 = new Vector3(p.x + radius * Mathf.Sin(currAngle), - p.y + radius * Mathf.Cos(currAngle)); - DrawTriangle(vh, p, p2, p3, toColor, color, color); + float currAngle = realStartAngle + i * segmentAngle; + p3 = p + radius * GetDire(currAngle); + DrawTriangle(vh, realCenter, p2, p3, toColor, color, color); p2 = p3; } + if (needBorder || needSpace) + { + var borderX2 = p + radius * GetDire(realToAngle); + DrawTriangle(vh, realCenter, p2, borderX2, toColor, color, color); + if (needBorder) + { + var realStartDegree = (realStartAngle - borderAngle) * Mathf.Rad2Deg; + var realToDegree = (realToAngle + borderAngle) * Mathf.Rad2Deg; + DrawDoughnut(vh, p, radius, radius + borderWidth, borderColor, Color.clear, realStartDegree, + realToDegree, smoothness); + } + } + } + + private static Vector3 GetPos(Vector3 center, float radius, float angle, bool isDegree = false) + { + angle = isDegree ? angle * Mathf.Deg2Rad : angle; + return new Vector3(center.x + radius * Mathf.Sin(angle), center.y + radius * Mathf.Cos(angle)); + } + + private static Vector3 GetDire(float angle, bool isDegree = false) + { + angle = isDegree ? angle * Mathf.Deg2Rad : angle; + return new Vector3(Mathf.Sin(angle), Mathf.Cos(angle)); } public static void DrawRoundCap(VertexHelper vh, Vector3 center, float width, float radius, float angle, @@ -592,56 +707,285 @@ namespace XCharts if (end) { if (clockwise) - ChartDrawer.DrawSector(vh, pos, width, color, angle, angle + 180); + ChartDrawer.DrawSector(vh, pos, width, color, angle, angle + 180, 0, Color.clear); else - ChartDrawer.DrawSector(vh, pos, width, color, angle, angle - 180); + ChartDrawer.DrawSector(vh, pos, width, color, angle, angle - 180, 0, Color.clear); } else { if (clockwise) - ChartDrawer.DrawSector(vh, pos, width, color, angle + 180, angle + 360); + ChartDrawer.DrawSector(vh, pos, width, color, angle + 180, angle + 360, 0, Color.clear); else - ChartDrawer.DrawSector(vh, pos, width, color, angle - 180, angle - 360); + ChartDrawer.DrawSector(vh, pos, width, color, angle - 180, angle - 360, 0, Color.clear); } } public static void DrawDoughnut(VertexHelper vh, Vector3 p, float insideRadius, float outsideRadius, - Color32 color, Color emptyColor, float smoothness = 2f, float startDegree = 0, float toDegree = 360) + Color32 color, Color emptyColor, float smoothness = 2f) { - DrawDoughnut(vh, p, insideRadius, outsideRadius, color, color, emptyColor, smoothness, - startDegree, toDegree); + DrawDoughnut(vh, p, insideRadius, outsideRadius, color, color, emptyColor, 0, 360, 0, Color.clear, + 0, smoothness); } public static void DrawDoughnut(VertexHelper vh, Vector3 p, float insideRadius, float outsideRadius, - Color32 color, Color32 toColor, Color emptyColor, float smoothness = 2f, float startDegree = 0, - float toDegree = 360) + Color32 color, Color emptyColor, float startDegree, + float toDegree, float smoothness = 2f) { + DrawDoughnut(vh, p, insideRadius, outsideRadius, color, color, emptyColor, startDegree, toDegree, + 0, Color.clear, 0, smoothness); + } + + public static void DrawDoughnut(VertexHelper vh, Vector3 p, float insideRadius, float outsideRadius, + Color32 color, Color emptyColor, float startDegree, + float toDegree, float borderWidth, Color32 borderColor, float smoothness = 2f) + { + DrawDoughnut(vh, p, insideRadius, outsideRadius, color, color, emptyColor, startDegree, toDegree, + borderWidth, borderColor, 0, smoothness); + } + + public static void DrawDoughnut(VertexHelper vh, Vector3 p, float insideRadius, float outsideRadius, + Color32 color, Color32 toColor, Color emptyColor, float smoothness = 2f) + { + DrawDoughnut(vh, p, insideRadius, outsideRadius, color, toColor, emptyColor, 0, 360, 0, Color.clear, + 0, smoothness); + } + + public static void DrawDoughnut(VertexHelper vh, Vector3 p, float insideRadius, float outsideRadius, + Color32 color, Color32 toColor, Color emptyColor, float startDegree, float toDegree, float borderWidth, + Color32 borderColor, float space, float smoothness, bool roundCap = false, bool clockwise = true) + { + if (toDegree - startDegree == 0) return; if (insideRadius <= 0) { - DrawSector(vh, p, outsideRadius, color, toColor, startDegree, toDegree, smoothness); + DrawSector(vh, p, outsideRadius, color, toColor, startDegree, toDegree, borderWidth, borderColor, + space, smoothness); return; } - Vector3 p1, p2, p3, p4; - int segments = (int)((2 * Mathf.PI * outsideRadius) / (smoothness < 0 ? 2f : smoothness)); + outsideRadius -= borderWidth; + insideRadius += borderWidth; + smoothness = smoothness < 0 ? 2f : smoothness; + Vector3 p1, p2, p3, p4, e1, e2; + var needBorder = borderWidth != 0; + var needSpace = space != 0; + var diffAngle = Mathf.Abs(toDegree - startDegree) * Mathf.Deg2Rad; + + int segments = (int)((2 * Mathf.PI * outsideRadius) * (diffAngle * Mathf.Rad2Deg / 360) / smoothness); float startAngle = startDegree * Mathf.Deg2Rad; - float angle = (toDegree - startDegree) * Mathf.Deg2Rad / segments; - p1 = new Vector3(p.x + insideRadius * Mathf.Sin(startAngle), - p.y + insideRadius * Mathf.Cos(startAngle)); - p2 = new Vector3(p.x + outsideRadius * Mathf.Sin(startAngle), - p.y + outsideRadius * Mathf.Cos(startAngle)); + float toAngle = toDegree * Mathf.Deg2Rad; + + float realStartOutAngle = startAngle; + float realToOutAngle = toAngle; + float realStartInAngle = startAngle; + float realToInAngle = toAngle; + float halfAngle = (toAngle - startAngle) / 2; + float borderAngle = 0, borderInAngle = 0, borderHalfAngle = 0; + float spaceAngle = 0, spaceInAngle = 0, spaceHalfAngle = 0; + + var spaceCenter = p; + var realCenter = p; + var startDire = new Vector3(Mathf.Sin(startAngle), Mathf.Cos(startAngle)).normalized; + var toDire = new Vector3(Mathf.Sin(toAngle), Mathf.Cos(toAngle)).normalized; + var middleDire = new Vector3(Mathf.Sin(startAngle + halfAngle), Mathf.Cos(startAngle + halfAngle)).normalized; + p1 = p + insideRadius * startDire; + p2 = p + outsideRadius * startDire; + e1 = p + insideRadius * toDire; + e2 = p + outsideRadius * toDire; + if (roundCap) + { + var roundRadius = (outsideRadius - insideRadius) / 2; + var roundAngleRadius = insideRadius + roundRadius; + var roundAngle = Mathf.Atan(roundRadius / roundAngleRadius); + if (diffAngle < 2 * roundAngle) + { + roundCap = false; + } + } + if (needBorder || needSpace) + { + if (needSpace) + { + var spaceDiff = space / Mathf.Sin(halfAngle); + spaceCenter = p + Mathf.Abs(spaceDiff) * middleDire; + realCenter = spaceCenter; + spaceAngle = 2 * Mathf.Asin(space / (2 * outsideRadius)); + spaceInAngle = 2 * Mathf.Asin(space / (2 * insideRadius)); + spaceHalfAngle = 2 * Mathf.Asin(space / (2 * (insideRadius + (outsideRadius - insideRadius) / 2))); + if (clockwise) + { + p1 = GetPos(p, insideRadius, startAngle + spaceInAngle, false); + e1 = GetPos(p, insideRadius, toAngle - spaceInAngle, false); + realStartOutAngle = startAngle + spaceAngle; + realToOutAngle = toAngle - spaceAngle; + realStartInAngle = startAngle + spaceInAngle; + realToInAngle = toAngle - spaceInAngle; + } + else + { + p1 = GetPos(p, insideRadius, startAngle - spaceInAngle, false); + e1 = GetPos(p, insideRadius, toAngle + spaceInAngle, false); + realStartOutAngle = startAngle - spaceAngle; + realToOutAngle = toAngle + spaceAngle; + realStartInAngle = startAngle - spaceInAngle; + realToOutAngle = toAngle + spaceInAngle; + } + p2 = GetPos(p, outsideRadius, realStartOutAngle, false); + e2 = GetPos(p, outsideRadius, realToOutAngle, false); + } + if (needBorder) + { + var borderDiff = borderWidth / Mathf.Sin(halfAngle); + realCenter += Mathf.Abs(borderDiff) * middleDire; + borderAngle = 2 * Mathf.Asin(borderWidth / (2 * outsideRadius)); + borderInAngle = 2 * Mathf.Asin(borderWidth / (2 * insideRadius)); + borderHalfAngle = 2 * Mathf.Asin(borderWidth / (2 * (insideRadius + (outsideRadius - insideRadius) / 2))); + if (clockwise) + { + realStartOutAngle = realStartOutAngle + borderAngle; + realToOutAngle = realToOutAngle - borderAngle; + realStartInAngle = startAngle + spaceInAngle + borderInAngle; + realToInAngle = toAngle - spaceInAngle - borderInAngle; + var newp1 = GetPos(p, insideRadius, startAngle + spaceInAngle + borderInAngle, false); + var newp2 = GetPos(p, outsideRadius, realStartOutAngle, false); + if (!roundCap) DrawPolygon(vh, newp2, newp1, p1, p2, borderColor); + p1 = newp1; + p2 = newp2; + if (toAngle - spaceInAngle - 2 * borderInAngle > realStartOutAngle) + { + var newe1 = GetPos(p, insideRadius, toAngle - spaceInAngle - borderInAngle, false); + var newe2 = GetPos(p, outsideRadius, realToOutAngle, false); + if (!roundCap) DrawPolygon(vh, newe2, e2, e1, newe1, borderColor); + e1 = newe1; + e2 = newe2; + } + } + else + { + realStartOutAngle = realStartOutAngle - borderAngle; + realToOutAngle = realToOutAngle + borderAngle; + realStartInAngle = startAngle - spaceInAngle - borderInAngle; + realToInAngle = toAngle + spaceInAngle + borderInAngle; + var newp1 = GetPos(p, insideRadius, startAngle - spaceInAngle - borderInAngle, false); + var newp2 = GetPos(p, outsideRadius, realStartOutAngle, false); + if (!roundCap) DrawPolygon(vh, newp2, newp1, p1, p2, borderColor); + p1 = newp1; + p2 = newp2; + if (toAngle + spaceInAngle + 2 * borderInAngle < realStartOutAngle) + { + var newe1 = GetPos(p, insideRadius, toAngle + spaceInAngle + borderInAngle, false); + var newe2 = GetPos(p, outsideRadius, realToOutAngle, false); + if (!roundCap) DrawPolygon(vh, newe2, e2, e1, newe1, borderColor); + e1 = newe1; + e2 = newe2; + } + } + } + } + if (roundCap) + { + var roundRadius = (outsideRadius - insideRadius) / 2; + var roundAngleRadius = insideRadius + roundRadius; + var roundAngle = Mathf.Atan(roundRadius / roundAngleRadius); + if (clockwise) + { + realStartOutAngle = startAngle + 2 * spaceHalfAngle + borderHalfAngle + roundAngle; + realStartInAngle = startAngle + 2 * spaceHalfAngle + borderHalfAngle + roundAngle; + } + else + { + realStartOutAngle = startAngle - 2 * spaceHalfAngle - borderHalfAngle - roundAngle; + realStartInAngle = startAngle - 2 * spaceHalfAngle - borderHalfAngle - roundAngle; + } + var roundTotalDegree = realStartOutAngle * Mathf.Rad2Deg; + var roundCenter = p + roundAngleRadius * GetDire(realStartOutAngle); + var sectorStartDegree = clockwise ? roundTotalDegree + 180 : roundTotalDegree; + var sectorToDegree = clockwise ? roundTotalDegree + 360 : roundTotalDegree + 180; + DrawSector(vh, roundCenter, roundRadius, color, sectorStartDegree, sectorToDegree, smoothness / 2); + if (needBorder) + { + DrawDoughnut(vh, roundCenter, roundRadius, roundRadius + borderWidth, borderColor, Color.clear, + sectorStartDegree, sectorToDegree, smoothness / 2); + } + p1 = GetPos(p, insideRadius, realStartOutAngle); + p2 = GetPos(p, outsideRadius, realStartOutAngle); + + if (clockwise) + { + realToOutAngle = toAngle - 2 * spaceHalfAngle - borderHalfAngle - roundAngle; + realToInAngle = toAngle - 2 * spaceHalfAngle - borderHalfAngle - roundAngle; + if (realToOutAngle < realStartOutAngle) realToOutAngle = realStartOutAngle; + } + else + { + realToOutAngle = toAngle + 2 * spaceHalfAngle + borderHalfAngle + roundAngle; + realToInAngle = toAngle + 2 * spaceHalfAngle + borderHalfAngle + roundAngle; + if (realToOutAngle > realStartOutAngle) realToOutAngle = realStartOutAngle; + } + roundTotalDegree = realToOutAngle * Mathf.Rad2Deg; + roundCenter = p + roundAngleRadius * GetDire(realToOutAngle); + sectorStartDegree = clockwise ? roundTotalDegree : roundTotalDegree + 180; + sectorToDegree = clockwise ? roundTotalDegree + 180 : roundTotalDegree + 360; + DrawSector(vh, roundCenter, roundRadius, color, sectorStartDegree, sectorToDegree, smoothness / 2); + if (needBorder) + { + DrawDoughnut(vh, roundCenter, roundRadius, roundRadius + borderWidth, borderColor, Color.clear, + sectorStartDegree, sectorToDegree, smoothness / 2); + } + e1 = GetPos(p, insideRadius, realToOutAngle); + e2 = GetPos(p, outsideRadius, realToOutAngle); + } + float segmentAngle = (realToInAngle - realStartInAngle) / segments; for (int i = 0; i <= segments; i++) { - float currAngle = startAngle + i * angle; + float currAngle = realStartInAngle + i * segmentAngle; p3 = new Vector3(p.x + outsideRadius * Mathf.Sin(currAngle), p.y + outsideRadius * Mathf.Cos(currAngle)); p4 = new Vector3(p.x + insideRadius * Mathf.Sin(currAngle), p.y + insideRadius * Mathf.Cos(currAngle)); if (emptyColor != Color.clear) DrawTriangle(vh, p, p1, p4, emptyColor); - //DrawPolygon(vh, p1, p2, p3, p4, color,Color.blue); DrawPolygon(vh, p2, p3, p4, p1, color, toColor); p1 = p4; p2 = p3; } + if (needBorder || needSpace || roundCap) + { + if (clockwise) + { + var isInAngleFixed = toAngle - spaceInAngle - 2 * borderInAngle > realStartOutAngle; + if (isInAngleFixed) DrawPolygon(vh, p2, e2, e1, p1, color, toColor); + else DrawTriangle(vh, p2, e2, p1, color, color, toColor); + if (needBorder) + { + var realStartDegree = (realStartOutAngle - (roundCap ? 0 : borderAngle)) * Mathf.Rad2Deg; + var realToDegree = (realToOutAngle + (roundCap ? 0 : borderAngle)) * Mathf.Rad2Deg; + if (realToDegree < realStartOutAngle) realToDegree = realStartOutAngle; + var inStartDegree = roundCap ? realStartDegree : (startAngle + spaceInAngle) * Mathf.Rad2Deg; + var inToDegree = roundCap ? realToDegree : (toAngle - spaceInAngle) * Mathf.Rad2Deg; + if (inToDegree < inStartDegree) inToDegree = inStartDegree; + if (isInAngleFixed) DrawDoughnut(vh, p, insideRadius - borderWidth, insideRadius, borderColor, Color.clear, + inStartDegree, inToDegree, smoothness); + DrawDoughnut(vh, p, outsideRadius, outsideRadius + borderWidth, borderColor, Color.clear, + realStartDegree, realToDegree, smoothness); + } + } + else + { + var isInAngleFixed = toAngle + spaceInAngle + 2 * borderInAngle < realStartOutAngle; + if (isInAngleFixed) DrawPolygon(vh, p2, e2, e1, p1, color, toColor); + else DrawTriangle(vh, p2, e2, p1, color, color, toColor); + if (needBorder) + { + var realStartDegree = (realStartOutAngle + (roundCap ? 0 : borderAngle)) * Mathf.Rad2Deg; + var realToDegree = (realToOutAngle - (roundCap ? 0 : borderAngle)) * Mathf.Rad2Deg; + var inStartDegree = roundCap ? realStartDegree : (startAngle - spaceInAngle) * Mathf.Rad2Deg; + var inToDegree = roundCap ? realToDegree : (toAngle + spaceInAngle) * Mathf.Rad2Deg; + if (inToDegree > inStartDegree) inToDegree = inStartDegree; + if (isInAngleFixed) DrawDoughnut(vh, p, insideRadius - borderWidth, insideRadius, borderColor, Color.clear, + inStartDegree, inToDegree, smoothness); + DrawDoughnut(vh, p, outsideRadius, outsideRadius + borderWidth, borderColor, Color.clear, + realStartDegree, realToDegree, smoothness); + } + } + } } ///