午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVB.NET、エクセルのグループ化とグループ化解除を真似したい6

 
グループ化後の変形とグループ化解除のテスト
前回からの続き、テストばっかりで本番前に力尽きそう
 
イメージ 1
赤枠はグループの範囲の境界線、青マスは1マス50
見た目の位置とサイズは水色のこと
前提
グループを回転や拡大率の指定をするときの中心点は各Thumb(四角)の中心ではなくグループ範囲の中心にする
 
初期状態は
水色と桃色をグループ化した後にさらに黄色をグループ化した状態
グループB
	┣黄色
	┗グループA
		┣水色
		┗桃色

これを1回解除すると
グループA
	┣水色
	┗桃色
 
黄色
こうなって
もう一回解除すると
 
水色
桃色
黄色
ってバラバラになる
 
難しいのが解除した時に解除前の位置や回転や拡大率とかの変形の引き継ぎ
 
回転の場合
イメージ 2
変化するのは見た目だけで内部のものは変化しない
実際に位置やサイズを指定するのは内部のものになる
 
 
グループ解除で中心点の変化
 
 
イメージ 3
内部の位置を変更して見た目の位置を変化させないようにしている
って今気づいたけど見た目の位置の表示がおかしい、変化しているw
→見た目の位置取得前に再描画する必要があったみたい
 
 
デザイン画面とXAML

f:id:gogowaten:20191030123937p:plain

2019/10/30追記ここから
<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Wpf_test128_TransformGroup"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
  <Grid>
    <DockPanel>
    
      <StatusBar DockPanel.Dock="Bottom">
        <TextBlock x:Name="tbk1" Text="tbk1"/>
        <TextBlock x:Name="tbk2" Text="tbk2"/>
        <TextBlock x:Name="tbk3" Text="tbk3"/>
      </StatusBar>
      <!--<StatusBar DockPanel.Dock="Bottom">
      </StatusBar>-->

      <StatusBar DockPanel.Dock="Bottom">
        <TextBlock x:Name="tbk4" Text="rect"/>
        <TextBlock x:Name="tbk5" Text="rect"/>
        <TextBlock x:Name="tbk6" Text="rect"/>
      </StatusBar>


      <Menu DockPanel.Dock="Bottom">
        <Button x:Name="btReset" Content="reset"/>
        <Button x:Name="btChack" Content="確認"/>
        <Button x:Name="bt1" Content="解除"/>
        <Button x:Name="bt2" Content="拡大率-0.1"/>
        <Button x:Name="bt3" Content="拡大率+0.1"/>
        <Button x:Name="bt4" Content="左15度回転"/>
        <Button x:Name="bt5" Content="右15度回転"/>
        <Button x:Name="btAngle" Content="Angle"/>
      </Menu>
      <Canvas x:Name="canvas1"/>
    </DockPanel>
  </Grid>
</Window>
2019/10/30追記ここまで
VBのコード

f:id:gogowaten:20191030123950p:plain

2019/10/30追記ここから

'グループ化後の変形とグループ化解除のテスト

Imports System.Windows.Controls.Primitives


Class MainWindow
    Private ActiveThumb As ExThumb2
    Private ActiveGroup As Group2
    Private tList As New List(Of ExThumb2)
    Private gridSize As Integer = 50

    'グリッドをPathで描画
    Private Sub DrawGridLine()
        Dim pFigure As PathFigure
        Dim pGeometry As New PathGeometry
        '横線
        For i As Integer = 0 To 50
            pFigure = New PathFigure
            pFigure.StartPoint = New Point(i * gridSize, 0)
            pFigure.Segments.Add(New LineSegment(New Point(i * gridSize, 350), True))
            pGeometry.Figures.Add(pFigure)
        Next
        '縦線
        For i As Integer = 0 To 35
            pFigure = New PathFigure
            pFigure.StartPoint = New Point(0, i * gridSize)
            pFigure.Segments.Add(New LineSegment(New Point(500, i * gridSize), True))
            pGeometry.Figures.Add(pFigure)
        Next

        '描画
        Dim mPath As New Path With {.Stroke = Brushes.Blue, .StrokeThickness = 1, .Data = pGeometry}
        canvas1.Children.Add(mPath)
        Panel.SetZIndex(mPath, -1) '背面に移動
    End Sub
    '位置指定
    Private Sub SetLocate(t As ExThumb2, p As Point)
        Canvas.SetLeft(t, p.X)
        Canvas.SetTop(t, p.Y)
    End Sub
    '今の位置から移動
    Private Sub OffSetLocate(t As ExThumb2, offset As Point)
        Dim p As Point = GetLocate(t) + offset
        Canvas.SetLeft(t, p.X)
        Canvas.SetTop(t, p.Y)
    End Sub
    '位置取得
    Private Function GetLocate(t) As Point
        Return New Point(Canvas.GetLeft(t), Canvas.GetTop(t))
    End Function


    '再描画
    Private Sub ReRender(uie As UIElement)
        uie.Dispatcher.Invoke(Threading.DispatcherPriority.Render, Sub()

                                                                   End Sub)
    End Sub

    Private Function GetCenterPointLocate(t As ExThumb2) As Point
        Dim gt As GeneralTransform = t.TransformToVisual(canvas1)
        Dim cp As New Point(t.Width / 2, t.Height / 2)
        Dim np As Point = gt.Transform(cp)
        Return np
    End Function
    Private Function GetCenterPoint(r As Rect) As Point
        Dim x As Double = r.Width / 2 + r.Left
        Dim y As Double = r.Height / 2 + r.Top
        Dim cp As New Point(x, y)
        Return cp
    End Function
    Private Function AddThumb(p As Point, col As Color) As ExThumb2
        Dim t As New ExThumb2

        With t
            .Width = 50
            .Height = 50
            .Background = New SolidColorBrush(col)
        End With
        SetLocate(t, p)
        canvas1.Children.Add(t)

        Call ReRender(t)
        t.CenterAxis = GetCenterPointLocate(t) '軸セット
        Return t
    End Function
    'グループ化のRectを返す、渡されたすべてのRectが収まるRect
    Private Function GetGroupRect(rl As List(Of Rect)) As Rect
        '左上と右下の座標を探す、これで位置とサイズが分かる
        Dim minX As Double = rl(0).X
        Dim minY As Double = rl(0).Y
        Dim maxX As Double = minX + rl(0).Width
        Dim maxY As Double = minY + rl(0).Height
        Dim r As Rect
        For i As Integer = 1 To rl.Count - 1
            r = rl(i)
            minX = Math.Min(minX, r.X)
            minY = Math.Min(minY, r.Y)
            maxX = Math.Max(maxX, r.X + r.Width)
            maxY = Math.Max(maxY, r.Y + r.Height)
        Next
        '座標からRect作成
        r = New Rect(minX, minY, maxX - minX, maxY - minY)
        Return r

        ''別計算バージョン
        'Dim x As New List(Of Double)
        'Dim y As New List(Of Double)
        'Dim xx As New List(Of Double)
        'Dim yy As New List(Of Double)
        'For Each rr As Rect In rl
        '    x.Add(rr.X)
        '    y.Add(rr.Y)
        '    xx.Add(rr.X + rr.Width)
        '    yy.Add(rr.Y + rr.Height)
        'Next
        'Dim minX As Double = x.Min : Dim minY As Double = y.Min
        'Dim maxX As Double = xx.Max : Dim maxY As Double = yy.Max
        'Dim rrr As New Rect(minX, minY, maxX - minX, maxY - minY)

        'Return rrr

    End Function

    '各ThumbのRect取得
    Private Function GetRect(t As ExThumb2) As Rect
        Dim gt As GeneralTransform = t.TransformToVisual(canvas1)
        Dim r As Rect = gt.TransformBounds(New Rect(New Size(t.Width, t.Height)))
        Return r
    End Function
    '各ThumbのRectのリストを取得
    Private Function GetRects(tl As List(Of ExThumb2)) As List(Of Rect)
        Dim rl As New List(Of Rect)
        For Each t As ExThumb2 In tl
            rl.Add(GetRect(t))
        Next
        Return rl
    End Function
    '枠の表示更新
    Private Sub WakuUpdate(g As Group2)
        Dim rll As List(Of Rect) = GetRects(g.Items)
        Dim r As Rect = GetGroupRect(rll)
        g.Bound = r '四角枠
    End Sub

    'グループ化後のTransformと変形の軸のセット
    Private Function GetTransformGroup2(axis As Point) As TransformGroup
        Dim tg As New TransformGroup
        With tg.Children
            .Add(New ScaleTransform(1, 1, axis.X, axis.Y))
            .Add(New SkewTransform(0, 0, axis.X, axis.Y))
            .Add(New RotateTransform(0, axis.X, axis.Y))
            .Add(New TranslateTransform)
        End With
        Return tg
    End Function

    'スタータスバー更新
    Private Sub StatusbarUpdate()
        Dim g As Group2 = ActiveGroup
        Dim t As ExThumb2 = ActiveThumb
        If g Is Nothing Then
            tbk3.Text = $"赤枠中心点(na)"
            tbk1.Text = $"赤枠位置(na)"
            tbk2.Text = $"赤枠サイズ(na)"
        Else

            tbk3.Text = $"赤枠中心点({g.CenterPoint:0.0})"
            tbk1.Text = $"赤枠位置({g.Waku.Data.Bounds.Location:0.0})"
            tbk2.Text = $"赤枠サイズ({g.Waku.Data.Bounds.Size:0.0})"
        End If
        Dim l As Point = GetLocate(t)
        tbk4.Text = $"水色の位置({GetLocate(t):0.0})"
        tbk5.Text = $"見た目の位置({GetRect(t).Location:0.0})"

        tbk6.Text = $"見た目のサイズ({GetRect(t).Size:0.0})"

    End Sub
    Private Sub SetGroup(tl As List(Of ExThumb2))
        'Group作成
        Dim g As New Group2
        g.Items.AddRange(tl)

        Call WakuUpdate(g)
        g.CenterPoint = GetCenterPoint(g.Bound) 'グループの中心点

        '各ThumbにGroupをセット
        Dim axis As Point
        For Each t As ExThumb2 In tl
            t.gtStack.Push(t.gtCollection) 'グループ化解除の時使うはず
            If t.NowGroup IsNot Nothing Then

                t.gStack.Push(t.NowGroup) 'グループ化解除の時使うはず
            End If

            t.NowGroup = g
            axis = g.CenterPoint - t.CenterAxis 'グループ化後の変形の軸
            t.gtCollection = GetTransformGroup2(axis).Children 'グループ化後のTransformセット

            Dim tg As TransformGroup = t.RenderTransform
            For i As Integer = 0 To 3
                tg.Children.Add(t.gtCollection(i))
            Next
        Next
        '枠表示
        canvas1.Children.Add(g.Waku)
        ActiveGroup = g

        Call StatusbarUpdate()

    End Sub
    'グループとThumbをグループ化
    Private Sub SetGroupAndThumb(oldG As Group2, tl As List(Of ExThumb2))
        'Group作成
        Dim g As New Group2
        g.Items.AddRange(oldG.Items)
        g.Items.AddRange(tl)

        Call WakuUpdate(g)
        g.CenterPoint = GetCenterPoint(g.Bound) 'グループの中心点

        '各ThumbにGroupをセット
        Dim axis As Point
        For Each t As ExThumb2 In g.Items
            Dim neko = t.NowGroup
            If t.NowGroup IsNot Nothing Then

                t.gStack.Push(t.NowGroup)
            End If
            t.gtStack.Push(t.gtCollection) 'グループ化解除の時使うはず
            t.NowGroup = g

            axis = g.CenterPoint - t.CenterAxis 'グループ化後の変形の軸
            t.gtCollection = GetTransformGroup2(axis).Children 'グループ化後のTransformセット

            'Dim cp As Point = GetCenterPointLocate(t) '自身の中心点
            ''自身の中心点から見てグループRectの中心点がどの位置(距離)になるのか
            't.DistansToGroupCenter = g.CenterPoint - cp '自身の中心点からグループの中心点までの距離をセット
            ''axis = t.PointDiffOfGroup 'グループ化後の変形の軸
            't.gtCollection = GetTransformGroup2(t.DistansToGroupCenter).Children 'グループ化後のTransformセット

            Dim tg As TransformGroup = t.RenderTransform
            For i As Integer = 0 To 3
                tg.Children.Add(t.gtCollection(i))
            Next
        Next
        '枠表示更新
        canvas1.Children.Remove(oldG.Waku)
        canvas1.Children.Add(g.Waku)
        ActiveGroup = g

        Call StatusbarUpdate()

    End Sub
    '変形の引き継ぎ
    Private Sub InheritsTransform(t As ExThumb2)
        'もとのTransformCollectionを取り出す
        Dim motoTransformCollection As TransformCollection = t.gtStack.Pop
        '変形の引き継ぎ
        'もとのTransformに解除前の回転を足す
        Dim tg As TransformGroup = t.RenderTransform

        Dim gro As RotateTransform = t.gtCollection(GTransform.Rotate) '解除前の
        Dim tro As RotateTransform = motoTransformCollection(GTransform.Rotate) '元の
        tro.Angle += gro.Angle

        '拡大率を足す
        Dim gsc As ScaleTransform = t.gtCollection(GTransform.Scale) ' 解除前の
        Dim tsc As ScaleTransform = motoTransformCollection(GTransform.Scale) '  '元の
        tsc.ScaleX *= gsc.ScaleX
        tsc.ScaleY *= gsc.ScaleY

        'Transform削除
        For Each tf As Transform In t.gtCollection
            tg.Children.Remove(tf)
        Next

        t.gtCollection = motoTransformCollection ' t.gtStack.Pop '1階層したのTransform取得セット

    End Sub



    'グループ化解除
    Private Sub UnGroup2(g As Group2)
        '移動
        '1階層下にグループがないThumbの場合の移動
        '各Thumbの今の見た目の中心点とグループ化前の実際の中心点との差分移動
        Dim jt As List(Of ExThumb2) = GetThumbsJustBelow(g)
        For Each t As ExThumb2 In jt
            Dim ncp As Point = GetCenterPointLocate(t) '今
            Dim npp As Point = ncp - t.CenterAxis '今 - 前
            OffSetLocate(t, npp) '差分移動
        Next

        '1階層下もグループの場合の移動
        'グループ化前後のグループの中心点の差分だけ各Thumbを移動
        Dim gl As List(Of Group2) = GetGroupsOneLevelBelow(g)
        For Each gg As Group2 In gl
            Dim rl As List(Of Rect) = GetRects(gg.Items)
            Dim r As Rect = GetGroupRect(rl)
            Dim ggOldCp = gg.CenterPoint          '前の中心点
            gg.CenterPoint = GetCenterPoint(r)    '
            Dim ggNewCp = gg.CenterPoint          '後の中心点
            Dim ggDiffCp = ggNewCp - ggOldCp      '差分
            For Each t As ExThumb2 In gg.Items    '各Thumb移動
                OffSetLocate(t, ggDiffCp)
                '自身の中心点を記録
                t.CenterAxis += ggDiffCp
            Next
            gg.Bound = r '枠の更新
        Next


        '変形の引き継ぎとグループ変更
        For Each t As ExThumb2 In g.Items
            '変形の引き継ぎ 
            Call InheritsTransform(t)

            'グループを1階層引き上げ
            If t.gStack.Count <> 0 Then
                '1階層したのGroup2取得して今のグループに指定
                Dim popG As Group2 = t.gStack.Pop
                t.NowGroup = popG
            Else
                '下にグループが無い時は今のグループになしを指定
                t.NowGroup = Nothing
            End If
        Next

        '枠非表示
        canvas1.Children.Remove(g.Waku)
        '新しい枠表示
        If ActiveThumb.NowGroup IsNot Nothing Then
            canvas1.Children.Add(ActiveThumb.NowGroup.Waku)
        End If

        ActiveGroup = ActiveThumb.NowGroup
        Call ReRender(canvas1)
        Call StatusbarUpdate()
    End Sub
    '1階層下のグループすべて取得
    Private Function GetGroupsOneLevelBelow(g As Group2) As List(Of Group2)
        Dim gl As New List(Of Group2)
        For Each t As ExThumb2 In g.Items
            If t.gStack.Count <> 0 Then

                gl.Add(t.gStack.Peek)
            End If
        Next
        gl = gl.Distinct.ToList '重複除去
        Return gl

    End Function
    'グループ直下のThumbすべて取得
    Private Function GetThumbsJustBelow(g As Group2) As List(Of ExThumb2)
        'グループがなければ直下のThumbになる
        Dim tl As New List(Of ExThumb2)
        For Each t As ExThumb2 In g.Items
            If t.gStack.Count = 0 Then
                tl.Add(t)
            End If
        Next
        Return tl

    End Function

    '最初のThumbの配置とグループ化まで自動
    Private Sub start()
        Call DrawGridLine()
        Panel.SetZIndex(canvas1, -1)
        tList.Add(AddThumb(New Point(100, 100), Colors.Cyan))
        tList.Add(AddThumb(New Point(200, 100), Colors.Magenta))
        tList.Add(AddThumb(New Point(300, 100), Colors.Yellow))
        ActiveThumb = tList(0)
        Call SetGroup(tList.GetRange(0, 2)) 't0とt1の2つをグループ化
        Call SetGroupAndThumb(ActiveGroup, tList.GetRange(2, 1)) 'さっきのグループとt2をグループ化
    End Sub





    '起動完了描画完了後
    Private Sub MainWindow_ContentRendered(sender As Object, e As EventArgs) Handles Me.ContentRendered
        Call start()
    End Sub
    'リセット
    Private Sub btReset_Click(sender As Object, e As RoutedEventArgs) Handles btReset.Click
        For Each t As ExThumb2 In tList

            canvas1.Children.Remove(t)
            t = Nothing
            Dim uie As UIElementCollection = canvas1.Children
            Dim pl As List(Of Path) = uie.OfType(Of Path).ToList
            For Each p As Path In pl
                canvas1.Children.Remove(p)
            Next
        Next
        tList.Clear()
        Call start()
        Call StatusbarUpdate()
    End Sub
    '確認用
    Private Sub btChack_Click(sender As Object, e As RoutedEventArgs) Handles btChack.Click
        Dim at As ExThumb2 = ActiveThumb
        Dim ag As Group2 = ActiveGroup
        Dim p = GetLocate(ActiveThumb)
        Dim ttc As TransformCollection = at.gtCollection
        Dim gtg As TransformGroup = at.RenderTransform
        Dim gtc As TransformCollection = gtg.Children

    End Sub
    'グループ化解除
    Private Sub bt1_Click(sender As Object, e As RoutedEventArgs) Handles bt1.Click
        If ActiveGroup Is Nothing Then Return
        Call UnGroup2(ActiveGroup)
        ActiveGroup = ActiveThumb.NowGroup
    End Sub

    Private Sub bt2_Click(sender As Object, e As RoutedEventArgs) Handles bt2.Click
        '10%縮小
        Call kakudai(ActiveGroup, -0.1)
    End Sub

    Private Sub bt3_Click(sender As Object, e As RoutedEventArgs) Handles bt3.Click
        '10%拡大
        Call kakudai(ActiveGroup, 0.1)
    End Sub

    Private Sub bt4_Click(sender As Object, e As RoutedEventArgs) Handles bt4.Click
        '左15度回転
        Call henkei(ActiveGroup, -15)
    End Sub
    '
    Private Sub bt5_Click(sender As Object, e As RoutedEventArgs) Handles bt5.Click
        '右15度回転
        Call henkei(ActiveGroup, 15)
    End Sub

    'Groupの変形
    Private Sub henkei(g As Group2, angle As Double)
        '回転
        If g IsNot Nothing Then
            'グループの時
            For Each t As ExThumb2 In g.Items
                Dim r As RotateTransform = t.gtCollection(GTransform.Rotate)
                r.Angle += angle
            Next
            Call WakuUpdate(g)
        Else
            '単体Thumbのとき
            Dim r As RotateTransform = ActiveThumb.gtCollection(GTransform.Rotate)
            r.Angle += angle
        End If
        Call StatusbarUpdate()
    End Sub
    '拡大率変更
    Private Sub kakudai(g As Group2, scale As Double)
        If g IsNot Nothing Then
            'グループの時
            For Each t As ExThumb2 In g.Items
                Dim s As ScaleTransform = t.gtCollection(GTransform.Scale)
                s.ScaleX += scale
                s.ScaleY += scale
            Next
            Call WakuUpdate(g)
        Else
            '単体Thumbのとき
            Dim s As ScaleTransform = ActiveThumb.gtCollection(GTransform.Scale)
            s.ScaleX += scale
            s.ScaleY += scale
        End If
        Call StatusbarUpdate()
    End Sub

    Private Sub btAngle_Click(sender As Object, e As RoutedEventArgs) Handles btAngle.Click
        'If ActiveGroup Is Nothing Then Return
        Call henkei(ActiveGroup, 15)
        Call kakudai(ActiveGroup, 0.1)
    End Sub
End Class



Public Class ExThumb2
    Inherits Thumb
    Public Property CenterAxis As Point
    Public Property NowGroup As Group2

    'グループ化後のTransformCollection
    Public Property gtCollection As New TransformCollection
    Public Property gtStack As New Stack(Of TransformCollection) '解除の時使う
    Public Property gStack As New Stack(Of Group2) '解除の時使う

    Public Sub New()
        Dim tg As New TransformGroup
        With tg.Children '順番が大切
            .Add(New ScaleTransform)
            .Add(New SkewTransform)
            .Add(New RotateTransform)
            .Add(New TranslateTransform)
        End With
        Me.RenderTransform = tg
        Me.RenderTransformOrigin = New Point(0.5, 0.5)
        gtCollection = tg.Children
        gtStack.Push(gtCollection)

    End Sub

End Class



Public Class Group2
    Public Property Items As New List(Of ExThumb2)
    Public Property Waku As New Path 'グループの枠表示用
    Public Property CenterPoint As Point

    Private Property _Bound As Rect
    Public Property Bound As Rect
        Get
            Return _Bound
        End Get
        Set(value As Rect)
            _Bound = value
            Waku.Data = New RectangleGeometry(value)
        End Set
    End Property

    Public Sub New()
        With Waku
            .Stroke = Brushes.Red
            .StrokeThickness = 1.0R
        End With
    End Sub
End Class

'TransformGroupの中から任意のTransformを探すときに使う
Public Enum GTransform
    Scale = 0
    Skew
    Rotate
    Translate
End Enum
2019/10/30追記ここまで
 
前回のこれ
A:自身のRenderTransformの中からRotateTransformを探しだして、その中のAngleプロパティを変更する
B:新たにRotateTransformを作って自身のRenderTransformのGroupに追加する
このどちらかになると思う

Aはムダがないけどちょっとめんどくさい
Bはラクだけど回転の変更する度に追加するからかなりのムダ、きりがない
前回はBの方法だったけど今回はまともなAの方法にすることになったけどグループ化後に回転すると位置がずれる!
これはグループ化の前後で回転軸の位置が変わるのが原因
例えば
グループ化前の時に10度回転、その後グループ化してグループを10度回転で合計20度回転
これが回転の変化で回転軸の変化が
グループ化前の回転軸は(0,0)、グループ化によって回転軸の位置が(50,30)になった場合
RotateTransform(10,0,0)から
RotateTransform(20,50,30)に変更することになるけど
これだと位置がずれる
 
追加方式のBなら
RotateTransform(10,0,0) + RotateTransform(10,50,30)
これならズレることはない、けど回転の変更する度に増えるから
RotateTransform(10,0,0) + RotateTransform(10,50,30) + RotateTransform(10,50,30) + RotateTransform(10,50,30) + RotateTransform(10,50,30)…
ってきりがないのは前回
なので
1回だけ追加(B方式)して、それ以降は追加したものに変更を加える(A方式)
RotateTransform(10,0,0) + RotateTransform(10,50,30)
こうして1回だけ追加して、ここからさらに10度回転して合計30度にするときは
RotateTransform(10,0,0) + RotateTransform(20,50,30)
こうする
 
変形用のTransformは回転以外に3つ用意されていて合計4つ
これをまとめたもの(Collection)を記録しておく入れ物が必要
同じグループ内でもThumbによって中心点は違ってくるからThumbに持たせる必要がある
 
ってことで前回同様Thumbを継承したクラスを作ってこんな感じになった
 
イメージ 6
492行目のgtCollectionがそれ、グループ化した時にScale、Skew、Rotate、Translateこの4つのTransformを作成して入れておく、変形するときはここから取り出して値を設定する
グループ化したものをさらに別のものとグループ化すると中心点も変化するから、また新しい4つのTransformを作成してgtCollectionを今のものと入れ替える
この時古い方は捨てないで取っておくとグループ化解除した時にまた使えるので、それの入れ物が493行目のgtStack
494行目は自身がどのグループに属しているかの目印用、Group2を入れておく
この辺りのStack型のCollectionの使い方は
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい3 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14187560.html
この時と同じ感じ
 
Group2、グループの情報用クラス
 
イメージ 7
これは
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい4 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14203583.html
この時とだいたい同じ感じ
違うのは516行目、CenterPointにはグループの中心点を記録しておく
 
イメージ 8
Collectionの中から取り出すときに使う
中に入っている順番は固定していてその順番に合わせてある
上から0,1,2,3
ScaleTransformを取り出したい時に
gtCollection(0)でもいいけど数値だけだとわかりにくいかなと
gtCollection(GTransform.Scale)
 
Thumbのグループ化
 
 
 
イメージ 9
グループ化するテストは
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい4 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14203583.html
ここで終わっているので違うところは
変形に使うTransformを設定しているあたり
198行目で新たなTransformを作成、このTransformの中心軸、基準点っていうのかな、この点の位置は
グループの中心点 - 自身の中心点(197行目)
これを指定している
イメージ 10
↑水色と桃色をグループ化する場合
175,125 グループの中心
125,125 水色の中心
なので
175-125=50、125-125=0で
50,0
これを新しいTransformの軸に指定する
4つのTransformを作成するGetTransformGroup2
イメージ 11
これに50,0を渡すと
ScaleTransform(1,1,50,0)
とかになる
この新しいTransformを198行目でtgCollectionに入れて
200から203行目でRenderTransformに追加している(B方式)
RenderTransformの中を見てみる
イメージ 12
グループ化前の4つ(0から3)と今追加した4つ(4から7)合わせて8個入っているのがわかる
4のScaleTransformを見てみると
イメージ 13
CenterXが50、CenterYが0と指定したとおりになっている
4から7の4つ全てのCenterXとCenterYは同じになっているはず
グループを変形するときはこれらを取り出して値を指定することになる
最初はこのとり出す方法がわからなかった
グループの拡大率を変えたいときは4番のScaleTransformが目的のものになるけど
0番にもScaleTransformがあるのでScaleTransformを探すってのは使えない
追加する順番や個数は決まっているから番号を覚えておけばできるけどわかりにくい
ってことで今回の方法
 
イメージ 14
さっきも載せたけどgtCollection
新しく作ったTransformはこのgtCollectionとRenderTransformのTransformGroupの両方に入れる、この両方の入れ物はCollectionでCollectionに入れたものは実際の値ではなくて参照(リンクみたい)になるのでどちらかに変更があるともう片方も変更される
gtCollectionには今のグループのTransformだけを入れておくので0から3番までの4つを覚えておけばいい
これなら簡単に目的のTransformを取得できるので、こっちで取得して値を変更する、両者は参照(リンク)関係なのでRenderTransformの方も変更される
 
グループの回転
 
イメージ 15
447行目で回転のRotateTransformを取得している
gtCollectionにGTransform.Rotate(は2番)を指定して取得
448行目で角度変更
これでRenderTransformの中の今のグループに関係あるRotateTransformも変更されるので期待通りの動作になる
 
15度回転
 
 
イメージ 17
この時の水色のgtCollectionとRenderTransformを見てみると
 
gtCollectionのRotateTransform
イメージ 16
2番めのRotateTransformのAngleが15になっている
 
RenderTransformのRotateTransform
イメージ 18
グループ化で追加した4から7のうち6番目のRotateTransformのAngleも15になっている
 
 
グループ化解除
移動
 
イメージ 20
2から3へは見た目の位置に変化はないけど変化しないように移動している
2の時点では1の時と全く同じ位置にあって、回転によって見た目の位置が変化しているだけ
3でグループ化解除して単体になる黄色はグループの回転から外れるので位置を変更しないと
 
イメージ 21
こうなってしまう、これだと不自然なので移動させる必要がある
 
どのグループにも属さないで単体になるThumbの移動
 
イメージ 19
今(解除前)の見た目の中心位置 - 前の中心位置 = 移動距離
前の位置 + 移動距離 = 期待する位置
二度手間な感じだけどこうなった
 
今の見た目の中心点を取得する
GetCenterPointLocate
イメージ 22
自身の元の中心点をTransformToVisualを使って得たGeneralTransformのTransformで変換して取得している
 
指定した距離分移動させる
OffsetLocate
 
イメージ 23
 
 
1階層下のグループの中のThumbすべての移動
これも移動させないと
イメージ 24
不自然になってしまうので
イメージ 25
解除するグループ(3つのThumb)の中心点と解除後のグループ(水色と桃色)の中心点
この2つの点の差
これの分だけ移動させると自然な位置になる
 
グループ化解除時の
回転とかの変形(Transform)の引き継ぎと削除
 
イメージ 27
引き継ぎしないと位置もおかしくなるし、これを変形させるともっとおかしくなるので
引き継ぎと削除する
InheritsTransform
イメージ 26
グループ化するときに捨てないで取っておいたTransformCollectionをgtStackから取り出す(258行目)
これにそれぞれ4つの値を引き継ぐ、って今回は回転と拡大率しか使っていないから2つしか書いてなかった
回転角度は足す、拡大率は掛け算でいいみたい(271行目まで)
引き継いだら今のをRenderTransformから削除(273から276行目)
gtCollectionも入れ替える(278行目)
これをグループ化解除の移動が終わった後のここで実行している
 
イメージ 28
ついでに今属しているグループの目印用の変数の中も入れ替え
これでやっとグループ化解除の処理が終わる
 
 
エクセルでのグループ化→回転→グループ化解除
イメージ 29
グループ化したものを回転するとかは
めったに使わないんだよねw
 
エクセルでグループ化→拡大率150%
イメージ 30
エクセルの拡大率変化の基準点は中心じゃなくて左上なんだなあ
 
イメージ 31
今回のテストでの基準点は全て中心にしたから結果が異なる
基準点の切り替えできるようにしたいけどこのままかなあ
 
 
 
やっとできたグループ化解除で不自然にならないようにつじつま合わせ
以前の方法のグループ化するときにはThumbのなかにThumbを入れる、っていうのだとこれができなさそうで諦めて今のThumbはThumbのままで擬似的なグループ化っていう方法を試していたんだけど、なんとかできたっぽい
 
グループ化のテストは次で最後になるかなあ
前々回の範囲をマウスで指定してグループ化するのと移動を今回のに付け足す感じ
 
 
今回のコード全部
どうやら↑ここに載っけたコードはMicrosoftのアカウントがないと見れないみたい?
GitHubとかなら誰でも見れるようなんだけど使い方がわからん
ヤフーブログの2万文字制限が無くなるか緩和してくれないかしら
 
 
前々回は5日前
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい4 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14203583.html
前回
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい5 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14209863.html
WPFVB.NET、FillContainsWithDetailとGeometryを使って面と面の重なりを判定 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14225368.html