Skip to content

Commit df4387a

Browse files
committed
improve graph geometry, cache graph vertices, support multiple plots per graph
1 parent 5d6a380 commit df4387a

File tree

6 files changed

+419
-123
lines changed

6 files changed

+419
-123
lines changed

src/main/java/com/cleanroommc/modularui/drawable/graph/AutoMajorTickFinder.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,56 @@
55
@ApiStatus.Experimental
66
public class AutoMajorTickFinder implements MajorTickFinder {
77

8-
private float multiple;
8+
private final boolean autoAdjust;
9+
private float multiple = 10;
10+
11+
public AutoMajorTickFinder(boolean autoAdjust) {
12+
this.autoAdjust = autoAdjust;
13+
}
914

1015
public AutoMajorTickFinder(float multiple) {
16+
this.autoAdjust = false;
1117
this.multiple = multiple;
1218
}
1319

1420
@Override
1521
public float[] find(float min, float max, float[] ticks) {
16-
int s = (int) Math.ceil((max - min) / multiple) + 1;
22+
int s = (int) Math.ceil((max - min) / multiple) + 2;
1723
if (s > ticks.length) ticks = new float[s];
1824
float next = (float) (Math.floor(min / multiple) * multiple);
1925
for (int i = 0; i < s; i++) {
26+
ticks[i] = next;
2027
if (next > max) {
21-
s--;
28+
s = i + 1;
2229
break;
2330
}
24-
ticks[i] = next;
2531
next += multiple;
2632
}
2733
if (ticks.length > s) ticks[s] = Float.NaN;
2834
return ticks;
2935
}
36+
37+
void calculateAutoTickMultiple(float min, float max) {
38+
float step = (max - min) / 5;
39+
if (step < 1) {
40+
int significantPlaces = (int) Math.abs(Math.log10(step)) + 2;
41+
float ten = (float) Math.pow(10, significantPlaces);
42+
step = (int) (step * ten + 0.2f) / ten;
43+
} else if (step == 1) {
44+
step = 0.2f;
45+
} else {
46+
int significantPlaces = (int) Math.log10(step) - 1;
47+
float ten = (float) Math.pow(10, significantPlaces);
48+
step = (int) (step / ten + 0.2f) * ten;
49+
}
50+
setMultiple(step);
51+
}
52+
53+
public boolean isAutoAdjust() {
54+
return autoAdjust;
55+
}
56+
57+
public void setMultiple(float multiple) {
58+
this.multiple = multiple;
59+
}
3060
}

src/main/java/com/cleanroommc/modularui/drawable/graph/GraphAxis.java

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.jetbrains.annotations.ApiStatus;
1212

1313
import java.text.DecimalFormat;
14+
import java.util.List;
1415

1516
@ApiStatus.Experimental
1617
public class GraphAxis {
@@ -27,21 +28,43 @@ public class GraphAxis {
2728
public float[] minorTicks = new float[16];
2829
public TextRenderer.Line[] tickLabels = new TextRenderer.Line[8];
2930
private float maxLabelWidth = 0;
30-
public MajorTickFinder majorTickFinder = new AutoMajorTickFinder(10);
31-
public MinorTickFinder minorTickFinder = new AutoMinorTickFinder(1);
31+
public MajorTickFinder majorTickFinder = new AutoMajorTickFinder(true);
32+
public MinorTickFinder minorTickFinder = new AutoMinorTickFinder(2);
3233
public String label;
3334
public float min, max;
3435
public boolean autoLimits = true;
35-
public float[] data;
3636

3737
public GraphAxis(GuiAxis axis) {
3838
this.axis = axis;
3939
}
4040

41-
void compute() {
41+
void compute(List<Plot> plots) {
4242
if (this.autoLimits) {
43-
this.min = FloatArrayMath.min(this.data);
44-
this.max = FloatArrayMath.max(this.data);
43+
if (plots.isEmpty()) {
44+
this.min = 0;
45+
this.max = 0;
46+
} else if (plots.size() == 1) {
47+
this.min = FloatArrayMath.min(plots.get(0).getData(this.axis));
48+
this.max = FloatArrayMath.max(plots.get(0).getData(this.axis));
49+
} else {
50+
float min = Float.MAX_VALUE, max = Float.MIN_VALUE;
51+
for (Plot plot : plots) {
52+
float m = FloatArrayMath.min(plot.getData(this.axis));
53+
if (m < min) min = m;
54+
m = FloatArrayMath.max(plot.getData(this.axis));
55+
if (m > max) max = m;
56+
}
57+
this.min = min;
58+
this.max = max;
59+
}
60+
if (this.axis.isVertical()) {
61+
float padding = (this.max - this.min) * 0.05f;
62+
this.max += padding;
63+
this.min -= padding;
64+
}
65+
}
66+
if (this.majorTickFinder instanceof AutoMajorTickFinder tickFinder && tickFinder.isAutoAdjust()) {
67+
tickFinder.calculateAutoTickMultiple(this.min, this.max);
4568
}
4669
this.majorTicks = this.majorTickFinder.find(this.min, this.max, this.majorTicks);
4770
this.minorTicks = this.minorTickFinder.find(this.min, this.max, this.majorTicks, this.minorTicks);
@@ -52,7 +75,7 @@ void compute() {
5275
textRenderer.setScale(TICK_LABEL_SCALE);
5376
this.maxLabelWidth = 0;
5477
float maxDiff = FloatArrayMath.max(FloatArrayMath.diff(this.majorTicks));
55-
int significantPlaces = (int) Math.abs(Math.log10(maxDiff)) + 1;
78+
int significantPlaces = (int) Math.abs(Math.log10(maxDiff)) + 2;
5679
DecimalFormat format = new DecimalFormat();
5780
format.setMaximumFractionDigits(significantPlaces);
5881
for (int i = 0; i < this.tickLabels.length; i++) {
@@ -87,12 +110,12 @@ void drawGridLines(BufferBuilder buffer, GraphView view, GraphAxis other, boolea
87110
float[] pos = major ? this.majorTicks : this.minorTicks;
88111
float dHalf = d / 2;
89112
if (axis.isHorizontal()) {
90-
float otherMin = view.transformYGraphToScreen(other.max);
91-
float otherMax = view.transformYGraphToScreen(other.min);
113+
float otherMin = view.g2sY(other.max);
114+
float otherMax = view.g2sY(other.min);
92115
drawLinesOnHorizontal(buffer, view, pos, dHalf, otherMin, otherMax, r, g, b, a);
93116
} else {
94-
float otherMin = view.transformXGraphToScreen(other.min);
95-
float otherMax = view.transformXGraphToScreen(other.max);
117+
float otherMin = view.g2sX(other.min);
118+
float otherMax = view.g2sX(other.max);
96119
drawLinesOnVertical(buffer, view, pos, dHalf, otherMin, otherMax, r, g, b, a);
97120
}
98121
}
@@ -101,10 +124,10 @@ void drawTicks(BufferBuilder buffer, GraphView view, GraphAxis other, boolean ma
101124
float[] pos = major ? this.majorTicks : this.minorTicks;
102125
float dHalf = thickness / 2;
103126
if (axis.isHorizontal()) {
104-
float otherMin = view.transformYGraphToScreen(other.min);
127+
float otherMin = view.g2sY(other.min);
105128
drawLinesOnHorizontal(buffer, view, pos, dHalf, otherMin - length, otherMin, r, g, b, a);
106129
} else {
107-
float otherMin = view.transformXGraphToScreen(other.min);
130+
float otherMin = view.g2sX(other.min);
108131
drawLinesOnVertical(buffer, view, pos, dHalf, otherMin, otherMin + length, r, g, b, a);
109132
}
110133
}
@@ -115,7 +138,7 @@ private void drawLinesOnHorizontal(BufferBuilder buffer, GraphView view, float[]
115138
if (Float.isNaN(p)) break;
116139
if (p < min || p > max) continue;
117140

118-
p = view.transformXGraphToScreen(p);
141+
p = view.g2sX(p);
119142

120143
float x0 = p - dHalf;
121144
float x1 = p + dHalf;
@@ -129,7 +152,7 @@ private void drawLinesOnVertical(BufferBuilder buffer, GraphView view, float[] p
129152
if (Float.isNaN(p)) break;
130153
if (p < min || p > max) continue;
131154

132-
p = view.transformYGraphToScreen(p);
155+
p = view.g2sY(p);
133156

134157
float y0 = p - dHalf;
135158
float y1 = p + dHalf;
@@ -142,23 +165,23 @@ void drawLabels(GraphView view, GraphAxis other) {
142165
if (axis.isHorizontal()) {
143166
textRenderer.setScale(TICK_LABEL_SCALE);
144167
textRenderer.setAlignment(Alignment.TopCenter, 100);
145-
float y = view.transformYGraphToScreen(other.min) + TICK_LABEL_OFFSET;
168+
float y = view.g2sY(other.min) + TICK_LABEL_OFFSET;
146169
for (int i = 0; i < this.majorTicks.length; i++) {
147170
float pos = this.majorTicks[i];
148171
if (Float.isNaN(pos)) break;
149172
if (pos < min || pos > max) continue;
150-
textRenderer.setPos((int) (view.transformXGraphToScreen(pos) - 50), (int) y);
173+
textRenderer.setPos((int) (view.g2sX(pos) - 50), (int) y);
151174
textRenderer.draw(this.tickLabels[i].getText());
152175
}
153176
} else {
154177
textRenderer.setScale(TICK_LABEL_SCALE);
155178
textRenderer.setAlignment(Alignment.CenterRight, this.maxLabelWidth, 20);
156-
float x = view.transformXGraphToScreen(other.min) - TICK_LABEL_OFFSET - this.maxLabelWidth;
179+
float x = view.g2sX(other.min) - TICK_LABEL_OFFSET - this.maxLabelWidth;
157180
for (int i = 0; i < this.majorTicks.length; i++) {
158181
float pos = this.majorTicks[i];
159182
if (Float.isNaN(pos)) break;
160183
if (pos < min || pos > max) continue;
161-
textRenderer.setPos((int) x, (int) (view.transformYGraphToScreen(pos) - 10));
184+
textRenderer.setPos((int) x, (int) (view.g2sY(pos) - 10));
162185
textRenderer.draw(this.tickLabels[i].getText());
163186
}
164187
}

0 commit comments

Comments
 (0)