I saw an example that uses the following to create a point that will be used to centre a window in Qt:
x = (screenWidth - WIDTH) / 2;
y = (screenHeight - HEIGHT) / 2;
Provided that screenWidth and screenHeight are found using the width() and height() functions respectively of QDesktopWidget.
How does the preceding code centre the window? Yes, I know it centres the window, but couldn't understand it from a calculation point of view.
Thanks.
First calculate the total amount of 'extra' horizontal space around your window:
extra_space = screenWidth - your_window_width
now, spread that space at left and right:
left_space + right_space = extra_space
the space at both sides should be the same:
right_space = left_space
==> 2 * left_space = extra_space
==> 2 * left_space = screenWidth - your_window_width
==> left_space = (screenWidth - your_window_width) / 2
that's your x. The same goes for the y coordinate.
Related
I have an interesting mathematical problem that I just cant figure out.
I am building a watch face for android wear and need to work out the angle of rotation for the hands based on the time.
Ordinarily this would be simple but here's the kicker: the hands are not central on the clock.
Lets say I have a clock face that measures 10,10
My minute hand pivot point resides at 6,6 (bottom left being 0,0) and my hour hand resides at 4,4.
How would I work out the angle at any given minute such that the point always points at the correct minute?
Thanks
Ok, with the help Nico's answer I've manage to make tweaks and get a working example.
The main changes that needed to be incorporated were changing the order of inputs to the atan calculation as well as making tweaks because of android's insistence to do coordinate systems upside down.
Please see my code below.
//minutes hand rotation calculation
int minute = mCalendar.get(Calendar.MINUTE);
float minutePivotX = mCenterX+minuteOffsetX;
//because of flipped coord system we take the y remainder of the full width instead
float minutePivotY = mWidth - mCenterY - minuteOffsetY;
//calculate target position
double minuteTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(minute * 6));
double minuteTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(minute * 6));
//calculate the direction vector from the hand's pivot to the target
double minuteDirectionX = minuteTargetX - minutePivotX;
double minuteDirectionY = minuteTargetY - minutePivotY;
//calculate the angle
float minutesRotation = (float)Math.atan2(minuteDirectionY,minuteDirectionX );
minutesRotation = (float)(minutesRotation * 360 / (2 * Math.PI));
//do this because of flipped coord system
minutesRotation = minutesRotation-180;
//if less than 0 add 360 so the rotation is clockwise
if (minutesRotation < 0)
{
minutesRotation = (minutesRotation+360);
}
//hours rotation calculations
float hour = mCalendar.get(Calendar.HOUR);
float minutePercentOfHour = (minute/60.0f);
hour = hour+minutePercentOfHour;
float hourPivotX = mCenterX+hourOffsetX;
//because of flipped coord system we take the y remainder of the full width instead
float hourPivotY = mWidth - mCenterY - hourOffsetY;
//calculate target position
double hourTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(hour * 30));
double hourTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(hour * 30));
//calculate the direction vector from the hand's pivot to the target
double hourDirectionX = hourTargetX - hourPivotX;
double hourDirectionY = hourTargetY - hourPivotY;
//calculate the angle
float hoursRotation = (float)Math.atan2(hourDirectionY,hourDirectionX );
hoursRotation = (float)(hoursRotation * 360 / (2 * Math.PI));
//do this because of flipped coord system
hoursRotation = hoursRotation-180;
//if less than 0 add 360 so the rotation is clockwise
if (hoursRotation < 0)
{
hoursRotation = (hoursRotation+360);
}
This also included a small helper function:
public double ConvertToRadians(double angle)
{
return (Math.PI / 180) * angle;
}
Thanks for your help all
Just calculate the angle based on the direction vector.
First, calculate the target position. For the minute hand, this could be:
targetX = radius * sin(2 * Pi / 60 * minutes)
targetY = radius * cos(2 * Pi / 60 * minutes)
Then calculate the direction vector from the hand's pivot to the target:
directionX = targetX - pivotX
directionY = targetY - pivotY
And calculate the angle:
angle = atan2(directionX, directionY)
I know that to draw a regular polygon from a center point, you use something along the lines of:
for (int i = 0; i < n; i++) {
p.addPoint((int) (100 + 50 * Math.cos(i * 2 * Math.PI / n)),
(int) (100 + 50 * Math.sin(i * 2 * Math.PI / n))
);
}
However, is there anyway to change this code (without adding rotations ) to make sure that the polygon is always drawn so that the topmost or bottommost edge is parallel to a 180 degree line? For example, normally, the code above for a pentagon or a square (where n = 5 and 4 respectively) would produce something like:
When what I'm looking for is:
Is there any mathematical way to make this happen?
You have to add Pi/2-Pi/n
k[n_] := Pi/2 - Pi/n;
f[n_] := Line[
Table[50 {Cos[(2 i ) Pi/n + k[n]] ,Sin[(2 i) Pi/n + k[n]]}, {i,0,n}]];
GraphicsGrid#Partition[Graphics /# Table[f[i], {i, 3, 8}], 3]
Edit
Answering your comment, I'll explain how I arrived at the formula. Look at the following image:
As you may see, we want the middle point of a side aligned with Pi/2. So ... what is α? It's obvious
2 α = 2 Pi/n (one side) -> α = Pi/n
Edit 2
If you want the bottom side aligned with the x axis, add 3 Pi/2- Pi/n instead ...
Add Math.PI / n to the angles.
Background: I have a bird view's JavaScript game where the player controls a space ship by touching a circle -- e.g. touch to the left of the circle center, and the ship will move left, touch the top right and it will move to the top right and so on... the further away from the circle center of pseudo joystick, the more speed in that direction. However, I'm not directly adjusting the ship's speed, but rather set a targetSpeed.x and targetSpeed.y value, and the ship will then adjust its speed using something like:
if (this.speed.x < this.targetSpeed.x) {
this.speed.x += this.speedStep;
}
else if (this.speed.x > this.targetSpeed.x) {
this.speed.x -= this.speedStep;
}
... and the same for the y speed, and speedStep is a small value to make it smoother and not too abrupt (a ship shouldn't go from a fast leftwards direction to an immediate fast rightwards direction).
My question: Using above code, I believe however that the speed will be adjusted quicker in diagonal directions, and slower along the horizontal/ vertical lines. How do I correct this to have an equal target speed following?
Thanks so much for any help!
var xdiff = targetSpeed.x - speed.x;
var ydiff = targetSpeed.y - speed.y;
var angle = Math.atan2(ydiff, xdiff);
speed.x += speedStep * Math.cos(angle);
speed.y += speedStep * Math.sin(angle);
Assuming you already checked that the touch is inside the circle, and that the edge of the circle represents max speed, and that the center of the circle is circleTouch == [0, 0]
In some C++-like pseudo code:
Scalar circleRadius = ...;
Scalar maxSpeed = ...;
Scalar acceleration = ...;
Vector calculateTargetSpeed( Vector circleTouch ) {
Vector targetSpeed = maxSpeed * circleTouch / circleRadius;
return targetSpeed;
}
Vector calculateNewSpeed( Vector currentSpeed, Vector targetSpeed ) {
Vector speedDiff = targetSpeed - currentSpeed;
Vector newSpeed = currentSpeed + acceleration * normalized(speedDiff);
return newSpeed;
}
// Divide v by its length to get normalized vector (length 1) with same x/y ratio
Vector normalized( Vector v ) {
return v / length(v);
}
// Pythagoras for the length of v
Scalar length( Vector v ) {
Scalar length = sqrt(v.x * v.x + v.y * v.y); // or preferably hypot(v.x, v.y)
return length;
}
This is just off the top of my head, and i haven't tested it. The other answer is fine, i just wanted to give an answer without trigonometry functions. :)
This is very programming related but a somewhat non-programming question. I am performing image scaling in a web based application and I need to maintain my image relative to a fixed location even though it scales anchored by its top, left corner. Hope the graphic make this possible.
The idea is that C is a fixed location that I want to maintain as my scaling origin rather than B which which is the current css behavior. C may or may not be within the actual image. So as the image scale, B needs to move relative to C. Example: if the image was scaled 50%, then B would move 1/2 the distance to C. If the image grew to 200% of its size, then B would move twice the distance away from C.
Ultimately looking for a formula for x & y for B given the location of C and a scaling factor for the image. Not sure the size of the image needs to be part of this but I have it if needed.
Thanks for any help!
Things I know:
I know the width and height of the
image rectangle.
I know the offset of B from A.
I know the offset of C from A.
I know the scale factor in percent of the image.
Effectively, you want to treat C as the origin, and just "move" B by the scaling amount. By treating it as a vector from C to B, and scaling it by the amount in question, you can do this fairly easily.
newBx = Cx - (Cx - Bx) * scale;
newBy = Cy - (Cy - By) * scale;
For example, with a scale of 0.5 (50%), this becomes:
newBx = 100 - (100 - 50) * 0.5
= 100 - 25
= 75 // 1/2 the distance to C
newBy = 100 - (100 - 25) * 0.5
= 100 - 37.5
= 62.5 // 1/2 the distance to C
With a scale of 2 (200%):
newBx = 100 - (100 - 50) * 2
= 100 - 100
= 0 // 2x the distance to C
newBy = 100 - (100 - 25) * 2
= 100 - 150
= -50 // 2x the distance to C
First you need to calculate the distance from B to C, then you just change that to scale, and that is where the new B is relative to C:
newB = C - (C - B) * scale
As you want the coordinates, it's the same function for x and y:
newBx = Cx - (Cx - Bx) * scale
newBy = Cy - (Cy - By) * scale
(The scale value used is not percentage but a size multiplier. An increase in size by 50% gives a scale of 1.5.)
So you want point C in the image which is currently at (C_x, C_y) to remain at the same position after scaling the image by a factor of s?
New position of C, say, C_new = (s*C_x,s*C_y).
And you want to move the image so that C_new = C.
Which means you'll have to shift B = (B_x,B_y) by (s*C_x-C_x,s*C_y-C_y), or the new origin of the image, say B_new is:
B_new = (B_x + s*C_x-C_x, B_y + s*C_y-C_y)
So now you can display the scaled image at B_new --- and C should remain fixed.
If I understand the problem:
X(b) = X(c) - Width*(1/3)
Y(b) = Y(c) - Height*(3/4)
The formula seems simple enough, but your sample image can't get any larger than 133x200 (scale = 133%) before it overruns Y=0 (which I assume is your northern limit).
If you want to stop it from moving past Y=0 or X=0, and push-out further to the south and east once it reaches either limit, one approach might be:
IIF(Height > 133, Y(b) = 0, Y(b) = Y(c) - Height*(3/4))
IIF(Width > 450, X(b) = 0, X(b) = X(c) - Width*(1/3))
I think scale should be converted to height and width, instead of using scale as a variable in these formulas, since your original image could be any size (assuming they're not always going to be 100x150 per your sample)
dave
here's a C# snippet that is tested to work:
void Main()
{
Application.Run(new form1());
}
public class form1 : Form
{
static Point C = new Point(100,100);
static Point origLocB = new Point(50,25);
static Size origSizeB = new Size(150,100);
Panel Rec = new Panel()
{
Left = origLocB.X,
Top = origLocB.Y,
Width = origSizeB.Width,
Height = origSizeB.Height,
BorderStyle = BorderStyle.FixedSingle,
};
NumericUpDown nud = new NumericUpDown()
{
Value = 1M,
Increment = .01M,
DecimalPlaces = 2,
Dock = DockStyle.Bottom,
};
public form1()
{
nud.ValueChanged += NumericUpDown_ValueChanged;
Controls.Add(nud);
Controls.Add(Rec);
}
public void NumericUpDown_ValueChanged(object sender, EventArgs e)
{
Rec.Location = new Point(((int)((origLocB.X - C.X) * nud.Value + C.X)),
((int)((origLocB.Y - C.Y) * nud.Value + C.Y)));
Rec.Size = new Size((int)(origSizeB.Width*nud.Value),
(int)(origSizeB.Height*nud.Value));
}
}
it really just echo's #Reed's Answer
Here is pseudo-code of how I setup an array representing the MandelBrot set, yet it becomes horribly stretched when leaving an aspect ratio of 1:1.
xStep = (maxX - minX) / width;
yStep = (maxY - minY) / height;
for(i = 0; i < width; i++)
for(j = 0; j < height; j++)
{
constantReal = minReal + xStep * i;
constantImag = minImag + yStep * j;
image[i][j] = inSet(constantReal, constantImag);
}
Thanks!
Here is pseudo-code of how I setup an array representing the MandelBrot set, yet it
becomes horribly stretched when leaving an aspect ratio of 1:1.
xStep = (maxX - minX) / width;
yStep = (maxY - minY) / height;
Aha! It's because you must keep the same aspect ratio both for the image you will draw and for the region of the complex plane you want to draw. In other words, it must hold
width maxX - minX
---------- = ---------------------
height maxY - minY
(It follows that xStep == yStep.) Your code probably does not enforce this requirement.
Make sure your casts are all correct. xStep and yStep might be the products of integer division instead of the expected floating point division (if that's C# in your sample, it would require some explicit casts to work correctly).
It probably has to do with how you are displaying the image array. You use the width variable i as the first index, but usually the first index should be the slowest changing, that is, the height.
Try changing the last line to image[j][i] = ...