21 / 21 / 3
Регистрация: 23.12.2015
Сообщений: 51
1

Получить GraphicsPath из Region

05.02.2017, 17:31. Показов 1940. Ответов 12
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам

Друзья, спасите! Заблудился в трех соснах: GaphicsPath, Region и Intersect.
Вот пример задачи:
Кликните здесь для просмотра всего текста
VB.NET
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
    Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
        'исходные фигуры - прямоугольник rect и замкнутый контур grpth
        Dim rect As New Rectangle(70, 120, 160, 120)
        Dim pts As Point() = {New Point(100, 100), New Point(100, 200), New Point(200, 200), New Point(200, 300),
                              New Point(300, 300), New Point(300, 100), New Point(100, 100)}
 
        Dim grpth As New GraphicsPath(pts, {0, 1, 1, 1, 1, 1, 1})
        '==========
        Dim reg As New Region(grpth)
        'часть прямоугольника внутри контура
        reg.Intersect(rect)
        e.Graphics.FillRegion(Brushes.Yellow, reg)
        'отодвинем результирующий регион для наглядности
        Dim mx As New Matrix
        mx.Translate(250, 0)
        reg.Transform(mx)
        e.Graphics.FillRegion(Brushes.Yellow, reg)
        'сверху рисуем исходные фигуры
        e.Graphics.DrawPath(Pens.Blue, grpth)
        e.Graphics.DrawRectangle(Pens.Red, rect)
        'что дальше???
        Dim newGraphicsPath As New GraphicsPath '= reg.???????
 
 
    End Sub

и картинка:
Кликните здесь для просмотра всего текста
Получить GraphicsPath из Region


Надо получить GraphicsPath желтого Region.

Либо сразу GraphicsPath общей области красной и синей фигуры.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.02.2017, 17:31
Ответы с готовыми решениями:

Как получить GraphicsPath?
пробую работать с графикой, хочу рисовать многоугольноики, для этого прочитал в хелпах можно...

Конвертация System.Drawing.Region в GraphicsPath[]
Как можно выполнить такое? Можно ли интерпретировать RegionData с наименьшей затратой сил и...

GraphicsPath
такая проблема я обьединяю несколько областей вот так: globalpdc.AddPolygon(myPoints3); а у меня...

Передача GraphicsPath
я создал обьект GraphicsPath отобразил его в одной панели, как мне отобразить его в другой паенли с...

12
307 / 248 / 40
Регистрация: 28.09.2013
Сообщений: 600
06.02.2017, 21:18 2
Вот чем делятся наши заморские друзья
1
21 / 21 / 3
Регистрация: 23.12.2015
Сообщений: 51
06.02.2017, 22:22  [ТС] 3
Winney, премного благодарен!
Я на это не натыкался. Жаль, что там не рассматривается VB.NET...
Буду рыть...
0
4407 / 3531 / 843
Регистрация: 02.02.2013
Сообщений: 3,417
Записей в блоге: 2
06.02.2017, 23:01 4
Как понимаю вопрос в реализации перехода Region=>GraphicsPath, ну или хотя бы получение списка координат описывающих границу Region. Насколько могу судить, в рамках GDI+ вопрос не решен.
В типе Region привлекает наличие таких операций как Intersect, Union и т.д., однако ни граница, ни узлы при этом не определяются. Обычно такие операции реализуются в библиотеках связанных с GIS, но здесь они отягощены специфическими типами и структурами. Остается только самостоятельная реализация этих операций в рамках GraphicsPath. Если же нужна только граница полученного объекта Region (на картинке) то можно воспользоваться следующим кодом (демонстрационным кодом).
Кликните здесь для просмотра всего текста
VB.NET
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
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Public Class Form7
    <DllImport("gdi32")> _
    Private Shared Function FrameRgn(hDC As System.IntPtr, hRgn As System.IntPtr, hBrush As IntPtr, nWidth As Integer, nHeight As Integer) As Boolean
    End Function
    <DllImport("gdi32")> _
    Private Shared Function CreateSolidBrush(colorref As UInteger) As IntPtr
    End Function
    <DllImport("gdi32.dll")> _
    Private Shared Function DeleteObject(<[In]()> hObject As IntPtr) As Boolean
    End Function
    <StructLayout(LayoutKind.Explicit)> _
    Private Structure COLORREF
        <FieldOffset(0)> _
        Public colorref As UInteger
        <FieldOffset(0)> _
        Public red As Byte
        <FieldOffset(1)> _
        Public green As Byte
        <FieldOffset(2)> _
        Public blue As Byte
        Public Sub New(color As Color)
            red = color.R
            green = color.G
            blue = color.B
        End Sub
    End Structure
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim rc1 As New RectangleF(70, 20, 40, 150)
        Dim rc2 As New RectangleF(10, 70, 170, 40)
        Dim gp1 As New GraphicsPath(), gp2 As New GraphicsPath()
        gp1.AddRectangles({rc1, rc2})
        gp2.AddRectangle(rc1)
        Dim gr As New Region(gp2)
        Select Case True
            Case RadioButton1.Checked
                gr.Intersect(rc2)
            Case RadioButton2.Checked
                gr.Union(rc2)
            Case RadioButton3.Checked
                gr.Xor(rc2)
            Case RadioButton4.Checked
                gr.Complement(rc2)
            Case RadioButton5.Checked
                gr.Exclude(rc2)
        End Select
        Dim gg As Graphics = PictureBox1.CreateGraphics
        gg.Clear(PictureBox1.BackColor)
        Dim myPen As New Pen(Color.Green, 2)
        gg.DrawPath(myPen, gp1)
        Dim dx As Single = 260
        Dim dy As Single = 0.0
        gr.Translate(dx, dy)
        gg.FillRegion(Brushes.YellowGreen, gr)
        DrawRegion(gg, Color.Red, gr) 'рисуем границу области
        gr.Dispose()
        gp1.Dispose()
        gp2.Dispose()
        gg.Dispose()
    End Sub
    Private Sub DrawRegion(graphics As Graphics, color As Color, region As Region)
        Dim colorref As New COLORREF(color)
        Dim hdc As IntPtr = IntPtr.Zero, hbrush As IntPtr = IntPtr.Zero, hrgn As IntPtr = IntPtr.Zero
        Try
            hrgn = region.GetHrgn(graphics)
            hdc = graphics.GetHdc()
            hbrush = CreateSolidBrush(colorref.colorref)
            FrameRgn(hdc, hrgn, hbrush, 2, 2)
        Finally
            If hrgn <> IntPtr.Zero Then
                region.ReleaseHrgn(hrgn)
            End If
            If hbrush <> IntPtr.Zero Then
                DeleteObject(hbrush)
            End If
            If hdc <> IntPtr.Zero Then
                graphics.ReleaseHdc(hdc)
            End If
        End Try
    End Sub
End Class
Миниатюры
Получить GraphicsPath из Region   Получить GraphicsPath из Region  
2
4407 / 3531 / 843
Регистрация: 02.02.2013
Сообщений: 3,417
Записей в блоге: 2
06.02.2017, 23:06 5
Как понимаю вопрос в реализации перехода Region=>GraphicsPath, ну или хотя бы получение списка координат описывающих границу Region. Насколько могу судить, в рамках GDI+ вопрос не решен.
В типе Region привлекает наличие таких операций как Intersect, Union и т.д., однако ни граница, ни узлы при этом не определяются. Обычно такие операции реализуются в библиотеках связанных с GIS, но здесь они отягощены специфическими типами и структурами. Остается только самостоятельная реализация этих операций в рамках GraphicsPath. Если же нужна только граница полученного объекта Region (на картинке), то можно воспользоваться следующим кодом (демонстрационным кодом).
Кликните здесь для просмотра всего текста
VB.NET
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
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Public Class Form7
    <DllImport("gdi32")> _
    Private Shared Function FrameRgn(hDC As System.IntPtr, hRgn As System.IntPtr, hBrush As IntPtr, nWidth As Integer, nHeight As Integer) As Boolean
    End Function
    <DllImport("gdi32")> _
    Private Shared Function CreateSolidBrush(colorref As UInteger) As IntPtr
    End Function
    <DllImport("gdi32.dll")> _
    Private Shared Function DeleteObject(<[In]()> hObject As IntPtr) As Boolean
    End Function
    <StructLayout(LayoutKind.Explicit)> _
    Private Structure COLORREF
        <FieldOffset(0)> _
        Public colorref As UInteger
        <FieldOffset(0)> _
        Public red As Byte
        <FieldOffset(1)> _
        Public green As Byte
        <FieldOffset(2)> _
        Public blue As Byte
        Public Sub New(color As Color)
            red = color.R
            green = color.G
            blue = color.B
        End Sub
    End Structure
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim rc1 As New RectangleF(70, 20, 40, 150)
        Dim rc2 As New RectangleF(10, 70, 170, 40)
        Dim gp1 As New GraphicsPath(), gp2 As New GraphicsPath()
        gp1.AddRectangles({rc1, rc2})
        gp2.AddRectangle(rc1)
        Dim gr As New Region(gp2)
        Select Case True
            Case RadioButton1.Checked
                gr.Intersect(rc2)
            Case RadioButton2.Checked
                gr.Union(rc2)
            Case RadioButton3.Checked
                gr.Xor(rc2)
            Case RadioButton4.Checked
                gr.Complement(rc2)
            Case RadioButton5.Checked
                gr.Exclude(rc2)
        End Select
        Dim gg As Graphics = PictureBox1.CreateGraphics
        gg.Clear(PictureBox1.BackColor)
        Dim myPen As New Pen(Color.Green, 2)
        gg.DrawPath(myPen, gp1)
        Dim dx As Single = 260
        Dim dy As Single = 0.0
        gr.Translate(dx, dy)
        gg.FillRegion(Brushes.YellowGreen, gr)
        DrawRegion(gg, Color.Red, gr) 'рисуем границу области
        gr.Dispose()
        gp1.Dispose()
        gp2.Dispose()
        gg.Dispose()
    End Sub
    Private Sub DrawRegion(graphics As Graphics, color As Color, region As Region)
        Dim colorref As New COLORREF(color)
        Dim hdc As IntPtr = IntPtr.Zero, hbrush As IntPtr = IntPtr.Zero, hrgn As IntPtr = IntPtr.Zero
        Try
            hrgn = region.GetHrgn(graphics)
            hdc = graphics.GetHdc()
            hbrush = CreateSolidBrush(colorref.colorref)
            FrameRgn(hdc, hrgn, hbrush, 2, 2)
        Finally
            If hrgn <> IntPtr.Zero Then
                region.ReleaseHrgn(hrgn)
            End If
            If hbrush <> IntPtr.Zero Then
                DeleteObject(hbrush)
            End If
            If hdc <> IntPtr.Zero Then
                graphics.ReleaseHdc(hdc)
            End If
        End Try
    End Sub
End Class


Добавлено через 1 минуту
Извиняюсь за дублирование. Какой то сбой.
0
21 / 21 / 3
Регистрация: 23.12.2015
Сообщений: 51
06.02.2017, 23:26  [ТС] 6
ovva, спасибо!!!
Детально пока не разобрался, нет пока времени. Много интересного, но на первый взгляд пока не увидел то, что мне надо.
Попозже поковыряюсь...
З.Ы.
Я частично решил свою проблему для прямоугольных фигур через GetRegionScans, но это добавляет другую проблему - слияние субконтуров в GraphicsPath.
0
4407 / 3531 / 843
Регистрация: 02.02.2013
Сообщений: 3,417
Записей в блоге: 2
06.02.2017, 23:58 7
Лучший ответ Сообщение было отмечено edward_freedom как решение

Решение

Можно и точки расставить
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'…
    DrawRegion(gg, Color.Red, gr) 'рисуем границу области
    If CheckBox1.Checked Then setPoints(gr, gg)
'…
End Sub
Private Sub setPoints(ByVal reg As Region, ByVal g As Graphics)
    Dim ww As Single = 9
    Dim x, y As Single
    Dim rects() As RectangleF = reg.GetRegionScans(New System.Drawing.Drawing2D.Matrix())
    For Each rr As RectangleF In rects
        x = rr.X - ww / 2
        y = rr.Y - ww / 2
        g.FillEllipse(Brushes.Yellow, x, y, ww, ww)
        g.DrawEllipse(Pens.Red, x, y, ww, ww)
        g.FillEllipse(Brushes.Yellow, x + rr.Width, y, ww, ww)
        g.DrawEllipse(Pens.Red, x + rr.Width, y, ww, ww)
        g.FillEllipse(Brushes.Yellow, x + rr.Width, y + rr.Height, ww, ww)
        g.DrawEllipse(Pens.Red, x + rr.Width, y + rr.Height, ww, ww)
        g.FillEllipse(Brushes.Yellow, x, y + rr.Height, ww, ww)
        g.DrawEllipse(Pens.Red, x, y + rr.Height, ww, ww)
    Next
End Sub
Миниатюры
Получить GraphicsPath из Region  
2
4407 / 3531 / 843
Регистрация: 02.02.2013
Сообщений: 3,417
Записей в блоге: 2
08.02.2017, 21:00 8
Нашел реализацию булевых функций для GraphicsPath (http://www.cs.man.ac.uk/~toby/alan/software/). Некоторые проблемы возникают при отладке: появляются сообщения от MDA, хотя откомпилированный exe запускается без проблем (VS2010, NET 4.0). Как побороть? Можно в Compile Option установить NET Framework 2.0 или оставаясь в NET 4, убрать Debug/Exceptions…/MDA/PInvokeStackInbalance.
Привожу пример использования.
Миниатюры
Получить GraphicsPath из Region   Получить GraphicsPath из Region  
Вложения
Тип файла: rar GPcombine.rar (27.6 Кб, 30 просмотров)
1
307 / 248 / 40
Регистрация: 28.09.2013
Сообщений: 600
13.02.2017, 19:09 9
Цитата Сообщение от Abber Посмотреть сообщение
Буду рыть...
Предчувствую, вас ждет успех) Если несложно, по окончании решения вашей задачи разместите способ решения в FAQ раздела, ибо на мой взгляд задача достаточно интересная.
0
21 / 21 / 3
Регистрация: 23.12.2015
Сообщений: 51
14.02.2017, 02:54  [ТС] 10
Winney, обязательно поделюсь.
На данный момент решено для прямоугольных областей и небольших скосов.
Надо причесать...
0
21 / 21 / 3
Регистрация: 23.12.2015
Сообщений: 51
19.02.2017, 03:53  [ТС] 11
Ну вот. Function GetGraphicsPath(region As Region) As GraphicsPath()
Работает для прямоугольных областей. Не все наклонные линии обрабатывает (надо пилить ) и не понимает кривые.

Кликните здесь для просмотра всего текста
VB.NET
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class Form1
    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        Dim grf As Graphics = e.Graphics
        'исходные фигуры - прямоугольник rect и замкнутый контур grp0
        Dim rect As New Rectangle(70, 120, 200, 120)
        Dim pts As Point() = {New Point(40, 50), New Point(100, 300), New Point(150, 300), New Point(150, 105), New Point(180, 105),
                              New Point(180, 300), New Point(300, 300), New Point(300, 100)}
        Dim grp0 As New GraphicsPath(pts, {0, 1, 1, 1, 1, 1, 1, 129})
        Dim grp2 As New GraphicsPath
        grp2.AddRectangle(rect)
        '==========
        Dim reg As New Region(grp0)
        'часть прямоугольника внутри контура
        reg.Intersect(rect)
        e.Graphics.FillRegion(Brushes.Yellow, reg)
        'отодвинем результирующий регион для наглядности
        Dim mx As New Matrix
        mx.Translate(250, 0)
        reg.Transform(mx)
        grf.FillRegion(Brushes.Yellow, reg)
        'сверху рисуем исходные фигуры
        grf.DrawPath(Pens.Blue, grp0)
        'grf.DrawRectangle(Pens.Red, rect)
        'grf.DrawPath(Pens.Red, grp1)
        grf.DrawPath(Pens.Black, grp2)
        'что дальше???
 
        Dim rects() As RectangleF = reg.GetRegionScans(New System.Drawing.Drawing2D.Matrix())
        Dim NGP As New GraphicsPath
        NGP.AddRectangles(rects)
        grf.DrawPath(Pens.Green, NGP)
        Dim ngp1 As GraphicsPath() = GetGraphicsPath(reg)
        For Each i In ngp1
            grf.DrawPath(New Pen(Brushes.Red, 2), i)
        Next
        grp2.Dispose()
        grp0.Dispose()
        grf.Dispose()
    End Sub
    Class PointData
        Public point As PointF
        Public direction As PathDirection
        Enum PathDirection
            Unknow = 0
            West_external = 1
            Nord_external = 2
            West_direct = 3
            East_external = 4
            Turn_left_H = 5
            Nord_direct = 6
            West_interior = 7
            South_external = 8
            South_direct = 9
            Turn_left_V = 10
            South_interior = 11
            East_direct = 12
            East_interior = 13
            Nord_interior = 14
            InteriorPoint = 15
            StartPoint = 16
        End Enum
    End Class
    Function GetGraphicsPath(region As Region) As GraphicsPath()
        Dim rects = region.GetRegionScans(New Matrix)
        Dim GrPath As New GraphicsPath
        GrPath.AddRectangles(rects)
        Dim regionA As New Region(GrPath)
        '1
        'собираем в два списка координаты всех точек контура после аппроксимации (без дублирования)
        Dim Xpoints As New List(Of Single)
        Dim Ypoints As New List(Of Single)
        For Each i As PointF In GrPath.PathPoints
            If Not Xpoints.Contains(i.X) Then
                Xpoints.Add(i.X)
            End If
            If Not Ypoints.Contains(i.Y) Then
                Ypoints.Add(i.Y)
            End If
        Next
        Xpoints.Sort()
        Ypoints.Sort()
        '2
        'создаем матрицу точек контура региона
        Dim PointMatrix(Xpoints.Count - 1, Ypoints.Count - 1) As PointData
        Dim PointCount As Integer = 0
        For Each i As PointF In GrPath.PathPoints
            Dim curPnt As PointF = i ' GPath.PathPoints(i)
            Dim _X As Integer = Xpoints.IndexOf(curPnt.X)
            Dim _Y As Integer = Ypoints.IndexOf(curPnt.Y)
            If IsNothing(PointMatrix(_X, _Y)) Then
                'определяем направление обхода контура после текущей точки с помощью тестового квадратика
                Dim _direct As PointData.PathDirection = PointData.PathDirection.Unknow
                Dim mx As New Matrix
                mx.Translate(-1, -1)
                Dim test As New GraphicsPath
                test.AddRectangle(New RectangleF(curPnt, New SizeF(2, 2)))
                test.Transform(mx)
                For a = 0 To 3
                    If regionA.IsVisible(test.PathPoints(a)) Then
                        _direct += 2 ^ a
                    End If
                Next
                mx.Dispose()
                test.Dispose()
                'записываем данные точки в матрицу
                PointMatrix(_X, _Y) = New PointData With {.point = curPnt, .direction = _direct}
                PointCount += 1
            End If
        Next
        regionA.Dispose()
        '3
        Dim GrPathes As New List(Of GraphicsPath)
        'пока есть не пройденные точки
        Do While PointCount > 1
            Try
                Dim Points As New List(Of PointF)
                Dim Xm As Integer = 0 : Dim Ym As Integer = 0
                Dim p As New PointF
                Dim start As Boolean = True
                Dim offset As New Size(0, 0)
 
                Do Until Points.Count > 1 AndAlso p.Equals(Points(0))
                    If start And Points.Count = 1 Then
                        PointMatrix(Xm, Ym) = New PointData With {.point = p, .direction = PointData.PathDirection.StartPoint}
                        start = False
                    End If
                    Xm += offset.Width : Ym += offset.Height
                    If IsNothing(PointMatrix(Xm, Ym)) Then
                        Select Case True
                            Case offset.IsEmpty
                                offset.Width = 1
                            Case (Xm + offset.Width) < 0, (Xm + offset.Width) > PointMatrix.GetLength(0) - 1,
                                (Ym + offset.Height) < 0, (Ym + offset.Height) > PointMatrix.GetLength(1) - 1
                                MsgBox("не обработанный наклон")
                                'Exit Do
                        End Select
                    Else
                        p = PointMatrix(Xm, Ym).point
                        Dim direction = PointMatrix(Xm, Ym).direction
                        Select Case direction
                            Case PointData.PathDirection.StartPoint
                                PointMatrix(Xm, Ym) = Nothing
                                Exit Do
                            Case PointData.PathDirection.Unknow
                                MsgBox("unknow point")
                            Case PointData.PathDirection.West_external, PointData.PathDirection.West_interior
                                Points.Add(p)
                                offset.Width = -1 : offset.Height = 0
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.Nord_external, PointData.PathDirection.Nord_interior
                                Points.Add(p)
                                offset.Width = 0 : offset.Height = -1
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.East_external, PointData.PathDirection.East_interior
                                Points.Add(p)
                                offset.Width = 1 : offset.Height = 0
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.South_external, PointData.PathDirection.South_interior
                                Points.Add(p)
                                offset.Width = 0 : offset.Height = 1
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.West_direct
                                offset.Width = -1 : offset.Height = 0
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.Nord_direct
                                offset.Width = 0 : offset.Height = -1
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.East_direct
                                offset.Width = 1 : offset.Height = 0
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.South_direct
                                offset.Width = 0 : offset.Height = 1
                                PointMatrix(Xm, Ym) = Nothing
                                PointCount -= 1
                            Case PointData.PathDirection.Turn_left_H
                                Points.Add(p)
                                If offset.Height = -1 Then
                                    PointMatrix(Xm, Ym).direction = PointData.PathDirection.East_interior
                                Else
                                    PointMatrix(Xm, Ym).direction = PointData.PathDirection.West_interior
                                End If
                                offset = New Size(offset.Height, 0)
                            Case PointData.PathDirection.Turn_left_V
                                Points.Add(p)
                                If offset.Width = -1 Then
                                    PointMatrix(Xm, Ym).direction = PointData.PathDirection.Nord_interior
                                Else
                                    PointMatrix(Xm, Ym).direction = PointData.PathDirection.South_interior
                                End If
                                offset = New Size(0, 0 - offset.Width)
                            Case Else
                                MsgBox("error direction")
                        End Select
                    End If
                Loop
                If Points.Count > 1 Then
                    Dim types(Points.Count - 1) As Byte
                    For i = 1 To types.Count - 2
                        types(i) = 1
                    Next
                    types(0) = 0
                    types(Points.Count - 1) = 129
                    Dim ngp As New GraphicsPath(Points.ToArray, types)
                    GrPathes.Add(ngp)
                Else
                    Exit Do
                End If
            Catch ex As Exception
                MsgBox(ex.Message & vbCrLf & vbCrLf & ex.StackTrace)
            End Try
        Loop
        Dim r = GrPathes.ToArray
        GrPath.Dispose()
 
        Return r
    End Function
 
End Class


Извиняюсь, я это попытался изобразить максимально развернуто, чтоб алгоритм был виден, но на подробные коментарии сил и времени не хватило.
Этот алгоритм, причем в усеченом виде, вполне удовлетворил мои потребности, но заело... Будут силы и время - продолжу.
0
4407 / 3531 / 843
Регистрация: 02.02.2013
Сообщений: 3,417
Записей в блоге: 2
19.02.2017, 20:56 12
Напомню общий смысл задачи. Определение процедуры выполнения логических преобразований для площадных объектов описываемых набором плоских координат (например, в форме GraphicsPath или любой другой форме) и получение результата операции представленного как набор плоских координат.
В рамках этой задачи представленный ТС подход, я бы сказал, малопродуктивен. Ну, если только рассматривать задачу в усеченном виде, где площадные объекты представлены исключительно прямоугольниками.
В полной мере эту задачу решает код предложенный выше (https://www.cyberforum.ru/post10092548.html). Далее я предлагаю еще один вариант кода также полностью решающий задачу.
Кликните здесь для просмотра всего текста
VB.NET
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
Imports ClipperLib
'с использованием библиотеки Clipper [url]http://www.angusj.com/delphi/clipper.php[/url]
Public Class Form2
    Private scal As Single
    Private mode As String
    Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ListBox1.SelectedIndex = 0
        scal = 1
        RadioButton5.Checked = True
        mode = "None"
    End Sub
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        TextBox1.Clear()
        Dim base As List(Of List(Of IntPoint)) = CreateData1()
        Dim clip As List(Of List(Of IntPoint)) = CreateData2()
        Dim sol As New List(Of List(Of IntPoint))
        Dim cc As New Clipper
        Dim gg As Graphics = PictureBox1.CreateGraphics
        gg.Clear(PictureBox1.BackColor)
        Select Case mode
            Case "None"
                DrawPolygons(base, Color.FromArgb(22, 0, 0, 255), Color.FromArgb(96, 0, 0, 255), gg)
                DrawPolygons(clip, Color.FromArgb(32, 255, 255, 0), Color.FromArgb(48, 255, 0, 0), gg)
            Case "Intersect"
                cc.AddPolygons(base, PolyType.ptSubject)
                cc.AddPolygons(clip, PolyType.ptClip)
                cc.Execute(ClipType.ctIntersection, sol, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd)
                DrawPolygons(base, Color.FromArgb(22, 0, 0, 255), Color.FromArgb(96, 0, 0, 255), gg)
                DrawPolygons(clip, Color.FromArgb(32, 255, 255, 0), Color.FromArgb(48, 255, 0, 0), gg)
                DrawPolygons(sol, Color.FromArgb(48, 0, 255, 0), Color.FromArgb(255, 0, 102, 0), gg)
            Case "Union"
                cc.AddPolygons(base, PolyType.ptSubject)
                cc.AddPolygons(clip, PolyType.ptClip)
                cc.Execute(ClipType.ctUnion, sol, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd)
                DrawPolygons(base, Color.FromArgb(22, 0, 0, 255), Color.FromArgb(96, 0, 0, 255), gg)
                DrawPolygons(clip, Color.FromArgb(32, 255, 255, 0), Color.FromArgb(48, 255, 0, 0), gg)
                DrawPolygons(sol, Color.FromArgb(48, 0, 255, 0), Color.FromArgb(255, 0, 102, 0), gg)
            Case "Difference"
                cc.AddPolygons(base, PolyType.ptSubject)
                cc.AddPolygons(clip, PolyType.ptClip)
                cc.Execute(ClipType.ctDifference, sol, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd)
                DrawPolygons(base, Color.FromArgb(22, 0, 0, 255), Color.FromArgb(96, 0, 0, 255), gg)
                DrawPolygons(clip, Color.FromArgb(32, 255, 255, 0), Color.FromArgb(48, 255, 0, 0), gg)
                DrawPolygons(sol, Color.FromArgb(48, 0, 255, 0), Color.FromArgb(255, 0, 102, 0), gg)
            Case "XOR"
                cc.AddPolygons(base, PolyType.ptSubject)
                cc.AddPolygons(clip, PolyType.ptClip)
                cc.Execute(ClipType.ctXor, sol, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd)
                DrawPolygons(base, Color.FromArgb(22, 0, 0, 255), Color.FromArgb(96, 0, 0, 255), gg)
                DrawPolygons(clip, Color.FromArgb(32, 255, 255, 0), Color.FromArgb(48, 255, 0, 0), gg)
                DrawPolygons(sol, Color.FromArgb(48, 0, 255, 0), Color.FromArgb(255, 0, 102, 0), gg)
            Case Else
                Exit Sub
        End Select
        gg.Dispose()
        getXY(base, "base")
        getXY(clip, "clip")
        If sol.Count > 0 Then getXY(sol, "solution")
    End Sub
 
    Private Sub RadioButton1_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles RadioButton5.CheckedChanged, RadioButton4.CheckedChanged, RadioButton3.CheckedChanged, RadioButton2.CheckedChanged, RadioButton1.CheckedChanged
        Dim rb As RadioButton = CType(sender, RadioButton)
        mode = rb.Text
    End Sub
    Private Sub DrawPolygons(ByVal pp As List(Of List(Of IntPoint)), ByVal c1 As Color, ByVal c2 As Color, ByVal g As Graphics)
        Dim br As SolidBrush = New SolidBrush(c1)
        Dim pn As Pen = New Pen(c2)
        Dim pf() As PointF
        For Each p In pp
            pf = PolygonToPointFArray(p)
            g.FillPolygon(br, pf)
            g.DrawPolygon(pn, pf)
        Next
    End Sub
    Private Function PolygonToPointFArray(pg As List(Of IntPoint)) As PointF()
        Dim n As Integer = pg.Count
        Dim result As PointF() = New PointF(n - 1) {}
        For i As Integer = 0 To n - 1
            result(i).X = CSng(pg(i).X) / scal
            result(i).Y = CSng(pg(i).Y) / scal
        Next
        Return result
    End Function
    Private Function CreateData1() As List(Of List(Of IntPoint))
        'моделирование объекта Poligons1
        Dim pgs As New List(Of List(Of IntPoint))
        Dim pg As New List(Of IntPoint)
        Dim rnd As New Random
        Dim n As Integer = 6
        Dim xx() As Double = {20, 80.99, 150, 200.45, 150, 50}
        Dim yy() As Double = {20.22, 10.77, 70, 220, 270.35, 100}
        Dim dx As Double = 10.77
        Dim dy As Double = 15.33
        pg.Capacity = n
        For i = 0 To n - 1
            pg.Add(GenerateRandomPoint(xx(i), yy(i), dx, dy, rnd))
        Next
        pgs.Add(pg)
        n = 7
        xx = {210, 280.99, 350, 400.45, 350, 250, 200}
        yy = {90.22, 50.77, 130, 220, 270.35, 200, 180}
        dx = 12.77
        dy = 11.33
        pg = New List(Of IntPoint) : pg.Capacity = n
        For i = 0 To n - 1
            pg.Add(GenerateRandomPoint(xx(i), yy(i), dx, dy, rnd))
        Next
        pgs.Add(pg)
        Return pgs
    End Function
    Private Function CreateData2() As List(Of List(Of IntPoint))
        'моделирование объекта Poligons2
        Dim pgs As New List(Of List(Of IntPoint))
        Dim pg As New List(Of IntPoint)
        Dim rnd As New Random
        Dim n As Integer = 6
        Dim xx() As Double = {20, 150.99, 170, 200.45, 250, 150}
        Dim yy() As Double = {20.22, 50.77, 130, 180, 270.35, 200}
        Dim dx As Double = 10.77
        Dim dy As Double = 15.33
        pg.Capacity = n
        For i = 0 To n - 1
            pg.Add(GenerateRandomPoint(xx(i), yy(i), dx, dy, rnd))
        Next
        pgs.Add(pg)
        n = 7
        xx = {210, 280.99, 350, 400.45, 350, 250, 200}
        yy = {20.22, 50.77, 30, 120, 270.35, 200, 180}
        dx = 12.77
        dy = 11.33
        pg = New List(Of IntPoint) : pg.Capacity = n
        For i = 0 To n - 1
            pg.Add(GenerateRandomPoint(xx(i), yy(i), dx, dy, rnd))
        Next
        pgs.Add(pg)
        Return pgs
    End Function
    Private Function GenerateRandomPoint(ByVal x As Double, ByVal y As Double, ByVal dx As Double, ByVal dy As Double, rand As Random) As IntPoint
        Dim xx As Integer = CInt(x * scal)
        Dim yy As Integer = CInt(y * scal)
        Return New IntPoint(rand.Next(xx - dx, xx + dx), rand.Next(yy - dy, yy + dy))
    End Function
    Private Sub getXY(ByVal plgs As List(Of List(Of IntPoint)), ByVal nm As String)
        Dim pf() As PointF
        Dim k As Integer = 0
        TextBox1.Text &= "========= " & nm & vbCrLf
        For Each p In plgs
            pf = PolygonToPointFArray(p)
            k += 1
            TextBox1.Text &= "------ R " & k.ToString & vbCrLf
            For j = 0 To pf.Length - 1
                TextBox1.Text &= Format(pf(j).X, "0.00").PadLeft(10) & Format(pf(j).Y, "0.00").PadLeft(10) & vbCrLf
            Next
        Next
    End Sub
    Private Sub ListBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
        Dim lb As ListBox = CType(sender, ListBox)
        Select Case lb.SelectedIndex
            Case 0
                scal = 1
            Case 1
                scal = 10
            Case 2
                scal = 100
            Case Else
                scal = 1
        End Select
    End Sub
End Class
Миниатюры
Получить GraphicsPath из Region   Получить GraphicsPath из Region  
2
21 / 21 / 3
Регистрация: 23.12.2015
Сообщений: 51
26.02.2017, 21:18  [ТС] 13
ovva, еще раз хочу раскланяться за clipper_library 6.4!
Окончательно меня эта библиотека купила классом ClipperOffset. То, что доктор прописал...

Хотелось, правда, все средствами VB.NET решить (чужие решения хороши, но доблести не добавляют ), однако пока отложу это под сукно за недостатком времени.
0
26.02.2017, 21:18
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.02.2017, 21:18
Помогаю со студенческими работами здесь

Перемещение фигуры GraphicsPath
Доброго времени суток! Прошу помощи по реализации осмысленного перемещения фигуры по форме. Задумка...

GraphicsPath и кастомный ImageBox
Добрый день. Есть несколько вопросов: 1. Как отрисовать регион используя GraphicsPath принимая...

Как использовать GraphicsPath.Outline method?
Ссылка на msdn: http://msdn.microsoft.com/en-us/library/ms535564(v=vs.85).aspx Как использовать?...

Перемещение GraphicsPath плавно в нужные координаты
Доброго дня. Возможно, я все делаю не так, потому прошу подсказки, ибо застрял. Есть объект...

Где прочитать про использование GraphicsPath с примерами
Собственно, еслть несколько вопросов: 1 - глобальный. Посоветуйие, где прочитать про...

Как убрать лесенки используя метод GraphicsPath C# Windows Forms
Здравствуйте, пробую реализовать закругление краев формы при помощи метода GraphicsPath(пример кода...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru