This question already has an answer here:
How to set button by a contour polygon? Android
(1 answer)
Closed 9 years ago.
Have a look at below image.
Total image is around 300X300. Inside that 1 Diamond shape is there. I know its Points as below
pointA = new Point(0, 183);
pointB = new Point(183, 0);
pointC = new Point(366, 183);
pointD = new Point(183, 366);
If I touch on this whole image, how can I detect whether touched point is inside Diamond area or outside?
I also had a look at this link but could not understand some points.
create a Shape object from your Points and
check that point exists inside that Shpae
m not sure about this but it should be similar to this one...
Rectangle rect = new Rectangle();//use your points co-ordinates
if (rect.contains(x,y))
{
//isinside
}
What you are referring to is the L1 Norm, or Manhattan Distance. To test if your clicked point is inside your diamond (or less than an L1 norm of 183, all you need to do is do the following (in pseudo-code):
isInside(ClickedPoint)
{
X=abs(ClickedPoint.x-183);
Y=abs(Clickedpoint.y-183);
if (X+Y<=183) return inside
else return outside
}
Sorry for not including true Java code, but that shouldn't be too hard to code up.
What you have to do is rotate the touched point and the diamond points by 45 degrees:
public Point rotatePoint(Point pt, Point center)
{
double cosAngle = Math.cos(45);
double sinAngle = Math.sin(45);
double dx = (pt.x-center.x);
double dy = (pt.y-center.y);
pt.x = center.x + (int) (dx*cosAngle-dy*sinAngle);
pt.y = center.y + (int) (dx*sinAngle+dy*cosAngle);
return pt;
}
create a Rect from the points:
Point centerPoint = new Point(183,183);
Rect r = new Rect(rotatePoint(pointA, centerPoint).x, rotatePoint(pointA, centerPoint).y, rotatePoint(pointC, centerPoint).x, rotatePoint(pointC, centerPoint).y);
then use test if it contains the point:
r.contains(rotatePoint(ClickedPoint, centerPoint))
This will return true if the point is in the diamond.
Related
I'm trying to detect a collision between a small rectangle around the cursor and a "Connector", which is basically just a line between two points.
Now, I've decided to use the Intersector.intersectLinePolygon(p1, p2, polygon) method to do so, but when I run the code. It detects a collision everytime any of the rectangle X or Y points are in the same range as the line's bounding box and I can't really get my head around it. The desired result is the collision reporting only when the rectangle is actually touching the line.
Vector3 worldPos = cam.unproject(new Vector3(mouseX, mouseY, 0));
Rectangle rect = new Rectangle(worldPos.x-4, worldPos.y-4, 8, 8);
Boolean connectorIntersected = false;
for (int i = 0; i < nodeConnectorHandler.getAllConnectors().size(); i++) {
//Getting two points that make the connector line
Node n1 = nodeConnectorHandler.getAllConnectors().get(i).getFrom();
Node n2 = nodeConnectorHandler.getAllConnectors().get(i).getTo();
float x1 = n1.getCX();
float y1 = n1.getCY();
float x2 = n2.getCX();
float y2 = n2.getCY();
//Making a polygon out of rect
Polygon p = new Polygon(new float[] {
rect.getX(),
rect.getY(),
(rect.getX()+8f),
rect.getY(),
(rect.getX()+8f),
(rect.getY()+8f),
rect.getX(),
(rect.getY()+8f)
});
//Checking if the line intersects the polygon (representing the rectangle around the cursor)
if (Intersector.intersectLinePolygon(new Vector2(x1,y1), new Vector2(x2,y2), p))
{
selectedIndex = nodeConnectorHandler.getAllConnectors().get(i).getID();
System.out.println("ConnectorIntersected!");
connectorIntersected = true;
}
break
}
The code reports a collision everytime the rectangle is in these areas (shown in yellow, aprox):
photoshopped image link
The red line inbetween those 2 dots is the "connector"
Cursor is right below the line. It reports a collision in those yellow areas spanning across the whole game world.
I suppose I'm either not using the function properly or that I've made some obvious mistake. Or is this how the function should react? I really don't know. Thanks for any help :)
Ok, apparently I used the wrong method. intersectSegmentPolygon works as expected. My bad ¯_(ツ)_/¯.
I am trying to map two points on one image to two points on the original image so i divided the work into three main actions first scaling the n rotation then translation after everything but cant position them correctly the scaling works fine and the translation also the rotation works perfectly if i didn't scale the images only way the rotation work perfectly when i rotate around custom point but the image get distorted
Rotate rotation = new Rotate();
rotation.setPivotX(proj.s2[0]);
rotation.setPivotY(proj.s2[1]);
MainView1.getTransforms().add(rotation);
MainView1.setManaged(false);
rotation.setAngle(Angle);
here is the code without custom rotation
guidebutton.setOnMouseClicked(event->{
if (!first_rot) {
proj.f2[0]=Lball.getCenterX();
proj.f2[1]= Lball.getCenterY();
proj.f1[0]=Rball.getCenterX();
proj.f1[1]= Rball.getCenterY();
MainView.setStyle("-fx-opacity : 0.0;");
guidetext.setText("now position them on the second image and click done");
first_rot=true;
}else {
proj.s2[0]=Lball.getCenterX();
proj.s2[1]= Lball.getCenterY();
proj.s1[0]=Rball.getCenterX();
proj.s1[1]= Rball.getCenterY();
//fixing the image first then fixing the points
// fixing the image
//adjusting the scale
double f[]=tranformations.dis_vec_d(proj.f1, proj.f2);//get the distance between the two points on the first image
double s[]=tranformations.dis_vec_d(proj.s1, proj.s2);//get the distance between the two points on the secondimage
double facx=f[0]/s[0];//factor of scale in x direction
double facy=f[1]/s[1];//factor of scale in y direction
//getting the position of second image inside the window
Bounds bounds = MainView1.getBoundsInLocal();
Bounds screenBounds = MainView1.localToScreen(bounds);
double x = screenBounds.getMinX();
double y = screenBounds.getMinY();
MainView1.setScaleX(facx);
// get the new position of image after scaling to adjust the position
bounds = MainView1.getBoundsInLocal();
screenBounds = MainView1.localToScreen(bounds);
double nx = screenBounds.getMinX();
double ny = screenBounds.getMinY();
double nmx = screenBounds.getMaxX()-nx;
double nmy = screenBounds.getMaxY()-ny;
MainView1.setTranslateX(x-nx);
MainView1.setTranslateY(y-ny);
double[]orig={nmx/2,nmy/2};
//adjusting rotation
//calculating the angle between the two line to adjust the rotation
double Angle=tranformations.angle_d(proj.s1, proj.s2);
Angle-=tranformations.angle_d(proj.f1, proj.f2);
//Add the Rotate to the ImageView's Transforms
MainView1.setRotate(Angle);
MainView1.setTranslateX(MainView.getTranslateX()+proj.f2[0]-proj.s2[0]);
MainView1.setTranslateY(MainView.getTranslateY()+proj.f2[1]-proj.s2[1]);
}
});
both views and points in unmanaged group "draw" when i get every thing work it get down when i use zooming when positioning points on the second image
i use this code for zooming using mouse wheel
final double SCALE_DELTA = 1.1;
draw.setOnScroll(event->{
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor =(event.getDeltaY() > 0)? SCALE_DELTA: 1/SCALE_DELTA;
draw.setScaleX(draw.getScaleX() * scaleFactor);
draw.setScaleY(draw.getScaleY() * scaleFactor);
});
edit to explain the question more i have these two separate images and i use the two red points on lights as to correctly position them over each other to so they can form the new image complete image
First align one of the points using a translation then scale using the aligned point's coordinates as pivot and finally use the same pivot point to perform a rotation aligning the other points.
The following example uses groups containing 2 circles each, but it should be simple enough to replace centerX/centerY with the image coordinates of the points:
#Override
public void start(Stage primaryStage) throws Exception {
// create group containing scene that remains in place
Circle target1 = new Circle(100, 200, 20, Color.RED);
Circle target2 = new Circle(150, 100, 20, Color.RED);
Group targetGroup = new Group(target1, target2);
// create group that will be transformed
Circle c1 = new Circle(30, 30, 20, Color.BLUE);
Circle c2 = new Circle(400, 400, 20, Color.BLUE);
Group g = new Group(c1, c2);
Scene scene = new Scene(new Pane(targetGroup, g), 500, 500);
// register handler for swapping between transformed/untransformed scene on button click
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
boolean transformed;
final Translate translate = new Translate();
final Scale scale = new Scale();
final Rotate rotate = new Rotate();
{
// add transforms to transformation target
g.getTransforms().addAll(rotate, scale, translate);
}
#Override
public void handle(MouseEvent event) {
if (transformed) {
// reset transforms to identity
translate.setX(0);
translate.setY(0);
scale.setX(1);
scale.setY(1);
rotate.setAngle(0);
} else {
// align c1 and target1
translate.setX(target1.getCenterX() - c1.getCenterX());
translate.setY(target1.getCenterY() - c1.getCenterY());
// scale
double scaleFactor = Math.hypot(target1.getCenterX() - target2.getCenterX(), target1.getCenterY() - target2.getCenterY())
/ Math.hypot(c1.getCenterX() - c2.getCenterX(), c1.getCenterY() - c2.getCenterY());
scale.setPivotX(target1.getCenterX());
scale.setPivotY(target1.getCenterY());
scale.setX(scaleFactor);
scale.setY(scaleFactor);
// rotate
rotate.setPivotX(target1.getCenterX());
rotate.setPivotY(target1.getCenterY());
rotate.setAngle(Math.toDegrees(Math.atan2(target2.getCenterY() - target1.getCenterY(), target2.getCenterX() - target1.getCenterX())
- Math.atan2(c2.getCenterY() - c1.getCenterY(), c2.getCenterX() - c1.getCenterX())));
}
transformed = !transformed;
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
This is particularly simple using complex numbers.
An arbitrary similarity transform can be written
Z = a.z + b
where the modulus of a is the scaling factor, the argument of a is the rotation angle and b is the translation.
These coefficients are readily obtained from the known pairs of points by the usual two-points interpolation formula
Z = Z0 + (z - z0).(Z1 - Z0)/(z1 - z0)
or
a = (Z1 - Z0)/(z1 - z0)
b = Z0 - a.z0
You have the option of using a complex data type, or to retranscript the formulas in terms of real/imaginary parts.
If the square isn't rotated, then yeah, pick x and y independently.
If the square is rotated, the math gets a little trickier. Let's let the two end points of the diagonal be X and Y, represented as complex numbers.
Then look at the equation:
(Y - X)/(1 + i) x + X
When x = 0, this returns X. When x = 1 + i, it returns Y. In fact, this equation maps the unit rectangle onto the square whose diagonal's endpoints are X and Y.
So pick two random numbers 0 ≤ a, b ≤ 1, turn it into a random point a + bi on the unit rectangle, and then use the above equation to map into into a random point in the square.
I am currently using OpenCV to create a system which detects whether vehicles are in certain zones. So far, I've got to the point where a Rect is drawn around each vehicle. My next step is to find the central points of these rectangles and see whether that falls within a particular zone.
I realise that the best way of doing this is probably to find the coordinates of the Rect's four corners and then take an average x and average y-coordinate to find the coordinates for the central point. However, I'm not sure how to do this. Is there some function which lets me access OpenCV's Rect coordinates directly?
Edit to original: As was pointed out, we cannot use '+' operator directly on tl() and br().
Use this instead to get the center of a rectangle:
Point p1 = new Point(100, 100);
Point p2 = new Point(600, 800);
Rect myrect = new Rect(p1, p2);
System.out.println(String.format("Rectangle: %s", myrect));
Point centroid = new Point(myrect.x + 0.5*(myrect.width), myrect.y + 0.5*(myrect.height));
System.out.println(String.format("centroid: %s", centroid));
This prints:
Rectangle: {100, 100, 500x700}
centroid: {350.0, 450.0}
Old answer:
[Use rect's methods:
tl ()
br ()
to get the top left and bottom right points, respectively.]
If you did want to use tl, br methods you can do:
Point anotherCentroid = new Point(0.5 * (myrect.br().x + myrect.tl().x), 0.5 * (myrect.br().y + myrect.tl().y));
I already searched over stackoverflow for similar questions, and tried to implement using some suggestions from other answers like this one:
Point p1 = prop.getDisplayPoint();
Point p2 = prop2.getDisplayPoint();
int xCenter = p1.x - 50;
int yCenter;
if(p1.y > p2.y)
yCenter = p1.y - ((p1.y-p2.y)/2);
else
yCenter = p2.y - ((p2.y-p1.y)/2);
int r = (int)Math.sqrt((p1.x-xCenter)*(p1.x-xCenter) + (p1.y-yCenter)*(p1.y-yCenter));
int x = xCenter-r;
int y = yCenter-r;
int width = 2*r;
int height = 2*r;
int startAngle = (int) ((180/Math.PI)*Math.atan2(p1.y-yCenter, p1.x-xCenter));
int endAngle = (int) ((180/Math.PI)*Math.atan2(p2.y-yCenter, p2.x-xCenter));
g.drawArc(x, y, width, height, startAngle, endAngle);
But still this didnt helped me.
I tried to compute the center of my two points, but the result of the arc was not what I was waiting for.
This was the result:
This is what I am looking for:
I have the coordinates of each pair of points I want to connect, like the point at "car" and the point at "bus" then I want to draw an arc between them. The angle will always be something like that.
Looking at the picture, it appears that you have two problems.
The first is that your origin point is incorrect. I haven't tried specific values, but I think it's because you're calculating an arbitrary center based on the first point, and then calculating the start and end of your arcs based on that center point (rather than the actual text locations).
However, I think that the bigger problem is that an arc isn't really appropriate to the task. With an arc, you could go for a semi-circle (or semi-oval), or maybe 1/3 of a circle, but those won't look very good. They certainly won't look like your desired example.
Instead, you want a Bezier Curve, so that you can deepen the sides of the "arc". Here's a SO question that points you to the docs for the bezier curve functions in Java2D. There are also a bunch of examples if you Google for "java draw bezier".
Okay I'm trying to rotate a Java Polygon based on it's original position of angle 0. x, and y end up being converted to an int at the end of me using them, so I could understand not seeing some change, but when the difference in angles is big like 0 to 180 I think I should see something.
I've been at this for a little while and can't think of what it is. Here's the method. (Sorry if it messes up in the code tags, my firefox messes them up.)
public void rotate(double x, double y, obj o1)
{
double dist = Math.sqrt(Math.pow(x - (o1.x + (o1.w/2)), 2) + Math.pow(y - (o1.y + (o1.h/2)),2));
x += (Math.sin(Math.toRadians(o1.a)) * dist);
y -= (Math.cos(Math.toRadians(o1.a)) * dist);
}
The values of x and y that are being manipulated in the rotate method will not be seen in the method that is calling it because Java passes method arguments by value.
Therefore, the x and y values that are being changed in the rotate method is a local copy, so once it goes out of scope (i.e. returning from the rotate method to its calling method), the values of x and y will disappear.
So currently, what is happening is:
x = 10;
y = 10;
o1 = new obj();
o1.a = 100;
rotate(x, y, obj);
System.out.println(x); // Still prints 10
System.out.println(y); // Still prints 10
The only way to get multiple values back from a method in Java is to pass an object, and manipulate the object that is passed in. (Actually, a copy of the reference to the object is passed in when an method call is made.)
For example, redefining rotate to return a Point:
public Point rotate(int x, int y, double angle)
{
// Do rotation.
return new Point(newX, newY);
}
public void callingMethod()
{
int x = 10;
int y = 10;
p = rotate(x, y, 45);
System.out.println(x); // Should print something other than 10.
System.out.println(y); // Should print something other than 10.
}
That said, as Pierre suggests, using the AffineTransform would be much easier in my opinion.
For example, creating a Rectangle object and rotating it using AffineTransform can be performed by the following:
Rectangle rect = new Rectangle(0, 0, 10, 10);
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(45));
Shape rotatedRect = at.createTransformedShape(rect);
AffineTransform can be applied to classes which implement the Shape interface. A list of classes implementing Shape can be found in the linked Java API specifications for the Shape interface.
For more information on how to use AffineTransform and Java 2D:
Trail: 2D Graphics
Lesson: Advanced Topics in Java2D
Transforming Shapes, Text, and Images
FYI: Rotating shapes and points has been implemented in java.awt.geom.AffineTransform
You're performing a 2D rotational transformation.
It ought to look something like this:
xnew = xold*cos(t) - yold*sin(t)
ynew = xold*sin(t) + yold*cos(t)
The rotation angle t must be in radians, of course. It's zero at the x-axis, and increased in the anti-clockwise direction.
Both the old and new points need to be expressed relative to the origin you're rotating about.