Image rotation moving resulting image unpredictably - c#

I've been looking all over SO today and I can't get anything to work for my needs.
I have a web application that let's users drag and drop text/images and then it sends the details to the server to draw those to a pdf. I'm trying to enable rotation, but I can't get a hold of the translatetransform stuff. My image in testing prints out great, rotated well, but it is not in the correct location. I'm missing how the intitial translatetransform changes things and my mind is shot at the end of the day. Do I have to draw this as a bitmap first using a different graphics instance, and then draw that bitmap to my background? Any help on this would be great! Thanks!
CODE:
i is the image object from the browser
coord is the x & y of the upper corner of the image on the canvas (990wx1100h) on the browser
size is the h & w of the element on the browser
Bitmap b = new Bitmap(wc.OpenRead(i.img));
if (i.rotation != 0)
{
g.TranslateTransform(this.CanvasDetails.size.width/2, this.CanvasDetails.size.height/2);
g.RotateTransform(i.rotation);
g.DrawImage(b, new Rectangle(- i.coord.x/2, -i.coord.y/2, i.size.width, i.size.height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
}
else
{
g.DrawImage(b, new Rectangle(i.coord.x, i.coord.y, i.size.width, i.size.height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
}
EDIT
I added the translatransform reversal as suggested by Adam, but the image is still drawn in a different location.
g.TranslateTransform(this.CanvasDetails.size.width / 2, this.CanvasDetails.size.height / 2);
g.RotateTransform(i.rotation);
g.TranslateTransform(-this.CanvasDetails.size.width / 2, -this.CanvasDetails.size.height / 2);
g.DrawImage(b, new Rectangle(-i.coord.x / 2, -i.coord.y / 2, i.size.width, i.size.height), 0, 0, b.Width, b.Height, GraphicsUnit.Pixel, ia);
Examples:
Browser View
.NET drawn version

Ok, completely reworking this answer to try to explain it clearer. A couple of things to know are that transformations 'accumulate' and rotation transforms happen around the origin. So to just explain the affect of accumulating (multiplying) transforms, look at this example:
//draw an ellipse centered at 200,200
g.DrawEllipse(Pens.Red, 195, 195, 10, 10);
//apply translate transform - shifts origin to 200,200
g.TranslateTransform(200, 200);
//draw another ellipse, should draw around first ellipse
//because translate tranforms essentially moves our coordinates 200,200
g.DrawEllipse(Pens.Blue, -7, -7, 14, 14);
//now do rotate transform
g.RotateTransform(90f); //degree to rotate object
//now, anything we draw with coordinates 0,0 is actually going to be draw at 200,200 AND be rotated by 45*
//this line will be vertical, through 200,200, instead of horizontal through 0,0
g.DrawLine(Pens.Green, -20,0,20,0);
//If we add another translate, this time 50x, it would normally translate by 50 in the X direction
//BUT - because we already have transforms applied, including the 90 rotate, it affects this translation
//so this in effect because a 50px translation in Y, because it's rotated 90*
g.TranslateTransform(50, 0);
//so even though we translated 50x, this line will draw 50px below the last line
g.DrawLine(Pens.Green, -20, 0, 20, 0);
So for your case, you want to draw an object Centered at CenterPoint and rotated by Angle. So you would do:
g.TranslateTransform(-CenterPoint.X, -CenterPoint.Y);
g.RotateTransform(Angle);
g.DrawImage(b, -ImageSize/2, -ImageSize/2, ImageSize, ImageSize);
You'd then need to reset the transforms for additional drawing, which you can do with:
g.ResetTransform();
If that doesn't leave the image where you want it, then you'll need to check the values you're using to position it. Are you storing it's center? Or top left? Etc.

Related

Get clicked coordinates on rotated image

I don't have a great concept on matrix math, so the other questions I have found have confused me, and I would like to know how to use Win2D-provided items to solve this issue.
I am creating a pixel art editor. I have an image, for simplicity sake, 2x2 pixels. In the editor, this image is scaled and rotated based on user interaction so that they may edit it. To make it rotate about it's center, I have also applied a translation. Here is my code to transform a 2x2 image into a rotated, scaled image which is rendered on the screen:
Matrix3x2 rotateMatrix = Matrix3x2.CreateRotation((float)(Rotation * Math.PI / 180));
Matrix3x2 scaleMatrix = Matrix3x2.CreateScale(Scale);
Matrix3x2 translationMatrix = Matrix3x2.CreateTranslation(-(float)layer.Height / 2, -(float)layer.Width / 2);
Matrix3x2 transformation = translationMatrix * rotateMatrix * scaleMatrix;
This correctly draws my image on the screen. To allow the user to pan around the editor, there are also two additional translations happening with the rendered image, OffsetX and OffsetY, as seen here:
ICanvasImage image = new Transform2DEffect
{
Source = source,
TransformMatrix = transformation,
InterpolationMode = CanvasImageInterpolation.NearestNeighbor
};
ctx.DrawImage(image, new Vector2(OffsetX, OffsetY));
So the rotated, scaled image is drawn at center (OffsetX, OffsetY). All works fine.
Now I need to translate a screenspace click into an imagespace click. For example, if a user clicks the canvas at (300, 400), and the image is rotated and scaled and translated in such a way that the pixel at (0, 1) is under the cursor visually, I need to be able to translate (300, 400) into (0, 1).

c# draw an arc in a rectangle

Spiral:
I have coded squares in C# based on the Fibonacci series exactly as shown in the included image. The problem I am having is trying to draw the arcs. I am not sure if I should be using arcs, curves or bezier curves. I assume an arc is what I want, but I have been unable to get the results I am trying for.
If someone could show me an example of how to draw an arc from corner to corner within a square it would be very much appreciated. I just hard coded the squares for fun. I want to try to write an algorithm to generate them, but right now I am stumped by the behavior of the arcs.
Bitmap bmp = new Bitmap(50, 50);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawArc(Pens.Black, new Rectangle(0, 0, 100, 100), 0, 90);
}
Parameters
Stroke color
Bounding box for the circle the arc would be part of
Starting angle (in degrees)
Ending angle (in degrees)
The arc is drawn clockwise from the starting arc. To do a counterclockwise arc, supply a negative value for the ending angle.
Bitmap bmp = new Bitmap(50, 50);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawArc(Pens.Black, new Rectangle(0, 0, 100, 100), 0, 90);
}
It seems the bounding box must be twice the size of the square in order for the arc to go from corner to corner.
Curve
The "rectangle" is a square. The center of the arc is a corner, the radius is a side, the starting angle is a multiple of 90° and the sweep angle is 90°. No rocket science.

Lines represented as long thin triangles are not visble in 3D?

I am trying to draw a 3D line in wpf and I have this xaml code:
<Grid>
<Viewport3D x:Name="ViewerViewport"
RenderOptions.BitmapScalingMode="HighQuality"
Focusable="True" Grid.RowSpan="2">
<ModelVisual3D x:Name="Model">
</ModelVisual3D>
<!-- Camera -->
<Viewport3D.Camera>
<PerspectiveCamera x:Name="Camera"
Position="0,0,0"
LookDirection="0,1,0"
UpDirection="0,0,1"
FieldOfView="100"
FarPlaneDistance="10"
NearPlaneDistance="0.1"/>
</Viewport3D.Camera>
</Viewport3D>
</Grid>
and this c# code:
public MainWindow()
{
InitializeComponent();
var ModelsGroup = new Model3DGroup();
ModelsGroup.Children.Add(this.AddLine(new Point3D(0, 0, 100), new Point3D(0, 100, 100),"line 1)"));
ModelsGroup.Children.Add(new AmbientLight(Colors.White));
Model.Content = ModelsGroup;
}
and line creation code:
private Model3D AddLine(Point3D startPoint, Point3D EndPoint, string name)
{
SolidColorBrush brush = new SolidColorBrush(Colors.Black);
var material = new DiffuseMaterial(brush);
var mesh = new MeshGeometry3D();
mesh.Positions.Add(startPoint);
mesh.Positions.Add(EndPoint);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(0);
return new GeometryModel3D(mesh, material);
}
but it doesn't show any line in output?
What is wrong with this?
I know that there are some 3d libraries that can do this easily, but I like to learn how to do it in WPF and then investigate how to do this using libraries (such as helix3d)
You are creating a triangle where two corners are at the same point, that is a triangle with zero area so it can never be seen from any angle. WPF uses only triangles with area
To create a line you must make a rectangle the length and width of the line, and split it with a diagonal to create two narrow triangles. So you need four positions and two triangles, like "0 1 2 0 1 3". Then of course you must make sure that the orientation of this rectangle is so that it is facing the camera.
You can google or bing for helix toolbox which is an excellent library of utilities for 3D in WPF. There you might find a useful helper function.
Why do you want to draw just line. In 3D you usually need triangles. If you have triangle you can determine normals. They are used to define facing of triangle which is used in lighting and texturing.
Camera settings
Typical camera Position is somewhere in positive z coordinates (something like 0, 0, 2 or 5, 0, 20), LookDirection vector is 0, 0, -1 and UpDirection vector is 0, 1, 0. In this case axes should be positioned as they usually are (positive y axis goes up and positive x axis goes to the right).
If you change UpDirection to 1, 0, 0 then positive x axis goes up not y axis.
If you change Position to negative z coordinates (0, 0, -5) and LookDirection to 0, 0, 1 then you look at your sceen from "behind" so positive x axis goes to the left (not to the right) but y axis still goes up.
In your settings your camera is pointing to the positive y numbers from origin and z axis goes up. X axis still goes to the right. If I add third point to your code. Point 100, 0, 100, than you can see small black triangle.
mesh.Positions.Add(startPoint);
mesh.Positions.Add(endPoint);
mesh.Positions.Add(new Point3D(100, 0, 100));
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
This triangle is small because of distance from camera - 100. So as #Samuels says in comment another error in settings is FarPlaneDistance="10".
you're building lines with no thickness....actually this and pixel coloring are the 2 most important problems of WPF....
If you want to draw lines you'll have to build it as a quadrangle (2 connex triangles), if you want to get smarter and have a lower number of triangles you can use other tricks (I'll let you think about it ^^, but for a given mesh you can have a wireframe that has exactly the same number of triangles as your mesh, which would not be the case if you create quadrangles)

Open Gl Tao Framework rotating an group of object around their axes

I am making a 3d bicicle and a track. So far i draw them and animate their movements. However in the begining the whole track + bicicle rotated around the view. Like i am rotating the whole thing. Later i made so that the bicicles can rotate on their axes when changing directions. Whit the help of popmatrix and pushmatrix. Now when i try to rotate the view the track and the drivers dont rotate arrond the center axes but insted arround my camera. I tried to place them at the 0 coordinate rotate and put them back but it does not work at all.
Gl.glTranslatef(0, 0, -100);
Gl.glTranslatef(0, 0, 0);
Gl.glRotatef(rotate, 0, 1, 0);
Gl.glTranslatef(0, 0, -100);
I am using this before i draw any models. If i do it between only one model will rotate.
This seem to work. Dont know why.
Gl.glTranslatef(0, 0, zoom);
Gl.glRotatef(rotate, 0, 1, 0);

Rotate Text for printing

I am using a PrintDocument to print a page. At one point I want to rotate the text 90 degrees and print it ie print text vertically. Any ideas ???
g.RotateTransform(90);
does not work for OnPaint.
When you call RotateTransform you will need to pay attention to where the coordinate system ends up. If you run the following code, the "Tilted text" will appear to the left of the left edge; so it's not visible:
e.Graphics.Clear(SystemColors.Control);
e.Graphics.DrawString("Normal text", this.Font, SystemBrushes.ControlText, 10, 10);
e.Graphics.RotateTransform(90);
e.Graphics.DrawString("Tilted text", this.Font, SystemBrushes.ControlText, 10, 10);
Since you have tilted the drawing surface 90 degrees (clock wise), the y coordinate will now move along the right/left axis (from your perspective) instead of up/down. Larger numbers are further to the left. So to move the tilted text into the visible part of the surface, you will need to decrease the y coordinate:
e.Graphics.Clear(SystemColors.Control);
e.Graphics.DrawString("Normal text", this.Font, SystemBrushes.ControlText, 10, 10);
e.Graphics.RotateTransform(90);
e.Graphics.DrawString("Tilted text", this.Font, SystemBrushes.ControlText, 10, -40);
By default the coordinate system has its origo in the top left corner of the surface, so that is the axis around which RotateTransform will rotate the surface.
Here is an image that illustrates this; black is before call to RotateTransform, red is after call to RotateTransform(35):

Categories