Setting the pivot point of a JPanel to its center - java

I am building a Java application that is going to feature two circles of random sizes that need to be clicked by the user. The time between the click on the first and the second circle is going to be measured. Unfortunately, since I am new to Java so things have been slow for me. Currently I have my application draw circles and measure time between clicks using System.nanoTime() but now I am running into a problem.
Because the circles need to be a fixed distance away from eachother I want to use the center of the circles as the origin points. So basically I want to be able to provide coordinates for the circle so that the center of the circle should be at those coordinates. The distance between the circles then describes the distance between the centers. My circle currently is embedded into a JPanel but if I set the JPanel's position it moves the top left to that position.
Of course I have done some searching read that I may need to play around with either AffineTransform or Graphics2D.translate() which I have tried in paintComponent() but this got a bit confusing so then I tried to override setlocation and subtract the radius from the position. It sort of works but it is not the most clean solution. Can aonyone give me some pointers on how to do this?
Thanks in advance.

If I understand the problem statement, all such pairs of circles will lie on opposite sides of a circle centered in the enclosing panel, as shown here. Simply choose a random 0 ≤ θ < π and find its opposite at π - θ. Note how the example's rendering scales as the panel is resized.
As an aside, the example uses setPreferredSize() to establish the dimensions of the drawing panel, but you may want to override getPreferredSize() instead.
Addendum: The example uses fillOval() to render the circles, but you can use draw() with any desired Shape; the latter provides several contains() methods suitable for hit testing, as mentioned here.

You have the coordinates for the two center for the circle (x1, y1) and (x2, y2).
The size of the radius is random.
Once you have the radius of the two, r1 and r2, simply position them at (x1-r1, y1-r1) and (x2-r2, y2-r2).
You can use java.awt.Point to represent the center, and use
center.translate(-radius, -radius)
and use the new translated value as position for the drawing.
Maybe you think it is not a clean solution, but why not? Everything in Java is painted by giving the top left corner for the position, so is the use of the center that is not clean :).
To calculate the left top position by doing -radius is clean :)

Related

Libgdx Y axis, how to invert it?

How to invert Y axis? When I touch on bottom or top of the screen, the Y value is opposite I want
You can't invert an axis per se. You see, in computer graphics, the 2D coordinate system is a bit different from the canonical one taught at school in maths. The difference is that in computer graphics the y-axis is in the opposite direction, that is, from the origin to the bottom it has positive values and from the origin to the top it has negative values. Also, the origin is at the top left corner of the screen. If you can't get used to it then you can always take the opposite value to what you get, for this, asume ycoord holds the value obtained then you can do ycoord = -ycoord and that will get you the value as you're used to. Also, if you want the origin to be in the bottom left corner then you should check your y-coordinate, if it's positive then substract the vertical resolution to it, and if it's negative then add the vertical resolution to it.
But keep mind that you're going against the standard definition for coordinate systems in computer graphics.
I would say this is a duplicate questions of this one:
Move a shape to place where my finger is touched
Check on my answer there, so I won't repeat my self.
Or in short - use camera.unproject() method to get world coordinates from screen coordinates.

Trying to make a circular layout with elements positioned around centre at different distances

I'm building a prototype android app and I'm trying to make a circular layout. Basically, I have a centre point, and I want to be able to place other elements in a circle around it, like this. There's a library called ArcLayout that I tried using, and it works well, but it doesn't quite work for what I want to do. The elements I'm trying to place have a dynamic distance from the centre, and may have similar or identical distances at any given time.
I could just create a new arc layout for each distance level, but I'm trying to avoid something like this. Ideally, each element in the layout should position itself at a maximum distance from all other elements, while staying at the correct distance from the centre.
I've looked up a lot of different things from radar graphs, to orbiting animations, and none of them seem to work with what I want to do. How would I go about making something like this?
Here is a high level description of how I would do this:
Make your original view extend View class. In your ondraw method, do the following:
first draw the circle in the center of the view by getting the coordinate for the small circle by getWidth()/2, getHeight()/2. set some fixed radius. Store the center as cx,cy
Now, you need to draw other circles at the right position, for that you need the center of each circle. Now, from cx,cy if you have the angle it makes with x - axis and the distance from cx,cy to the new point, you can get the coordinates to the new points as follows:
cx1 = cx + r*cos(theta) and cy2 = cy + r*sin(theta).
where r is the distance between the points and theta is the angle between line joining the points and the positive x-axis.
Just remember to convert degrees to radians in your calculations.
Once you get coordinates for the new circle, just draw it using canvas.drawCircle method.
Repeat this method as often as needed.

Finding nearest free position for a circle for any point [x,y] in a 2D space with circles

I am making a game in which the user player places circles on the screen. It is important that the circles never overlap, so I need to figure out the nearest possible free spot from the cursor. I have found circle packing algorithms, but they do not seem a fit for my problem. I have also solved a similar problem in the past for boxes (here), but with circles, I cannot seem to figure it out.
I figured out how I can find the nearest free position when it intersects with one circle, or even when two are involved. However, I cannot find a robust algorithm that can deal with complex cases that have any number of circles in any arrangement.
Precise description of problem:
I have a 2D space with any number of non-intersecting circles, all with identical radii (though that may not matter). I want to find a position for the next circle that will make it not intersect with any other circle, and which center [x,y] is nearest to a specified location [x,y].
Suggestions of any kind appreciated (references, approaches, or (Java) libraries).
p.s. Bonus points if the solution includes making sure the circle stays within a specific bounding box (i.e. display).
My final solution: (based on David Wallace's suggestions)
Calculate the minimal distance between the centers of two circles (in my case, all circles are the same size, so always 2*radius)
Make a list of all circles that are closer to the mouse position than the minimum distance
If 0 overlaps: all good!
If 1 overlap: move the new circle's center to the minimum distance from the compared circle's center, along the vector that runs from compared circle's center to mouse position
If 2 overlap: find out where the two overlapping circles intersect. Place the new circle on the intersection closest to the mouse position. If this position still overlaps with any circle, move to the other intersection. If that one doesn't work, leave the new circle were it is.
If 3 overlap: same as in 2 overlap, just take the two circles closest to the new circle.
Note that this does not work perfectly, but good enough in my case, where a user is dragging the new circle on the screen. It works in most cases and in those it doesn't, usually when there are many circles very close together, the new circle simply stays in the last position (which was valid). The user can then decide to drag it a fit further and be more precise in where he wants the new circle to go.
This isn't a complete answer, but you may be able to make it into one.
Suppose you've already placed circles of radii r1, r2, r3 ... rn with centres C1, C2, C3 ... Cn, and you're looking to place a new circle of radius rz, the new circle's centre will have to be outside all of a set of "enlarged" circles, centred at C1, C2, C3 ... Cn; with radii (r1+rz), (r2+rz), (r3+rz) ... (rn+rz). So if the cursor is at point P, then there are some cases to consider.
(1) If P is not in any of the enlarged circles, then the problem is solved.
(2) If P is in just one of the enlarged circles, then move outwards along a radius of that circle, until you either reach a point that's outside all of the enlarged circles, or until you reach another enlarged circle. The former case reduces to scenario (1); the latter reduces to scenario (2). Pick an arbitrary direction if P happens to be the centre of the circle.
(3) If P is in several of the circles, then find the directions from P to each centre of a circle that it's in. Find the pair of directions that have the widest interval between them, and bisect that angle, to work out which direction to head along. For example, if the directions to the centres of the circles are 30deg, 120deg and 330deg, then bisect the angle between 120deg and 330deg - then head in a direction of 225deg. Head in that direction until you reach the edge of a circle, then recalculate. Keep doing this until you get back to scenario (2).
The thing that I can't work out is what to do if you get stuck in scenario (3). Maybe only allow a certain number of steps, then exit. After all, it's possible that there's no suitable place to put the circle.
To calculate the distance between a point and a circle is with the center, considering your Circle class is like this one:
public class Circle{
int x;
int y;
int radius;
}
public interface CircleHelper{
public int distanceBetweenCircleAndPoint(Circle c, Point p);
public int distanceBetweenTwoCircles(Circle c1, Circle c2);
}
First of all, I would think about using Quadtrees and check if there is any quad without surrounding circles
The quadtree deep can be selected considering the radius of the circles.
so if you have a point in one of the quads, you would look to its surrounding quads to check if there is any circle there and move from the point in the direction of empty quads.
I hope you understand my approach
Here is a solution that will work for varying radiuses, and can be simplified if all radiuses are equal, as in your case. We first transform the problem slightly. Instead of fitting a circle among other circles, we extend the radiuses of all other circles by the radius of our circle to place, and instead try to place a point outside of these extended circles. This is equivalent to the original problem. We proceed as follows:
First a special case. If the point is outside of all circles, we have a trivial solution.
Find all the circles the point is inside. Calculate the closest point on their circumference (just move out from the original point along the radius).
Find all the intersection points between pairs of circles.
Combine the sets of points from steps 2 and 3, and filter these by finding the ones that are not covered by any other circle.
Pick the closest point from the remaining set. Done!
This seems to be O(n^3), so not terribly fast, but should be doable if your set is not too huge.

Java - Scaling a canvas about a particular point

I am more or less finished a very simple planetary gravity simulator using Newtonian physics. It can transform and scale the planets for pan and zoom. This works fine, mouse input and everything. The problem I have is more aesthetic than anything else. Since the origin of the canvas is at the top left corner of the window (within a JPanel, within a JFrame), everything scales about that point. I was wondering is there any way to either set the origin to the center of the screen, or to scale about a particular point? (Even though AffineTransform.scale() only has one constructor, with scaleX and scaleY as the args). I have tried setting the bounds of the canvas as negative numbers as such:
canvas.setBounds(-width/2, -height/2, width/2, height/2);
(Width and height are the screen size).
This obviously doesn't work as negative numbers are outside the co-ords of the panel.
So does anyone know anyway of accomplishing this? Either setting the centre of the screen as the origin or scaling about a particular point rather than the origin?
The trick here is to concatenate instances of AffineTransform.
Move the entire rendering so the center is at the origin.
Scale the rendering.
Move the center of the rendering (now at the origin) back to the center of the view.

Making fillRect fill dynamically from right to left

Hi i am currently working on a Java app and i have to draw a little using Canvas, Graphics etc..
So if i click a point and drag it across, it should have a line drawn in between (Think of drawing a line in paint).
I am currently using fillRect and the question is, is there a way to fillRect from right to left? Or do i have to explicitly create a workaround for this?
fillRect() method needs four arguments, x, y, width, height. What you should do is just compute the values of those arguments. If you want to draw fillRect from right to left, you just need to decrease x and increase width perhaps as your mouse move. That's it.
To add to ntalbs excellent answer (+1).
Basically, when the user clicks a point, you need to store that as the anchor point. When they drag the mouse, you need to determine in which direction the mouse has dragged.
If the click.x > drag.x, the the drag.x becomes the x parameter for your rectangle, otherwise it's the click.x.
Width and height are simple determine as the difference between the click and drag points (taking into consideration which is larger ;))

Categories