-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChartScaleClass.vb
144 lines (123 loc) · 3.97 KB
/
ChartScaleClass.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
Public Class ChartScaleBounds
' Calculates nice-looking values for chart scale bounds and number of intervals
' Final number of intervals will be closest to the requested (optimal) number
' Input parameters
Private _lower_data_bound As Double
Private _upper_data_bound As Double
Private _optimal_num As Integer
' Results
Private _min As Double
Private _max As Double
Private _n As Integer
Private _interval As Double
''' <summary>
''' Constructor
''' </summary>
''' <param name="lower_data_bound">Lower data bound</param>
''' <param name="upper_data_bound">Upper data bound</param>
''' <param name="optimal_num">Optimal number of intervals</param>
Public Sub New(lower_data_bound As Double, upper_data_bound As Double, optimal_num As Integer)
_lower_data_bound = lower_data_bound
_upper_data_bound = upper_data_bound
_optimal_num = optimal_num
Call Calc()
End Sub
''' <summary>
''' Minimum value of data range (input)
''' </summary>
Public Property LowerDataBound As Double
Get
Return _lower_data_bound
End Get
Set(value As Double)
_lower_data_bound = value
Call Calc()
End Set
End Property
''' <summary>
''' Maximum value of data range (input)
''' </summary>
Public Property UpperDataBound As Double
Get
Return _upper_data_bound
End Get
Set(value As Double)
_upper_data_bound = value
Call Calc()
End Set
End Property
''' <summary>
''' Desired number of intervals (input)
''' </summary>
Public Property OptimalN As Integer
Get
Return _optimal_num
End Get
Set(value As Integer)
_optimal_num = value
Call Calc()
End Set
End Property
''' <summary>
''' Lower scale bound (output)
''' </summary>
Public ReadOnly Property Min As Double
Get
Return _min
End Get
End Property
''' <summary>
''' Upper scale bound (output)
''' </summary>
Public ReadOnly Property Max As Double
Get
Return _max
End Get
End Property
''' <summary>
''' Number of intervals (output)
''' </summary>
Public ReadOnly Property N As Integer
Get
Return _n
End Get
End Property
''' <summary>
''' Size of the interval (output)
''' </summary>
Public ReadOnly Property Interval As Double
Get
Return _interval
End Get
End Property
Private Sub Calc()
Dim MinStep, s(4), tmp_num(4), tmp_min(4), tmp_max(4) As Double
MinStep = (_upper_data_bound - _lower_data_bound) / _optimal_num
s(0) = 10 ^ (Math.Ceiling(Math.Log10(MinStep)))
s(1) = 10 ^ (Math.Ceiling(Math.Log10(MinStep))) / 2
s(2) = 10 ^ (Math.Ceiling(Math.Log10(MinStep))) / 4
s(3) = 10 ^ (Math.Ceiling(Math.Log10(MinStep))) / 5
s(4) = 10 ^ (Math.Ceiling(Math.Log10(MinStep))) / 10
For i As Integer = 0 To 4
tmp_min(i) = s(i) * Math.Floor(_lower_data_bound / s(i))
tmp_max(i) = s(i) * Math.Ceiling(_upper_data_bound / s(i))
tmp_num(i) = (tmp_max(i) - tmp_min(i)) / s(i)
Next
Dim best, diff As Integer
best = 0
diff = Math.Abs(_optimal_num - tmp_num(0))
For i As Integer = 1 To 4
If Math.Abs(_optimal_num - tmp_num(i)) < diff Then
diff = Math.Abs(_optimal_num - tmp_num(i))
best = i
ElseIf (Math.Abs(_optimal_num - tmp_num(i)) = diff) And (tmp_num(i) < _optimal_num) Then '// choose smaller number of intevals
diff = Math.Abs(_optimal_num - tmp_num(i))
best = i
End If
Next
_n = tmp_num(best)
_min = tmp_min(best)
_max = tmp_max(best)
_interval = (_max - _min) / _n
End Sub
End Class