I want to get all the Box2D bodies in a certain radius.
That for afaik I need to use a QueryCallback. I try it like this:
private def getBodies(position: Vector2, radius: Float): LibgdxArray[Body] =
{
val lowerBound = new Vector2(position - radius)
val upperBound = new Vector2(position + radius)
val bodies: LibgdxArray[Body] = new LibgdxArray[Body]
val callback: QueryCallback = new QueryCallback
{
override def reportFixture(fixture: Fixture): Boolean =
{
bodies.add(fixture.getBody)
true
}
}
world.queryAABB(callback, lowerBound.x, lowerBound.y, upperBound.x, upperBound.y)
bodies
}
My problem is, that I always get an empty LibgdArray. Do I need to do something more than just call queryAABB on the world? Is my code not correct?
edit: Okay, I don't understand this at all: I set the radius to a bigger value. I can remove static bodies, but the dynamic bodies do not care at all :(
I add them like this:
if(Gdx.input.isButtonPressed(Buttons.RIGHT))
{
val mousePos: Vector3 = new Vector3(Gdx.input.getX, Gdx.input.getY, 0)
val worldPos = camera.unproject(mousePos)
val ballShape: CircleShape = ShapeFactory.circle(new Vector2(worldPos.x, worldPos.y), 0.5f)
val ballDef: BodyDef = new BodyDef
ballDef.`type` = BodyType.DynamicBody
val ballBody = world.createBody(ballDef)
ballBody.createFixture(ballShape, 0.5f)
ballShape.dispose
}
Potential Solution
If you want to find all objects within a given area, one method is to first find the size of the smallest object in the world, then iteratively test all points in that area from your start point to your end point (assuming a rectangular area), with the iteration step being equal to half of the smallest size found (to avoid accidentally skipping over them).
Example code:
Finding the smallest area iteration step:
public static float smallestStep(World world) {
//Start min size at max float value
Vector2 minSize = Float.MAX_VALUE;
//Gets bodies in world
Array<Body> bodies = new Array<Body>();
world.getBodies(bodies);
//Iterate over every body
for(Body body: bodies) {
//Iterate over each fixture for each body
for(Fixture fixture : body.getFixtureList()) {
//Get fixture shape
Shape shape = fixture.getShape();
//Check if shape's "radius" is smaller than current min value
if(shape.getRadius() < minSize) {
//Updates min size
minSize = shape.getRadius();
}
}
}
//Returns half of the min found value
return minValue / 2;
}
Testing if a fixture contains a given point is the next step, by iterating over all fixtures of a body and adding the body to a list if one of the fixtures of the body contains the point using the fixture.testPoint() method, you should be able to generate a list of all of the bodies that overlap the given point.
Related
I have a task in currently on, Its a 2D rocket animation, with the rocket composed of 3 separate objects, a nose(triangle), body(square) and a jet(circle).
I have to set the body(s) relative to the nose(t) so that they align when the rocket moves.
this is the rocket class,
public Rocket(Triangle t, Square s, Circle c) {
this.nose = t;
this.body = s;
this.jet = c;
this.nose.setXPos(50);//initial positions of the nose X
this.nose.setYPos(300);//initial positions of the nose Y
this.body.setXPos(getBodyXPos());//sets the body relative to the nose X
this.body.setYPos(getBodyYPos());//sets the body relative to the nose Y
these are the methods i have to use.
private int getBodyXPos() {
return ;
}
private int getBodyYPos() {
return ;
}
these methods cannot use fixed numbers, rather calculate position of the nose and set the body to this. So, How would I go about doing this?
I am generating a List of points that have only integer components using GenerateSolidThetaZero function. My goal is to rotate these discrete points using an angle theta in radians and the new point after the rotation should still have integer components. The problem is I do not want any two points mapping to the same value. I want the same number of unique points before and after the rotation. I used the round function to remedy this problem a bit but I will still get some non-unique mappings. Basically I just want to find a way to rotate these points and preserve as much of the structure as possible(losing the least amount of points as possible). I am willing to use any library. Any help or guidance would be great.
Note: In my code the radius is 2 and 13 points are generated. After the rotation of Pi/6 I end up losing 4 points due to those points mapping to the same value another point already mapped to.
public class pointcheck{
// this HashSet will be used to check if a point is already in the rotated list
public static HashSet<Point> pointSet = new HashSet<Point>();
public static void main(String args[]) {
//generates sort of circular solid with param being the radius
ArrayList<Point> solid_pointList = GenerateSolidThetaZero(2);
//used to store original point as first part of pair and rotated point as second part of pair
ArrayList<Pair> point_pair = new ArrayList<Pair>();
//goes through all points in Solid_pointList adds each point to Point List with its corresponding rotated angle
for(Point t : solid_pointList){
point_pair.add(new Pair(t,rotation_about_origin(t,Math.PI / 6)));
}
for(Pair t : point_pair){
System.out.println(t.getFirst() + " " + t.getSecond());
}
System.out.println(pointSet.size());
}
//takes the point we want to rotate and then the angle to rotate it by
public static Point rotation_about_origin(Point P, double theta){
Point new_P = null;
double old_X = P.x;
double old_Y = P.y;
double cos_theta = Math.cos(theta);
double sin_theta = Math.sin(theta);
double new_X = old_X * cos_theta - old_Y * sin_theta;
double new_Y = old_X * sin_theta + old_Y * cos_theta;
new_P = new Point((int)Math.round(new_X),(int)Math.round(new_Y));
//if new_p is already in rotated solid
if(pointSet.contains(new_P))
System.out.println("Conflict " + P + " " + new_P);
else
//add new_P to pointSet so we know a point already rotated to that spot
pointSet.add(new_P);
return new_P;
}
private static ArrayList<Point> GenerateSolidThetaZero(int r){
int rsq = r * r;
ArrayList<Point> solidList=new ArrayList<Point>();
for (int x=-r;x<=r;x++)
for (int y=-r;y<=r;y++)
if (x*x + y*y <= rsq)
solidList.add(new Point(x,y));
return solidList;
}
public static class Pair<F,S>{
private F first; //first member of pair
private S second; //second member of pair
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
public void setFirst(F first) {
this.first = first;
}
public void setSecond(S second) {
this.second = second;
}
public F getFirst() {
return first;
}
public S getSecond() {
return second;
}
}
}//end of pointcheck class
How would I be able to rotate the points using angles that aren't using integer multiples of 90? Where should I translate a point after rotation if the mapping is already taken?
The rotated disk will cover the exact same pixels as the original one. Therefore, you actually want to solve an assignment problem from original pixels to rotated pixels.
The cost for assigning an original pixel (ox, oy) to a corresponding pixel (cx, cy) can be expressed with a potential. For example, the distance:
E_o,c = length(R(ox, oy, theta) - (cx, cy))
, where R is the rotation operator. Alternatively, you could also try other norms, e.g. the quadratic distance.
Then, the problem is finding the correspondences that minimize the overall energy:
min_C Sum_{o \in O} E_o,c
An algorithm that solves this exactly is the Hungarian Algorithm. However, it is quite expensive if you have a large number of pixels.
Instead, here is an idea of an approximation:
In the target pixels, instead of having only the color, also store the rotated position. Then, rotate the original pixels sequentially as you did before. Round the rotated position and check if the according pixel is still occupied.
If not, store the rotated (unrounded) position along with the new color.
If it is occupied, check if the energy would decrease if you swapped the correspondences. If it does, swap them, which leaves you with the former pixel. In any case, you have an unmapped original pixel. Store this pixel in a list.
After this procedure, you have a partial correspondence map and a list of unmapped pixels. Pick any of the unmapped pixels. Analyze the target pixel's neighbors. There will probably always be an unoccupied pixel (although I have no proof for that). If so, choose this one. If not, check all neighboring pixels for the best energy decrease and swap. Continue until the list is empty.
The approximation algorithm is just an idea and I have no proof that it will actually work. But it sounds as if it is worth a try. And it will definitely be faster than the Hungarian algorithm. Though, this approximation will only work with Lp-norms having p>=1 for the potential definition.
Edit 2: http://youtu.be/KiCzUZ69gpA - as you can see in this video, the shaking effect is amplified when I also render some text for each body. Observe how the ground body (blue) shakes violently when each body has some text rendered near it, and how it does not when text rendering is commented out. This has to be connected!
Edit: I've made two important additions to the original question: I've added my rendering functions, and the camera (translation) methods, and I think that the error is actually there, not in JBox2D.
I'm trying to simulate and render a lot of random bodies (2-20) connected with RevoluteJoints. One body can be connected to multiple others, and there are no separate constructions, i.e. all the bodies are interconnected.
However, when watching the live rendering, it is very shaky and unstable. By that I mean that bodies' positions (or maybe angles) seem to be randomly fluctuating for no apparent reason, making the simulation look unstable.
Here's a video of what I'm observing:
http://youtu.be/xql-ypso1ZU
Notice the middle square and the rotating rectangle. The middle square is shifting its position back and forth slightly at seemingly random intervals, and the rotating rectangle is very jittery (take a look at the point it is rotating about).
What could this effect be due? Is it some known issue with (J)Box2D, or is it an issue with my rendering system? I think that I have somehow misconfigured the physics engine, but also some floating point math in the rendering system could be the culprit.
Here's how I'm creating the bodies and the joints:
private Body setPart(Part part) {
// body definition
BodyDef bd = new BodyDef();
bd.position.set(0f, -10f);
bd.angle = 0f;
bd.type = BodyType.DYNAMIC;
// define shape of the body.
PolygonShape Shape = new PolygonShape();
Shape.setAsBox(part.width / 2, part.height / 2);
// define fixture of the body.
FixtureDef fd = new FixtureDef();
Filter filter = new Filter();
filter.groupIndex = -1;
fd.filter = filter;
fd.shape = Shape;
fd.density = 0.5f;
fd.friction = 0.3f;
fd.restitution = 0.5f;
// create the body and add fixture to it
Body body = world.createBody(bd);
body.createFixture(fd);
body.setUserData(new PartUserData());
return body;
}
private void setJoint(PartJoint partJoint) {
Body bodyOne = partToBody.get(partJoint.partOne);
Body bodyTwo = partToBody.get(partJoint.partTwo);
RevoluteJointDef jointDef = new RevoluteJointDef();
jointDef.bodyA = bodyOne;
jointDef.bodyB = bodyTwo;
jointDef.localAnchorA = partJoint.partOne
.getAnchor(partJoint.percentOne);
jointDef.localAnchorB = partJoint.partTwo
.getAnchor(partJoint.percentTwo);
// rotation
jointDef.lowerAngle = GeomUtil.circle(partJoint.rotateFrom);
jointDef.upperAngle = GeomUtil.circle(partJoint.rotateTo);
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0f; // TODO limit maximum torque
jointDef.motorSpeed = GeomUtil.circle(partJoint.angularVelocity);
jointDef.enableMotor = true;
world.createJoint(jointDef);
}
The time step is 0.01f.
Here is how I draw bodies:
private void drawBody(Body body) {
// setup the transforms
Vector position = camera.translate(body.getPosition());
currentGraphics.translate(position.x, position.y);
currentGraphics.rotate(body.getAngle());
// do the actual rendering
for (Fixture fixture = body.getFixtureList(); fixture != null; fixture = fixture
.getNext()) {
PolygonShape shape = (PolygonShape) fixture.getShape();
if (body.getUserData() instanceof PartUserData) {
fillShape(shape, partFillColor);
currentGraphics.setStroke(partOutlineStroke);
outlineShape(shape, partOutlineColor);
} else {
fillShape(shape, groundFillColor);
outlineShape(shape, groundOutlineColor);
}
}
// clean up
currentGraphics.rotate(-body.getAngle());
currentGraphics.translate(-position.x, -position.y);
currentGraphics.setColor(defaultColor);
currentGraphics.setStroke(defaultStroke);
}
I think that the issue might be the way I'm handling rendering of all the bodies.
This is the algorithm for each body:
1. Translate the Graphics2D object to its position
2. Rotate it by body.getAngle()
3. Render the body
4. Rotate the graphics back
5. Translate the graphics back
Could it be that amongst all these transforms something goes wrong?
When I removed the calls to camera's methods, the effect seems to have been reduced. These are the relevant camera methods:
public Vector translate(Vec2 worldPosition) {
Vector point = new Vector();
point.x = (int) (worldPosition.x * pixelsPerMeter) - position.x;
point.y = (int) (worldPosition.y * pixelsPerMeter) - position.y;
point.x = (int) (point.x * zoom);
point.y = (int) (point.y * zoom);
point.x += renderer.getWidth() / 2;
point.y += renderer.getHeight() / 2;
return point;
}
public Vector translateRelative(Vec2 worldPosition) {
Vector point = new Vector();
point.x = (int) (worldPosition.x * pixelsPerMeter);
point.y = (int) (worldPosition.y * pixelsPerMeter);
point.x = (int) (point.x * zoom);
point.y = (int) (point.y * zoom);
return point;
}
But what part of them would cause an issue?
tl;dr: I've found a solution, but haven't identified the exact problem. Quite sure it's with my translation methods.
It seems that I have identified the scope of the problem and the solution, but I am still not sure what exactly is causing this behavior.
In those translation formulas I posted in the question, all JBox2D vectors are multiplied by a scale called pixelsPerMeter. When I set this scale to a low value, the shaking effect occurs (it's also important to note that there is another factor as well, called zoom, which is usually greater for a lower pixelsPerMeter).
So, it could be that when multiplying by a relatively low pixelsPerMeter, I have to multiply with a higher zoom factor, and since I'm converting to ints in both steps, there could be some errors in the floating point math or something. Please see the translation methods I've posted in the question.
Here's a video that demonstrates this: (to be uploaded)
Notice that when I set the pixelsPerMeter to 250, shaking seems to be gone, while when I set it to 25, it's quite visible.
Your solution was the correct one. You are not supposed to use pixel units for the Box2D physics engine :)
http://box2d.org/2011/12/pixels/
and
https://code.google.com/p/box2d/wiki/FAQ#How_do_I_convert_pixels_to_meters?
I think when you apply force to a body it is applied to origin of body ( could be center of mass ). Now I am trying to to create tetris-like blocks and make them jump by applying linearPulse like this:
body.applyLinearImpulse(0, 5f, this.body.getPosition().x, this.body.getPosition().y, true);
this works excellent if you only have one box fixture as body, but when you create multiple fixtures the origin gets misplaced and I can't place it to center of fixture.
Here is picture of what I mean:
I create fixtures from matrix like this:
int array[][]= {{0,0,0,0,0},
{0,0,1,0,0},
{0,1,1,1,0},
{0,0,0,0,0},
{0,0,0,0,0}};
and I use array to create fixtures like this:
public void setBody(int[][] blocks){
BodyDef def = new BodyDef();
def.type = BodyType.DynamicBody;
def.position.set(new Vector2(100 * WORLD_TO_BOX, 100 * WORLD_TO_BOX));
Body body = world.createBody(def);
body.setTransform(150*WORLD_TO_BOX, 200*WORLD_TO_BOX, -90*MathUtils.degreesToRadians);
for (int x = 0; x < 5; x++) { // HARDCODED 5
for (int y = 0; y < 5; y++) { // HARDCODED 5
if(blocks[x][y] == 1){
PolygonShape poly = new PolygonShape();
Vector2 v = new Vector2((-5/2+x),(-5/2+y));
poly.setAsBox(size/2 * WORLD_TO_BOX, size/2 * WORLD_TO_BOX, v, 0);
body.createFixture(poly, 1);
poly.dispose();
}
}
}
this.body = body;
}
WORLD_TO_BOX values is 0.032f
and size of one block is 32f
so my guestion is, how can I manually set center of mass/origin of my complex multifixture body?
I don't believe you get to set the center of mass for a body, it is calculated by the system. From the manual:
You can access the center of mass position in local and world
coordinates. Much of the internal simulation in Box2D uses the center
of mass. However, you should normally not need to access it. Instead
you will usually work with the body transform. For example, you may
have a body that is square. The body origin might be a corner of the
square, while the center of mass is located at the center of the
square.
const b2Vec2& GetPosition() const;
float32 GetAngle() const;
const b2Vec2& GetWorldCenter() const;
const b2Vec2& GetLocalCenter()
I believe you will use GetWorldCenter() as the linear impulse is applied in world coordinates (also per the manual):
You can apply forces, torques, and impulses to a body. When you apply
a force or an impulse, you provide a world point where the load is
applied.
Was this helpful?
I have a region defined by a set List of geopoints and I need to know if a coordinate is inside this region
public class Region{
List<Coordinate> boundary;
}
public class Coordinate{
private double latitude;
private double longitude;
}
public static boolean isInsideRegion(Region region, Coordinate coordinate){
}
You can apply a Point in polygon algorithm from the Computational Geometry set of problems.
There are four algorithms written in C by Paul Bourke, you can see the code here. There is an adaptation to Java in a Processing Forum, just in case you can't use Java7:
public class RegionUtil {
boolean coordinateInRegion(Region region, Coordinate coord) {
int i, j;
boolean isInside = false;
//create an array of coordinates from the region boundary list
Coordinate[] verts = (Coordinate)region.getBoundary().toArray(new Coordinate[region.size()]);
int sides = verts.length;
for (i = 0, j = sides - 1; i < sides; j = i++) {
//verifying if your coordinate is inside your region
if (
(
(
(verts[i].getLongitude() <= coord.getLongitude()) && (coord.getLongitude() < verts[j].getLongitude())
) || (
(verts[j].getLongitude() <= coord.getLongitude()) && (coord.getLongitude() < verts[i].getLongitude())
)
) &&
(coord.getLatitude() < (verts[j].getLatitude() - verts[i].getLatitude()) * (coord.getLongitude() - verts[i].getLongitude()) / (verts[j].getLongitude() - verts[i].getLongitude()) + verts[i].getLatitude())
) {
isInside = !isInside;
}
}
return isInside;
}
}
Use Path2D to construct the region boundary shape. Then, create an Area using the Path2D and you can query contains quickly to determine whether your points are contained in the area. :-)
/* assuming a non-zero winding rule */
final Path2D boundary = new Path2D.Double();
/* initialize the boundary using moveTo, lineTo, quadTo, etc. */
final Area area = new Area(boundary);
...
/* test for whether a point is inside */
if (area.contains(...)) {
...
}
Note: there is little reason to roll your own Region and Coordinate classes for what the Java geometry classes provide. I suggest you abandon Coordinate (which is technically a misnomer as it's actually a pair of graticular coordinates) in favor of Point2D.
Note that there is a Polygon class, though it is tailored towards actual use for graphics and a relic of the past. It only supports int coordinates, which likely won't do you any good when using geopoints!