annotated drawing must remain same position where it was done in WPF - c#

i used WPF application and i have drawn a line on a dicom image.but my problem is when i resize main window, line positions are changed. it wont persist on the place where i drawn. i have tried with pointtoscreen method and translatepoint method. but didnt work. what is the correct way to do this.
i used two wpf image controls. one is to display the dicom image and other is on top of it to draw annotation.following is my wpf xaml code.
<Border x:Name="Border" ClipToBounds="True">
<Grid>
<Image x:Name="ImageTileViewer"
Margin="-234"
Source="{Binding CurrentImage}"
Stretch="None"
StretchDirection="DownOnly" RenderTransformOrigin="0.5,0.5"/>
<Grid Name="AnnotationImageGrid">
<Image Name="AnnotationImage" Stretch="None" RenderTransformOrigin="0.5,0.5"/>
</Grid>
</Grid>

<Grid>
<Canvas Name="canDrawing" Height="450" Width="800"
MouseMove="canDrawing_MouseMove_NotDown"
MouseDown="canDrawing_MouseDown">
<Image Name="imgTrash"
StretchDirection="DownOnly" RenderTransformOrigin="0.5,0.5"
Source="C:\Users\Chaithika\Downloads\after_resize.PNG" />
</Canvas>
</Grid>
public Window1()
{
InitializeComponent();
TransformGroup group = new TransformGroup();
ScaleTransform xform = new ScaleTransform();
group.Children.Add(xform);
TranslateTransform tt = new TranslateTransform();
group.Children.Add(tt);
imgTrash.RenderTransform = group;
canDrawing.RenderTransform = group;
}
private void Window1_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
var width = Convert.ToInt32(e.NewSize.Width);
var height = Convert.ToInt32(e.NewSize.Height);
double factor = Math.Min((width / imgTrash.ActualWidth), (height / imgTrash.ActualHeight));
if (width >= imgTrash.ActualWidth && height >= imgTrash.ActualHeight)
{
factor = 1;
}
TransformGroup transformGroup = (TransformGroup)imgTrash.RenderTransform;
ScaleTransform st = (ScaleTransform)transformGroup.Children[0];
st.ScaleX = factor;
st.ScaleY = factor;
TransformGroup transformGroup2 = (TransformGroup)canDrawing.RenderTransform;
ScaleTransform st2 = (ScaleTransform)transformGroup2.Children[0];
st2.ScaleX = factor;
st2.ScaleY = factor;
}

Related

c# Canvas Zoom Functionality issue ?Not able to zoom out to original postion after zooming in to a point using matrix transform

I'm trying to implement a canvas zoom functionality in c# using matrix transform. I'm able to zoom in to one particular point, but while zooming out to the original scale(i've limited to original scale) the position of the canvas changes(out of the window) . I would like it to zoom out to its original position. Can anyone help?
Please find the code below:
<ScrollViewer Name="C1_S" Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" VerticalAlignment="Bottom" Grid.ColumnSpan="2" >
<Canvas Name="canvas_core0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="600" Width="1000000" MouseWheel="Canvas_MouseWheel" ClipToBounds="True" >
<Canvas.Background>
<DrawingBrush TileMode="Tile" Viewport="0,20,40,40" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,50,50"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="Gray" Thickness=".1"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
<Canvas.RenderTransform>
<MatrixTransform/>
</Canvas.RenderTransform>
</Canvas>
</ScrollViewer>
C# Code:`
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
var element = sender as UIElement;
var position = e.GetPosition(element);
if(e.Delta>0)
{
previousposition = position;
}
var transform = element.RenderTransform as MatrixTransform;
var matrix = transform.Matrix;
scrollcountprevious = scrollcountcurrent;
scrollcountcurrent = scrollcountcurrent + e.Delta;
// var scale1 = scrollcountcurrent > scrollcountprevious ? 1.1 : scrollcountcurrent <scrollcountprevious0 ? 1.0 : (1.0 / 1.1); // choose appropriate scaling factor
var scale1=1.0;
if (scrollcountcurrent > scrollcountprevious)
{
scale1 = 1.1;
matrix.ScaleAtPrepend(scale1, scale1, position.X, position.Y);
transform.Matrix = matrix;
}
else if (scrollcountcurrent < scrollcountprevious&&scrollcountcurrent>=0)
{
scale1 = 1 / 1.1;
matrix.ScaleAtPrepend(scale1, scale1, previousposition.X, previousposition.Y);
transform.Matrix = matrix;
}
else
{
scale1 = 1;
scrollcountcurrent = 0;
matrix.ScaleAtPrepend(scale1, scale1, previousposition.X, previousposition.Y);
transform.Matrix = matrix;
}
}
Not sure if I understand what you're exactly trying to achieve. Also, having the Canvas in a ScrollViewer might mess things up.
But probably this MouseWheel handler does what you want:
private double scale = 1;
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
var element = (UIElement)sender;
var position = e.GetPosition(element);
var matrix = Matrix.Identity;
scale = Math.Max(e.Delta > 0 ? scale * 1.1 : scale / 1.1, 1.0);
matrix.ScaleAt(scale, scale, position.X, position.Y);
((MatrixTransform)element.RenderTransform).Matrix = matrix;
}
In order to also scale the actual size of the Canvas in the ScrollViewer, scale its LayoutTransform instead of the RenderTransform:
<Canvas.LayoutTransform>
<MatrixTransform/>
</Canvas.LayoutTransform>
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
var element = (FrameworkElement)sender;
var position = e.GetPosition(element);
var matrix = Matrix.Identity;
scale = Math.Max(e.Delta > 0 ? scale * 1.1 : scale / 1.1, 1.0);
matrix.ScaleAt(scale, scale, position.X, position.Y);
((MatrixTransform)element.LayoutTransform).Matrix = matrix;
}

WPF Image Cropping

I have a problem with image cropping. When I try to crop image with rectangle the cropping area is set to some strange value.
Here is xaml code:
<Grid Name="GridImage">
<Image Name="LoadedImage" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="HighQuality">
</Image>
<Canvas x:Name="ImageCanvas" ClipToBounds="True">
<Rectangle x:Name="SelectionRectangle" Stroke="LightBlue" Fill="#220000FF" Visibility="Collapsed" />
</Canvas>
</Grid>
and here how I crop image:
var imagePosition = LoadedImage.TransformToAncestor(GridImage).Transform(new Point(0, 0));
Rect rect1 = new Rect(Math.Max(Canvas.GetLeft(SelectionRectangle) - imagePosition.X, 0), Math.Max(Canvas.GetTop(SelectionRectangle) - imagePosition.Y, 0), SelectionRectangle.Width, SelectionRectangle.Height);
var ratioX = LoadedImage.Source.Width / LoadedImage.ActualWidth;
var ratioY = LoadedImage.Source.Height / LoadedImage.ActualHeight;
Int32Rect rcFrom = new Int32Rect
{
X = (int)(rect1.X * ratioX),
Y = (int)(rect1.Y * ratioY),
Width = (int)(rect1.Width * ratioX),
Height = (int)(rect1.Height * ratioY)
};
try
{
BitmapSource bs = new CroppedBitmap((BitmapSource)LoadedImage.Source, rcFrom);
LoadedImage.Source = bs;
SetImageStretch(LoadedImage);
SetElementVisibility(Visibility.Hidden, Visibility.Visible, SelectionRectangle);
}
private void SetImageStretch(Image image)
{
if (image.Source.Width > image.ActualWidth || image.Source.Height > image.ActualHeight)
image.Stretch = Stretch.Uniform;
else image.Stretch = Stretch.None;
}
Does anybody know how to fix that?
Here how it looks before cropping:
How it looks after cropping:
Most likely the problem is with image resolution, e.g. 300 dpi, versus screen resolution (most likely 96 dpi). Have you checked image's PixelWidth and PixelHeight?

WPF How to get Width of a Panel dynamically

Hi I have an empty Panel, and want to add items to it at runtime. I also want to make sure that panel's Width doesn't extend the window's Width, If so I want o add items in other panel.
In my XAML :
<Border Grid.Row="1" Margin="5,0,5,0" Padding="2" Background="LightYellow"
BorderBrush="SteelBlue" BorderThickness="1" CornerRadius="3" >
<StackPanel Name="legendsPanel" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<DockPanel Name="legendsPnl1">
</DockPanel>
<DockPanel Name="legendsPnl2">
</DockPanel>
</StackPanel>
</Border>
In code behind :
int legendSize = 30; // W for 1 Legend
private void AddLegend(string title, double value, Brush clr)
{
MessageBox.Show("SP - " + legendsPanel.ActualHeight.ToString() + " DP - " + legendsPnl1.ActualHeight.ToString()); // 0, 0
Rectangle rect = new Rectangle();
rect.Width = 10; rect.Height = 10; rect.Fill = clr;
Label lbl = new Label();
lbl.Content = title + value;
/*
* Here, before adding to legendsPnl1 I want to make sure that it's W = (W + legendSize) <= legendsPanelWidth
* legendsPanel - > StackPanel i.e. Parent of legendsPnl1
* Width of legendsPanel, Grid, Window all are in wither Stretch mode or free Width - Auto or *,
* so can't make out how to get the W of them. At runtime, their W, ActualWidth are shown either 0, NaN, null
*/
legendsPnl1.Children.Add(rect);
legendsPnl1.Children.Add(lbl);
}
How to find legendsPnl1 panel hasenough space to add both elements (of size legendSize var ) , else add the elements in legendsPnl1 panel ????
Thanks

Strange behavior during movement of UIElement. Why?

I'm having some trouble understanding (and fixing) a bug I'm experiencing.
I have the UI like in the following picture:
All of those areas colored in lightblue are Canvases and they are movable. This is where I have my problem. The one from the top left can be moved without problems. The other two, when I'm dragging them, disappear. I can't explain why.
This is the code for the moving of elements:
// this is all inside the MouseMove event handler function
// If there is no dragged element
if (this.DraggedElement == null || !this.IsDragInProgress)
return;
/*
* Calculating the new position for the dragged element
*/
// Mouse current position
Point cursor = e.GetPosition(this);
double xMove = 0;
double yMove = 0;
// Movement detected
if (cursor != MouseClickLocation)
{
// Moving on the x-axis and y-axis
xMove = cursor.X - MouseClickLocation.X;
yMove = cursor.Y - MouseClickLocation.Y;
// Actually moving the element
if (this.ConstrainToBounds(this.DraggedElement, mainWindow))
{
TranslateTransform translate = new TranslateTransform(xMove, yMove);
this.DraggedElement.RenderTransform = translate;
}
}
The code for ConstrainToBounds() method is supposed to not allow me to move any Canvas outside the window borders (it works perfectly for the top left Canvas, but not for the others) and is as follows:
private Boolean ConstrainToBounds(Canvas element, UIElement container)
{
try
{
Boolean respects = true;
// Values used to reset the element position to a proper location
double xReset = 0;
double yReset = 0;
// Left x-axis constraint
if (element.TranslatePoint(new Point(), container).X <= new Point(0, 0).X)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X + 1;
yReset = element.TranslatePoint(new Point(), container).Y;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Right x-axis constraint
if (element.TranslatePoint(new Point(), container).X + element.RenderSize.Width >= container.RenderSize.Width)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X - 1;
yReset = element.TranslatePoint(new Point(), container).Y;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Top y-axis constraint
if (element.TranslatePoint(new Point(), container).Y <= new Point(0, 0).Y)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X;
yReset = element.TranslatePoint(new Point(), container).Y + 1;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Bottom y-axis constraint
if (element.TranslatePoint(new Point(), container).Y + element.RenderSize.Height >= container.RenderSize.Height)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X;
yReset = element.TranslatePoint(new Point(), container).Y - 1;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
return respects;
}
catch (Exception ex)
{
throw ex;
}
}
Edit_1: Added code from MainWindow.xaml:
<Window
Name="mainWindow"
x:Class="WPF_TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="480" Width="555">
<Grid Name="mainGrid">
<Canvas Grid.Row="0"
Grid.Column="0"
Background="AliceBlue"
Name="LeftTop"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp" >
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Canvas Grid.Row="0"
Grid.Column="2"
Background="AliceBlue"
Name="RightTop"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp">
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Label Grid.Row="2"
Grid.Column="0"
Name="LeftBottom">
</Label>
<Canvas Grid.Row="2"
Grid.Column="3"
Background="AliceBlue"
Name="RightBottom"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp">
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="50" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Edit_2: So, I've discovered that when I move the top right canvas, it actually moves outside of the view (at position 600,0). Currently trying to understand why this happens.
Instead of using render transforms, might be easier to update the Canvas's Margin property:
if (cursor != MouseClickLocation)
{
// Moving on the x-axis and y-axis
xMove = cursor.X - MouseClickLocation.X;
yMove = cursor.Y - MouseClickLocation.Y;
// Actually moving the element
this.DraggedElement.Margin = this.CalculateNewPosition(this.DraggedElement, mainWindow, xMove, yMove);
}
Where CalculateNewPosition might look something like this (warning, untested):
private Thickness CalculateNewPosition(Canvas element, UIElement container, double translationX, double translationY)
{
Thickness currentPosition = element.Margin;
Thickness newPosition = new Thickness(currentPosition.Left + translationX, currentPosition.Top + translationY, 0, 0);
int containerWidth = container.ActualWidth;
int containerHeight = container.ActualHeight;
int elementWidth = element.ActualWidth;
int elementHeight = element.ActualHeight;
if (newPosition.Left < 0)
newPosition.Left = 0;
else if (newPosition.Left + elementWidth > containerWidth)
newPosition.Left = containerWidth - elementWidth;
if (newPosition.Top < 0)
newPosition.Top = 0;
else if (newPosition.Top + elementHeight > containerHeight)
newPosition.Top = containerHeight - elementHeight;
return newPosition;
}
I'm not sure why specifically your code isn't working for the other circles. Possibly it has to do with the bounds checks like:
if (element.TranslatePoint(new Point(), container).X <= new Point(0, 0).X)
if (element.TranslatePoint(new Point(), container).X + element.RenderSize.Width >= container.RenderSize.Width)
The assumption is that the new Point(0,0) and TranslatePoint are returning points relative to each containing grid cell. I'm not sure if that assumption is correct; one (or both) of the comparisons may be absolute with respect to the application or something to that effect. It would be difficult to ascertain exactly just via a cursory examination of your code; you would need to run the debugger and check your values and see where they diverge from what you expect.

WPF How to check if in canvas is empty spaces

I am adding rectangles on a Canvas using Random because I don't know the width and height.
Code
HProDataContext db = new HProDataContext();
var RoomX = (from d in db.rooms select d.sizex).ToList();
var RoomY = (from d in db.rooms select d.sizey).ToList();
var random = new Random();
for (int i = 0; i < RoomX.Count; i++)
{
RoomX[i] = (Convert.ToDouble(RoomX[i]) * 10).ToString();
RoomY[i] = (Convert.ToDouble(RoomY[i]) * 10).ToString();
var rectangle = new Rectangle()
{
Stroke = Brushes.Black,
Fill = Brushes.SkyBlue,
Width = Convert.ToDouble(RoomX[i]),
Height = Convert.ToDouble(RoomY[i]),
Margin = new Thickness(
left: random.NextDouble() * 300,
top: random.NextDouble() * 150,
right: 0,
bottom: 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
mainCanvas.Children.Add(rectangle);
}
}
It works good, but some rectangles are drawing over another rectangles.
How to draw rectangles there where is empty space?
You can calculate a Rect for each WPF Rectangle and use IntersectsWith method found in Rect to test if the code can a draw a new Rectangle without overlaps. I also recommend using rectangle properties Canvas.Left and Canvas.Top instead of adjusting the Margin.
I've included a simple example that you test to get you started.
Here is some XAML containing 4 Rectangles:
<Window x:Class="OverlapRectangeTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Canvas x:Name="c" Grid.Row="0">
<Rectangle x:Name="b1" Fill="Aqua" Canvas.Left="0" Canvas.Top="0" Width="100" Height="200"/>
<Rectangle x:Name="b2" Fill="Bisque" Canvas.Left="0" Canvas.Top="0" Width="200" Height="100"/>
<Rectangle x:Name="b3" Fill="BlueViolet" Canvas.Left="250" Canvas.Top="0" Width="100" Height="200"/>
<Rectangle x:Name="b4" Fill="Cornsilk" Canvas.Left="111" Canvas.Top="0" Width="100" Height="200"/>
</Canvas>
<Button Grid.Row="1" Click="Button_Click"/>
</Grid>
</Window>
Here is a button click event handler where I test the IntersectsWith method:
private void Button_Click(object sender, RoutedEventArgs e)
{
double top1 = (double)b1.GetValue(Canvas.TopProperty);
double left1 = (double)b1.GetValue(Canvas.LeftProperty);
Rect rect1 = new Rect(left1, top1, b1.Width, b1.Height);
double top2 = (double)b2.GetValue(Canvas.TopProperty);
double left2 = (double)b2.GetValue(Canvas.LeftProperty);
Rect rect2 = new Rect(left2, top2, b2.Width, b2.Height);
double top3 = (double)b3.GetValue(Canvas.TopProperty);
double left3 = (double)b3.GetValue(Canvas.LeftProperty);
Rect rect3 = new Rect(left3, top3, b3.Width, b3.Height);
double top4 = (double)b4.GetValue(Canvas.TopProperty);
double left4 = (double)b4.GetValue(Canvas.LeftProperty);
Rect rect4 = new Rect(left4, top4, b4.Width, b4.Height);
bool rc0 = rect1.IntersectsWith(rect4);
bool rc1 = rect1.IntersectsWith(rect2);
bool rc2 = rect2.IntersectsWith(rect3);
bool rc3 = rect3.IntersectsWith(rect1);
bool rc4 = rect2.IntersectsWith(rect4);
}

Categories