WPF: Rotate a rectangle with slider - c#

I'm trying to rotate a rectangle when scrolling slider
there are 2 steps: Click on a rectangle - Scroll the slider.
If I draw only one rectangle, everything is ok.
But when I draw 2 rectangles or more and start rotating, all of my rectangle are rotated together with same angle.
I have no idea about this.
Can anyone help me?
Thanks in advance!
Here is my code: (I found the code for rotating at another post in this page)
Shape _shape;
RotateTransform rt = new RotateTransform();
private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs)
{
/////////////////////////////////////////////////////
//for know which rectangle has been clicked
if (MyTransform_type == TRANSFORM_TYPE.ROTATE)
{
_shape = e.OriginalSource as Shape;
if (_shape != null)
{
_shape = (Shape)e.OriginalSource;
}
}
}
private void MyCanvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
if (MyTransform_type != TRANSFORM_TYPE.NONE && MyTransform_type != TRANSFORM_TYPE.ROTATE)
{
if (_shape == null)
return;
//_shape.ReleaseMouseCapture();
Cursor = Cursors.Arrow;
}
}
private void sldRotate_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_shape != null)
{
_shape.RenderTransform = rt;
_shape.RenderTransformOrigin = new Point(0.5, 0.5);
var da = new DoubleAnimation(rt.Angle, sldRotate.Value, new Duration(TimeSpan.FromSeconds(0.001)));
rt.BeginAnimation(RotateTransform.AngleProperty, da);
rt.Angle = sldRotate.Value;
}
}

Your mistake is that you create a single RotateTransform object and assign it to the different shapes. So after clicking on several rectangles, every rectangle has the same rotatetransform instance. If you now change the value of the rotatetransform, every rectangle will rotate...
In order to fix that you should change your sldRotate_ValueChanged method. Check if the current shape has already a rotatetransform. If not then create one, if yes adjust the rotatetransform...
Additionally, if you have such a small animation time, you can just leave it out:
private void sldRotate_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_shape != null)
{
var rt = new RotateTransform();
rt.Angle = sldRotate.Value;
_shape.RenderTransform = rt;
_shape.RenderTransformOrigin = new Point(0.5, 0.5);
}
}

It looks like you are using the same RotateTransform named "rt" for all of your rectangles. The simpliest solution will be:
private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs)
{
if (MyTransform_type == TRANSFORM_TYPE.ROTATE)
{
_shape = e.OriginalSource as Shape;
//creating new RotateTransform
rt=new RotateTransform();
if (_shape != null)
{
_shape = (Shape)e.OriginalSource;
}
}
}
also you could do
_shape.RenderTransform = rt;
in MyCanvas_MouseRightButtonDown after
_shape = e.OriginalSource as Shape;
instead of doing it each time, when sldRotate_ValueChanged executes to avoid unneeded assignments.

Related

Move object when mouse move on Helix- viewport 3D

I try to move multiple object open on Helix viewport 3D. so curtly mutiple object are open succesfuly. but problem in when i try to move any specific model at that time object move mouse opposit position like when i move on Right side at time object is goes to left side same as all axis. so i past here mouse move click event hrer, please provide a solution.
Number of query -
multiple object open at time i need to select particular object and move it. curntly all model are move in oposite axix.
Mouse move time object move opposite direction.
Object load Event :
private void loadbtn_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".stl";
dlg.Filter = "STL Files|*.stl;";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
string filename = dlg.FileName;
openfile = filename;
// txt1.Text = dlg.FileName;
}
ModelVisual3D device3D = new ModelVisual3D();
device3D.Content = Display3d(openfile);
// viewPort3d.Children.Add(device3D);
var reader = new StLReader();
_modelGroup = reader.Read(openfile);
var modelVisual = new ModelVisual3D();
modelVisual.Content = _modelGroup;
// Apply the TranslateTransform3D to your STL object
_modelGroup.Transform = _translate;
// Add the ModelVisual3D to the Children property of the HelixViewport3D
viewPort3d.Children.Add(modelVisual);
}
Mouse Down event is as per below.
private void viewPort3d_MouseDown(object sender, MouseButtonEventArgs e)
{
//*** MOVE ***
var position = e.GetPosition(viewPort3d);
var origin = new Point3D(position.X, position.Y, 0);
Point originPoint = new Point(origin.X, origin.Y);
var transformedOrigin = Viewport3DHelper.UnProject(ConvertToViewport3D(viewPort3d), originPoint);
_lastPosition = position;
viewPort3d.MouseMove += viewPort3d_MouseMove;
viewPort3d.MouseUp += viewPort3d_MouseUp;
}
private Viewport3D ConvertToViewport3D(HelixViewport3D helixViewport)
{
Viewport3D viewport = new Viewport3D();
viewport.Camera = helixViewport.Camera;
foreach (var child in helixViewport.Children)
{
if (child is ModelVisual3D modelVisual)
{
if (modelVisual.Content is Model3D model)
{
ModelVisual3D newChild = new ModelVisual3D();
newChild.Content = model;
viewport.Children.Add(newChild);
}
else
{
// handle other types of modelVisual.Content if necessary
}
}
else
{
// handle other types of Visual3D objects if necessary
}
}
return viewport;
}
Mouse Move event is as per below.
private void viewPort3d_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
System.Windows.Point position = e.GetPosition(this); // this = viewPort3D
double pX = position.X;
double pY = position.Y;
_translate.OffsetX -=pX;
_translate.OffsetY += pY;
_lastPosition = position;
}
Mouse Up event is as per below.
private void viewPort3d_MouseUp(object sender, MouseButtonEventArgs e)
{
//_isDragging = false;
viewPort3d.MouseMove -= viewPort3d_MouseMove;
viewPort3d.MouseUp -= viewPort3d_MouseUp;
//ReleaseMouseCapture();
}

Drag and Drop Object onto Canvas with coordinates

I managed to drag and drop items from my ListView onto a canvas and show an image on it. I used this question as a template:
https://social.msdn.microsoft.com/Forums/en-US/cef5c42c-87a0-4e19-afc8-935284607488/drag-and-drop-controls-issue-from-listbox-into-canvas-wpf?forum=wpf
I also added the suggestion in that thread, so that the Item gets rendered where I drop it. These are the code behinds for my "Drawing Plate" (The canvas) and the ListView:
Canvas:
public partial class DrawingPlateUC : UserControl
{
IMessenger messenger = Messenger.Instance;
public DrawingPlateUC()
{
InitializeComponent();
}
void Canvas_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("MyFormat"))
{
var module = e.Data.GetData("MyFormat") as Module;
Canvas CanvasView = sender as Canvas;
Image image = new Image();
image.Source = module.ModuleImage;
CanvasView.Children.Add(image);
}
}
private void Canvas_DragOver(object sender, DragEventArgs e)
{
// write down this point to a private member
Point enterPoint = e.GetPosition(this.moduleCanvas);
messenger.Send<Point>(enterPoint, MessengerTopics.MousePoint);
}
void Canvas_DragEnter(object sender, DragEventArgs e)
{
if (!(e.Data.GetDataPresent("contact")) || (sender == e.Source))
{
e.Effects = DragDropEffects.Copy;
}
}
}
ListView:
public partial class ItemListViewUC : UserControl
{
IMessenger messenger = Messenger.Instance;
Point startPoint;
Point enterPoint;
public ItemListViewUC()
{
messenger.Register<Point>(this, MessengerTopics.MousePoint, GetEnterPoint);
InitializeComponent();
}
private void GetEnterPoint(Point point)
{
enterPoint = point;
}
void StackPanel_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
void StackPanel_PreviewMouseMove(object sender, MouseEventArgs e)
{
Point mousPos = e.GetPosition(null);
Vector diff = startPoint - mousPos;
if ((e.LeftButton == MouseButtonState.Pressed) && (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance) && (Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null) { return; }
var contact = (Module)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
DataObject dataObject = new DataObject("MyFormat", contact);
try
{
DragDrop.DoDragDrop(listViewItem, dataObject, DragDropEffects.Copy);
}
catch { }
// Set the Margin property to place the drag item on the canvas.
listViewItem.Margin = new Thickness(enterPoint.X, enterPoint.Y, 0, 0);
}
}
static T FindAnchestor<T>(DependencyObject current) where T : DependencyObject
{
do
{
if (current is T)
{
return (T)current;
}
current = VisualTreeHelper.GetParent(current);
}
while (current != null);
return null;
}
}
This here is supposed to draw the Image on the spot where I dropped it:
listViewItem.Margin = new Thickness(enterPoint.X, enterPoint.Y, 0, 0);
But it only renders on the top left corner, coordinates 0, 0 of the canvas. This is for all Items I drop, they overlay on that position. I already checked the coordinates, they are not 0, 0, but the ones where my mouse is when I drop the item.
This is my Window:
when you drop an item, you don't set any coordinate for Image:
void Canvas_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("MyFormat"))
{
var module = e.Data.GetData("MyFormat") as Module;
Canvas CanvasView = sender as Canvas;
Image image = new Image();
image.Source = module.ModuleImage;
image.SetValue(Canvas.LeftProperty, _enterPoint.X);
image.SetValue(Canvas.TopProperty, _enterPoint.Y);
CanvasView.Children.Add(image);
}
}
private Point _enterPoint;
private void Canvas_DragOver(object sender, DragEventArgs e)
{
_enterPoint = e.GetPosition(this.moduleCanvas);
messenger.Send<Point>(_enterPoint, MessengerTopics.MousePoint);
}

I'm trying to drag and element using the mouse but it always starts dragging from a specific location and not the current location

I'm trying to drag a rectangle element called "Rec" using the mouse. I can drag it to the location I want and the rectangle stays there, but when I try to drag it again it returns to the first location and the dragging starts from there. I want to drag it from where I left it the last time. I just don't get where the problem is.
I have one Canvas only and all my elements are inside it, the Canvas is called the "maincanvas". I use the following very simple events to for dragging.
Point originalPosition = new Point(0, 0);
private void Rec_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
Point CurrPosition = Mouse.GetPosition(MainCanvas);
Canvas.SetLeft(e.Source as UIElement, -( originalPosition.X - CurrPosition.X));
Canvas.SetTop(e.Source as UIElement, -(originalPosition.Y - CurrPosition.Y));
}
private void Rec_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
UIElement a = e.Source as UIElement;
a.CaptureMouse();
Rec.MouseMove += Rec_MouseMove;
originalPosition = Mouse.GetPosition(MainCanvas);
}
private void Rec_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Rec.MouseMove -= Rec_MouseMove;
UIElement a = e.Source as UIElement;
a.ReleaseMouseCapture();
originalPosition = new Point(0, 0);
}
I hope you guys could help me.
You should handle the mouse events on the Canvas like this:
<Canvas MouseLeftButtonDown="CanvasMouseLeftButtonDown"
MouseLeftButtonUp="CanvasMouseLeftButtonUp"
MouseMove="CanvasMouseMove">
...
</Canvas>
In the mouse down handler you would get the element that should be dragged by the MouseButtonEventArgs's OriginalSource property:
private UIElement draggedElement;
private Point lastMousePos;
private void CanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource != sender)
{
IInputElement canvas = (IInputElement)sender;
canvas.CaptureMouse();
draggedElement = e.OriginalSource as UIElement;
lastMousePos = e.GetPosition(canvas);
}
}
private void CanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
((IInputElement)sender).ReleaseMouseCapture();
draggedElement = null;
}
private void CanvasMouseMove(object sender, MouseEventArgs e)
{
if (draggedElement != null)
{
var p = e.GetPosition((IInputElement)sender);
var dx = p.X - lastMousePos.X;
var dy = p.Y - lastMousePos.Y;
lastMousePos = p;
Canvas.SetLeft(draggedElement, Canvas.GetLeft(draggedElement) + dx);
Canvas.SetTop(draggedElement, Canvas.GetTop(draggedElement) + dy);
}
}

WPF How to dynamically draw one shape over another using Path and Geometry Group

I'm trying to make an application for a homework assignment that adds a RectangleGeometry to the path.data as GeometryGroup Children and then updates the size while I hold down the mouse button and move the mouse and then finalizes it when on mouseup. The problem is that I need the subsequent rectangles to be drawn over top of the preceeding ones. Setting FillRule to nonzero doesn't accomplish this because it still shows the stroke of the underlying rectangles. So how can I accomplish this?
private void path_MouseDown(object sender, MouseButtonEventArgs e)
{
path.Stroke = strokeColor;
path.Fill = fillColor;
path.StrokeThickness = thickness;
p = Mouse.GetPosition((UIElement)sender);
gg = path.Data as GeometryGroup;
gg.Children.Add(new RectangleGeometry());
}
private void path_MouseMove(object sender, MouseEventArgs e)
{
if (p == null) return;
var pp = Mouse.GetPosition((UIElement)sender);
gg = path.Data as GeometryGroup;
if (index == 0)
{
var pg = gg.Children.Last() as RectangleGeometry;
pg.Rect = new Rect(p.Value, pp);
}
else if(index == 1)
{
var pg = gg.Children.Last() as RectangleGeometry;
pg.RadiusX = pp.X - p.Value.X;
pg.RadiusY = pp.Y - p.Value.Y;
pg.Rect = new Rect(p.Value, pp);
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
p = null;
}

Drawing Line to next point in realtime

My current program allows the user to click a point, then click another point (at least 20 pixels away) and draws a line between the 2 points. I've used a Polyline so that this can be done multiple times. Though the set of all the lines only appear after all the click are done.
void DrawingCanvas_MouseUp(object sender, MouseButtonEventArgs e) {
Point position = e.GetPosition(this);
if (leftList == null) {
//starting a new set
leftList.Add(position);
lastPoint = position;
return;
}
//calculate distance, i.e. end click
double a = lastPoint.X - position.X;
double b = lastPoint.Y - position.Y;
double distance = Math.Sqrt(a * a + b * b);
if (distance > 20) {
//continue to add to list
leftList.Add(position);
lastPoint = position;
} else {
//end of the line
paint();
leftList = new PointCollection();
}
}
private void paint() {
Polyline line = new Polyline();
line.Visibility = System.Windows.Visibility.Visible;
line.StrokeThickness = 2;
line.Stroke = System.Windows.Media.Brushes.Black;
line.Points = leftList;
myCanvas.Children.Add(line);
}
So my question is two-fold:
A) How do I make it so that after each click the new line is immediately added.
B) How do I render a line between the last point and where the mouse cursor is currently at (i.e. just before you choose your next point)
The following simple example starts drawing a new polyline when the left mouse button is pressed and the mouse is moved by the minimum point distance of 20, with the button kept pressed. It draws the last polyline segment (to the current mouse position) in either red or green, depending on its length. If the mouse button is released and the length of the new segment is >= 20, a new point is appended to the polyline. Otherwise the polyline is terminated, and a new polyline can be created.
private Polyline polyline;
private Polyline segment = new Polyline { StrokeThickness = 2 };
private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (polyline == null)
{
var canvas = (Canvas)sender;
var point = e.GetPosition(canvas);
// create new polyline
polyline = new Polyline { Stroke = Brushes.Black, StrokeThickness = 2 };
polyline.Points.Add(point);
canvas.Children.Add(polyline);
// initialize current polyline segment
segment.Stroke = Brushes.Red;
segment.Points.Add(point);
segment.Points.Add(point);
canvas.Children.Add(segment);
}
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (polyline != null)
{
// update current polyline segment
var canvas = (Canvas)sender;
segment.Points[1] = e.GetPosition(canvas);
var distance = (segment.Points[0] - segment.Points[1]).Length;
segment.Stroke = distance >= 20 ? Brushes.Green : Brushes.Red;
}
}
private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (polyline != null)
{
var canvas = (Canvas)sender;
segment.Points[1] = e.GetPosition(canvas);
var distance = (segment.Points[0] - segment.Points[1]).Length;
if (distance >= 20)
{
polyline.Points.Add(segment.Points[1]);
segment.Points[0] = segment.Points[1];
}
else
{
if (polyline.Points.Count < 2)
{
canvas.Children.Remove(polyline);
}
polyline = null;
segment.Points.Clear();
canvas.Children.Remove(segment);
}
}
}
please maintain a collection of points on every click. in collection you can add one class which will have two properties like StartPoint and EndPoint.
when the mouse is clicked first time just add one class object to collection having start point only.
and when you click the mouse next time, ad end point to the last object of the class and meanwhile create a new object and assign this point as its start point and add it to collection, after that call the paint function.

Categories

Resources