1 #Region "Microsoft.VisualBasic::5315adb7af81bfbb9b35846cd37c6e0d, Microsoft.VisualBasic.Core\ComponentModel\Ranges\Extensions.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Module Extensions
35     
36     '         Function: (+2 OverloadsGetScaler, (+2 Overloads) RangeTransform, SymmetricalRange
37     
38     '         Sub: Parser
39     
40     
41     ' /********************************************************************************/
42
43 #End Region
44
45 Imports System.Runtime.CompilerServices
46 Imports System.Text.RegularExpressions
47 Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
48 Imports Microsoft.VisualBasic.Linq
49 Imports Microsoft.VisualBasic.Scripting.Runtime
50 Imports r = System.Text.RegularExpressions.Regex
51
52 Namespace ComponentModel.Ranges
53
54     Public Module Extensions
55
56         ''' <summary>
57         ''' 对称的的范围,假若X为正数,那么其为max,而-x为min。假若x为负数,那么-x为max
58         ''' </summary>
59         ''' <param name="x#"></param>
60         ''' <returns></returns>
61         <Extension>
62         Public Function SymmetricalRange(x#) As DoubleRange
63             If x > 0 Then
64                 Return {-x, x}
65             Else
66                 Return {x, -x}
67             End If
68         End Function
69
70         Const RegexpFloatRange$ = RegexpFloat & "\s*,\s*" & RegexpFloat
71
72         ''' <summary>
73         ''' + ``min -> max``
74         ''' + ``min—max``
75         ''' + ``min~max``
76         ''' + ``[min,max]``
77         ''' + ``{min,max}``
78         ''' + ``(min,max)``
79         ''' + ``min,max``
80         ''' </summary>
81         ''' <param name="exp$"></param>
82         ''' <param name="min#"></param>
83         ''' <param name="max#"></param>
84         <Extension> Public Sub Parser(exp$, ByRef min#, ByRef max#)
85             Dim t$()
86             Dim raw$ = exp
87
88             If InStr(exp, "->") > 0 Then
89                 t = Strings.Split(exp, "->")
90             ElseIf InStr(exp, "—") > 0 Then
91                 ' 使用的是中文的分隔符
92                 t = Strings.Split(exp, "—")
93             ElseIf InStr(exp, "~") > 0 Then
94                 t = Strings.Split(exp, "~")
95             ElseIf exp.IsPattern(RegexpDouble & "\s*[-]\s*" & RegexpDouble) Then
96                 ' 使用的是英文的分隔符
97                 ' 因为可能会和负号弄混,所以在这里需要使用正则表达式来匹配出这个分隔符
98                 ' 因为是这种格式的range: dd-dd
99                 ' 故而分隔符的pattern肯定是数字加连接符本身,将这个pattern匹配出来,然后利用这个pattern进行分割即可
100                 Dim del$ = r.Match(exp, "\d\s*[-]").Value
101                 t = Strings.Split(exp, del)
102                 ' 需要将存在于del的pattern之中的前面的数字的最后一个数值补回来
103                 t(0) = t(0) & del.Trim("-"c)
104             Else
105                 exp = r _
106                     .Match(exp, RegexpFloatRange, RegexOptions.Singleline) _
107                     .Value
108
109                 If String.IsNullOrEmpty(exp) Then
110                     exp = $"'{raw}' is not a valid expression format!"
111                     Throw New FormatException(exp)
112                 Else
113                     t = exp.Split(","c)
114                 End If
115             End If
116
117             t = t _
118                 .Select(AddressOf Trim) _
119                 .ToArray
120
121             min = Casting.ParseNumeric(t(Scan0))
122             max = Casting.ParseNumeric(t(1))
123         End Sub
124
125         ''' <summary>
126         ''' 返回一个实数区间的范围百分比的生成函数:``[0-1]``之间
127         ''' </summary>
128         ''' <param name="range"></param>
129         ''' <returns></returns>
130         <Extension>
131         Public Function GetScaler(range As DoubleRange) As Func(Of DoubleDouble)
132             Dim length# = range.Length
133             Dim min# = range.Min
134
135             Return Function(x#)
136                        Return (x - min) / length
137                    End Function
138         End Function
139
140         <Extension>
141         Public Function GetScaler(vector As IEnumerable(Of Double)) As Func(Of DoubleDouble)
142             With vector.ToArray
143                 Return New DoubleRange(.Min, .Max).GetScaler
144             End With
145         End Function
146
147         ''' <summary>
148         ''' 将目标区间内的任意实数全部转换为<paramref name="to"/>区间内的实数
149         ''' </summary>
150         ''' <param name="from"></param>
151         ''' <param name="[to]"></param>
152         ''' <returns></returns>
153         <Extension>
154         Public Function RangeTransform(from As IEnumerable(Of Double), [to] As DoubleRange) As Double()
155             If from Is Nothing Then
156                 Return {}
157             End If
158
159             Dim vector#() = from.ToArray
160             Dim scale = New DoubleRange(vector).GetScaler
161             Dim percentages#() = vector.Select(scale).ToArray
162             Dim length# = [to].Length
163             Dim min# = [to].Min
164             Dim maps#() = percentages.Select(Function(x) x * length + min).ToArray
165             Return maps
166         End Function
167
168         ''' <summary>
169         ''' 将目标区间内的任意实数全部转换为<paramref name="to"/>区间内的实数
170         ''' </summary>
171         ''' <param name="from"></param>
172         ''' <param name="[to]"></param>
173         ''' <returns></returns>
174         <Extension>
175         Public Function RangeTransform(from As IEnumerable(Of Integer), [to] As IntRange) As Integer()
176             Return from _
177                    .Select(Function(x) CDbl(x)) _
178                    .RangeTransform(New DoubleRange([to])) _
179                    .Select(Function(x) CInt(x)) _
180                    .ToArray
181         End Function
182     End Module
183 End Namespace