1 #Region "Microsoft.VisualBasic::fb6d1db40cfe4429caec8ea48bba81f9, Microsoft.VisualBasic.Core\Extensions\Image\Math\GeomTransform.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 GeomTransform
35     
36     '         Function: Angle, Area, (+2 Overloads) CalculateAngle, CenterAlign, (+2 Overloads) CentralOffset
37     '                   (+4 Overloads) Centre, CircleRectangle, (+4 Overloads) Distance, (+2 OverloadsGetBounds, GetCenter
38     '                   (+2 OverloadsInRegion, MirrorX, MirrorY, (+5 OverloadsOffSet2D, Offsets
39     '                   (+4 Overloads) Scale, ShapePoints, SquareSize
40     
41     
42     ' /********************************************************************************/
43
44 #End Region
45
46 Imports System.Drawing
47 Imports System.Math
48 Imports System.Runtime.CompilerServices
49 Imports Microsoft.VisualBasic.CommandLine.Reflection
50 Imports Microsoft.VisualBasic.Language
51 Imports Microsoft.VisualBasic.Linq
52 Imports Microsoft.VisualBasic.Scripting.MetaData
53 Imports sys = System.Math
54
55 Namespace Imaging.Math2D
56
57     <Package("GDI.Transform")> Public Module GeomTransform
58
59         ''' <summary>
60         ''' Returns a size value that its width equals height. 
61         ''' </summary>
62         ''' <param name="width%"></param>
63         ''' <returns></returns>
64         <MethodImpl(MethodImplOptions.AggressiveInlining)>
65         <Extension>
66         Public Function SquareSize(width%) As Size
67             Return New Size(width, width)
68         End Function
69
70         ''' <summary>
71         ''' 这个方形区域的面积
72         ''' </summary>
73         ''' <param name="rect"></param>
74         ''' <returns></returns>
75         ''' 
76         <MethodImpl(MethodImplOptions.AggressiveInlining)>
77         <Extension>
78         Public Function Area(rect As Rectangle) As Double
79             Return rect.Width * rect.Height
80         End Function
81
82         ''' <summary>
83         ''' left,top -> right, top -> right, bottom -> left, bottom
84         ''' </summary>
85         ''' <param name="rect"></param>
86         ''' <returns></returns>
87         <Extension>
88         Public Iterator Function ShapePoints(rect As RectangleF) As IEnumerable(Of PointF)
89             With rect
90                 Yield New PointF(.Left, .Top)
91                 Yield New PointF(.Right, .Top)
92                 Yield New PointF(.Right, .Bottom)
93                 Yield New PointF(.Left, .Bottom)
94             End With
95         End Function
96
97         ''' <summary>
98         ''' Is target point in the target region?
99         ''' </summary>
100         ''' <param name="x"></param>
101         ''' <param name="rect"></param>
102         ''' <returns></returns>
103         ''' 
104         <MethodImpl(MethodImplOptions.AggressiveInlining)>
105         <Extension>
106         Public Function InRegion(x As Point, rect As Rectangle) As Boolean
107             Return New PointF(x.X, x.Y).InRegion(rect)
108         End Function
109
110         ''' <summary>
111         ''' Is target point in the target region?
112         ''' </summary>
113         ''' <param name="x"></param>
114         ''' <param name="rect"></param>
115         ''' <returns></returns>
116         <Extension>
117         Public Function InRegion(x As PointF, rect As Rectangle) As Boolean
118             If x.X < rect.Left OrElse x.X > rect.Right Then
119                 Return False
120             End If
121             If x.Y < rect.Top OrElse x.Y > rect.Bottom Then
122                 Return False
123             End If
124
125             Return True
126         End Function
127
128         ''' <summary>
129         ''' Calculate the center location of the target sized region
130         ''' </summary>
131         ''' <param name="size"></param>
132         ''' <returns></returns>
133         ''' 
134         <MethodImpl(MethodImplOptions.AggressiveInlining)>
135         <Extension> Public Function GetCenter(size As Size) As Point
136             Return New Point(size.Width / 2, size.Height / 2)
137         End Function
138
139         ''' <summary>
140         ''' 返回位移的新的点位置值
141         ''' </summary>
142         ''' <param name="p"></param>
143         ''' <param name="x"></param>
144         ''' <param name="y"></param>
145         ''' <returns></returns>
146         <ExportAPI("Offset")>
147         <MethodImpl(MethodImplOptions.AggressiveInlining)>
148         <Extension> Public Function OffSet2D(p As Point, x As Integer, y As IntegerAs Point
149             Return New Point(x + p.X, y + p.Y)
150         End Function
151
152         ''' <summary>
153         ''' 返回位置的新的点位置值
154         ''' </summary>
155         ''' <param name="p"></param>
156         ''' <param name="offset"></param>
157         ''' <returns></returns>
158         <ExportAPI("Offset")>
159         <MethodImpl(MethodImplOptions.AggressiveInlining)>
160         <Extension> Public Function OffSet2D(p As Point, offset As Point) As Point
161             Return p.OffSet2D(offset.PointF)
162         End Function
163
164         ''' <summary>
165         ''' 返回位置的新的点位置值
166         ''' </summary>
167         ''' <param name="p"></param>
168         ''' <param name="offset"></param>
169         ''' <returns></returns>
170         <ExportAPI("Offset")>
171         <MethodImpl(MethodImplOptions.AggressiveInlining)>
172         <Extension> Public Function OffSet2D(p As Point, offset As PointF) As Point
173             Return New Point(offset.X + p.X, offset.Y + p.Y)
174         End Function
175
176         ''' <summary>
177         ''' Default is ``A + B``
178         ''' </summary>
179         ''' <param name="pt"></param>
180         ''' <param name="offset"></param>
181         ''' <returns></returns>
182         <MethodImpl(MethodImplOptions.AggressiveInlining)>
183         <Extension> Public Function OffSet2D(pt As PointF, offset As PointF, Optional d% = 1) As PointF
184             With pt
185                 Return New PointF(d * offset.X + .X, d * offset.Y + .Y)
186             End With
187         End Function
188
189         ''' <summary>
190         ''' <see cref="Point"/> <paramref name="pt"/> + offset
191         ''' </summary>
192         ''' <param name="pt"></param>
193         ''' <param name="x!"></param>
194         ''' <param name="y!"></param>
195         ''' <returns></returns>
196         <MethodImpl(MethodImplOptions.AggressiveInlining)>
197         <Extension> Public Function OffSet2D(pt As PointF, x!, y!) As PointF
198             With pt
199                 Return New PointF(x + .X, y + .Y)
200             End With
201         End Function
202
203         <MethodImpl(MethodImplOptions.AggressiveInlining)>
204         <Extension>
205         Public Function Offsets(points As IEnumerable(Of Point), offset As PointF) As Point()
206             Return points.Select(Function(pt) pt.OffSet2D(offset)).ToArray
207         End Function
208
209         <MethodImpl(MethodImplOptions.AggressiveInlining)>
210         <Extension>
211         Public Function MirrorX(pt As PointF, rect As RectangleF) As PointF
212             Return New PointF With {
213                 .X = rect.Right - (pt.X - rect.Left),
214                 .Y = pt.Y
215             }
216         End Function
217
218         ''' <summary>
219         ''' 
220         ''' </summary>
221         ''' <param name="pt">假设<paramref name="pt"/>是位于<paramref name="rect"/>内部的</param>
222         ''' <param name="rect"></param>
223         ''' <returns></returns>
224         <MethodImpl(MethodImplOptions.AggressiveInlining)>
225         <Extension>
226         Public Function MirrorY(pt As PointF, rect As RectangleF) As PointF
227             Return New PointF With {
228                 .X = pt.X,
229                 .Y = rect.Bottom - (pt.Y - rect.Top)
230             }
231         End Function
232
233         ''' <summary>
234         ''' <see cref="Graphics.DrawEllipse(Pen, RectangleF)"/>
235         ''' </summary>
236         ''' <param name="center"></param>
237         ''' <param name="r!"></param>
238         ''' <returns></returns>
239         <Extension>
240         Public Function CircleRectangle(center As PointF, r!) As RectangleF
241             Dim d = r * 2
242             Return New RectangleF(center.OffSet2D(-r, -r), New SizeF(d, d))
243         End Function
244
245         <Extension>
246         Public Function CenterAlign(rect As RectangleF, size As SizeF) As PointF
247             Dim x! = (rect.Width - size.Width) / 2 + rect.Left
248             Dim y! = (rect.Height - size.Height) / 2 + rect.Top
249             Return New PointF(x, y)
250         End Function
251
252         <MethodImpl(MethodImplOptions.AggressiveInlining)>
253         Public Function Distance(x1#, y1#, x2#, y2#) As Double
254             Return sys.Sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
255         End Function
256
257         <MethodImpl(MethodImplOptions.AggressiveInlining)>
258         <Extension>
259         Public Function Distance(a As Point, b As Point) As Double
260             Return Distance(a.X, a.Y, b.X, b.Y)
261         End Function
262
263         ''' <summary>
264         ''' 计算任意两点之间的欧几里得距离
265         ''' </summary>
266         ''' <param name="a"></param>
267         ''' <param name="b"></param>
268         ''' <returns></returns>
269         <MethodImpl(MethodImplOptions.AggressiveInlining)>
270         <Extension>
271         Public Function Distance(a As PointF, b As PointF) As Double
272             Return Distance(a.X, a.Y, b.X, b.Y)
273         End Function
274
275         ''' <summary>
276         ''' 计算每一个顶点到同一个锚点的距离值的集合
277         ''' </summary>
278         ''' <param name="points"></param>
279         ''' <param name="anchor"></param>
280         ''' <returns></returns>
281         <MethodImpl(MethodImplOptions.AggressiveInlining)>
282         <Extension>
283         Public Function Distance(points As IEnumerable(Of Point), anchor As Point) As Double()
284             Return points _
285                 .Select(Function(pt) Distance(pt.X, pt.Y, anchor.X, anchor.Y)) _
286                 .ToArray
287         End Function
288
289         ''' <summary>
290         ''' 函数返回角度
291         ''' </summary>
292         ''' <param name="p1"></param>
293         ''' <param name="p2"></param>
294         ''' <returns></returns>
295         <MethodImpl(MethodImplOptions.AggressiveInlining)>
296         <Extension> Public Function CalculateAngle(p1 As PointF, p2 As PointF) As Double
297             Dim xDiff As Single = p2.X - p1.X
298             Dim yDiff As Single = p2.Y - p1.Y
299             Return sys.Atan2(yDiff, xDiff) * 180.0 / PI
300         End Function
301
302         ''' <summary>
303         ''' 函数返回角度
304         ''' </summary>
305         ''' <param name="p1"></param>
306         ''' <param name="p2"></param>
307         ''' <returns></returns>
308         <MethodImpl(MethodImplOptions.AggressiveInlining)>
309         <Extension> Public Function CalculateAngle(p1 As Point, p2 As Point) As Double
310             Return CalculateAngle(p1.PointF, p2.PointF)
311         End Function
312
313         ''' <summary>
314         ''' 函数返回切线和X轴之间的夹角
315         ''' </summary>
316         ''' <param name="tangent"></param>
317         ''' <returns>单位为角度</returns>
318         ''' 
319         <MethodImpl(MethodImplOptions.AggressiveInlining)>
320         <Extension>
321         Public Function Angle(tangent As (A As PointF, B As PointF)) As Double
322             Return CalculateAngle(tangent.A, tangent.B)
323         End Function
324
325         ''' <summary>
326         ''' 获取目标多边形对象的边界结果,包括左上角的位置以及所占的矩形区域的大小
327         ''' </summary>
328         ''' <param name="points"></param>
329         ''' <returns></returns>
330         ''' 
331         <MethodImpl(MethodImplOptions.AggressiveInlining)>
332         <Extension>
333         Public Function GetBounds(points As IEnumerable(Of Point)) As RectangleF
334             Return points.Select(Function(pt) pt.PointF).GetBounds
335         End Function
336
337         ''' <summary>
338         ''' 获取目标多边形对象的边界结果,包括左上角的位置以及所占的矩形区域的大小
339         ''' </summary>
340         ''' <param name="points"></param>
341         ''' <returns></returns>
342         <Extension>
343         Public Function GetBounds(points As IEnumerable(Of PointF)) As RectangleF
344             Dim array = points.ToArray
345             Dim xmin = array.Min(Function(pt) pt.X)
346             Dim xmax = array.Max(Function(pt) pt.X)
347             Dim ymin = array.Min(Function(pt) pt.Y)
348             Dim ymax = array.Max(Function(pt) pt.Y)
349             Dim topLeft As New PointF(xmin, ymin)
350             Dim size As New SizeF(xmax - xmin, ymax - ymin)
351             Return New RectangleF(topLeft, size)
352         End Function
353
354         ''' <summary>
355         ''' Gets the center location of the region rectangle.
356         ''' </summary>
357         ''' <param name="rect"></param>
358         ''' <returns></returns>
359         <ExportAPI("Center")>
360         <MethodImpl(MethodImplOptions.AggressiveInlining)>
361         <Extension> Public Function Centre(rect As Rectangle) As Point
362             Return New Point(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2)
363         End Function
364
365         ''' <summary>
366         ''' Resize the rectangle
367         ''' </summary>
368         ''' <param name="rect"></param>
369         ''' <param name="factor"></param>
370         ''' <returns></returns>
371         <Extension> Public Function Scale(rect As RectangleF, factor As SizeF) As RectangleF
372             Dim size = New SizeF(rect.Width * factor.Width, rect.Height * factor.Height)
373             Dim delta = size - rect.Size
374             Dim location As New PointF(rect.Left - delta.Width / 2, rect.Top - delta.Height / 2)
375             Return New RectangleF(location, size)
376         End Function
377
378         ''' <summary>
379         ''' 宽和高进行等比缩放
380         ''' </summary>
381         ''' <param name="size"></param>
382         ''' <param name="factor#"></param>
383         ''' <returns></returns>
384         <MethodImpl(MethodImplOptions.AggressiveInlining)>
385         <Extension>
386         Public Function Scale(size As SizeF, factor#) As SizeF
387             Return New SizeF(size.Width * factor, size.Height * factor)
388         End Function
389
390         ''' <summary>
391         ''' 宽和高进行等比缩放
392         ''' </summary>
393         ''' <param name="size"></param>
394         ''' <param name="factor#"></param>
395         ''' <returns></returns>
396         <MethodImpl(MethodImplOptions.AggressiveInlining)>
397         <Extension>
398         Public Function Scale(size As Size, factor#) As Size
399             Return New Size(size.Width * factor, size.Height * factor)
400         End Function
401
402         <MethodImpl(MethodImplOptions.AggressiveInlining)>
403         <Extension> Public Function Scale(rect As Rectangle, factor As SizeF) As Rectangle
404             With rect
405                 With New RectangleF(.Location.PointF, .Size.SizeF).Scale(factor)
406                     Return New Rectangle(.Location.ToPoint, .Size.ToSize)
407                 End With
408             End With
409         End Function
410
411         ''' <summary>
412         ''' 获取目标多边形对象的中心点的坐标位置
413         ''' </summary>
414         ''' <param name="shape"></param>
415         ''' <returns></returns>
416         <Extension>
417         Public Function Centre(shape As IEnumerable(Of PointF)) As PointF
418             Dim x As New List(Of Single)
419             Dim y As New List(Of Single)
420
421             Call shape.DoEach(Sub(pt)
422                                   x += pt.X
423                                   y += pt.Y
424                               End Sub)
425
426             Return New PointF(x.Average, y.Average)
427         End Function
428
429         <MethodImpl(MethodImplOptions.AggressiveInlining)>
430         <Extension>
431         Public Function Centre(shape As IEnumerable(Of Point)) As PointF
432             Return shape.PointF.Centre
433         End Function
434
435         ''' <summary>
436         ''' Gets the center location of the region rectangle.
437         ''' </summary>
438         ''' <param name="rect"></param>
439         ''' <returns></returns>
440         ''' 
441         <MethodImpl(MethodImplOptions.AggressiveInlining)>
442         <ExportAPI("Center")>
443         <Extension> Public Function Centre(rect As RectangleF) As PointF
444             Return New PointF(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2)
445         End Function
446
447         ''' <summary>
448         ''' 获取将目标多边形置于区域的中央位置的位置偏移量
449         ''' </summary>
450         ''' <param name="pts"></param>
451         ''' <param name="frameSize"></param>
452         ''' <returns></returns>
453         ''' 
454         <MethodImpl(MethodImplOptions.AggressiveInlining)>
455         <Extension>
456         Public Function CentralOffset(pts As IEnumerable(Of Point), frameSize As Size) As PointF
457             Return pts _
458                 .Select(Function(pt) pt.PointF) _
459                 .CentralOffset(frameSize.SizeF)
460         End Function
461
462         ''' <summary>
463         ''' 获取将目标多边形置于区域的中央位置的位置偏移量
464         ''' </summary>
465         ''' <param name="pts"></param>
466         ''' <param name="frameSize"></param>
467         ''' <returns></returns>
468         <Extension>
469         Public Function CentralOffset(pts As IEnumerable(Of PointF), frameSize As SizeF) As PointF
470             Dim xOffset!() = pts.Select(Function(x) x.X).ToArray
471             Dim yOffset!() = pts.Select(Function(x) x.Y).ToArray
472             Dim xo, yo As Single
473
474             If xOffset.Length > 0 Then
475                 xo = xOffset.Min
476             End If
477             If yOffset.Length > 0 Then
478                 yo = yOffset.Min
479             End If
480
481             Dim size As New SizeF(xOffset.Max - xOffset.Min, yOffset.Max - yOffset.Min)
482             Dim left! = (frameSize.Width - size.Width) / 2
483             Dim top! = (frameSize.Height - size.Height) / 2
484
485             Return New PointF(left - xo, top - yo)
486         End Function
487     End Module
488 End Namespace