Node resizing reverse after mirroring node or flipping node

Hi, I have created a Template which i am rotating vertically or mirroring then the resize behaviour of the node is also mirrored.

            <Behaviors:Interaction.Triggers>
                <Behaviors:EventTrigger EventName="MouseLeftButtonDown">
                    <Behaviors:InvokeCommandAction Command="{Binding Path=Data.MouseLeftButtonDown}" PassEventArgsToCommand="True" />
                </Behaviors:EventTrigger>
            </Behaviors:Interaction.Triggers>
            <Grid Name="ItemData" MinHeight="10" MinWidth="15" Height="{Binding Path=Data.Height, Mode=TwoWay}" 
                  Width="{Binding Path=Data.Width, Mode=TwoWay}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="5"/>
                    <ColumnDefinition Width="45*"/>
                    <ColumnDefinition Width="10*"/>
                    <ColumnDefinition Width="45*" />
                    <ColumnDefinition Width="5"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="5"/>
                    <RowDefinition Height="40*"/>
                    <RowDefinition Height="20*"/>
                    <RowDefinition Height="40*"/>
                </Grid.RowDefinitions>
                <!--Right port-->
                <flowsheeter:CustomPort PortColor="Red" PortType="NodeH2O" x:Name="In" go:Node.LinkableMaximum="1" ToolTip="{x:Static prop:Resources.In}" go:Node.PortId="{x:Static prop:Resources.In}" Grid.Row="2"  Grid.Column="3" Grid.ColumnSpan="2"  HorizontalAlignment="Right" VerticalAlignment="Center" go:Node.LinkableFrom="False" go:Node.LinkableTo="True"  Margin="0,0,2.7,0" Panel.ZIndex="1"/>
                <!--Left port-->
                <flowsheeter:CustomPort PortColor="Red" PortType="NodeH2O" x:Name="Out" go:Node.LinkableMaximum="1" ToolTip="{x:Static prop:Resources.Out}" go:Node.PortId="{x:Static prop:Resources.Out}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Center" go:Node.LinkableFrom="True" go:Node.LinkableTo="False" Margin="2.7,0,0,0" Panel.ZIndex="1" />
                <!--Top port-->
                <flowsheeter:CustomPort PortColor="Black" PortType="NodeSignal" x:Name="SignalInPort" go:Node.LinkableMaximum="1" ToolTip="{x:Static prop:Resources.Signal}" go:Node.PortId="{x:Static prop:Resources.Signal}" Grid.Row="0" Grid.RowSpan="2" Grid.Column="2"  HorizontalAlignment="Center" VerticalAlignment="Top" go:Node.LinkableFrom="False" go:Node.LinkableTo="True" Margin="0,2.7,0,0" Panel.ZIndex="1" />

                <Path Grid.Row="1" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="3" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="White" Data="M 8 4 L 8 0 L 0 4 L 0 0 L 8 4 M 2 1 L 4 0 L 6 1" Stroke="Black" StrokeThickness="1"></Path>
                <Ellipse  Grid.Row="2"  Grid.Column="2"  Stroke="Black" StrokeThickness="1" Stretch="Fill"  Fill="Black" Panel.ZIndex="1"/>
            </Grid>
            <TextBlock Name="AggregateName" HorizontalAlignment="Center" Text="Control Valve" />
        </StackPanel>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=Data.IsAggregateNameHidden}" Value="True">
                <Setter TargetName="AggregateName" Property="Visibility" Value="Collapsed" />
                <Setter TargetName="ShapeLayout" Property="ForceCursor" Value="False"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

private void MirrorAggregate(bool isVertical)
{
GoXamModel.StartTransaction(“MirrorAggregates”);

        GetSelectedNodes()?.ToList().ForEach(node =>
        {
            ShapeData data = (ShapeData)node.Data;


            ScaleTransform scaleTransform = isVertical ? GetScaleTransformForVertical(data.MirrorX, data.MirrorY, node.RotationAngle) : GetScaleTransformForHorizontal(data.MirrorX, data.MirrorY, node.RotationAngle);
            if (!data.MirrorX.Equals(scaleTransform.ScaleX))
                data.MirrorX = scaleTransform.ScaleX;
            if (!data.MirrorY.Equals(scaleTransform.ScaleY))
                data.MirrorY = scaleTransform.ScaleY;

            if (IsCustomNodeEnabled)
            {
                ((CustomNode)node).SetScale((ShapeData)node.Data);

                node.LinksConnected.ToList().ForEach(link => { link.Route.UpdateLayout(); link.Route.RecomputePoints(); });
                node.UpdateLayout();
                node.UpdateAdornments();
            }
        });
        GoXamModel.CommitTransaction("MirrorAggregates");

    }

private ScaleTransform GetScaleTransformForHorizontal(double scaleX, double scaleY, double angle)
{
if (angle == 0 || angle == 180)
return new ScaleTransform(-scaleX, scaleY);
return new ScaleTransform(scaleX, -scaleY);
}

    private ScaleTransform GetScaleTransformForVertical(double scaleX, double scaleY, double angle)
    {
        if (angle == 0 || angle == 180)
            return new ScaleTransform(scaleX, -scaleY);
        return new ScaleTransform(-scaleX, scaleY);
    }

image

Before Mirroring :

image

If i select on top right and move down then it becomes smaller which is right.

After Mirroring :

image

If i select on top right and move down then it becomes larger which is wrong.

After mirroring the behaviour of resize is also mirrored. don’t understand why? What can be done to resolve this problem?

          entire template
      <StackPanel Tag="ControlValve" 
              go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"
                    go:Node.RotationAngle="{Binding Path=Data.RotationAngle, Mode=TwoWay}"
              go:Part.Rotatable="True"
              go:Part.RotateAdornmentTemplate="{StaticResource NodeRotateAdornmentTemplate}"
              go:Node.LocationSpot="Center"  ToolTip="{Binding Path=Data.Key}"
              go:Node.SelectionElementName="ItemData" Name="ShapeLayout" ForceCursor="True"
              go:Node.Resizable="True" Cursor="SizeAll"
              go:Part.LayerName="{Binding Path=Part.IsSelected, Converter={StaticResource selectedLayerConverter}}"  
               HorizontalAlignment="Center" VerticalAlignment="Center">
            <Behaviors:Interaction.Triggers>
                <Behaviors:EventTrigger EventName="MouseLeftButtonDown">
                    <Behaviors:InvokeCommandAction Command="{Binding Path=Data.MouseLeftButtonDown}" PassEventArgsToCommand="True" />
                </Behaviors:EventTrigger>
            </Behaviors:Interaction.Triggers>
            <Grid Name="ItemData" MinHeight="10" MinWidth="15" Height="{Binding Path=Data.Height, Mode=TwoWay}" 
                  Width="{Binding Path=Data.Width, Mode=TwoWay}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="5"/>
                    <ColumnDefinition Width="45*"/>
                    <ColumnDefinition Width="10*"/>
                    <ColumnDefinition Width="45*" />
                    <ColumnDefinition Width="5"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="5"/>
                    <RowDefinition Height="40*"/>
                    <RowDefinition Height="20*"/>
                    <RowDefinition Height="40*"/>
                </Grid.RowDefinitions>
                <!--Right port-->
                <flowsheeter:CustomPort PortColor="Red" PortType="NodeH2O" x:Name="In" go:Node.LinkableMaximum="1" ToolTip="{x:Static prop:Resources.In}" go:Node.PortId="{x:Static prop:Resources.In}" Grid.Row="2"  Grid.Column="3" Grid.ColumnSpan="2"  HorizontalAlignment="Right" VerticalAlignment="Center" go:Node.LinkableFrom="False" go:Node.LinkableTo="True"  Margin="0,0,2.7,0" Panel.ZIndex="1"/>
                <!--Left port-->
                <flowsheeter:CustomPort PortColor="Red" PortType="NodeH2O" x:Name="Out" go:Node.LinkableMaximum="1" ToolTip="{x:Static prop:Resources.Out}" go:Node.PortId="{x:Static prop:Resources.Out}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Center" go:Node.LinkableFrom="True" go:Node.LinkableTo="False" Margin="2.7,0,0,0" Panel.ZIndex="1" />
                <!--Top port-->
                <flowsheeter:CustomPort PortColor="Black" PortType="NodeSignal" x:Name="SignalInPort" go:Node.LinkableMaximum="1" ToolTip="{x:Static prop:Resources.Signal}" go:Node.PortId="{x:Static prop:Resources.Signal}" Grid.Row="0" Grid.RowSpan="2" Grid.Column="2"  HorizontalAlignment="Center" VerticalAlignment="Top" go:Node.LinkableFrom="False" go:Node.LinkableTo="True" Margin="0,2.7,0,0" Panel.ZIndex="1" />

                <Path Grid.Row="1" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="3" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="White" Data="M 8 4 L 8 0 L 0 4 L 0 0 L 8 4 M 2 1 L 4 0 L 6 1" Stroke="Black" StrokeThickness="1"></Path>
                <Ellipse  Grid.Row="2"  Grid.Column="2"  Stroke="Black" StrokeThickness="1" Stretch="Fill"  Fill="Black" Panel.ZIndex="1"/>
            </Grid>
            <TextBlock Name="AggregateName" HorizontalAlignment="Center" Text="Control Valve" />
        </StackPanel>

I cannot tell from the code that you have supplied how the ScaleTransform is used. Are you setting the LayoutTransform or the RenderTransform?

My guess is that the ResizingTool.DoActivate is calling DiagramTool.FindToolHandleAt in order to decide what to do, but it is getting the top-left handle because your mirroring has changed the apparent location of the handle, but it really still is at its original location.

Hi Walter, I am applying the RenderTransform. Could you please suggest to fix this? or any sample would be helpful.

Thanks!!

Best Regards,
Darshit

The problem with RenderTransform is that elements appear elsewhere from where they actually are, which affects hit testing and geometric computations. You will need to override various ResizingTool methods in order for it to get the points in the correct coordinate system.

I’ll provide you with the implementation of the ResizingTool so that you can see how it works and figure out how to handle your sometimes-weird node.

I am using below method to override using new scale after mirroring.

public override void UpdateAdornments(Part part)
{
base.UpdateAdornments(part);
double scaleX = 1, scaleY = 1;
if (part.GetAdornment(ToolCategory) is CustomAdornment adornment)
{
Node node = (Node)part;

            var elt = node.SelectionElement;
            if (elt.RenderTransform != null && elt.RenderTransform != Transform.Identity)
            {
                Transform transform = elt.RenderTransform;
                ScaleTransform st = getScaleTransform(transform);
                if (st != null && !st.IsFrozen)
                {
                    scaleX = st.ScaleX;
                    scaleY = st.ScaleY;
                }
            }
            FrameworkElement frameworkElement = adornment.SelectionElement;
            adornment.SetScale(frameworkElement, scaleX, scaleY);
        }
    }

    private ScaleTransform getScaleTransform(Transform transform)
    {
        ScaleTransform st = transform as ScaleTransform;
        if (st == null && transform is TransformGroup tg)
        {
            foreach (Transform t in tg.Children)
            {
                st = t as ScaleTransform;
                if (st != null) break;
            }
        }

        return st;
    }

If that code is correct, it will help position the resizing handles where they expect to be. However, when dragging the handle, the points are still in the wrong coordinate system, since the code doesn’t know about that RenderTransform.

The RenderTransform only transforms coordinates when rendering – not for hit testing or any other operation.