JFreechart draw arc on chart - annotations

I have 2 questions
1)I am trying to draw an arc on an XYplot using the shape annotation. I used the XYLine annotation to draw a line and I want the arc to start where the line ends. I am having some issues with the parameters.I want the arc to have a height of 17, width 44, and start at the point(3.0, 17) of the plot(this is where the line ends). But the code below does not work. Can someone please tell me what is wrong with the code?
Arc2D.Double arc = new Arc2D.Double(3.0,
16.9,
44.0,
17.04,
180.0,
180.0,
Arc2D.OPEN
);
plot.addAnnotation(new XYShapeAnnotation(arc,
new BasicStroke(2.0f), Color.white));
XYLineAnnotation a1 = new XYLineAnnotation(3.0, 0.0, 3.0,
16.9, new BasicStroke(2.0f), Color.white);
2)How can I draw a similar figure on a polar plot?
Thanks

The critical thing about Arc2D is the bounding rectangle. To make the half-arc H units high, the bounds must be 2 * H units high.
AFAIK, PolarPlot does not support annotations.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Arc2D;
import java.util.Random;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYLineAnnotation;
import org.jfree.chart.annotations.XYShapeAnnotation;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/** #see http://stackoverflow.com/questions/6604211 */
public class ArcTest {
private static final Random r = new Random();
private static final double PI = 180d;
private static final int X = 3;
private static final int Y = 0;
private static final int W = 44;
private static final int H = 17;
public static void main(String[] args) {
JFreeChart chart = ChartFactory.createXYLineChart(
"ArcTest", "X", "Y", createDataset(),
PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = chart.getXYPlot();
XYLineAnnotation line = new XYLineAnnotation(
X, Y, X, H, new BasicStroke(2f), Color.blue);
plot.addAnnotation(line);
Arc2D.Double arc = new Arc2D.Double(
X, Y, W, 2 * H, PI, PI, Arc2D.OPEN);
plot.addAnnotation(new XYShapeAnnotation(arc,
new BasicStroke(2.0f), Color.blue));
ChartFrame frame = new ChartFrame("First", chart);
frame.pack();
frame.setVisible(true);
}
private static XYDataset createDataset() {
XYSeriesCollection result = new XYSeriesCollection();
XYSeries series = new XYSeries("ArcTest");
series.add(0, 0);
series.add(W, W);
result.addSeries(series);
return result;
}
}

Related

How to make my circle appear with classes and mouseclicks?

I am new to JavaFx and i am making a simple drawing program where i draw shapes. The problem i am having now is that i dont know how to make the circle appear on the screen when i click on the screen. So first I want to press a button that says "Circle" and then when i click on the canvas i want it to spawn. (I am switching between scenebuilder and intellij btw).
This is some of my program:
Classes:
public abstract class Shape {
double x;
double y;
double width;
double height;
public Color color = Color.WHITE;
public void creatingShapes(double x, double y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void setColor(Color color) {
this.color = color;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public Color getColor() {
return color;
}
public abstract void draw(GraphicsContext g);
}
public class Circle extends Shape {
#Override
public void draw(GraphicsContext g) {
g.setFill(color);
g.fillOval(200,200,200,200);
g.fillRect(getX(),getY(),getWidth(),getHeight());
g.setStroke(Color.BLACK);
g.strokeOval(getX(),getY(),getWidth(),getHeight());
====================================================
Controller class:
public class HelloController {
#FXML
private Button logoutButton;
#FXML
private BorderPane scenePane;
Stage stage;
#FXML
private ColorPicker myColorPicker;
#FXML
private ChoiceBox<String> myChoiceBox;
#FXML
private Button circle;
#FXML
private GraphicsContext g;
private final Shape[] shapes = new Shape[500];
Canvas canvas = new Canvas(310,333);
boolean drawShape = true;
int count = 0;
private final Color currentColor = Color.BLUE;
private final String[] menuAlternatives = {"Sparning", "Testing?", "Exit?"};
public void onCircleClicked() {
circle.setOnAction((event) -> addShape(new Circle()));
}
//skapa shapes
public void addShape(Shape shape) {
shape.setColor(currentColor);
shape.creatingShapes(10,10,150,100);
shapes[count] = shape;
count++;
paintCanvas();
}
public void changeColor(ActionEvent event) {
Color myColor = myColorPicker.getValue();
scenePane.setBackground(new Background(new BackgroundFill(myColor, null, null)));
}
public void initialize() {
g = canvas.getGraphicsContext2D();
}
public void paintCanvas() {
g.setFill(Color.WHITE);
g.fillRect(0,0,400,400);
Arrays.stream(shapes, 0, count).forEach(s -> s.draw(g));
}
Placing a circle on canvas with mouse event
From Doc
public void fillOval(double x,
double y,
double w,
double h)
Fills an oval using the current fill paint.
This method will be affected by any of the global common or fill attributes
as specified in the Rendering Attributes Table.
Parameters:
x - the X coordinate of the upper left bound of the oval.
y - the Y coordinate of the upper left bound of the oval.
w - the width at the center of the oval.
h - the height at the center of the oval.
As we can see x and y params from fillOval() will put the circle at the left upper corner of its bound . to spawn at its very center , we need to subtract half widht and half height to x and y coordinates given by mouseclick event.
this is a single class javafx app you can try
App.java
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage stage) {
Canvas canvas = new Canvas(640, 480);
GraphicsContext context = canvas.getGraphicsContext2D();
canvas.setOnMouseClicked(e -> {
double x = e.getX();
double y = e.getY();
context.setFill(Color.AQUAMARINE);
context.setStroke(Color.BLACK);
context.fillOval(x - 20, y - 20, 40, 40);
context.strokeOval(x - 20, y - 20, 40, 40);
});
var scene = new Scene(new Group(canvas), 640, 480);
stage.setScene(scene);
stage.setTitle("spawn with mouse click");
stage.show();
}
public static void main(String[] args) {
launch();
}
}

JavaFX 8 Dynamic Node scaling

I'm trying to implement a scene with a ScrollPane in which the user can drag a node around and scale it dynamically. I have the dragging and scaling with the mouse wheel working as well as a reset zoom, but I'm having trouble with the calculations to fit the node to the width of the parent.
Here is my code as an sscce.
(works) Mouse wheel will zoom in and out around the mouse pointer
(works) Left or right mouse press to drag the rectangle around
(works) Left double-click to reset the zoom
(doesn't work) Right double-click to fit the width
If I zoom in or out or change the window size, the fit to width does not work.
If anyone can help me with the calculations to fit the node to the width of the parent, I would very much appreciate it.
EDITED:
I marked the method that is not working correctly. It is fitWidth(), which is invoked by right mouse button double-clicking.
I edited the text of the question for clarity and focus
Hopefully this is more clear now.
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ZoomAndPanExample extends Application {
private ScrollPane scrollPane = new ScrollPane();
private final DoubleProperty zoomProperty = new SimpleDoubleProperty(1.0d);
private final DoubleProperty deltaY = new SimpleDoubleProperty(0.0d);
private final Group group = new Group();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
scrollPane.setPannable(true);
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
AnchorPane.setTopAnchor(scrollPane, 10.0d);
AnchorPane.setRightAnchor(scrollPane, 10.0d);
AnchorPane.setBottomAnchor(scrollPane, 10.0d);
AnchorPane.setLeftAnchor(scrollPane, 10.0d);
AnchorPane root = new AnchorPane();
Rectangle rect = new Rectangle(80, 60);
rect.setStroke(Color.NAVY);
rect.setFill(Color.NAVY);
rect.setStrokeType(StrokeType.INSIDE);
group.getChildren().add(rect);
// create canvas
PanAndZoomPane panAndZoomPane = new PanAndZoomPane();
zoomProperty.bind(panAndZoomPane.myScale);
deltaY.bind(panAndZoomPane.deltaY);
panAndZoomPane.getChildren().add(group);
SceneGestures sceneGestures = new SceneGestures(panAndZoomPane);
scrollPane.setContent(panAndZoomPane);
panAndZoomPane.toBack();
scrollPane.addEventFilter( MouseEvent.MOUSE_CLICKED, sceneGestures.getOnMouseClickedEventHandler());
scrollPane.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
scrollPane.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
scrollPane.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());
root.getChildren().add(scrollPane);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
class PanAndZoomPane extends Pane {
public static final double DEFAULT_DELTA = 1.3d;
DoubleProperty myScale = new SimpleDoubleProperty(1.0);
public DoubleProperty deltaY = new SimpleDoubleProperty(0.0);
private Timeline timeline;
public PanAndZoomPane() {
this.timeline = new Timeline(60);
// add scale transform
scaleXProperty().bind(myScale);
scaleYProperty().bind(myScale);
}
public double getScale() {
return myScale.get();
}
public void setScale( double scale) {
myScale.set(scale);
}
public void setPivot( double x, double y, double scale) {
// note: pivot value must be untransformed, i. e. without scaling
// timeline that scales and moves the node
timeline.getKeyFrames().clear();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.millis(200), new KeyValue(translateXProperty(), getTranslateX() - x)),
new KeyFrame(Duration.millis(200), new KeyValue(translateYProperty(), getTranslateY() - y)),
new KeyFrame(Duration.millis(200), new KeyValue(myScale, scale))
);
timeline.play();
}
/**
* !!!! The problem is in this method !!!!
*
* The calculations are incorrect, and result in unpredictable behavior
*
*/
public void fitWidth () {
double scale = getParent().getLayoutBounds().getMaxX()/getLayoutBounds().getMaxX();
double oldScale = getScale();
double f = (scale / oldScale)-1;
double dx = getTranslateX() - getBoundsInParent().getMinX() - getBoundsInParent().getWidth()/2;
double dy = getTranslateY() - getBoundsInParent().getMinY() - getBoundsInParent().getHeight()/2;
double newX = f*dx + getBoundsInParent().getMinX();
double newY = f*dy + getBoundsInParent().getMinY();
setPivot(newX, newY, scale);
}
public void resetZoom () {
double scale = 1.0d;
double x = getTranslateX();
double y = getTranslateY();
setPivot(x, y, scale);
}
public double getDeltaY() {
return deltaY.get();
}
public void setDeltaY( double dY) {
deltaY.set(dY);
}
}
/**
* Mouse drag context used for scene and nodes.
*/
class DragContext {
double mouseAnchorX;
double mouseAnchorY;
double translateAnchorX;
double translateAnchorY;
}
/**
* Listeners for making the scene's canvas draggable and zoomable
*/
public class SceneGestures {
private DragContext sceneDragContext = new DragContext();
PanAndZoomPane panAndZoomPane;
public SceneGestures( PanAndZoomPane canvas) {
this.panAndZoomPane = canvas;
}
public EventHandler<MouseEvent> getOnMouseClickedEventHandler() {
return onMouseClickedEventHandler;
}
public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
return onMousePressedEventHandler;
}
public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
return onMouseDraggedEventHandler;
}
public EventHandler<ScrollEvent> getOnScrollEventHandler() {
return onScrollEventHandler;
}
private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
sceneDragContext.mouseAnchorX = event.getX();
sceneDragContext.mouseAnchorY = event.getY();
sceneDragContext.translateAnchorX = panAndZoomPane.getTranslateX();
sceneDragContext.translateAnchorY = panAndZoomPane.getTranslateY();
}
};
private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
panAndZoomPane.setTranslateX(sceneDragContext.translateAnchorX + event.getX() - sceneDragContext.mouseAnchorX);
panAndZoomPane.setTranslateY(sceneDragContext.translateAnchorY + event.getY() - sceneDragContext.mouseAnchorY);
event.consume();
}
};
/**
* Mouse wheel handler: zoom to pivot point
*/
private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {
#Override
public void handle(ScrollEvent event) {
double delta = PanAndZoomPane.DEFAULT_DELTA;
double scale = panAndZoomPane.getScale(); // currently we only use Y, same value is used for X
double oldScale = scale;
panAndZoomPane.setDeltaY(event.getDeltaY());
if (panAndZoomPane.deltaY.get() < 0) {
scale /= delta;
} else {
scale *= delta;
}
double f = (scale / oldScale)-1;
double dx = (event.getX() - (panAndZoomPane.getBoundsInParent().getWidth()/2 + panAndZoomPane.getBoundsInParent().getMinX()));
double dy = (event.getY() - (panAndZoomPane.getBoundsInParent().getHeight()/2 + panAndZoomPane.getBoundsInParent().getMinY()));
panAndZoomPane.setPivot(f*dx, f*dy, scale);
event.consume();
}
};
/**
* Mouse click handler
*/
private EventHandler<MouseEvent> onMouseClickedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.getButton().equals(MouseButton.PRIMARY)) {
if (event.getClickCount() == 2) {
panAndZoomPane.resetZoom();
}
}
if (event.getButton().equals(MouseButton.SECONDARY)) {
if (event.getClickCount() == 2) {
panAndZoomPane.fitWidth();
}
}
}
};
}
}
I found the answer. I was looking at the wrong calculations, assuming it to be related to the translations. The real culprit was the calculation for the difference in scale. I simply changed this:
double f = (scale / oldScale)-1;
to this:
double f = scale - oldScale;

using JavaFX, how can I place one shape on top of the other?

I am trying to make a checkers game. I will have 64 rectangles, and some of the rectangles will have circles on top of them (representing a checkers piece). How can I do this (i.e. place one shape on top of the other)?
If it matters I'm using Scala, not Java (though the syntax is similar, at least for this part of the project...)
Wrap your shapes in another node; StackPane seems ideal for this. Set its alignment to Pos. CENTER to achieve the effect you want.
Bear in mind, this is not an entirely efficient solution as you will be creating 64 StackPanes. If you want to avoid that, then you would need to do some math to manually position your pieces above the desired game board location. This, however, should not be entirely difficult as you know the dimensions of your board squares, pieces, and how they are laid out.
CAG Gonzo's answer will work, but also be aware that if you place multiple nodes in the same cell in a grid pane, they will be placed on top of each other. This might work pretty well for you application:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class CheckerBoard extends Application {
private static final int BOARD_SIZE = 8 ;
private static final int SQUARE_SIZE= 40 ;
private static final int NUM_PIECES = 12 ;
#Override
public void start(Stage primaryStage) {
GridPane checkerBoard = new GridPane();
configureBoardLayout(checkerBoard);
addSquaresToBoard(checkerBoard);
Circle[] whitePieces = new Circle[NUM_PIECES];
Circle[] blackPieces = new Circle[NUM_PIECES];
addPiecesToBoard(checkerBoard, whitePieces, blackPieces);
BorderPane root = new BorderPane(checkerBoard);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
private void addPiecesToBoard(GridPane checkerBoard, Circle[] whitePieces,
Circle[] blackPieces) {
for (int i=0; i<NUM_PIECES; i++) {
whitePieces[i] = new Circle(SQUARE_SIZE/2-4, Color.WHITE);
whitePieces[i].setStroke(Color.BLACK);
checkerBoard.add(whitePieces[i], i%(BOARD_SIZE/2) * 2 + (2*i/BOARD_SIZE)%2, BOARD_SIZE - 1 - (i*2)/BOARD_SIZE);
blackPieces[i] = new Circle(SQUARE_SIZE/2 -4, Color.BLACK);
blackPieces[i].setStroke(Color.WHITE);
checkerBoard.add(blackPieces[i], i%(BOARD_SIZE/2) * 2 + (1 + 2*i/BOARD_SIZE)%2, (i*2)/BOARD_SIZE);
}
}
private void addSquaresToBoard(GridPane board) {
Color[] squareColors = new Color[] {Color.WHITE, Color.BLACK};
for (int row = 0; row < BOARD_SIZE; row++) {
for (int col = 0; col < BOARD_SIZE; col++) {
board.add(new Rectangle(SQUARE_SIZE, SQUARE_SIZE, squareColors[(row+col)%2]), col, row);
}
}
}
private void configureBoardLayout(GridPane board) {
for (int i=0; i<BOARD_SIZE; i++) {
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setMinHeight(SQUARE_SIZE);
rowConstraints.setPrefHeight(SQUARE_SIZE);
rowConstraints.setMaxHeight(SQUARE_SIZE);
rowConstraints.setValignment(VPos.CENTER);
board.getRowConstraints().add(rowConstraints);
ColumnConstraints colConstraints = new ColumnConstraints();
colConstraints.setMinWidth(SQUARE_SIZE);
colConstraints.setMaxWidth(SQUARE_SIZE);
colConstraints.setPrefWidth(SQUARE_SIZE);
colConstraints.setHalignment(HPos.CENTER);
board.getColumnConstraints().add(colConstraints);
}
}
public static void main(String[] args) {
launch(args);
}
}

How does 3D picking work in JavaFX 8

Unfortunately I could not find any good tutorial for picking api.
Can anyone give me a brief tutorial about it or some useful links?
Update
world.setOnMouseClicked((event)->{
PickResult res = event.getPickResult();
System.out.println("res "+res);
//you can get a reference to the clicked node like this
if (res.getIntersectedNode() instanceof Node){
((Node)res.getIntersectedNode()).setTranslateZ(-50);
}
});
The code above only work on the first node that I click.
Does anyone know what is the problem?
It seems to work just fine without much understanding. My guess is it takes the element closest to the camera (ie. in front) in the 2D representation of where you clicked. It doesn't matter which face you click, it always gets the right node.
The code is very simple. I've made a scene with a Parent called world that has 3D elements.
package simple3dboxapp;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.PickResult;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class Simple3dBoxApp extends Application {
public Rotate rx = new Rotate();
{ rx.setAxis(Rotate.X_AXIS); }
public Rotate ry = new Rotate();
{ ry.setAxis(Rotate.Y_AXIS); }
public Rotate rz = new Rotate();
{ rz.setAxis(Rotate.Z_AXIS); }
Translate t = new Translate();
private final PerspectiveCamera camera = new PerspectiveCamera(true);
{camera.getTransforms().addAll(t, rz, ry, rx);}
Label data = new Label();{data.setWrapText(true);data.setPrefHeight(200);}
public Parent createContent() {
Group root = new Group();
for(int i = 0; i<10; i++){
Box box = new Box(50, 50, 50);
Text text = new Text("Hi "+i);
ImageView iv = new ImageView("file:apple-touch-icon.png");
Image im = iv.getImage();
Material m = new PhongMaterial(Color.CYAN, im, null, null, null);
box.setMaterial(m);
box.getTransforms().add(new Translate(-250 + i * 50 , -100, -100 + i * 50));
text.getTransforms().add(new Translate(-250 + i * 50 , 0, -100 + i * 50));
iv.getTransforms().add(new Translate(-250 + i * 50 , +100, -100 + i * 50));
root.getChildren().addAll(box,text,iv);
}
camera.setNearClip(1);
camera.setFarClip(2000);
camera.setFieldOfView(100);
// Use a SubScene
SubScene subScene = new SubScene(root, 500,500);
subScene.setFill(Color.ALICEBLUE);
subScene.setCamera(camera);
Group group = new Group();
group.getChildren().add(subScene);
return group;
}
#Override
public void start(Stage stage) {
VBox vbox = new VBox();
Parent world = createContent();
world.setFocusTraversable(true);
vbox.getChildren().addAll(world,data);
Scene scene = new Scene(vbox);
stage.setScene(scene);
stage.show();
world.setOnKeyPressed((evt)->{
switch (evt.getCode()){
case UP:
rx.setAngle(rx.getAngle()+5);
break;
case DOWN:
rx.setAngle(rx.getAngle()-5);
break;
case RIGHT:
t.setX(t.getX()+10);
//camera.setTranslateX(camera.getTranslateX()+10);
break;
case LEFT:
t.setX(t.getX()-10);
//camera.setTranslateX(camera.getTranslateX()-10);
break;
case Z:
double zoom = evt.isShortcutDown()?-10:+10;
t.setZ(t.getZ()+zoom);
//camera.setTranslateZ(camera.getTranslateZ()+zoom);
break;
}
});
world.setOnMouseClicked((event)->{
PickResult res = event.getPickResult();
data.setText("res "+res);
if (res.getIntersectedNode() instanceof Box){
((Box)res.getIntersectedNode()).setMaterial(
new PhongMaterial(event.isShiftDown() ? Color.BLACK : Color.RED));
}
});
}
public static void main(String[] args) {launch(args);}
}
And this is the result from clicking a Box
res PickResult [node = Box#1dc02a4, point = Point3D [x = 12.361420184603276, y = 15.984395060669844, z = -5.0], distance = 1866.0254037844388, texCoord = Point2D [x = 0.6236142018460328, y = 0.8196879012133969]
PickResult javadoc

add visual below finger swipe, Triangle strip like fruit ninja Andengine

I want to show a triangle strip when user swap finger on screen. I am not sure how to do it with AndEngine, using particle system or using sprites or using Triangle Strip algo...
I haven't wrote any code because I am struck that what to do. I am uploading an image please share your ideas.
Update
someone has done this in Iphone but unfortunately I am unfamiliar with language syntax please help me in understanding algo of this code https://github.com/hiepnd/CCBlade
**Effect I want **
Complete Android Project Download
http://www.andengine.org/forums/resources/complete-runnable-project/1301
I have done this code but could not get the desired effect...
package org.az.algo.examples;
import javax.microedition.khronos.opengles.GL10;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.particle.ParticleSystem;
import org.anddev.andengine.entity.particle.emitter.RectangleParticleEmitter;
import org.anddev.andengine.entity.particle.initializer.AlphaInitializer;
import org.anddev.andengine.entity.particle.initializer.ColorInitializer;
import org.anddev.andengine.entity.particle.initializer.GravityInitializer;
import org.anddev.andengine.entity.particle.initializer.RotationInitializer;
import org.anddev.andengine.entity.particle.modifier.AlphaModifier;
import org.anddev.andengine.entity.particle.modifier.ColorModifier;
import org.anddev.andengine.entity.particle.modifier.ExpireModifier;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.Toast;
public class ParticleSystemSimpleExample extends BaseExample {
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 720;
private static final int CAMERA_HEIGHT = 480;
// ===========================================================
// Fields
// ===========================================================
private Camera mCamera;
private BitmapTextureAtlas mBitmapTextureAtlas;
private TextureRegion mParticleTextureRegion;
private BitmapTextureAtlas mBitmapTextureAtlasStreak;
private TextureRegion mStreadTextureRegion;
private Sprite[] mSprite = new Sprite[20];
private int mIndex = 0;
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public Engine onLoadEngine() {
Toast.makeText(this, "Touch the screen to move the particlesystem.", Toast.LENGTH_LONG).show();
this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
}
#Override
public void onLoadResources() {
this.mBitmapTextureAtlas = new BitmapTextureAtlas(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mParticleTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, "gfx/particle_point.png", 0, 0);
this.mBitmapTextureAtlasStreak = new BitmapTextureAtlas(128, 16, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mStreadTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlasStreak, this, "gfx/streak1.png", 0, 0);
this.mEngine.getTextureManager().loadTextures(this.mBitmapTextureAtlas, this.mBitmapTextureAtlasStreak);
}
#Override
public Scene onLoadScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
// final CircleOutlineParticleEmitter particleEmitter = new CircleOutlineParticleEmitter(CAMERA_WIDTH * 0.5f, CAMERA_HEIGHT * 0.5f + 20, 80);
final RectangleParticleEmitter particleEmitter = new RectangleParticleEmitter(CAMERA_WIDTH * 0.5f, CAMERA_HEIGHT * 0.5f, 5f,5f);
// final PointParticleEmitter particleEmitter = new PointParticleEmitter(10, 10);
final ParticleSystem particleSystem = new ParticleSystem(particleEmitter, 100, 100, 1000, this.mParticleTextureRegion);
particleSystem.setParticlesSpawnEnabled(false);
scene.setOnSceneTouchListener(new IOnSceneTouchListener() {
#Override
public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_MOVE){
particleSystem.setParticlesSpawnEnabled(true);
particleEmitter.setCenter(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
mSprite[getIndex()].setPosition(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
mSprite[getIndex()].setVisible(true);
}else if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP){
particleSystem.setParticlesSpawnEnabled(false);
hideAll();
}else if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
particleSystem.reset();
}
return true;
}
});
particleSystem.addParticleInitializer(new ColorInitializer(1, 0, 0));
particleSystem.addParticleInitializer(new AlphaInitializer(0));
particleSystem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
// particleSystem.addParticleInitializer(new VelocityInitializer(-2, 2, -20, -10));
particleSystem.addParticleInitializer(new GravityInitializer());
// particleSystem.addParticleModifier(new ScaleModifier(0.5f, 1.0f, 0, 1.5f));
particleSystem.addParticleModifier(new ColorModifier(1, 1, 0, 0.5f, 0, 0, 0, 3));
particleSystem.addParticleModifier(new ColorModifier(1, 1, 0.5f, 1, 0, 1, 4, 6));
particleSystem.addParticleModifier(new AlphaModifier(0, 1, 0, 0.5f));
particleSystem.addParticleModifier(new AlphaModifier(1, 0, 2.5f, 3.5f));
particleSystem.addParticleModifier(new ExpireModifier(6, 6f));
scene.attachChild(particleSystem);
for(int i = 0; i < mSprite.length; i++){
mSprite[i] = new Sprite(-20, 0, mStreadTextureRegion);
mSprite[i].setVisible(false);
scene.attachChild(mSprite[i]);
}
return scene;
}
#Override
public void onLoadComplete() {
}
private int getIndex(){
if(mIndex >= mSprite.length -1){
mIndex = 0;
}
System.out.println("Index ........ "+mIndex);
return mIndex++;
}
private void hideAll(){
for(int i = 0; i<mSprite.length; i++){
mSprite[i].setVisible(false);
mSprite[i].setPosition(-CAMERA_WIDTH, 0);
}
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
image I used with this code is also attached
Updated
partial effect achieved.. but problem on fast swiping.. all complete projects are uploaded here http://www.andengine.org/forums/post31772.html#p31772
Here is a solution in LibGDX. It uses GL_TRIANGLE_STRIP.
https://github.com/mattdesl/lwjgl-basics/wiki/LibGDX-Finger-Swipe
The final solution uses two triangle strips and a custom texCoord attribute, allowing for us to use a lookup texture to achieve fake (but efficient) anti-aliasing. A more efficient/flexible anti-aliasing would use shaders and a single triangle strip. Use vertex attribute -1.0 for the top and 1.0 for the bottom edge of your swipe, and 1.0 for the tips. Then in the frag shader, use abs() -- so 0.0 means "center" and 1.0 means "edge."
Something like this:
color.a *= smoothstep(0.0, 2./thickness, 1.0-abs(vTexCoord.t));