Getting new position of a line after rotation - wpf

I need to find out new coordinates of line after rotation using RotateTransform method on a line.
For example, after this line:
line.RenderTransform = new RotateTransform(25, 0, 0);
line.X1 and the three other properties don't change. I have found some solution for shapes like rectangular, but it doesn't work for line. Line has different way how to treat with it.
EDIT: Thanks for your help H.B. The second way is exactly what I've been looking for.
SOLUTION:
Line line = new Line();
line.X1 = 10;
line.Y1 = 10;
line.X2 = 20;
line.Y2 = 30;
RotateTransform rotation = new RotateTransform();
Point p1 = rotation.Transform(new Point(line.X1, line.Y1));
Point p2 = rotation.Transform(new Point(line.X2, line.Y2));
line.X1 = p1.X;
line.Y1 = p1.Y;
line.X2 = p2.X;
line.Y2 = p2.Y;
This code rotates the line and sets a new values of coordinates to attached properties of this line.

You can transform points on their own:
var transform = new RotateTransform(25, 0, 0);
var newP1 = transform.Transform(new Point(line.X1,line.Y1));
//...
If you want a permanent transformation you can transform the start and end points and assign the new values to the respective properties.

Related

WPF-Rendering with TranslateTransform and Label

i do have the following Code:
private static void AddElements(Canvas canvas)
{
double canvasHeight = canvas.Height;
double canvasWidth = canvas.Width;
double y0 = canvasHeight / 2;
double x0 = canvasWidth / 2;
// Defining the new Coordinate-Point (0,0) to mid auf Canvas
TranslateTransform tt = new TranslateTransform(x0, y0);
Line line1 = new Line();
line1.X1 = -350;
line1.Y1 = 0;
line1.X2 = 350;
line1.Y2 = 0;
line1.Stroke = Brushes.Black;
line1.StrokeThickness = 2.0;
line1.RenderTransform = tt;
canvas.Children.Add(line1);
Line line2 = new Line();
line2.X1 = 0;
line2.Y1 = -350;
line2.X2 = 0;
line2.Y2 = 350;
line2.Stroke = Brushes.Black;
line2.StrokeThickness = 2.0;
line2.RenderTransform = tt;
canvas.Children.Add(line2);
Label lblN = new Label();
lblN.Width = 50;
lblN.Background = Brushes.Red;
lblN.Margin = new System.Windows.Thickness(0, -350, 0, 0);
lblN.Content = $"N";
lblN.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
lblN.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
lblN.RenderTransform = tt;
lblN.Padding = new System.Windows.Thickness(0);
lblN.BorderBrush = Brushes.Black;
lblN.BorderThickness = new System.Windows.Thickness(2.0);
lblN.RenderTransform = tt;
canvas.Children.Add(lblN);
Label lblS = new Label();
lblS.Width = 50;
lblS.Background = Brushes.Red;
lblS.Margin = new System.Windows.Thickness(0, 350, 0, 0);
lblS.Content = $"S";
lblS.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
lblS.VerticalContentAlignment = System.Windows.VerticalAlignment.Center;
lblS.RenderTransform = tt;
lblS.Padding = new System.Windows.Thickness(0);
lblS.BorderBrush = Brushes.Black;
lblS.BorderThickness = new System.Windows.Thickness(2.0);
lblS.RenderTransform = tt;
canvas.Children.Add(lblS);
}
this method is called on an Menu-Eventhandler and it shows an coordinate system with (0,0) in the mid of the canvas. It should show a label with "N" at the top and a label with "S" at the bottom.
But i shows the attached image
Does anyone know, why lblN looks different than lblS ?
best regards
Volkhard
=============
if i set the height of both Label-Objects to 15
lblN.Height=15
:
lblS.Height=15
i get the following:
i expected the lblN to be more upper on the y-coordinate.
What's causing it
Through a bit of testing, I can definitely say that it's the lblN.Margin = new System.Windows.Thickness(0, -350, 0, 0); that's causing the problem. Apparently, when you give a Label a negative margin like that, it will move upwards only as far is it's Height, and then it will start expanding instead of just continuing to move. So you end up with a Label that's 350 tall. We could try to figure out why that is, but really, that would be missing the point.
Admittedly, I don't have any direct documentation to back up the following statement this, but from years of experience in WPF I feel I can say:
Margin is intended to be used to give space between elements in a dynamic layout, not to give an element an absolute position.
This behavior of the Label seems to strengthen the idea that using Margin in this way was not something that was planed for by the designers.
What you should do instead
Canvas has tools for giving an element a set position, yet nowhere do you use Canvas's SetLeft, SetTop, SetRight, or SetBottom. Take a look at the example on MSDN. You shouldn't need to use a TranslateTransform or set Margin at all. Instead, you should calculate where you want the element to be and use one of the above four listed methods to assign that position.
Extra Tip
Don't use canvas.Height and canvas.Width, use canvas.ActualHeight and canvas.ActualWidth instead. The first pair only work if you are explicitly setting the size of the Canvas (which it seems you are). But in a senario where the Canvas is dynamically sized, the first pair will be NaN. The second pair always return the actual size that the Canvas is.
This doesn't make a difference in your current use case, but it might later on. If you're doing calculations based on the actual size of an element (as opposed to the size you might want it to be), always use ActualHeight and ActualWidth.

CAShapeLayer with shaded area below

I am drawing a graph line using CAShapeLayer now I want to fill the area below of that line created by CAShapeLayer, ?I have tried CAShapeLayer shadow, gradient but it doesn't work, Please guide me the correct way to achieve this. My code is below:
//1. Create bezier path from first point to second.
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:firstPoint];
[path addLineToPoint:secondPoint];
//2. Create a shape layer for above created path.
myLayer = [[CAShapeLayer alloc] init];
myLayer.strokeColor = [[UIColor whiteColor] CGColor];
myLayer.lineWidth = 3.0;
myLayer.lineJoin = kCALineJoinRound;
myLayer.lineCap = kCALineCapRound;
myLayer.shadowColor = [UIColor redColor].CGColor;
myLayer.path = path.CGPath;
myLayer.shadowOpacity = 0.8;
myLayer.shadowRadius = 12;
myLayer.masksToBounds = NO;
myLayer.shadowOffset = CGSizeMake(-15, 20);
myLayer.shadowRadius = 50;
myLayer.shadowOpacity = 0.5;
[drawnLayersArray addObject:myLayer];
[self.scroll.layer addSublayer:myLayer];
Thanks

Drawing multiple lines with DrawLines and DrawLine produces different result

I am trying to draw multiple lines on a winforms panel using it's graphics object in paint event. I am actually drawing a number of lines joining given points. So, first of all I did this,
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLines(new Pen(new SolidBrush(Color.Crimson), 3), PointFs.ToArray());
float width = 10;
float height = 10;
var circleBrush = new SolidBrush(Color.Crimson);
foreach (var point in PointFs)
{
float rectangleX = point.X - width / 2;
float rectangleY = point.Y - height / 2;
var r = new RectangleF(rectangleX, rectangleY, width, height);
e.Graphics.FillEllipse(circleBrush, r);
}
}
Which produces a result like the image below,
As you can see lines are drawn with having a little bit of extension at sharp turns, which is not expected. So, I changed the drawlines code to,
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
for (int i = 1; i < PointFs.Count; i++)
{
e.Graphics.DrawLine(pen, PointFs[i - 1], PointFs[i]);
}
And now the drawing works fine.
Can anyone tell the difference between the two approaches?
I have just had the same problem (stumbled upon this question during my research), but I have now found the solution.
The problem is caused by the LineJoin property on the Pen used. This DevX page explains the different LineJoin types (see Figure 1 for illustrations). It seems that Miter is the default type, and that causes the "overshoot" when you have sharp angles.
I solved my problem by setting the LineJoin property to Bevel:
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
pen.LineJoin = Drawing2D.LineJoin.Bevel;
Now DrawLines no longer overshoot the points.

Convert triangleindices to Point3d, then display as lines

I import a model using the Helix3d toolkit. Next, I perform a hit-test on the 3Dmodel. ThenI get the MeshGeometry3D information from rayMeshResult.Meshit. Finally I get the vertex position information, and triangleIndices from the MeshGeometry3D. Now I clone the points from LinesVisual3D, and then I feed the triangleIndices/vertex info into the clone. Finally, I copy the clone's point data into LinesVisual3D.Points, and add the lines to my viewport.
As you can see from the picture at the link, not all of the edges of the cube are drawn, yet all of the points are there.
http://www.freeimagehosting.net/fhws5
GeometryModel3D hitgeo = rayMeshResult.ModelHit as GeometryModel3D;
MeshGeometry3D newGeom = rayMeshResult.MeshHit as MeshGeometry3D;
Point3DCollection srtpnt = modelLines.Points.Clone();
for (int i = 0; i < newGeom.TriangleIndices.Count; i ++)
{
srtpnt.Add(newGeom.Positions[newGeom.TriangleIndices[i]]);
textBlock4.Text += newGeom.Positions[newGeom.TriangleIndices[i]].ToString() + "\n";
}
modelLines.Points = srtpnt;
modelPoints.Points = srtpnt;
modelPoints.Color = Colors.Red;
modelPoints.Size = 15;
modelLines.Thickness = 6;
modelLines.Color = Colors.Blue;
MainViewport.ClearChildren();
MainViewport.Children.Add(modelLines);
MainViewport.Children.Add(modelPoints);
UpdateResultInfo(rayMeshResult);

WPF transform confusion

I Have a canvas full of objects that I zoom and pan using
this.source = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
this.zoomTransform = new ScaleTransform();
this.transformGroup = new TransformGroup();
this.transformGroup.Children.Add(this.zoomTransform);
this.transformGroup.Children.Add(this.translateTransform);
this.source.RenderTransform = this.transformGroup;
I then have a method that moves the canvas to a a certain point (in the original coordinates) to the center of the screen:
public void MoveTo(Point p)
{
var parent= VisualTreeHelper.GetParent(this) as FrameworkElement;
Point centerPoint = new Point(parent.ActualWidth / 2, parent.ActualHeight / 2);
double x = centerPoint.X - p.X;
double y = centerPoint.Y - p.Y;
x *= this.zoomTransform.ScaleX;
y *= this.zoomTransform.ScaleY;
this.translateTransform.BeginAnimation(TranslateTransform.XProperty, CreatePanAnimation(x), HandoffBehavior.Compose);
this.translateTransform.BeginAnimation(TranslateTransform.YProperty, CreatePanAnimation(y), HandoffBehavior.Compose);
}
private DoubleAnimation CreatePanAnimation(double toValue)
{
var da = new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(300)));
da.AccelerationRatio = 0.1;
da.DecelerationRatio = 0.9;
da.FillBehavior = FillBehavior.HoldEnd;
da.Freeze();
return da;
}
Everything works great until I actually have a zoom animation active after which the pan animation is inaccurate. I've tried different ways of calculation x,y and the centerpoint but can't seem to get it right. Any help appreciated, should be simple :)
I'd also like to make a method that both animates zooming and pans to a point, a little unsure on the ordering to accomplish that
Nevermind, I'm stupid
Point centerPoint = new Point(parent.ActualWidth / 2 / this.zoomTransform.ScaleX, parent.ActualHeight / 2 / this.zoomTransform.ScaleY);
I am still interested in how I can combine the scale and zoom animations though
this.translateTransform.BeginAnimation(TranslateTransform.XProperty, CreatePanAnimation(x), HandoffBehavior.Compose);
this.translateTransform.BeginAnimation(TranslateTransform.YProperty, CreatePanAnimation(y), HandoffBehavior.Compose);
this.zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty, CreateZoomAnimation(factor));
this.zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty, CreateZoomAnimation(factor));
wont work since the scale and pan values wont be synced...

Resources