I can rotate an image by:
RotateTransform aRotateTransform = new RotateTransform();
aRotateTransform.CenterX = 0.5;
aRotateTransform.CenterY = 0.5;
tateTransform.Angle = rotationAngle;
ImageBrush bgbrush = new ImageBrush();
bgbrush.RelativeTransform = aRotateTransform;
ScaleTransform s = new ScaleTransform();
s.ScaleX = -1; // how to set without overriding the rotation?
...
How can I scale it in addition? I tried using matrices without success.
You could use a TransformGroup like so:
TransformGroup tg = new Transformgroup();
tg.Children.Add(rotateTransform);
tg.Children.Add(scaleTransform);
bgbrush.RelativeTransform = tg;
You could use a CompositeTransform, it combines translation, rotation and scaling in a single matrix.
Just for completeness. Using Matrix transformations, you would get the expected result by this:
var transform = Matrix.Identity;
transform.RotateAt(rotationAngle, 0.5, 0.5);
transform.Scale(-1, 1);
bgbrush.RelativeTransform = new MatrixTransform(transform);
However, I guess that actually you want to keep the image centered, so you might use ScaleAt instead of Scale:
var transform = Matrix.Identity;
transform.RotateAt(rotationAngle, 0.5, 0.5);
transform.ScaleAt(-1, 1, 0.5, 0.5);
bgBrush.RelativeTransform = new MatrixTransform(transform);
If you just need to rotate the Brush it self and put it into a rectangle later without having to adjust anything else, this worked for me:
// Get the image from somewhere...
ib = new ImageBrush(bmp);
// Here I get it from a larger texture picture.
ib.Viewbox = this.GetVBRect(1728, 634);
ib.Transform = new RotateTransform()
{
CenterX = 0.5,
CenterY = 0.5,
Angle = 180,
};
ib.TileMode = TileMode.Tile;
Related
I'm trying to understand rules of WPF animation usying code from this site:
https://www.codeproject.com/Articles/23257/Beginner-s-WPF-Animation-Tutorial
Now I have a code to rotate element around x, y point:
RotateTransform rt = new RotateTransform();
DoubleAnimation da = new DoubleAnimation();
da.From = 0;
da.To = 360;
da.Duration = new Duration(TimeSpan.FromSeconds(10));
da.RepeatBehavior = RepeatBehavior.Forever;
image.RenderTransformOrigin = new Point(x, y);
image.RenderTransform = rt;
rt.BeginAnimation(RotateTransform.AngleProperty, da);
This is GIF image like "^", so I want to rotate it 90 deg BEFORE animation to rotate image like ">".
Tried RotateTransform rt = new RotateTransform(90); but no success.
Any suggestions?
Besides setting the Angle property of rt to 90, you should also change the From property of da to 90 to start animating from this value:
RotateTransform rt = new RotateTransform(90);
...
da.From = 90;
I have an ellipse in the middle of a Canvas using this code:
var FixedCircle = new Ellipse
{
Width = 25,
Height = 25,
Stroke = color,
Fill = color,
StrokeThickness = 3
};
var centerX = ActualWidth / 2;
var centerY = ActualHeight / 2;
FixedCircle.Margin = new Thickness(centerX, centerY, 1, 1);
Children.Add(FixedCircle);
InvalidateVisual();
I want to animate the ellipse, making it go from left and back to center (starting middle point).
I am setting coordinates (centerX,centerY) and (0,centerY) as starting and end points, also I am using the lines
Point oldPoint = FixedCircle.TransformToAncestor(this).Transform(new Point(centerX,centerY));
Point newPoint = FixedCircle.TransformToAncestor(this).Transform(new Point(0,centerY));
to indicate that transform must be set to starting pointg, I tried deleting this but the movement gets worse and starts from botton, or coordinate (0,0) is seen as the middle instead of (ActualWidth / 2, ActualHeight / 2) which is something I dont want.
TranslateTransform trans = new TranslateTransform();
FixedCircle.RenderTransform = trans;
Point oldPoint = FixedCircle.TransformToAncestor(this).Transform(new Point(centerX,centerY));
Point newPoint = FixedCircle.TransformToAncestor(this).Transform(new Point(0,centerY));
var EndX = FixedCircle.Width / 2 + newPoint.X - oldPoint.X - (FixedCircle.Width);
var EndY = FixedCircle.Height / 2 + newPoint.Y - oldPoint.Y - (FixedCircle.Height);
var a1X = new DoubleAnimation(0, EndX, TimeSpan.FromSeconds(3));
a1X.Completed += (s, e) =>
{
oldPoint = FixedCircle.TransformToAncestor(this).Transform(new Point(0, centerY));
newPoint = FixedCircle.TransformToAncestor(this).Transform(new Point(centerX, centerY));
EndX = FixedCircle.Width / 2 + newPoint.X - oldPoint.X - (FixedCircle.Width);
EndY = FixedCircle.Height / 2 + newPoint.Y - oldPoint.Y - (FixedCircle.Height);
var a2X = new DoubleAnimation(0, EndX, TimeSpan.FromSeconds(3));
trans.BeginAnimation(TranslateTransform.XProperty, a2X);
};
trans.BeginAnimation(TranslateTransform.XProperty, a1X);
The effect I get is ellipse correctly go from middle to left
then the issue of my problem, it starts in the middle and go to the right, when I need the ellipse to go from left to middle, not middle to right:
What am I missing?
The following code runs a repeated animation from middle to left and back. It uses a Path with an EllipseGeometry, because that is centered (instead of top/left aligned like an Ellipse). It also draws no stroke, but just adds the stroke thickness to the ellipse's radius.
var transform = new TranslateTransform(canvas.ActualWidth / 2, canvas.ActualHeight / 2);
var radius = 14;
var circle = new Path
{
Data = new EllipseGeometry(new Point(), radius, radius),
Fill = Brushes.White,
RenderTransform = transform
};
canvas.Children.Add(circle);
var animation = new DoubleAnimation
{
To = radius,
Duration = TimeSpan.FromSeconds(3),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever
};
transform.BeginAnimation(TranslateTransform.XProperty, animation);
For a repeated animation from right to left and back that starts at the center point, use a negative BeginTime:
var transform = new TranslateTransform(
canvas.ActualWidth - radius, canvas.ActualHeight / 2);
var animation = new DoubleAnimation
{
To = radius,
Duration = TimeSpan.FromSeconds(6),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever,
BeginTime = TimeSpan.FromSeconds(-3)
};
Currently I need to rotate a line about the midpoint based on angles generically. I have tried using Rotate Transform but it works finely for some angle but doest gives the exact result for some other angles. Kindly suggest if there any solution for rotation .
cx= (line.X1+line.2)/2;
cy=(line.Y1+line.Y2)/2;
RotateTransform transform = new RotateTransform();
transform.Angle = angle;
transform.CenterX = cx / zoomFactor;
transform.CenterY = cy / zoomFactor;
group.Children.Add(transform);
line.RenderTransform = group;
var cx = new Point( (line.X2 - line.X1)/2, (line.Y2 - line.Y1) / 2);
var rotate = new RotateTransform
{
Angle = angle
};
var translate = new TranslateTransform
{
X = (line.X1 + cx.X),
Y = (line.Y1 + cx.Y)
};
var group = new TransformGroup
{
Children =
{
(Transform) translate.Inverse,
rotate,
translate
}
};
line.RenderTransform = group;
So I was trying to set a scale and translation values to a wpf canvas render transform, and then draw some circles according to this new transformation matrix.
I have the code like this.
Setting the canvas render transform scale and translation properties.
window.canvas.RenderTransform.Value.Scale(xScale, yScale);
window.canvas.RenderTransform.Value.Translate(offsetX, offsetY);
and adding a circle like this.
Ellipse circle = new Ellipse()
{
Width = 5,
Height = 5,
Stroke = Brushes.Red,
StrokeThickness = 8
};
circle.SetValue(Canvas.LeftProperty, (double) x);
circle.SetValue(Canvas.TopProperty, (double) y);
window.canvas.Children.Add(circle);
But the canvas doesn't apply the transformation matrix on the circle points, what should I do?
The expression
window.canvas.RenderTransform.Value
returns a copy of the transform matrix, because struct Matrix is a value type, not a reference type. Any operation you perform on the copy is lost.
Use
var matrix = new Matrix();
matrix.Scale(xScale, yScale);
matrix.Translate(offsetX, offsetY);
window.canvas.RenderTransform = new MatrixTransform(matrix);
or just
window.canvas.RenderTransform =
new MatrixTransform(xScale, 0, 0, yScale, offsetX, offsetY);
In case a MatrixTransform was previously assigned to the RenderTransform property, you may also just set its Matrix value:
var matrix = new Matrix();
matrix.Scale(xScale, yScale);
matrix.Translate(offsetX, offsetY);
((MatrixTransform)window.canvas.RenderTransform).Matrix = matrix;
I'm trying to print a Image in Landscape mode in Silverlight.
I found a great example here. Where most of the code comes from. The code worked perfectly as expected. When I changed the Line to an Image it failed.
Code
Canvas OuterCanvas = new Canvas();
/* a container for everything that will print */
Border OuterBorder = new Border()
{
BorderThickness = new Thickness(3),
BorderBrush = new SolidColorBrush(Colors.Red),
Margin = new Thickness(10)
};
double Width = e.PrintableArea.Width - OuterBorder.Margin.Left - OuterBorder.Margin.Right;
double Height = e.PrintableArea.Height - OuterBorder.Margin.Top - OuterBorder.Margin.Bottom;
/* NOTE: We're trying to force landscape, so swop the width and height */
OuterBorder.Width = Height;
OuterBorder.Height = Width;
/* on portrait, this line goes down (leave the printer settings, we're trying to force landscape) */
Line Line = new Line()
{
X1 = OuterBorder.Width / 2,
Y1 = 0,
X2 = OuterBorder.Width / 2,
Y2 = OuterBorder.Height,
Stroke = new SolidColorBrush(Colors.Blue),
StrokeThickness = 3
};
//
// Here is where I changed the Line to an Image
//
OuterBorder.Child = imageElementInXaml; //Line;
OuterCanvas.Children.Add(OuterBorder);
/* rotate 90 degrees, and move into place */
var transformGroup = new TransformGroup();
transformGroup.Children.Add(new RotateTransform() { Angle = 90 });
transformGroup.Children.Add(new TranslateTransform() { X = e.PrintableArea.Width });
OuterBorder.RenderTransform = transformGroup;
e.PageVisual = OuterCanvas;
e.HasMorePages = false;
I know that a Border can only contain 1 element in which I have done so, and when I printed the image on its own without trying to make it landscape this worked too. So why wont it work when I simply replace the Line with the image Element
So since posting this I found some code (cant remember where now) that has helped me get the printing working. Its not as clean as I would have liked but it works.
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
Image image = new Image();
image.Source = imgPlayer.Source;
//This is important
image.Stretch = Stretch.Uniform;
// Find the full size of the page
Size pageSize = new Size(e.PrintableArea.Width + e.PageMargins.Left + e.PageMargins.Right, e.PrintableArea.Height + e.PageMargins.Top + e.PageMargins.Bottom);
var MARGIN= 10;
// Get additional margins to bring the total to MARGIN (= 96)
Thickness additionalMargin = new Thickness
{
Left = Math.Max(0, MARGIN - e.PageMargins.Left),
Top = Math.Max(0, MARGIN - e.PageMargins.Top),
Right = Math.Max(0, MARGIN - e.PageMargins.Right),
Bottom = Math.Max(0, MARGIN - e.PageMargins.Bottom)
};
// Find the area for display purposes
Size displayArea = new Size(e.PrintableArea.Width - additionalMargin.Left - additionalMargin.Right, e.PrintableArea.Height - additionalMargin.Top - additionalMargin.Bottom);
bool pageIsLandscape = displayArea.Width > displayArea.Height;
bool imageIsLandscape = image.ActualWidth > image.ActualHeight;
double displayAspectRatio = displayArea.Width / displayArea.Height;
double imageAspectRatio = (double)image.ActualWidth / image.ActualHeight;
double scaleX = Math.Min(1, imageAspectRatio / displayAspectRatio);
double scaleY = Math.Min(1, displayAspectRatio / imageAspectRatio);
// Calculate the transform matrix
MatrixTransform transform = new MatrixTransform();
if (pageIsLandscape == imageIsLandscape)
{
// Pure scaling
transform.Matrix = new Matrix(scaleX, 0, 0, scaleY, 0, 0);
}
else
{
// Scaling with rotation
scaleX *= pageIsLandscape ? displayAspectRatio : 1 / displayAspectRatio;
scaleY *= pageIsLandscape ? displayAspectRatio : 1 / displayAspectRatio;
transform.Matrix = new Matrix(0, scaleX, -scaleY, 0, 0, 0);
}
Image image2 = new Image
{
Source = image.Source,
Stretch = Stretch.Fill,
Width = displayArea.Width,
Height = displayArea.Height,
RenderTransform = transform,
RenderTransformOrigin = new Point(0.5, 0.5),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Margin = additionalMargin,
};
Border border = new Border
{
Child = image,
};
e.PageVisual = border;
}