There are no. of components around and on Line2D.I want to find only the overlapped ones.I tried line.getbounds().intersects(component) but it gives the rectangular area components which I don't need.Also,distance sometimes gives me a component which is very near to Line but not on line.Any solution?
Short answer: check if at least one of these two conditions is true
any endpoint of the line is inside the component, use the method contains
the line intersects any side of the component bounds, use the intersect method.
Detailed description:
These are the possible cases:
one endpoint of the line is inside the component (this include the case where the line is entirely inside the component);
the line cross the component but all the end points of the line are outside of the objects;In this case it will intersect two sides, but one is enough to validate.
in all other case, the line and the component do not overlap each other and we do not care.
Only the middle bullet is a bit tricky, however since you are testing only jcomponent, the life is simple, because they are rectangles aligned with the axis. You can easily compute the endpoint of the sides of the bounds of the component. The bounds are given by a point (x,y) the width w and the height h. This gives you the four sides as:
(x,y) - (x+w,y)
(x,y) - (x, y+h)
(x,y+h) - (x, y+h)
(x+w,y) - (x+w,y+h)
If the components you are talking about are java Components then they are rectangular and you can use line.intersects(component.getBounds())
if they are any other kind of shape you have to define that shape and work with the line mathematically if they are not rectangular
Related
I'm in the process of writing a "Paint" application in Java consisting of rectangular nodes and undirected edges. The problem is that the beginning of the edge is in the center of the rectangle the edge is connected to, and the end of the edge is in the center of the other rectangle this edge is connected to.
To avoid drawing the intersection between the rectangle and the edge, I draw edges first and nodes afterwards, so that they are placed on top of the edges, thus hiding the intersection.
The problem arises when another node, which does not correspond to that edge is placed along the edge. In this scenario, because edges are drawn first, the node appears on top of the edge. However, that is not what I want. I want the edge to show on top of the node.
Images:
how it is and how it should be
The most comprehensive way I can think of to fix this would be to draw nodes first and afterwards draw the edges avoiding the intersections of the edge with the two nodes it is connected to. However that is difficult to do on paper because I draw edges using drawLine, and I do not have the possibility to check for intersections.
This is why I draw edges first, but then the problem I mentioned arises. Any ideas?
What you need is a solution to problem #1. You need to "move" the edge's endpoints away from the center of the rectangle. That way you won't have to draw the nodes last and automatically solve your question at hand.
My proposed solution in Step 2 only works if the connecting nodes are left and right of each other, otherwise you need slightly more advanced math of which I made a start in Step 2.1.
Step 1: an edge is nothing more than two Points where a Point is just an x and y value. Find the left and right ends of the edge by comparing the x of each edge. We'll save this as xLeft, xRight, yLeft and yRight for simplicity. Maybe you have something else for this, but you get the idea.
Step 2: move the xLeft half the width of the rectangle to the right and subtract half the width of the rectangle from xRight.
(Optional) Step 2.1: in case two connecting nodes are above each other, you can use Math.atan2(yRight-yLeft, xRight-xLeft) to calculate the angle. If the value is in the lower spectrum (between -3pi/4 and -pi/4) add and subtract half the height of the rectangle on the respective y values. You can fiddle around with this to create the math and logic for all 4 directions if you want.
Step 3: draw the new edges after having drawn the nodes. The edges are now "connected" to the edge(s) of your rectangles.
Feel free to ask questions, although I suggest you try putting this into code first.
I am currently trying to draw and fill a Polygon which has a hole in it in Java. Normally this would not be a big problem, since I would draw the exterior ring and then draw the interior ring with the color of the background.
But the problem is, that the polygon is displayed above a image which should be "seen" through the hole.
I am writing the code in Java and am using JTS Topology Suite for my geometry data.
This is my current code, which just paints the border and fills the polygon with a color.
private void drawPolygon(com.vividsolutions.jts.geom.Polygon gpoly, Color color, Graphics2D g2d){
java.awt.Polygon poly = (java.awt.Polygon)gpoly;
for(Coordinate co : gpoly.getExteriorRing().getCoordinates() {
poly.addPoint(co.x, co.y);
}
g2d.setColor(col);
g2d.fill(poly);
g2d.setColor(Color.BLACK);
g2d.draw(poly);
}
Sadly java.awt.Polygon does not support Polygons with holes.
Use the Polygon as the basis for an Area (e.g. called polygonShape).
Create an Ellipse2D for the 'hole', then establish an Area for it (ellipseShape).
Use Area.subtract(Area) something like:
Area polygonWithHole = polygonShape.subtract(ellipseShape);
There are some ways to draw shapes or areas that are more complex than a simple polygon (another answer already mentioned Area).
Besides those, you could try to tessellate your final polygon. There are lots of algorithms to do this. For more complex shapes, the algorithms get a bit more complex as well. Basically, you're dividing your final shape into little polygons (usually triangles, but it also can be something else) and then draw those polygons.
You can take a look at your possibilities by searching for "Tessellation Algorithm", there are also some already implemented libraries for Java.
You can use java.awt.geom.Path2D to render a "compound shape" with a hole in it:
If you have java.awt.Shape objects defining the outside & inside edges of the shape, use append(shape, false) to add each shape.
If you have a set of path points for the outside edge and a set of path points for the inside edge, use lineTo() to add the first set of points - creating a closed loop by either ending with the same point you started with, or calling closePath() to automatically close the loop. Then use moveTo() to create a break before adding the inner set of points via more lineTo() calls.
In either case, you must create the path passing Path.WIND_NON_ZERO to the constructor - otherwise the hole won't be left unfilled.
See How to create shape with a hole? for a longer code example.
You could fill the polygon first, and then draw the holes on top, giving the illusion that it filled everything but the holes.
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.
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 :)
I have constructed a Path2D that represents an unclosed shape consisting of straight lines:
I want to be able to detect when the mouse is clicked and the mouse pointer is near to (within a few pixels of) the path. Using the contains method does not work because the algorithm treats the unclosed shape as implicitly closed (i.e. by drawing a straight line between the start and end points).
Does anyone know of another mechanism for achieving this?
Create a BasicStroke (the width controls your pixel-distance-tolerance)
Don't draw with it, only use its createStrokedShape method to create a second shape from your shape. This second shape describes the outline of the shape that would be filled if you would draw your first shape with the BasicStroke.
Use the contains method of this second shape
From Stroke.createStrokedShape API documentation:
Returns an outline Shape which encloses the area that should be
painted when the Shape is stroked according to the rules defined by
the object implementing the Stroke interface.