C# How to scale rectangles with PictureBox? - winforms

I have a PictureBox and I draw rectangles on it.
I use SizeMode.Zoom property to scale my PictureBox
This is my code:
float width = (int)(Math.Abs(left - right) * ratio); // Resizing works good
float height = (int)(Math.Abs(top - bottom) * ratio);
float x = w / 2; // w, h - PictureBox.Width, PictureBox.Height
float y = h / 2; // The rectangle is always in the center
I want the rectangles to stick to the image.
How do I change the position of these rectangles when my PictureBox is resizing?
How to find out the position of a rectangle relative to the center of the box?
without sticking

Related

Texture mapping on a cylinder in C (building a raytracer)

This is my first question here so I hope I'm doing it right.
I'm trying to build a raytracer for a school project, and I'd like to add some texture mapping to my basic shapes. I already did it for the sphere and it worked perfectly, this is the algorithm I used (UV mapping):
d = vector3d_normalize(vector3d_sub(hit->point, object->position));
u = 0.5 + atan2(d.z, d.x) / M_PI * 0.5;
v = 0.5 - asin(d.y) / M_PI;
For the cylinder, I can't find any algorithm so I'm trying different things but I can't make it work. Actually, it works fine for a cylinder when it's fixed at (x: 0, y: 0, z: 0) but from the moment I'm moving it in space, the texture looks stretched.
For the code at this moment, it's the following:
d = vector3d_sub(hit->point, vector3d_mult(object->position, ray->direction));
u = 0.5 + atan2(d.z, d.x) / M_PI * 0.5;
v = d.y / M_PI;
v = v - floor(v);
Cylinder in (0, 0, 0):
With translation:
I'm stuck so if you have any idea, it could help me a lot!
Here's some pseudo-code from Jamis' Buck's The Ray Tracer Challenge (highly recommended):
// Based off of pseudocode from Jamis Buck: http://raytracerchallenge.com/bonus/texture-mapping.html
// Input: point on the cylinder. The cylinder is assumed to be of radius 1, centered at the origin and parallel with the y axis.
// Output: (u,v) with u and v both between 0 and 1.
// u will vary from 0 to 1 with the azimuthal angle, counter-clockwise.
// v will vary from 0 to 1 with whole units of y; note that the cylinder will have to be scaled by PI in the y axis to prevent stretching
map_cylinder_point_to_uv(point: (x: float, y: float, z: float)) -> (float, float) {
// compute the azimuthal angle, -PI < theta <= PI
float theta = arctan2(point.x, point.z);
// convert from radians to units
// -0.5 < rawU <= 0.5
float rawU = theta / (2 * Constants.PI)
// convert to correct scale, and flip it so that u increases with theta counter-clockwise
// 0 <= u < 1
float u = 1 - (rawU + 0.5);
// v will vary from 0 to 1 between whole units of y
// Use whatever modulus method or operator your language has to gauarantee a positive value for v.
// It's different for every programming language: https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages
float v = point.y % 1
return (u, v)
}
Your problem may have to do with the fact that you are placing a square texture on a cylinder, and the length of the texture applied to the side of a cylinder will be some multiple of 2 PI (the circumference of a circle). You may be able to fix your issue by simply scaling the cylinder in the y axis by PI or 2 PI.
If you don't want to be limited to cylinders of particular dimensions, and you have a texture that can be repeated like a checker pattern, then you can scale v to prevent stretching. Replace the v calculation above with this line, instead:
// let v go from 0 to 1 between 2*pi units of y
let v = point.y % (2 * Constants.PI) * 1 / (2 * Constants.PI);
I'll also note that these days there's also a separate stack exchange for computer graphics that might be of more help than SO: https://computergraphics.stackexchange.com/.

How to render 3D axes given pitch, roll, and yaw?

I'm attempting to render a simple axes display like the following, except using simple 2D lines.
I have angle values for the pitch, yaw, and roll that the axes should display. (e.g. PI/2, PI/4, PI*3/2)
I have a function that can render 2D lines given start and end points in 2D space.
How can I properly render a rotated set of axes given the angles? I don't care about z-indexing (so if sometimes the lines incorrectly show up on top of each other, that is OK as long as they point the correct direction).
What I've tried
I know that the start points for all the lines will just be in the center of the axis, and we'll say the center is at (0, 0) and the length of the axes will be 100. That leaves me to calculate the endpoints for each of the 3 axes.
I have defined the X axis to be left-to-right, the Y axis to be up-and-down and the Z axis to be back-forward (i.e. out of the screen).
Pitch is rotation around the X axis, roll is rotation around Z axis, and yaw is rotation around Y axis.
To calculate the X-axis end point I've done:
x = cos(roll) * cos(yaw) * 100;
y = sin(-roll) * 100;
To calculate the Y-axis end point I've done:
x = cos(roll + PI/2) * 100;
y = sin(-roll - PI/2) * sin(PI/2 - pitch) * 100;
To calculate the Z-axis end point I've done:
x = cos(PI/2 - yaw) * 100;
y = sin(PI - pitch) * 100;
It's probably evident that I don't really know what I'm doing. I feel like I am taking a very naive approach when I should be using something more advanced like matrices. If it makes a difference, I'm using C, but psuedocode is fine. Any help would be appreciated.
First, you need to agree on an order of the rotations. In the following, I assume the order x, y, z (pitch, yaw, roll).
The end points are simply the column vectors of the according rotation matrix. Then, you need to project the 3d points onto the 2d screen. It seems as if you use a simple orthogonal projection (removing the z-coordinate). So here are the results:
x1 = 100 (cos yaw * cos roll)
y1 = 100 (cos pitch * sin roll + cos roll * sin pitch * sin yaw)
x2 = 100 (-cos yaw * sin roll)
y2 = 100 (cos pitch * cos roll - sin pitch * sin yaw * sin roll)
x3 = 100 (sin yaw)
y3 = 100 (-cos yaw * sin pitch)

Finding the angle a vector makes over variable axes

The typical way to find the angle a vector makes from the x axis (assuming the x axis runs left to right, and the y axis runs bottom to top) is:
double vector_angle = atan2( y , x )
However, I want my axes to have their origin at a point on a circle so that the x axis runs from the point on the edge of the circle through the centre of the circle, and the y axis runs tangent to the circle at that point (which would thus be perpendicular to the x axis).
Assumedly the code would still be the same, but now adjusted by a distance k and an angle theta, perhaps:
double y_position = ( y + k ) * theta;
double x_position = ( x + k ) * theta;
double vector_angle = atan2( y_position, x_position );
But I'm not sure about this. This is a generalised problem for a touch-based application where I would like to have a general way to move a sprite (in cocos2d) using swipe motions which is always a constant distance from the center of a circle.
Here, B is the origin of the vector which could be transformed by a rotation theta. For example, if we transformed the circle and point B by 90 degrees, B would be at (4, 0) and the line B->A would be along the axis at 4 (y = 4). I would like to get the angle in node-space of point B, when under transform.
Arctan returns the correct angle for the vector where the "x axis" is the line perpendicular to your tangent.

Calculating radials of a shape

I'm traing to identify road-sign shapes using radials.
I have the center point of the shape and I must find 7 radials to identify the figure.
To find 7 radials I must find points at 0º, 30º, 60º and 90º, like in the following image (image a):
https://lh4.googleusercontent.com/-sFsGXGD9VGI/TqxRjwIoSPI/AAAAAAAAAD0/yUOhN7RNUhU/s445/radiais.png
The problem is, I don't know how to find a point that is on 30º from my center.
Look, on my first implamentation I was calculating 5 radials (0º, 45º and 90º), like image b:
To find the points at 0º I did:
//fix the y coordinate and increment x coord
for(x = center.x to width)
pixel(x, center.y)
To find the points at 90º I did:
//fix the x coordinate and increment y coord
for(y = center.y to height)
pixel(center.x, y)
To find the points at 45º I did:
//increment x and y coord in the same number
for(x = center.x, y = center.y to width, height)
pixel(x, y)
So, I want to know how to access points at 30º and 60º.
ps.: sorry, a cannot post images yet! no reputation.
You can use the polar coordinate system. Here's a pseudocode:
theta = 30 * pi / 180 // 30, 60, whatever
for r = 0 to length_of_line
x = center.x + r * cos(theta)
y = center.y + r * sin(theta)
pixel(x, y)
This way you can draw radials with inclination of 12, 16, 94.7362, ... degree

Computing "average" of two colors

This is only marginally programming related - has much more to do w/ colors and their representation.
I am working on a very low level app. I have an array of bytes in memory. Those are characters. They were rendered with anti-aliasing: they have values from 0 to 255, 0 being fully transparent and 255 totally opaque (alpha, if you wish).
I am having trouble conceiving an algorithm for the rendering of this font. I'm doing the following for each pixel:
// intensity is the weight I talked about: 0 to 255
intensity = glyphs[text[i]][x + GLYPH_WIDTH*y];
if (intensity == 255)
continue; // Don't draw it, fully transparent
else if (intensity == 0)
setPixel(x + xi, y + yi, color, base); // Fully opaque, can draw original color
else { // Here's the tricky part
// Get the pixel in the destination for averaging purposes
pixel = getPixel(x + xi, y + yi, base);
// transfer is an int for calculations
transfer = (int) ((float)((float) (255.0 - (float) intensity/255.0) * (float) color.red + (float) pixel.red)/2); // This is my attempt at averaging
newPixel.red = (Byte) transfer;
transfer = (int) ((float)((float) (255.0 - (float) intensity/255.0) * (float) color.green + (float) pixel.green)/2);
newPixel.green = (Byte) transfer;
// transfer = (int) ((float) ((float) 255.0 - (float) intensity)/255.0 * (((float) color.blue) + (float) pixel.blue)/2);
transfer = (int) ((float)((float) (255.0 - (float) intensity/255.0) * (float) color.blue + (float) pixel.blue)/2);
newPixel.blue = (Byte) transfer;
// Set the newpixel in the desired mem. position
setPixel(x+xi, y+yi, newPixel, base);
}
The results, as you can see, are less than desirable. That is a very zoomed in image, at 1:1 scale it looks like the text has a green "aura".
Any idea for how to properly compute this would be greatly appreciated.
Thanks for your time!
You need to blend the background and foreground colours. A-la:
pixelColour = newColour * intensity + backgroundColour * (1 - intensity)
By the way, this is a really slow way of rendering and blending fonts. You should instead render all the characters of the font to an off-screen surface with all the properties you need, and then use that as a texture to render to other surfaces when you need text.
Edit:
This doesn't look right:
(255.0 - (float) intensity/255.0)
It should instead be:
(255.0 - (float) intensity)/255.0
I believe that "aura" is caused by anti aliasing. The technique averages pixels with their neighbors.
I realize you don't seem to be using OpenGL but this chapter might help explain some of the theory. Wish I had a better answer, but hopefully this points you in the right direction. My first attempt would be to disable Antialiasing since it seems to do more harm than good. There is probably a better solution than that though.
It may be too much complicated to doing alpha blending pixel by pixel because current pixel value modifies next pixel value.
I would redesign the algorithm with the thinking of box wise blending.
With many getPixel calling for a single glyph, you can't produce proper target image.

Resources