Java JPanel Arc formation around edge of circle - java

Im trying to draw an arc that stretches around part of the circle. Im confused on how to use the DrawArc method. I read few articles online and to simply put, im confused on how the parameters exactly work. My circle is centered at 100, 100 with radius of 50. How would i use the drawArc method to draw an arc that overlaps the circle ? Any thoughts would be highly appreciated

Reading articles is good, but you should always read a method's documentation.
The drawArc method does not take a center and radius as arguments. Instead, it takes a rectangle. The x and y arguments are the upper-left corner of that rectangle; the width and height are the horizontal and vertical diameters of your arc's ellipse.
You can just do the math yourself:
int centerX = 100;
int centerY = 100;
int radius = 50;
graphics.drawArc(centerX - radius,
centerY - radius,
radius * 2,
radius * 2,
startAngle,
span);
Note that the final argument is the number of degrees the arc spans, not the absolute end angle.

Related

Why is a Pixmap circle off by 1?

I'm trying to draw a circle using Pixmap. To make the problem clearer, I'm filling the entire Pixmap area in white, then drawing the circle in a different color. Here is the code that I feel should work.
I'm setting the width/height of the Pixmap to twice the size of the radius of the circle.
Then I'm drawing a circle in the middle of the Pixmap at (radius, radius).
public static Texture circle(int radius, Color color) {
Pixmap pixmap = new Pixmap(radius * 2, radius * 2, Pixmap.Format.RGBA4444);
pixmap.setColor(Color.WHITE);
pixmap.fill();
pixmap.setColor(color);
pixmap.fillCircle(radius, radius, radius);
Texture texture = new Texture(pixmap);
pixmap.dispose();
}
Unfortunately, the Pixmap cuts off the circle on the right and bottom sides. For example:
If I increase the size of the Pixmap by 1 in both the width and height, then it looks fine:
I can just arbitrarily add an extra pixel but I'd like to understand why this is necessary. Why does setting the radius of the circle to X result in a diameter that is actually X + 1?
To get the result you want, the location of the circle's center would have to fall between two pixels, so that there are a similar number of whole pixels on either side of that location. My guess is that the Pixmap code defines a pixel's location to mean the center of a pixel. So the point (radius, radius) is closer to the right edge than the left, and (radius-1, radius-1) is closer to the left edge than the right. With this definition of location, the center of your circle should be at location (radius-.5, radius-.5).
If you have to put the center of the circle in the middle of a pixel, then it makes sense that you'd use the location (radius, radius) for the circle and that you'd need the width and height of the Pixmap to be (2*radius + 1, 2*radius+1). This way, there are the same number of pixels, radius+.5 pixels, on either side of the center of the circle. You might at that point want to draw a circle of radius radius + .5 if the library will take that.
Because it draws a circle centered on a pixel, not between pixels.
So the actual radius of the circle drawn is one more than passed in, a circle with radius 1 is drawn as (numbers are coordinates in this example):
012
0 X
1XCX
2 X
This technically has a radius of 1.5, but now it's centered on a pixel (C).
I am guessing this is to allow you to place it accurately, as if it actually had a radius of 2, you wouldn't be able to place the center on a pixel.

How to calculate a point out of an angle and a distance?

I searched and implemented things from this forum, it doesn't come out right.
What I'm trying to achieve is to calculate a spawnPoint for player bullets relative to his position and rotation.
The spawnPoint should be and his X + his width (the player is set to point to the right by default) and y + height/2 (to spawn from his center on the Y axis).
This is what I got from this forum:
this.bulletSpawn.x = (float)(this.position.x + this.width/2 + this.width * Math.cos(rotation));
this.bulletSpawn.y = (float)(this.position.y + this.height/2 + this.height/2 * Math.sin(rotation));
The rotation is in Radians. The this is the Player class.
Images showing what I expect to happen:
Original Position
Expected Behaviour
The red dot is the spawnPoint I'm trying to calculate knowing the player position and rotation.
The player Sprite is what rotates, and it rotates related to his center x and y, which is done with a lib, i do not have these variables. The entire arrow would be the player , the arrow direction is where the player is pointing at, and the red dot would be the bulletSpawn point (or the expected one)
Using the code I posted, the bullets seem to be spawning from somewhere else. Even at the beggining they have an offset and when I rotate the player the spawnPoint seems to be relative to a different origin than what I'm expecting.
This is the bullet position code:
position.x = holder.bulletSpawn.x - (float)(this.width/2 * holder.rotation);
position.y = holder.bulletSpawn.y - (float)(this.height/2 * holder.rotation);
This is inside the Bullet class. The position variable is a Vector2 of bullet, and holder is the player instance. This code is merely to give an offset for the bullet to spawn at the center of its own size
I added some fixes related to the comments, but the bullets still have a tiny offset that looks wrong at certain angles.
Basically the distance i want to get is the width of the player, and his center y which is height/2.
Let's initial position is X0, Y0, rotation is about center point CX, CY, and rotation angle is Theta. So new position after rotation is:
NX = CX + (X0-CX) * Cos(Theta) - (Y0-CY) * Sin(Theta)
NY = CY + (X0-CX) * Sin(Theta) + (Y0-CY) * Cos(Theta)
This equations describe affine transformation of rotation of arbitrary point about center point, and affine matrix is combination of translation, rotation, and back translation matrices.
About center CX, CY - you wrote
it rotates related to his x and y origin at his bottom left
About initial point coordinate - for bullet it seems to be
X + Width, Y + Height/2
Swift extension:
extension CGSize {
static func offsetFrom(angle:CGFloat, distance:CGFloat) -> CGSize {
let rad = angle * CGFloat.pi / 180
return CGSize(width: sin(rad) * distance, height: cos(rad) * distance)
}
}

How to rotate a line based on a given number of degrees

I have a line drawn with a Graphics object. I want to rotate this line a certain amount of degrees based on how much the mouse is dragged. I can get the number of degrees i need to rotate it but how do i then rotate the line based on that?
Thank You!
You can create a Line2D object for your original line. Then you can use AffineTransform#getRotateInstance to obtain an AffineTransform that does the rotation about a certain angle, around a certain point. Using this AffineTransform, you can create a rotated Line2D object to paint. So your painting code could roughly look like this:
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
// Create the original line, starting at the origin,
// and extending along the x-axis
Line2D line = new Line2D.Double(0,0,100,0);
// Obtain an AffineTransform that describes a rotation
// about a certain angle (given in radians!), around
// the start point of the line. (Here, this is the
// origin, so this could be simplified. But in this
// form, it's more generic)
AffineTransform at =
AffineTransform.getRotateInstance(
Math.toRadians(angleInDegrees), line.getX1(), line.getY1());
// Draw the rotated line
g.draw(at.createTransformedShape(line));
}
Alright, you will need to compute the length of the line, assuming that the ends of the line are (x0,y0) and (x1,y1), and (x,y) are the mouse coordinates, what you want is the point (x2,y2) that's on the line between (x0,y0) and (x,y), the distance between (x0,y0) and (x2,y2) must be the same as the one between (x0,y0) and (x1,y1).
The distance between (x0,y0) and (x1,y1) is:
double dx = x1-x0;
double dy = y1-y0;
double length = Math.sqrt(dx*dx, dy*dy);
The distance between (x0,y0) and (x,y) is:
double dx1 = x-x0;
double dy1 = y-y0;
double mouseDist = Math.sqrt(dx1*dx1, dy1*dy1);
And (x2,y2) are:
int x2 = x0 + (int)(dx1*length/mouseDist);
int y2 = y0 + (int)(dy1*length/mouseDist);
I suppose you are talking about Java AWT Graphics class. Graphics can be thought of as a canvas. It's an array of pixel values and "drawing a line" is just a utility function that changes the values of some of these pixels - there is no "line object" to speak of, from it's point of view. Normally you should erase the whole thing and draw a new line with the angle you want. However for that, you may want to look at Graphics2D (http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html) and in particular at setTransform and the AffineTransform class.
static Point rotateLineClockWise(Point center, Point edge, int angle) {
double xRot = (int) center.x + Math.cos(Math.toRadians(angle)) * (edge.x - center.x) - Math.sin(Math.toRadians(angle)) * (edge.y - center.y);
double yRot = (int) center.y + Math.sin(Math.toRadians(angle)) * (edge.x - center.x) + Math.cos(Math.toRadians(angle)) * (edge.y - center.y);
return new Point((int) xRot, (int) yRot);
}

draw ellipse using center point (not upper left corner)

I try to find a solution for drawing ellipses based on the center point, not the upper left corner as it is specified in the constructor of Ellipse2D.Double. As seen in the picture the ellipses should have the same center point and scale, is that somehow possible?
Thanks in advance for your help.
If (x,y) is the center you want to use and you can only specify the upper left corner, then use the following:
private Ellipse2D getEllipseFromCenter(double x, double y, double width, double height)
{
double newX = x - width / 2.0;
double newY = y - height / 2.0;
Ellipse2D ellipse = new Ellipse2D.Double(newX, newY, width, height);
return ellipse;
}
If called with the center point and the width and height, this will "transform" your center point to the upper left corner and create an Ellipse2D which is located just as you want it to be.
The 'Upper' coordinate is misleading , it only works assuming y >=0 ( which works fine for a screen referential , bur not if you use the primitive with y <0 , for instance calculating object collisions )
With the usual math referential , where y<0 is possible , up is at the bottom
so it lacks a general definition not to get confused
The exact definition is that x and y are the min coordinates of the bounding rectangle.
It can be 'up' or 'down' ( relatively to your screen i suppose ) depending on the y axis orientation and y coordinate sign

How to position a Node along a circular orbit around a fixed center based on mouse coordinates (JavaFX)?

Im trying to get into some basic JavaFX game development and I'm getting confused with some circle maths.
I have a circle at (x:250, y:250) with a radius of 50.
My objective is to make a smaller circle to be placed on the circumference of the above circle based on the position of the mouse.
Where Im getting confused is with the coordinate space and the Trig behind it all.
My issues come from the fact that the X/Y space on the screen is not centered at 0,0. But the top left of the screen is 0,0 and the bottom right is 500,500.
My calculations are:
var xpos:Number = mouseEvent.getX();
var ypos:Number = mouseEvent.getY();
var center_pos_x:Number = 250;
var center_pos_y:Number = 250;
var length = ypos - center_pos_y;
var height = xpos - center_pos_x;
var angle_deg = Math.toDegrees(Math.atan(height / length));
var angle_rad = Math.toRadians(angle_deg);
var radius = 50;
moving_circ_xpos = (radius * Math.cos(angle_rad)) + center_pos_x;
moving_circ_ypos = (radius * Math.sin(angle_rad)) + center_pos_y;
I made the app print out the angle (angle_deg) that I have calculated when I move the mouse and my output is below:
When the mouse is (in degrees moving anti-clockwise):
directly above the circle and horizontally inline with the center, the angle is -0
to the left and vertically centered, the angle is -90
directly below the circle and horizontally inline with the center, the angle is 0
to the right and vertically centered, the angle is 90
So, what can I do to make it 0, 90, 180, 270??
I know it must be something small, but I just cant think of what it is...
Thanks for any help
(and no, this is not an assignment)
atan(height/length) is not enough to get the angle. You need to compensate for each quadrant, as well as the possibility of "division-by-zero". Most programming language libraries supply a method called atan2 which take two arguments; y and x. This method does this calculation for you.
More information on Wikipedia: atan2
You can get away without calculating the angle. Instead, use the center of your circle (250,250) and the position of the mouse (xpos,ypos) to define a line. The line intersects your circle when its length is equal to the radius of your circle:
// Calculate distance from center to mouse.
xlen = xpos - x_center_pos;
ylen = ypos - y_center_pos;
line_len = sqrt(xlen*xlen + ylen*ylen); // Pythagoras: x^2 + y^2 = distance^2
// Find the intersection with the circle.
moving_circ_xpos = x_center_pos + (xlen * radius / line_len);
moving_circ_ypos = y_center_pos + (ylen * radius / line_len);
Just verify that the mouse isn't at the center of your circle, or the line_len will be zero and the mouse will be sucked into a black hole.
There's a great book called "Graphics Gems" that can help with this kind of problem. It is a cookbook of algorithms and source code (in C I think), and allows you to quickly solve a problem using tested functionality. I would totally recommend getting your hands on it - it saved me big time when I quickly needed to add code to do fairly complex operations with normals to surfaces, and collision detections.

Categories