DOBON.NET DOBON.NETプログラミング掲示板過去ログ

2つのPictureの重複部分の塗りつぶし

環境/言語:[WindowsXP]
分類:[.NET]

方法がわからないので、教えてください。
塗りつぶされた図形を書いているPictureが2つあります。
この図形を重ねて、重複した部分のみ塗りつぶした新たなPictureを
つくりたいのですが、方法が思いつきません。
ヒントでも構いません。よろしくお願いいたします
■No31170に返信(ぶぶさんの記事)
> 塗りつぶされた図形を書いているPictureが2つあります。
> この図形を重ねて、重複した部分のみ塗りつぶした新たなPictureを
> つくりたいのですが、方法が思いつきません。

(1) それぞれの図形の領域を表す Region を用意する。

(2) Region.Intersect メソッドで、交差領域の Region を得る。

(3) Graphics の FillRegion メソッドで、2 の交差領域を塗りつぶす。


という手順で如何でしょうか。
http://www.java2s.com/Tutorial/VB/0300__2D-Graphics/RegionIntersect.htm
http://dobon.net/vb/dotnet/graphics/fillrectangel.html


手順 1 にあたる「図形から Region を作る」方法については、このあたり。
http://smdn.jp/programming/tips/create_region_from_bitmap/
http://chokuto.ifdef.jp/urawaza/mcn/bmprgn2.html
ありがとうございます。
不慣れなもので、一つ一つ試していっています。
> http://www.java2s.com/Tutorial/VB/0300__2D-Graphics/RegionIntersect.htm
より、四角形の重複部分の塗りつぶしについては、ヒントを得ましたが、
これが多角形になった場合が
> http://smdn.jp/programming/tips/create_region_from_bitmap/
> http://chokuto.ifdef.jp/urawaza/mcn/bmprgn2.html
の内容を理解できず、困っています。
申し訳ありません。
> http://smdn.jp/programming/tips/create_region_from_bitmap/
では、ピクセルの透明度により、Regionを作成しているようですが、
図形の頂点座標がわかっている場合、どのようにRegionを作成すればよいのでしょうか?

図形はおおよそ10〜50角形の予定です。
重ねてもう一つお尋ねしたいことができました。
> http://dobon.net/vb/dotnet/graphics/fillrectangel.html
にて多角形を描画する際、

'多角形の角を決める
Dim points As Point() = {New Point(10, 20), _
New Point(190, 20), _
New Point(160, 120), _
New Point(80, 100), _
New Point(30, 110)}

'FillMode.Windingで塗りつぶす
g.FillPolygon(Brushes.Black, points, FillMode.Winding)

等座標点をpoint構造体で指定すると思うのですが、
このポイントの内容が、何点できるかわからない場合、
(ファイル等の読み込み内容によって頂点数が可変の場合)
どういう設定の仕方ができるでしょうか?

教えていただけるとありがたいです。
よろしくお願いいたします
■No31172に返信(ぶぶさんの記事)
>>http://www.java2s.com/Tutorial/VB/0300__2D-Graphics/RegionIntersect.htm
> より、四角形の重複部分の塗りつぶしについては、ヒントを得ましたが、
> これが多角形になった場合が

GraphicsPath クラスで多角形のパスを作り、それを Region に渡せば OK です。

GraphicsPath のサンプルは、このあたりを参考にしてみてください。
http://dobon.net/vb/dotnet/graphics/drawpath.html
http://uchukamen.com/Programming1/Region/index.htm


また、GraphicsPath のメソッドをそれぞれ使う代わりに、
「New GraphicsPath( Point配列, PathPointType配列 )」
のコンストラクタを使って作成することもできます。


以下、GraphicsPath で多角形を作るサンプル。

同じ大きさの PictureBox を 2 つ並べて配置し、
背景色を変更するか画像を貼るかしておいてください。

PictureBox1 上の任意の座標をクリックしていくと、
PictureBox2 がその座標から構成される多角形に切り抜かれます。


'---------------
Imports System.Drawing.Drawing2D
Public Class Form1
    Private points As New List(Of Point)()   'クリックされた位置を保存する変数

    Private Sub PictureBox1_MouseClick(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseClick
        points.Add(e.Location)
        If points.Count >= 3 Then
            Dim types = Enumerable.Repeat(CByte(PathPointType.Line), points.Count)

            '★「New GraphicsPath( Point配列, PathPointType配列 )」の呼び出し
            Using gpath As New GraphicsPath(points.ToArray(), types.ToArray())

                '☆ GraphicsPath から多角形の Region を作成
                Dim newRegion As New Region(gpath)

                Dim oldRegion = PictureBox2.Region
                PictureBox2.Region = newRegion
                If oldRegion IsNot Nothing Then
                    oldRegion.Dispose()
                End If
            End Using
        End If
    End Sub
End Class
なんとか、重複部分の図形を塗りつぶすことができました。
魔界の仮面弁士さんありがとうございました。
つたないコードですが、どうしていいかわからなかった状態から
ここまでこれてほっとしました。
本当にありがとうございました。


以下、入力したコードです。
FormにPictureBox1とButton1を貼り付け、PictureBox1はstrechモードにしています。
--------------------------------------------------------
Imports System.Drawing.Drawing2D
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim fno1 As Integer
Dim Line_Data As String
Dim i As Integer
Dim Token() As String

' -----描画サイズ
Dim cv_Width As Integer = 1700
Dim cv_Height As Integer = 1000

' ----- 多角形の頂点情報
Dim Zukei2_Y(50), Zukei2_X(50) As Single
Dim Zukei2_i As Integer
' ----- 多角形の頂点情報
Dim Zukei1_Y(4), Zukei1_X(4) As Single
Dim Zukei1_i As Integer = 0

' ----- 多角形頂点情報1を読み込んでワークに代入する
fno1 = FreeFile()
FileOpen(fno1, "c:\zukei_1.csv", OpenMode.Input, OpenAccess.Read)
Line_Data = LineInput(fno1)
Do While Not EOF(fno1)
Line_Data = LineInput(fno1)
Token = Split(Line_Data, ",")
i = CInt(Val(Trim(Token(0))))
Zukei1_X(i) = CInt(Val(Trim(Token(1))))
Zukei1_Y(i) = CInt(Val(Trim(Token(2))))
Loop
Zukei1_i = i
FileClose(fno1)

' ----- 多角形頂点情報2を読み込んでワークに代入する
fno1 = FreeFile()
FileOpen(fno1, "c:\zukei_2.csv", OpenMode.Input, OpenAccess.Read)
Line_Data = LineInput(fno1)
Do While Not EOF(fno1)
Line_Data = LineInput(fno1)
Token = Split(Line_Data, ",")
i = CInt(Val(Trim(Token(0))))
Zukei2_X(i) = CInt(Val(Trim(Token(1))))
Zukei2_Y(i) = CInt(Val(Trim(Token(2))))
Loop
Zukei2_i = i
FileClose(fno1)

Dim canvas = New Bitmap(cv_Width, cv_Height)
Dim g As Graphics = Graphics.FromImage(canvas)
g.Clear(Color.White) ' ----- 背景クリア

Dim Pos As Point
Dim Zukei2_Ps As New List(Of Point)()
For i = 1 To Zukei2_i
Pos.X = Zukei2_X(i)
Pos.Y = Zukei2_Y(i)
Zukei2_Ps.Add(Pos)
Next i

Dim Zukei1_Ps As New List(Of Point)()
For i = 1 To Zukei1_i
Pos.X = Zukei1_X(i)
Pos.Y = Zukei1_Y(i)
Zukei1_Ps.Add(Pos)
Next i

Dim types1 = Enumerable.Repeat(CByte(PathPointType.Line), Zukei2_Ps.Count)
Dim types2 = Enumerable.Repeat(CByte(PathPointType.Line), Zukei1_Ps.Count)

' New GraphicsPath(Point配列,PathPointType配列)の呼び出し
'Using gpath As New GraphicsPath(Zukei1_Ps.ToArray(), types.ToArray())
Dim gpath1 As New GraphicsPath(Zukei2_Ps.ToArray(), types1.ToArray())
Dim gpath2 As New GraphicsPath(Zukei1_Ps.ToArray(), types2.ToArray())

g.FillPolygon(Brushes.LawnGreen, Zukei1_Ps.ToArray())

'----- GraphicsPath から 多角形のRegionを作成
Dim Region As New Region(gpath1)

' ----- 交差領域のRegionを得る
Region.Intersect(gpath2)

g.Clear(Color.White) ' ----- 背景のクリア・
g.FillRegion(Brushes.LawnGreen, Region)

' ----- 画像を表示する
PictureBox1.Image = canvas
End Sub

End Class
チェックし忘れました。
ありがとうございました。
解決済み!
■No31176に返信(ぶぶさんの記事)
> つたないコードですが、どうしていいかわからなかった状態から
> ここまでこれてほっとしました。

補足。

使い終わった描画オブジェクト(Graphics、GraphicsPath、Region 等)は
最後に「Dispose メソッド」を呼び出して、後始末するべきです。
(もしくは Dispose が自動的に呼ばれるよう、Using ブロックを使います)


同様に、Bitmap も本来であれば Dispose すべき対象ですが、
今回のコードではまだ使い終わっておらず、最後に
>         ' ----- 画像を表示する
>         PictureBox1.Image = canvas
として使用されているため、こちらは Dispose してはいけません。
■No31178に返信(魔界の仮面弁士さんの記事)
> 補足。
>
> 使い終わった描画オブジェクト(Graphics、GraphicsPath、Region 等)は
> 最後に「Dispose メソッド」を呼び出して、後始末するべきです。
> (もしくは Dispose が自動的に呼ばれるよう、Using ブロックを使います)
>
ご指摘ありがとうございました。
最後に追加します。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板