I am writing an application that maps eyetracking data to an image that is displayed to the user. To make sure the GUI doesn't freeze i do the eyetracking data polling, mapping and other calculations in a separate Task.
The problem i am facing is, that for mapping screen coordinates to my displayed image, i have to call Node.screenToLocal(x,y). How can i make these calls without violating thread-safety?
Use a AnimationTimer to do this call:
Task<Point2D> task = new Task<Point2D>() {
#Override
protected Point2D call() throws Exception {
while (!isCancelled()) {
Point2D eyePos = getEyePos();
updateValue(eyePos);
}
}
};
AnimationTimer animation = new AnimationTimer() {
#Override
public void handle(long now) {
Point2D point = task.getValue();
if (value != null) {
Point2D pointOnScreen = node.screenToLocal(point);
// TODO: use result
}
}
};
animation.play();
Related
I'm trying to create an update function for multiple ImageView's but kept running into issues. I'm currently passing an individual ImageView to the updateBlobPosition function inside a timer, which works fine for one ImageView. But as soon I pass a second ImageView (blob2), now both ImageViews mimic each other as they have the same trajectory and velocity.
In addition, when one ImageView hits a wall and bounces back, the other one does the same. What I want is for each ImageView to be independent of each other. Any help would be appreciated.
...
blob1.setX(generateRandomNumber(0, 930));
blob1.setY(generateRandomNumber(0, 1750));
blob2.setX(generateRandomNumber(0, 930));
blob2.setY(generateRandomNumber(0, 1750));
...
//start the timer
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
playerMovement();
updateBlobPosition(blob1);
updateBlobPosition(blob2);
collision(blob1);
collision(blob2);
}
});
}
}, 0, 20);
...
protected ImageView updateBlobPosition(ImageView blob) {
blobX = blob.getX();
blobY = blob.getY();
blobX += blobVelocityX;
blobY += blobVelocityY;
//left
if ((blob.getX() + blobVelocityX < 0)) {
blobVelocityX = -blobVelocityX;
}
//right
else if (blob.getX() - blobVelocityX > 930) {
blobVelocityX = -Math.abs(blobVelocityX);
}
//top
if ((blob.getY() + blobVelocityY < -20)) {
blobVelocityY = -blobVelocityY;
}
//bottom
else if (blob.getY() - blobVelocityY > 1750) {
blobVelocityY = -Math.abs(blobVelocityY);
}
blob.setX(blobX);
blob.setY(blobY);
return blob;
}
You're using the same velocity variables for both. So of course they be updated in the same way. If you want them to move independently, give them independent speeds.
I'm working on modifying the Attraction2D example from the Toxiclibs library to be controlled by gestures from a Leap Motion sensor, as opposed to the mouse in the example.
I'm doing all my gesture recognition in an Open Frameworks app, and sending that over OSC.
When a Gesture 0 event occurs, I call the method below to remove the gestureAttractor from the physics object:
void resetAttraction() {
if (gestureAttractor != null){
physics.removeBehavior(gestureAttractor);
println("ATTRACTOR NULL");
} else {
println("not null");
}
}
If a Gesture 1 event occurs, I call this method to create a new gestureAttractor, and add it back to the physics object:
void addAttraction(){
if (gestureAttractor == null) {
println("ATTRACTOR NULL");
position1.set(340, 191);
gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
physics.addBehavior(gestureAttractor);
} else {
println("not null");
}
}
What seems to happen consistently is whenever the gesture state changes, I'll get a ConcurrentModificationException crash at physics.update(); in the draw method.
I'm sure it has something to do with the way the lifecycle of these objects are handled, but I haven't been able to determine anything yet - anyone have any ideas?
Below is the entirety of the sketch:
import toxi.geom.*;
import toxi.physics2d.*;
import toxi.physics2d.behaviors.*;
import oscP5.*;
import netP5.*;
OscP5 oscP5;
int NUM_PARTICLES = 750;
VerletPhysics2D physics;
//AttractionBehavior2D mouseAttractor;
AttractionBehavior2D gestureAttractor;
//Vec2D mousePos;
Vec2D position1;
boolean isGestureAttractorAdded;
void setup() {
size(680, 382,P3D);
// setup physics with 10% drag
physics = new VerletPhysics2D();
physics.setDrag(0.05f);
physics.setWorldBounds(new Rect(0, 0, width, height));
// the NEW way to add gravity to the simulation, using behaviors
physics.addBehavior(new GravityBehavior2D(new Vec2D(0, 0.15f)));
// start oscP5, listening for incoming messages at port 12000
oscP5 = new OscP5(this, 6000);
position1 = new Vec2D(340, 191);
addAttraction();
//gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
//physics.addBehavior(gestureAttractor);
}
void addParticle() {
VerletParticle2D p = new VerletParticle2D(Vec2D.randomVector().scale(5).addSelf(width / 2, 0));
physics.addParticle(p);
// add a negative attraction force field around the new particle
physics.addBehavior(new AttractionBehavior2D(p, 20, -1.2f, 0.01f));
}
void draw() {
background(255,0,0);
noStroke();
fill(255);
if (physics.particles.size() < NUM_PARTICLES) {
addParticle();
}
physics.update();
for (VerletParticle2D p : physics.particles) {
ellipse(p.x, p.y, 5, 5);
}
}
void mousePressed() {
//position1 = new Vec2D(mouseX, mouseY);
//create a new positive attraction force field around the mouse position (radius=250px)
//gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
//physics.addBehavior(gestureAttractor);
//println(physics.behaviors);
}
void mouseDragged() {
// update mouse attraction focal point
//position1.set(mouseX, mouseY);
}
void mouseReleased() {
// remove the mouse attraction when button has been released
//physics.removeBehavior(gestureAttractor);
}
///// OSC RECEIVING
void oscEvent(OscMessage theOscMessage) {
/* check if theOscMessage has the address pattern we are looking for. */
if (theOscMessage.checkAddrPattern("/gesture_classification") == true) {
/* check if the typetag is the right one. */
if(theOscMessage.checkTypetag("i")) {
/* parse theOscMessage and extract the values from the osc message arguments. */
int gestureClassLabel = theOscMessage.get(0).intValue();
println(" Gesture is: ", gestureClassLabel);
if (gestureClassLabel == 0){
resetAttraction();
} else if (gestureClassLabel == 1) {
addAttraction();
} else if (gestureClassLabel == 2) {
//physics.removeBehavior(gestureAttractor);
}
}
}
}
//////METHODS FOR SETTING POSITION / REMOVAL OF ATTRACTORS...
void resetAttraction() {
if (gestureAttractor != null){
physics.removeBehavior(gestureAttractor);
println("ATTRACTOR NULL");
} else {
println("not null");
}
}
void addAttraction(){
if (gestureAttractor == null) {
println("ATTRACTOR NULL");
position1.set(340, 191);
gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
physics.addBehavior(gestureAttractor);
} else {
println("not null");
}
}
tl;dr: You shouldn't modify a data structure with one thread while you're iterating over it from another thread.
The draw() function is happening on one thread, and it's accessing and modifying data structures inside the physics library.
The oscEvent() function is happening on another thread, and it's also accessing and modifying those same data structures. That's what's causing your error. And please note that wrapping it in a try block is not fixing anything. It's just printing out more information when the error does happen.
To really fix the problem, you need to read up on synchornizing data access between threads. For example, you could use synchronized blocks to prevent different threads from accessing the same data structure. You'll find a ton of results if you google your error.
I have a car in my javaFX project where the position of the car(Node) should change(the car should jump smoothly) when SPACE is pressed . so I have used an event handler which invokes a method named :moveUp()
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode())
{
case SPACE:
moveUp();
break;
}
}
});
This creates a new Thread where the speed of the car is changed 10 times with an interval of 75 milliseconds.
private void moveUp() {
new Thread(new Runnable() {
#Override
public void run() {
carSpeed = 10;
for(;carSpeed>=0;carSpeed--)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y-=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
for(carSpeed=0;carSpeed<=10;carSpeed++)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y+=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
}
}).start();
}
This code is doing like this (pressing SPACE once and jumping the car):
If I don't use a different thread the GUI thread will be freeze and if I don't use Thread.sleep() the car will jump abruptly(not smoothly). This code is doing well . But I have learnt that thread.start() doesn't guarantee immediate execution of the thread. How can I guarantee immediate execution ?
I would suggest to stay in the FX Application Thread and to use the class AnimationTimer. Here is a short demo for a smooth jump:
private void moveUp() {
new AnimationTimer() {
long startTime = -1;
double initCarPosition_Y;
#Override
public void handle(long now) {
if(startTime == -1){
startTime = now;
initCarPosition_Y = carPosition_Y;
carSpeedX = 3d;
carSpeedY = -15d;
}
double time = (now - startTime) / 1E9d;
carPosition_X += carSpeedX * time;
carPosition_Y += carSpeedY * time;
if(carSpeed > 0 && initCarPosition_Y <= carPosition_Y){
carPosition_Y = initCarPosition_Y;
stop();
}
carSpeedY += 0.8d * time; //gravity
car.relocate(carPosition_X, carPosition_Y);
}
}.start();
}
This approach gives you full and direct control over what happens in every single frame. However, javaFX also provides high level animation classes including predefined interpolators and transitions. Suitable for alternative approaches could be the following classes:
PathTransition: Allows you to define points and curves which a given node is animated along.
TimeLine: Allows you to define arbitrary animation key frames based on properties like the position of a node.
Note that generally working with these high level classes could become challenging when you want to animate an user controlled actor like your car. These classes all take an exact duration for the animation to last. For example when you want to translate a node as long as a specific key is pressed, you don't know the duration of the animation in beforehand.
I need specific behaviour when my custom control resized. When control resized(resize or resizeRelocate methods called) first I want just scale child nodes to fit new bounds. And if there is no size changes in i.e. 1 second - make expensive calculations and relayout of child nodes. If I recalculate on every resize call - it makes Stage resizing very laggy. How can I achieve that?
This is example, here CurvePlot is just data model:
class ShapeCurvePlot extends Polyline {
private final CurvePlot model;
public ShapeCurvePlot(CurvePlot model) {
Objects.requireNonNull(model);
this.model = model;
strokeProperty().bind(model.strokeProperty());
strokeWidthProperty().bind(model.strokeWidthProperty());
}
#Override
public boolean isResizable() {
return true;
}
#Override
public void resize(double width, double height) {
// "expensive calculation"
Series series = model.getSeries();
double xOffset = series.valueAxis().getLeft();
double yOffset = series.keyAxis().getLeft();
double yScale = height / series.keyAxis().range();
double xScale = width / series.valueAxis().range();
getPoints().clear();
for (Map.Entry<Double, Double> item : series.data().entrySet()) {
double x = item.getValue();
double y = item.getKey();
getPoints().addAll((x - xOffset) * xScale, (y - yOffset) * yScale);
}
}
}
While in this example resize works fast, other shapes, that I need, not so easy to recalculate. I'm asking for generic solution to delay calculation until there was no resizing within X seconds.
ps. sorry for my english, I'm not native speaker..
I have come across this issue before, both in C# and Java. My solution, not saying that it is the best solution, but it seems to work, is to use some form of timer that triggers the expensive re-calculation.
In my situation, I have used this in search text boxes, the actual search is only triggered after the user has not pressed a key for some time (say 500ms), preventing the triggering of the search for every key stroke.
In your situation, you could trigger the timer within the resize() method. When the timer runs out, it then performs the expensive operation. Triggering the timer while it is already waiting results in the timer being reset.
In java I did this by using a java.util.Timer for the timer which would then run a java.util.TimerTask that I created. Within the run() method of the TimerTask, I created a javafx.concurrent.Task and ran that in a new Thread. The call() method of the Task is where the work was done. This ensured that the work was done on the JavaFX thread, otherwise you get threading issues.
Hopefully this is some help to you.
Edit ... here's some code that should do what I was talking about above. Note: This code is completely untested, I think it should work though
class ShapeCurvePlot extends Polyline {
private class ResizeTimerTask extends TimerTask {
private ShapeCurvePlot plot;
public ResizeTimerTask(ShapeCurvePlot plot) {
this.plot = plot;
}
/* (non-Javadoc)
* #see java.util.TimerTask#run()
*/
#Override
public void run() {
Task<Object> t = new Task<Object>() {
#Override
protected Object call() throws Exception {
// "expensive calculation"
Series series = plot.getSeries();
double xOffset = series.valueAxis().getLeft();
double yOffset = series.keyAxis().getLeft();
double yScale = height / series.keyAxis().range();
double xScale = width / series.valueAxis().range();
plot.getPoints().clear();
for (Map.Entry<Double, Double> item : series.data().entrySet()) {
double x = item.getValue();
double y = item.getKey();
plot.getPoints().addAll((x - xOffset) * xScale, (y - yOffset) * yScale);
}
}
}
new Thread(t).start();
}
}
private static int RESIZE_DELAY_MS = 1000;
private final CurvePlot model;
private Timer resizeTimer;
public ShapeCurvePlot(CurvePlot model) {
Objects.requireNonNull(model);
this.model = model;
strokeProperty().bind(model.strokeProperty());
strokeWidthProperty().bind(model.strokeWidthProperty());
}
#Override
public boolean isResizable() {
return true;
}
public Series getSeries() {
return this.model.getSeries();
}
#Override
public void resize(double width, double height) {
// cancel the current task (if any).
if(this.resizeTimer != null) {
this.resizeTimer.cancel();
this.resizeTimer.purge();
this.resizeTimer = null;
}
try {
// create a new task that will be executed in 1 second.
this.resizeTimer = new Timer();
this.resizeTimer.schedule(new ResizeTimerTask(this), RESIZE_DELAY_MS);
} catch (OutOfMemoryError oom) {
oom.printStackTrace();
if(this.resizeTimer != null) {
this.resizeTimer.cancel();
this.resizeTimer.purge();
this.resizeTimer = null;
}
}
}
}
Further Edit ... Just spent some of today playing with JavaFX threading issues, there is another option that you could use for running the time consuming task in the JavaFX display thread. Rather than using a Task, you could execute a Runnable in the JavaFX thread using javafx.application.Platform.runLater(Runnable r). This will execute the runnable some time in the future, with the benefit that all runnables that are run in this way are processed in FIFO order. This can be handy to prevent things from getting out of order while still being able to run them in an async manner on the JavaFX display thread.
To do that, you would change the implementation of the run() method of the ResizeTimerTask class to:
public void run() {
Platform.runLater(new Runnable() {
#Override
public void run() {
// "expensive calculation"
Series series = plot.getSeries();
double xOffset = series.valueAxis().getLeft();
double yOffset = series.keyAxis().getLeft();
double yScale = height / series.keyAxis().range();
double xScale = width / series.valueAxis().range();
plot.getPoints().clear();
for (Map.Entry<Double, Double> item : series.data().entrySet()) {
double x = item.getValue();
double y = item.getKey();
plot.getPoints().addAll((x - xOffset) * xScale, (y - yOffset) * yScale);
}
}
});
}
does anyone knows how to use the blackberry JDE API to create a screen slide animation similar to Featured Items screen in the Blackberry App World? I am aware that in blackberry 5.0, there are some transition apis to perform that. But I am looking to do it for version 4.6 OS. It has the nice scrolling effect using the scrolling ball in blackberry bold.
Thanks.
As an alternative to the screenshot/Bitmap approach...
In the paint method of your screen you can use Graphics.pushContext(..) to push a clipping region and drawing offset. For best results, you'll want to do the transition in a runnable, and synchronize on the event lock. This will ensure that your screen can be dismissed in the middle of a transition.
Rough example:
class TransitionScreen extends Screen {
private int transitionOffset;
private boolean isTransitionHorizontal;
private ScreenTransition currentTransition;
public TransitionScreen(boolean isTransitionHorizontal) {
this.isTransitionHorizontal = isTransitionHorizontal;
transitionOffset = getTransitionMaximum(); // So the screen starts offset
}
protected void paint(Graphics graphics) {
// use transitionOffset as x or y depending on isTransitionHorizontal
graphics.pushContext(...);
}
protected void onExposed() {
transitionToOffset(0);
}
protected void onObscured() {
int target = getTransitionMaximum();
transitionToOffset(target);
}
private int getTransitionMaximum() {
return isTransitionHorizontal ? Display.getWidth() : Display.getHeight();
}
private void transitionToOffset(int target) {
if (currentTransition != null) {
currentTransition.stop();
}
currentTransition = new ScreenTransition(target);
getApplication().invokeLater(currentTransition);
}
}
class ScreenTransition implements Runnable {
private boolean animating;
private int target;
public ScreenTransitionUpdater(int target) {
this.target = target;
}
public void stop() {
animating = false;
}
public void run() {
while(animating) {
Object eventLock = getApplication().getEventLock();
synchronized(eventLock) {
// Interpolate myOffset to target
// Set animating = false if myOffset = target
invalidate();
}
}
}
}
No need to mark animating as volatile as it is ignored on this platform.
Maybe use a timer to change the coordinate position of the images in the paint method