I'm working on a project with Processing that requires the ability to determine whether or not the mouse is inside of a circle. Therefore, I need to obtain the position of the circle and the position of the mouse. However, the position of the circle has been modified using matrix functions such as translate and scale. For example:
float circle_x;
float circle_y;
float circle_radius;
void setup() {
circle_x = 10.0;
circle_y = 17.0;
circle_radius = 15.0;
}
void draw() {
pushMatrix();
/* ... arbitrary number of calls to modify the matrix ... */
translate(THING, THING);
scale(THING);
translate(THING);
/* ... */
/* draw the circle */
ellipse(circle_x, circle_y, circle_radius, circle_radius);
/* now I want to detect whether or not my mouse is inside of the
circle. In order to do that, I need to modify the coordinates
of the mouse in the same fashion as circle_x and circle_y. I'm
hoping to do something like this: */
float world_x = screenToWorld_X(mouseX);
float world_y = screenToWorld_Y(mouseY);
/* ... check if [world_x, world_y] is inside the circle ... */
popMatrix();
}
Is there any way to do this in Processing? I was looking at the documentation but I couldn't seem to find any functions. If not, how can I achieve my goal?
Thanks.
Check out the coordinates section of the reference.
Specifically, you're looking for the modelX() and modelY() functions. Or you could use the screenX() and screenY() functions to go the other way and convert your world coordinates into screen coordinates.
Related
For an assignment I am making a Boardgame. (In java) This Boardgame has a map, with multiple fields/lands that have to be used. Units can be placed on them, they can move. Other things are also placed on them.
For the map I have one image I use. I looked online for solutions, but the only ones I found where for a grid game (such as chess or checkers) and the map of this game can not be divided in just squares. I tried this, but the field shapes are to different to make that work.
I had a few faint ideas as to how to work this out, but I can't quite put them into code examples and have no clue if they would work, or how.
The ideas I had:
Make some invisible buttons and bind them to specific coordinates in the picture. The problem I had with this solution was that it also had to be able to display things placed on it. It would also be very inconvenient if not all of the field was clickable.
I have a 'overlay' image with the outlines of all the fields and the 'insides' removed. I made this overlay so I could add a faint color overlay over the board. Would it be possible to use this in any kind of way?
First I though of cutting out all the loose fields and putting them together to form the one image. Only, I don't know how I would do this. Not just where to place it, but also, how can I make sure that the elements are Always in the same place compared to eachother, and my board doesn't mess up when changing screen/resolution size?
I am using javafx for the graphical elements in my game.
If there are any suggestions of something I haven't thought of myself, those are also very welcome.
If it's sufficient to retrieve the color of the pixel where the mouse was clicked, then you can do that fairly easily. If you know the image is displayed in the image view unscaled and uncropped, then all you need is:
imageView.setOnMouseClicked(e -> {
Color color = imageView.getImage().getPixelReader().getColor((int)e.getX(), (int)e.getY());
// ...
});
More generally, you may need to map the image view coordinates to the image coordinates:
imageView.setOnMouseClicked(e -> {
double viewX = e.getX();
double viewY = e.getY();
double viewW = imageView.getBoundsInLocal().getWidth();
double viewH = imageView.getBoundsInLocal().getHeight();
Rectangle2D viewport = imageView.getViewport();
double imgX = viewport.getMinX() + e.getX() * viewport.getWidth() / viewW;
double imgY = viewport.getMinY() + e.getY() * viewport.getHeight() / viewH ;
Color color = imageView.getImage().getPixelReader().getColor((int)imgX, (int)imgY);
// ...
});
Once you have the color you can do some simple analysis to see if it approximately matches the color of various items in your image, e.g. check the hue component, or check if the "distance" from a fixed color is suitably small.
A typical implementation of that might look like:
// choose a color based on what is in your image:
private final Color FIELD_GREEN = Color.rgb(10, 10, 200);
private double distance(Color c1, Color c2) {
double deltaR = c1.getRed() - c2.getRed();
double deltaG = c1.getGreen() - c2.getGreen();
double deltaB = c1.getBlue() - c2.getBlue();
return Math.sqrt(deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
}
private boolean colorsApproximatelyEqual(Color c1, Color c2, double tolerance) {
return distance(c1, c2) < tolerance ;
}
And the back in the handler you can do
if (colorsApproximatelyEqual(color, FIELD_GREEN, 0.1)) {
// process click on field...
}
Whether or not this is a viable approach depends on the nature of the image map. If the coloring in the map is too complex (or objects are not easily distinguishable by color), then you will likely need to place other elements in the scene graph and register handlers on each of them, as you describe in the question.
I'm trying to write a class that shows vectors. If I create one vector object everything works as intended. In my example code the object lin1 gets drawn with the help of the draw() function.
If I now create a second vector object, the (unchanged) draw-function doesnt do anything anymore, even though the object itself is unchanged. It's the same the other way around: Is the second object the only one existing, then it can be drawn, but only as long as lin1 doesnt exist.
Does anyone know where my mistake is?
vector lin;
vector lin2;
void setup()
{
size(500,500);
background(255);
cenX = width/2;
cenY = height/2;
noLoop();
}
void draw()
{
coordSys();
lin = new vector(0,0,100,100);
lin2 = new vector(0,0,-200,-200);
lin.draw();
lin2.draw();
lin.getAll();
}
class vector
{
float x1,y1,x2,y2;
float length;
float angle;
float gegenK, anK;
vector(float nx1, float ny1, float nx2, float ny2)
{
translate(cenX,cenY);
x1 = nx1; y1 = -ny1; x2 = nx2; y2 = -ny2;
strokeWeight(2);
// Gegenkathete
gegenK = ny2 - ny1;
// Ankathete
anK = x2 - x1;
// length and angle
length = sqrt(sq(anK) + sq(gegenK));
angle = winkel(gegenK, anK);
}
void draw()
{
stroke(0);
line(x1,y1,x2,y2);
}
}
}
Please use standard naming conventions when writing code. Specifically, your class should be Vector with an upper-case V. Also, please post your code in the form of an MCVE that compiles and runs.
Anyway, the first call in your Vector() constructor is this:
translate(cenX,cenY);
This moves the origin of the window halfway across the window. When you do this once, this simply makes your drawing calls relative to the center of the window. But when you do this twice, it moves the origin to the bottom-right corner of the window, so all of your drawings are moved off the edge of the screen.
To fix your problem, you need to move this line so it only happens once (perhaps at the beginning of the draw() function) instead of every single time you draw a Vector. Another way to approach this would be to use the pushMatrix() and popMatrix() functions to avoid this stacking of window translations.
I'm trying to implement linear interpolation and a fixed time step for my game loop. I'm using the libGDX engine and box2D. I'm attempting to find the amount the simulation moves my character's body during a world step like this:
old_pos = guyBody.getPosition();
world.step(STEP_TIME, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
new_pos = guyBody.getPosition();
printLog(new_pos.x-old_pos.x);
This returns 0 each time. The simulation works fine, and the body definitely moves each step.
Additional code:
#Override
public void render(float delta) {
accumulator+=delta;
while (accumulator>=STEP_TIME){
accumulator-=STEP_TIME;
stepWorld();
}
alpha = accumulator/STEP_TIME;
update(delta);
//RENDER
}
private void stepWorld() {
old_pos = guyBody.getPosition();
old_angle = guyBody.getAngle() * MathUtils.radiansToDegrees;
world.step(STEP_TIME, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
new_angle = guyBody.getAngle() * MathUtils.radiansToDegrees;
new_pos = guyBody.getPosition();
}
I'm attempting to use alpha to check how far I am in between physics steps so I can interpolate a Sprite's position.
Thanks!
Body's getPosition method is returning Vector reference - that means that you not copying it by value but only assign "pointer" on position object to old_pos/new_pos. However you are assigning it once before step and then after step all in all both variables keeps the same object with state after step already.
What you need to do is to copy position vector by value - to do this you can use Vector's cpy() method.
Your code should looks like
old_pos = guyBody.getPosition().cpy();
world.step(STEP_TIME, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
new_pos = guyBody.getPosition().cpy();
printLog(new_pos.x-old_pos.x);
If you do not use y coordinate you should also consider keeping only x in float type variable to not copy whole object (however it should not really impact your performance).
While the accepted response does answer my question, I wanted to add some information I figured out while trying to get this to work that I wish I knew at the beginning of this.
If you're going to use a fixed timestep for your physics calculations (which you should), you should also interpolate(or extrapolate) a Sprite's position between physics steps. In my code, the screen is being rendered more often than the world is being stepped:
#Override
public void render(float delta) {
accumulator+=delta;
while (accumulator>=STEP_TIME){
accumulator-=STEP_TIME;
stepWorld();
}
alpha = accumulator/STEP_TIME;
update(delta);
//RENDER using alpha
}
To avoid a jittery rendering of moving objects, render Sprites or Textures at their positions, modified by alpha. Since alpha is the ratio of your accumulator to the step time, it will always be between 0 and 1.
You then need to find how much your body is moving during one step. This can be done with the accepted answer or using the body velocity:
newPos = oldPos + body.getLinearVelocity()*STEP_TIME*alpha
Then just render Sprite at the new position and you should see smooth movement with your fixed timestep at most frame rates.
I am using androidplot with PanZoom attached:
PanZoom.attach(plot);
Therefore I can zoom in and out as it should.
What I want next is to draw a circle at a given point.
Right now I use the strokewidth to set the dimension of the circle.
But when I zoom in and out, the circle size remains the same, although it should scale according to the zoom level. So imagine I zoom in infinitely, the circle should at a certain amount of zoom level cover the whole screen.
But it does not.
How can I achieve this?
I was thinking aboud increasing the strokewidth of the circle according to the zoomlevel but I was neither able to get the zoomlevel nor to get the domain levels on the left and right side of the plot.
EDIT:
In xml folder I create a file e.g. circle.xml:
<?xml version="1.0" encoding="utf-8"?>
<config
fillPaint.color="#00000000"
linePaint.color="#00000000"
linePaint.strokeWidth="0dp"
pointLabelFormatter.textPaint.color="#FFFFFF"
vertexPaint.color="#371cd1d4"
vertexPaint.strokeWidth="20dp"/>
and in java
sigmaLabelFormatter = new LineAndPointFormatter();
sigmaLabelFormatter.setPointLabelFormatter(new PointLabelFormatter());
sigmaLabelFormatter.configure(activity.getApplicationContext(), R.xml.circle);
sigmaLabelFormatter.setPointLabelFormatter(null);
Zoom only affects the drawing of XYSeries data; if you draw directly on the canvas, it will be drawn exactly where you specify on the canvas regardless of pan/zoom.
One thing you can do though is to make series to represent your circle and draw the circle there. This will make the circle respond to both pan and zoom actions. The tricky part will be picking enough points to ensure that the circle appears smooth at your highest supported zoom level.
I found a solution to my problem, since I finally managed:
to get the domain levels on the left and right side of the plot.
or to be more precise to get the width of the plot.
Since the dimensions of the plot is in meters, I do the calculation as follows:
private float calculateDP(float px){
return px / (densityDpi / densityDefault);
}
private float pixelsPerMeter(float value){
float w = plot.getGraph().getWidgetDimensions().canvasRect.width();
float w2 = plot.getBounds().getWidth().floatValue();
return value * (w / w2);
}
private void init(Activity activity){
densityDpi = activity.getResources().getDisplayMetrics().densityDpi;
densityDefault = android.util.DisplayMetrics.DENSITY_DEFAULT;
}
private void onCreate(){
// ... lots of stuff
labelFormatter.getVertexPaint().setStrokeWidth(calculateDP(pixelsPerMeter(2)));
}
Might it help somebody out there...
I've got a camera set up, and I can move with WASD and rotate the view with the mouse. But now comes the problem: I want to add physics to the camera/player, so that it "interacts" with my other jBullet objects. How do I do that? I thought about creating a RigidBody for the camera and storing the position there, so that jBullet can apply its physics to the camera. Then, when I need to change something (the position), I could simply change it in the RigidBody. But I didn't find any methods for editing the position.
Can you push me in the right direction or maybe give me an example source code?
I was asking the same question myself a few days ago. My solution was as Sierox said. To create a RigidBody of BoxShape and add that to the DynaicsWorld. To move the camera arund, apply force to its rigidbody. I have damping set to .999 for linear and 1 for angular to stop the camera when no force is applied, i.e. the player stops pressing the button.
I also use body.setAngularFactor(0); so the box isn't tumbling all over the place. Also set the mass really low as not to interfere too much with other objects, but still be able to jump on then and run into them, and otherwise be affected by them.
Remember to convert your x,y, and z coordinates to cartesian a plane so you move in the direction of the camera. i.e.
protected void setCartesian(){//set xyz to a standard plane
yrotrad = (float) (yrot / 180 * Math.PI);
xrotrad = (float) (xrot / 180 * Math.PI);
float pd = (float) (Math.PI/180);
x = (float) (-Math.cos(xrot*pd)*Math.sin(yrot*pd));
z = (float) (-Math.cos(xrot*pd)*Math.cos(yrot*pd));
//y = (float) Math.sin(xrot*pd);
}//..
public void forward(){// move forward from position in direction of camera
setCartesian();
x += (Math.sin(yrotrad))*spd;
z -= (Math.cos(yrotrad))*spd;
//y -= (Math.sin(xrotrad))*spd;
body.applyForce(new Vector3f(x,0,z),getThrow());
}//..
public Vector3f getThrow(){// get relative position of the camera
float nx=x,ny=y,nz=z;
float xrotrad, yrotrad;
yrotrad = (float) (yrot / 180 * Math.PI);
xrotrad = (float) (xrot / 180 * Math.PI);
nx += (Math.sin(yrotrad))*2;
nz -= (Math.cos(yrotrad))*2;
ny -= (Math.sin(xrotrad))*2;
return new Vector3f(nx,ny,nz);
}//..
to jump just use body.setLinearVelocity(new Vector3f(0,jumpHt,0)); and set jumpHt to whatever velocity you wish.
I use getThrow to return a vector for other objects i may be "throwing" on screen or carrying. I hope I answered your question and didn't throw in too much non-essential information.I'll try and find the source that gave me this idea. I believe it was on the Bullet forums.
------- EDIT ------
Sorry to have left that part out
once you have the rigid body functioning properly you just have to get it's coordinates and apply that to your camera for example:
float mat[] = new float[16];
Transform t = new Transform();
t = body.getWorldTransform(t);
t.origin.get(mat);
x = mat[0];
y = mat[1];
z = mat[2];
gl.glRotatef(xrot, 1, 0, 0); //rotate our camera on teh x-axis (left and right)
gl.glRotatef(yrot, 0, 1, 0); //rotate our camera on the y-axis (up and down)
gl.glTranslatef(-x, -y, -z); //translate the screen to the position of our camera
In my case I'm using OpenGL for graphics. xrot and yrot represent the pitch and yaw of your camera. the code above gets the world transform in the form of a matrix and for the purposes of the camera you need only to pull the x,y, and z coordinates then apply the transform.
from here, to move the camera, you can set the linear velocity of the rigid body to move the camera or apply force.
Before you read this answer I would like to mention that I have a problem with the solution stated in my answer. You can follow my question about that problem so that you can have the solution too if you use this answer.
So. First, you need to create a new BoxShape:
CollisionShape cameraHolder = new BoxShape(SIZE OF CAMERAHOLDER);
And add it to your world so that it interacts with all the other objects. Now you need to change all the methods about camera movement (not rotation) so that the methods move your cameraHolder but not your camera. Then set the position of your Camera to the position of the cameraHolder.
Again, if you have a problem where you can't move properly, you can check my question and wait for an answer. You also can find a better way of doing this.
If you have problems or did not understand something about the answer, please state it as a comment.