i have made a transform and rendered a Polygon object with it(mesh is of type Polygon):
at.setToTranslation(gameObject.position.x, gameObject.position.y);
at.rotate(Math.toRadians(rotation));
at.scale(scale, scale);
g2d.setTransform(at);
g2d.fillPolygon(mesh);
now i want to return the exact mesh i rendered so that i can do collision checks on it. only problem is that if i return mesh it returns the un-transformed mesh. so i tried setting the transform to the Polygon object (mesh) like so:
mesh = (Polygon)at.createTransformedShape(mesh);
but unfortunately at.createTransformedShape() returns a Shape that can only be casted to Path2D.Double. so if anyone knows how to convert Path2D.Double to Polygon or knows another way to set the transformations to the mesh please please help.
If AffineTransform#createTransformedShape doesn't provide the desired result for Polygons (as it seems to be the case), you can split the Polygon into Points, transform each Point and combine into a new Polygon. Try:
//Polygon mesh
//AffineTransform at
int[] x = mesh.xpoints;
int[] y = mesh.ypoints;
int[] rx = new int[x.length];
int[] ry = new int[y.length];
for(int i=0; i<mesh.npoints; i++){
Point2d p = new Point2d.Double(x[i], y[i]);
at.transform(p,p);
rx[i]=p.x;
ry[i]=p.y;
}
mesh = new Polygon(rx, ry, mesh.npoints)
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 have four randomly sorted points, and I can't seem to draw a convex/concave Polygon with these points. This is the code I am using:
int xPoly[] = new int[4];
int yPoly[] = new int[4];
for(int i = 0; i < quad.size(); i++){
g2d.fill(quad.get(i));
xPoly[i] = (int) (quad.get(i).getX());
yPoly[i] = (int) (quad.get(i).getY());
}
Polygon poly = new Poylgon(xPoly, yPoly, xPoly.length);
g2d.draw(poly);
Where quad is defined as ArrayList<Point> quad = new ArrayList();. Point is a simple class I wrote which is self explanatory. However, my solution keeps producing polygons like this:
The black points are part of quad. My desired result is a normal looking polygon, not an irregular one.
An example for the quad ArrayList:
(0,0), (5,3) (9,10), (6, 7)
There is no specified order for these points, so xPoly and yPoly aren't necessarily ordered either.
Switched to an answer:
You must order the points in a Polygon yourself - the points in a Polygon describe a fixed order in which it will be drawn. It won't interpolate what type of shape you want.
Hey all I'm trying to implement 3D picking into my program, and it works perfectly if I don't move from the origin. It is perfectly accurate. But if I move the model matrix away from the origin (the viewmatrix eye is still at 0,0,0) the picking vectors are still drawn from the original location. It should still be drawing from the view matrix eye (0,0,0) but it isn't. Here's some of my code to see if you can find out why..
Vector3d near = unProject(x, y, 0, mMVPMatrix, this.width, this.height);
Vector3d far = unProject(x, y, 1, mMVPMatrix, this.width, this.height);
Vector3d pickingRay = far.subtract(near);
//pickingRay.z *= -1;
Vector3d normal = new Vector3d(0,0,1);
if (normal.dot(pickingRay) != 0 && pickingRay.z < 0)
{
float t = (-5f-normal.dot(mCamera.eye))/(normal.dot(pickingRay));
pickingRay = mCamera.eye.add(pickingRay.scale(t));
addObject(pickingRay.x, pickingRay.y, pickingRay.z+.5f, Shape.BOX);
//a line for the picking vector for debugging
PrimProperties a = new PrimProperties(); //new prim properties for size and center
Prim result = null;
result = new Line(a, mCamera.eye, far);//new line object for seeing look at vector
result.createVertices();
objects.add(result);
}
public static Vector3d unProject(
float winx, float winy, float winz,
float[] resultantMatrix,
float width, float height)
{
winy = height-winy;
float[] m = new float[16],
in = new float[4],
out = new float[4];
Matrix.invertM(m, 0, resultantMatrix, 0);
in[0] = (winx / width) * 2 - 1;
in[1] = (winy / height) * 2 - 1;
in[2] = 2 * winz - 1;
in[3] = 1;
Matrix.multiplyMV(out, 0, m, 0, in, 0);
if (out[3]==0)
return null;
out[3] = 1/out[3];
return new Vector3d(out[0] * out[3], out[1] * out[3], out[2] * out[3]);
}
Matrix.translateM(mModelMatrix, 0, this.diffX, this.diffY, 0); //i use this to move the model matrix based on pinch zooming stuff.
Any help would be greatly appreciated! Thanks.
I wonder which algorithm you have implemented. Is it a ray casting approach to the problem?
I didn't focus much on the code itself but this looks a way too simple implementation to be a fully operational ray casting solution.
In my humble experience, i would like to suggest you, depending on the complexity of your final project (which I don't know), to adopt a color picking solution.
This solution is usually the most flexible and the easiest to be implemented.
It consist in the rendering of the objects in your scene with unique flat colors (usually you disable lighting as well in your shaders) to a backbuffer...a texture, then you acquire the coordinates of the click (touch) and you read the color of the pixel in that specific coordinates.
Having the color of the pixel and the tables of the colors of the different objects you rendered, makes possible for you to understand what the user clicked from a logical perspective.
There are other approaches to the object picking problem, this is probably universally recognized as the fastest one.
Cheers
Maurizio
I have a Line2D and a Area object and I want the intersecting Line2D. The result can be also a GeneralPath. How can I do this?
You can use the method instersects in class Area. Line2D could be replaced by a Rectangle2D though.
Second chance :
build your line2D, it is a shape.
Build an area around it (using new Area( line2d ) );
take the first area and call intersect with the second area obtained from the line.
your first area is now the intersection of the first.
take your leftmost, topmost, bottomost, rightmost coordinates
turn them into a line2d
and here you are.
Option 1, approximate the Line2D by triangles:
Polygon polygon = new Polygon(new int[]{x1, x2, x2}, new int[]{y1, y2+e, y2-e}, 3);
Area triangle = new Area(polygon);
triangle.intersect(area); // intersection of ray and area
return !triangle.isEmpty(); // returns true if intersects
Option 2, use the Geometry class instead
private final GeometryFactory geometryFactory = new GeometryFactory();
private ShapeReader shapeReader = new ShapeReader(geometryFactory);
Path2D.Double thePath = new Path2D.Double(area);
Geometry geometry = shapeReader.read(thePath.getPathIterator(null));
Coordinate[] coordinate = new Coordinate[] {new Coordinate(x1, y1), new Coordinate(x2, y2)};
LineString centerRay = geometryFactory.createLineString(coordinate);
return geometry.intersects(centerRay); // returns true if intersects
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.