I would like to draw an arrow in a JavaFX application, that rotates around an object that is bound to it (2 group objects that are connected with an arrow). To compute the correct angle I tried to compute it by substracting the two coordinates (end and start xy coordinates from the groups). But my arrow head will not move. Any ideas what I am doing wrong?
// controller code:
PlaceIcon startIconGroup = new PlaceIcon();
startIconGroup.setLayoutX(100);
startIconGroup.setLayoutY(120);
startIconGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, onClickEventHandler); // for dragging
startIconGroup.addEventHandler(MouseEvent.MOUSE_DRAGGED, onDragEventHandler);
startIconGroup.addEventHandler(MouseEvent.MOUSE_PRESSED, onPressEventHandler);
workplace.getChildren().add(startIconGroup); // workplace is the pane were the nodes are shown
PlaceIcon endIconGroup = new PlaceIcon();
endIconGroup.setLayoutX(100);
endIconGroup.setLayoutY(120);
endIconGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, onClickEventHandler);
endIconGroup.addEventHandler(MouseEvent.MOUSE_DRAGGED, onDragEventHandler);
endIconGroup.addEventHandler(MouseEvent.MOUSE_PRESSED, onPressEventHandler);
endIconGroup.getChildren().add(startIconGroup);
RelationIcon relationIcon = new RelationIcon();
relationIcon.setStartNode(startNode);
relationIcon.setEndNode(endNode);
...
EventHandler<MouseEvent> onDragEventHandler = new EventHandler<MouseEvent>() {
/**
* This method is used to compute the new position of an node. Therefore, the
* position in pixels (x/yLayout) is incremented by coordinate change of mouse
* movement.
*/
#Override
public void handle(MouseEvent event) {
Group clickedElement = (Group) event.getSource();
// Node node = clickedElement.getChildren().get(0);
double offsetX = event.getSceneX() - mousePosition.get().getX();
double offsetY = event.getSceneY() - mousePosition.get().getY();
clickedElement.setLayoutX(clickedElement.getLayoutX() + offsetX);
clickedElement.setLayoutY(clickedElement.getLayoutY() + offsetY);
mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY()));
eventlog.setText("Move "+ clickedElement + " to x=" + clickedElement.getLayoutX() + " y="
+ clickedElement.getLayoutY());
}
};
And here is the PlaceIconClass
public class RelationIcon extends Group {
Line line;
Polygon arrowHead;
Group startNode;
Group endNode;
public RelationIcon() {
//draw arrow line
line = new Line();
// draw arrow head
arrowHead = new Polygon();
arrowHead.getPoints().addAll(new Double[]{
-10.0, -20.0,
10.0, -20.0,
0.0, 0.0});
// merge into a group
this.getChildren().addAll(line, arrowHead);
}
public Group getStartNode() {
return startNode;
}
public void setStartNode(Group startNode) {
this.startNode = startNode;
line.startXProperty().bind(this.startNode.layoutXProperty());
line.startYProperty().bind(this.startNode.layoutYProperty());
}
public Group getEndNode() {
return endNode;
}
public void setEndNode(Group endNode) {
this.endNode = endNode;
line.endXProperty().bind(this.endNode.layoutXProperty());
line.endYProperty().bind(this.endNode.layoutYProperty());
arrowHead.layoutXProperty().bind(this.endNode.layoutXProperty());
arrowHead.layoutYProperty().bind(this.endNode.layoutYProperty());
arrowHead.rotateProperty().bind(this.endNode.layoutXProperty()); // THIS WORKS
arrowHead.rotateProperty().bind(Bindings.createDoubleBinding(() -> {
double x = line.endXProperty().getValue() - line.startXProperty().getValue();
double y = line.endYProperty().getValue() - line.startYProperty().getValue();
System.out.println(x+" "+y);
double a = Math.atan2(x, y);
return Math.toDegrees(a);
})); // THIS WORKS NOT
}
Thank you for your help!
Related
I need to change attributes of nodes and edges over time. The time is split into timeperiods, every timeperiod looks the same: Check every node and edge for possible changes and edit attribute if necessary. Specifically there are numeric attributes and the size of a node and the width of an edge are based on the attributes value. Initially the graph displays correctly. The nodes and edges have the supposed size. But changing the attribute values dynamically over time does not change the elements sizes. How can I make sure, attribute changes also change the graphs visualisation?
As far as I understand the Graphstream Docs and tutorials there are sources, sinks and sipes (a pipe is both a source and a sink). Sources create events, sinks consumes them. I use the GridGenerator which is a source. I can add the graph as a sink and let the generator create the graph. I think, I have to add a sink to the graph then, because changing attributes of elements of the graph makes it a source. But what do I use as sink? graph.display() returns a Viewer but I can't add it as sink, it says it's not compatible with the arguments for graph.addSink(sink). Even though the Graphstream Docs says that a Viewer is a sink and that the Viewer gets added automatically as a sink. Why do I don't see changes in the UI then? I don't get it.
After generating the graph the nodes and edges get there attributes
public static void configureElements(Graph world) {
for (Node node : world.getEachNode()) {
double random = Math.random() * 100;
if (random < 20) {
// remove obstacles
world.removeNode(node)
} else if (random < 30) {
// node have rohstoffe
node.addAttribute("ui.class", "rohstoff");
node.addAttribute("ui.label", node.getId());
node.addAttribute("isRohstoff");
int capacity = (int) (Math.random() * maxCapacity);
node.addAttribute("capacity", capacity);ity);
// nodes size is based on capacity of rohstoffe
node.setAttribute("ui.size", node.getNumber("capacity") + 10);
} else if (random < 32) {
// node is a lager
node.addAttribute("ui.class", "lager");
node.addAttribute("ui.label", node.getId());
node.addAttribute("isLager");
node.addAttribute("lagerstand", 0);
// nodes size is based on capacity of the lager
node.setAttribute("ui.size", node.getNumber("lagerstand") + 10);
} else {
// normal node
node.addAttribute("isNode");
}
}
for (Edge edge : world.getEachEdge()) {
// add pheromones to edge
edge.addAttribute("pheromones", 0);
// edges size is based on number of pheromones
edge.setAttribute("ui.size", edge.getNumber("pheromones"));
}
}
Here I change the node attribute dynamically over time
public void dropRohstoff(Node node) {
int oldRohstoff = (int) node.getNumber("rohstoff");
int newRohstoff = oldRohstoff++;
node.setAttribute("rohstoff", newRohstoff);
world.nodeAttributeChanged(world.getId(), (long) world.getStep(), node.getId(),"rohstoff", oldRohstoff, newRohstoff);
}
public void pickRohstoff(Node node) {
int oldCapacity = (int) node.getNumber("capacity");
int newCapicity = oldCapacity++;
node.setAttribute("capacity", newCapicity);
world.nodeAttributeChanged(world.getId(), (long) world.getStep(), node.getId(), "capacity", oldCapacity, newCapicity);
}
Here the edge attributes
public void evaporateAll() {
for (Edge edge : world.getEachEdge()) {
Double oldEvaporateRate = edge.getNumber("pheromones");
Double newEvaporateRate = oldEvaporateRate * (1.0 - evaporateRate);
edge.setAttribute("pheromones", newEvaporateRate);
world.edgeAttributeChanged(world.getId(), (long) world.getStep(), edge.getId(), "pheromones", oldEvaporateRate, newEvaporateRate);
}
}
Does anybody know how do I have to add the sink? Or am I missing something else?
First, you can have a ViewerPipe with your viewer like that :
ViewerPipe pipeIn = viewer.newViewerPipe();
With that, you can add a sink to your graph :
pipeIn.addAttributeSink( graph );
pipeIn.pump();
Also, if you want to make a dynamic size, don't forget to add the css property to your nodes :
size-mode: dyn-size;
Here a minimal example for graphstream 1.3
public class Issue {
public static void main(String args[]) {
System.setProperty( "org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer" );
new Issue();
}
protected boolean loop = true;
public Issue() {
Graph graph = new MultiGraph("main graph");
Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
ViewerPipe pipeIn = viewer.newViewerPipe();
viewer.addView("view1", new J2DGraphRenderer());
graph.addAttribute("ui.antialias");
pipeIn.addAttributeSink( graph );
pipeIn.pump();
Node A = graph.addNode("A");
Node B = graph.addNode("B");
Node C = graph.addNode("C");
graph.addEdge("AB", "A", "B", true);
graph.addEdge("BC", "B", "C", true);
graph.addEdge("CA", "C", "A", true);
A.addAttribute("xyz", 0, 1, 0);
B.addAttribute("xyz", 1, 0, 0);
C.addAttribute("xyz", -1, 0, 0);
A.setAttribute("ui.label", "A");
B.setAttribute("ui.label", "B");
C.setAttribute("ui.label", "C");
graph.addAttribute("ui.stylesheet", styleSheet);
float color = 0;
float dir = 0.01f;
float size = 20f;
float sizeInc = 1f;
while( loop ) {
pipeIn.pump();
sleep( 40 );
A.setAttribute( "ui.size", size );
size += sizeInc;
if( size > 50 ) {
sizeInc = -1f; size = 50f;
} else if( size < 20 ) {
sizeInc = 1f; size = 20f;
}
System.out.println(size);
}
System.exit(0);
}
protected void sleep( long ms ) {
try { Thread.sleep( ms ) ; }
catch (InterruptedException e) { e.printStackTrace(); }
}
private String styleSheet =
"graph {"+
" canvas-color: white;"+
" fill-mode: gradient-radial;"+
" fill-color: white, #EEEEEE;"+
" padding: 60px;"+
" }"+
"node {"+
" size-mode: dyn-size;"+
" shape: circle;"+
" size: 20px;"+
" fill-mode: plain;"+
" fill-color: #CCC;"+
" stroke-mode: plain;"+
" stroke-color: black;"+
" stroke-width: 1px;"+
"}";
}
You can find an example here in graphstream 2.0 swing, here in graphstream 2.0 javafx or here in graphstream 1.3 (in scala).
I am trying to extract text coordinates and line (or rectangle) coordinates from a PDF.
The TextPosition class has getXDirAdj() and getYDirAdj() methods which transform coordinates according to the direction of the text piece the respective TextPosition object represents (Corrected based on comment from #mkl)
The final output is consistent, irrespective of the page rotation.
The coordinates needed on the output are X0,Y0 (TOP LEFT CORNER OF THE PAGE)
This is a slight modification from the solution by #Tilman Hausherr. The y coordinates are inverted (height - y) to keep it consistent with the coordinates from the text extraction process, also the output is written to a csv.
public class LineCatcher extends PDFGraphicsStreamEngine
{
private static final GeneralPath linePath = new GeneralPath();
private static ArrayList<Rectangle2D> rectList= new ArrayList<Rectangle2D>();
private int clipWindingRule = -1;
private static String headerRecord = "Text|Page|x|y|width|height|space|font";
public LineCatcher(PDPage page)
{
super(page);
}
public static void main(String[] args) throws IOException
{
if( args.length != 4 )
{
usage();
}
else
{
PDDocument document = null;
FileOutputStream fop = null;
File file;
Writer osw = null;
int numPages;
double page_height;
try
{
document = PDDocument.load( new File(args[0], args[1]) );
numPages = document.getNumberOfPages();
file = new File(args[2], args[3]);
fop = new FileOutputStream(file);
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
osw = new OutputStreamWriter(fop, "UTF8");
osw.write(headerRecord + System.lineSeparator());
System.out.println("Line Processing numPages:" + numPages);
for (int n = 0; n < numPages; n++) {
System.out.println("Line Processing page:" + n);
rectList = new ArrayList<Rectangle2D>();
PDPage page = document.getPage(n);
page_height = page.getCropBox().getUpperRightY();
LineCatcher lineCatcher = new LineCatcher(page);
lineCatcher.processPage(page);
try{
for(Rectangle2D rect:rectList) {
String pageNum = Integer.toString(n + 1);
String x = Double.toString(rect.getX());
String y = Double.toString(page_height - rect.getY()) ;
String w = Double.toString(rect.getWidth());
String h = Double.toString(rect.getHeight());
writeToFile(pageNum, x, y, w, h, osw);
}
rectList = null;
page = null;
lineCatcher = null;
}
catch(IOException io){
throw new IOException("Failed to Parse document for line processing. Incorrect document format. Page:" + n);
}
};
}
catch(IOException io){
throw new IOException("Failed to Parse document for line processing. Incorrect document format.");
}
finally
{
if ( osw != null ){
osw.close();
}
if( document != null )
{
document.close();
}
}
}
}
private static void writeToFile(String pageNum, String x, String y, String w, String h, Writer osw) throws IOException {
String c = "^" + "|" +
pageNum + "|" +
x + "|" +
y + "|" +
w + "|" +
h + "|" +
"999" + "|" +
"marker-only";
osw.write(c + System.lineSeparator());
}
#Override
public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException
{
// to ensure that the path is created in the right direction, we have to create
// it by combining single lines instead of creating a simple rectangle
linePath.moveTo((float) p0.getX(), (float) p0.getY());
linePath.lineTo((float) p1.getX(), (float) p1.getY());
linePath.lineTo((float) p2.getX(), (float) p2.getY());
linePath.lineTo((float) p3.getX(), (float) p3.getY());
// close the subpath instead of adding the last line so that a possible set line
// cap style isn't taken into account at the "beginning" of the rectangle
linePath.closePath();
}
#Override
public void drawImage(PDImage pdi) throws IOException
{
}
#Override
public void clip(int windingRule) throws IOException
{
// the clipping path will not be updated until the succeeding painting operator is called
clipWindingRule = windingRule;
}
#Override
public void moveTo(float x, float y) throws IOException
{
linePath.moveTo(x, y);
}
#Override
public void lineTo(float x, float y) throws IOException
{
linePath.lineTo(x, y);
}
#Override
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException
{
linePath.curveTo(x1, y1, x2, y2, x3, y3);
}
#Override
public Point2D getCurrentPoint() throws IOException
{
return linePath.getCurrentPoint();
}
#Override
public void closePath() throws IOException
{
linePath.closePath();
}
#Override
public void endPath() throws IOException
{
if (clipWindingRule != -1)
{
linePath.setWindingRule(clipWindingRule);
getGraphicsState().intersectClippingPath(linePath);
clipWindingRule = -1;
}
linePath.reset();
}
#Override
public void strokePath() throws IOException
{
rectList.add(linePath.getBounds2D());
linePath.reset();
}
#Override
public void fillPath(int windingRule) throws IOException
{
linePath.reset();
}
#Override
public void fillAndStrokePath(int windingRule) throws IOException
{
linePath.reset();
}
#Override
public void shadingFill(COSName cosn) throws IOException
{
}
/**
* This will print the usage for this document.
*/
private static void usage()
{
System.err.println( "Usage: java " + LineCatcher.class.getName() + " <input-pdf>" + " <output-file>");
}
}
Was using the PDFGraphicsStreamEngine class to extract Line and Rectangle coordinates. The coordinates of lines and rectangles do not align with the coordinates of the text
Green: Text
Red: Line coordinates obtained as is
Black: Expected coordinates (Obtained after applying transformation on the output)
Tried the setRotation() method to correct for the rotation before running the line extract. However the results are not consistent.
What are the possible options to get the rotation and get a consistent output of the Line / Rectangle coordinates using PDFBox?
As far as I understand the requirements here, the OP works in a coordinate system with the origin in the upper left corner of the visible page (taking the page rotation into account), x coordinates increasing to the right, y coordinates increasing downwards, and the units being the PDF default user space units (usually 1/72 inch).
In this coordinate system he needs to extract (horizontal or vertical) lines in the form of
coordinates of the left / top end point and
the width / height.
Transforming LineCatcher results
The helper class LineCatcher he got from Tilman, on the other hand, does not take page rotation into account. Furthermore, it returns the bottom end point for vertical lines, not the top end point. Thus, a coordinate transformation has to be applied to of the LineCatcher results.
For this simply replace
for(Rectangle2D rect:rectList) {
String pageNum = Integer.toString(n + 1);
String x = Double.toString(rect.getX());
String y = Double.toString(page_height - rect.getY()) ;
String w = Double.toString(rect.getWidth());
String h = Double.toString(rect.getHeight());
writeToFile(pageNum, x, y, w, h, osw);
}
by
int pageRotation = page.getRotation();
PDRectangle pageCropBox = page.getCropBox();
for(Rectangle2D rect:rectList) {
String pageNum = Integer.toString(n + 1);
String x, y, w, h;
switch(pageRotation) {
case 0:
x = Double.toString(rect.getX() - pageCropBox.getLowerLeftX());
y = Double.toString(pageCropBox.getUpperRightY() - rect.getY() + rect.getHeight());
w = Double.toString(rect.getWidth());
h = Double.toString(rect.getHeight());
break;
case 90:
x = Double.toString(rect.getY() - pageCropBox.getLowerLeftY());
y = Double.toString(rect.getX() - pageCropBox.getLowerLeftX());
w = Double.toString(rect.getHeight());
h = Double.toString(rect.getWidth());
break;
case 180:
x = Double.toString(pageCropBox.getUpperRightX() - rect.getX() - rect.getWidth());
y = Double.toString(rect.getY() - pageCropBox.getLowerLeftY());
w = Double.toString(rect.getWidth());
h = Double.toString(rect.getHeight());
break;
case 270:
x = Double.toString(pageCropBox.getUpperRightY() - rect.getY() + rect.getHeight());
y = Double.toString(pageCropBox.getUpperRightX() - rect.getX() - rect.getWidth());
w = Double.toString(rect.getHeight());
h = Double.toString(rect.getWidth());
break;
default:
throw new IOException(String.format("Unsupported page rotation %d on page %d.", pageRotation, page));
}
writeToFile(pageNum, x, y, w, h, osw);
}
(ExtractLinesWithDir test testExtractLineRotationTestWithDir)
Relation to TextPosition.get?DirAdj() coordinates
The OP describes the coordinates by referring to the TextPosition class methods getXDirAdj() and getYDirAdj(). Indeed, these methods return coordinates in a coordinate system with the origin in the upper left page corner and y coordinates increasing downwards after rotating the page so that the text is drawn upright.
In case of the example document all the text is drawn so that it is upright after applying the page rotation. From this my understanding of the requirement written at the top has been derived.
The problem with using the TextPosition.get?DirAdj() values as coordinates globally, though, is that in documents with pages with text drawn in different directions, the collected text coordinates suddenly are relative to different coordinate systems. Thus, a general solution should not collect coordinates wildly like that. Instead it should determine a page orientation at first (e.g. the orientation given by the page rotation or the orientation shared by most of the text) and use coordinates in the fixed coordinate system given by that orientation plus an indication of the writing direction of the text piece in question.
I want to add an image for each marker i have on unfolding maps
Already tried to use Buffer but im not sure what i should do now.
My main class
import de.fhpotsdam.unfolding.*;
import de.fhpotsdam.unfolding.geo.*;
import de.fhpotsdam.unfolding.utils.*;
import de.fhpotsdam.unfolding.marker.*;
UnfoldingMap map;
import java.util.Map; // import java hashmaps
// declare country hashmaps
// key // value
HashMap<String, Country> countries = new HashMap<String, Country>();
//PGraphics buffer;
int countryNumber;
Button country;
public void setup() {
size(800, 600, P2D);
smooth();
//buffer = createGraphics(800, 600);
map = new UnfoldingMap(this);
map.setTweening(true);
map.zoomToLevel(3);
MapUtils.createDefaultEventDispatcher(this, map);
String[] lines = loadStrings("test.csv"); //read file and save lines in a string array
countryNumber = lines.length; // how many lines
println(countryNumber);
for (int i=0; i<countryNumber; i++) { //all csv lines
String line = lines[i]; /// get data from line. Ex: "Portugal,10,91"
String[] elements = split(line, ","); //separate line by ','
String name = elements[0]; // get country name
float lat = parseInt(elements[20]); // lat
float lon = parseInt(elements[21]); // lon
PImage flagIcon;
flagIcon = loadImage(elements[22]); //get image flag name
Country P = new Country(name, lat, lon, flagIcon);
Location mapMarker = new Location(lat,lon);
// Create point markers for locations
SimplePointMarker eachMapMarker = new
SimplePointMarker(mapMarker);
// Add markers to the map
map.addMarkers(eachMapMarker);
paises.put(nome, P );
}
}
public void draw() {
background(255);
map.draw(); // draw map
//image(buffer, 200, 50);
for (Map.Entry p : Countries.entrySet() ) { // get countries hashmap
Country country = (Country) p.getValue();
country.drawInfo();
country.drawCoor();
country.drawIcon();
}
}
My Country class
//my country class
class Country {
String name;
float lat;
float lon;
int posX, posY;
PImage flagIcon;
Pais (String n, float la, float lo, PImage ic) {
name = n;
lat = la;
lon = lo;
flagIcon = ic;
}
void drawIcon() {
image(flagIcon,lat,lon,16,16);
}
void drawInfo() {
Location mapLocal = new Location(lat, lon);
ScreenPosition mapPos = map.getScreenPosition(mapLocal);
float scale = map.getZoom();
// if pointer is near a country
boolean onOver = false;
if (dist(mouseX, mouseY, mapPos.x, mapPos.y)<2*scale) {
onOver = true;
}
if (onOver) {
noStroke();
//fill(255,255,255,255);
//rect(mouseX+18, mouseY-20, 120, 50);
fill(0);
text(name + "\nLat: " + lat + "\nLon: " + lon , mouseX+25, mouseY-5);
}
}
void drawCoor() {
//println(coordinates);
fill(0);
text("coordinates: " + mouseX + " " + mouseY, 650,10);
}
}
Image links are stored on my CSV
This is what im getting and as i can see my images arent synced with my lat and lon. Can anyone give me an hand ?
When you draw the country icon on the map, for the input of x and y in the image(PImage image, float x, float y) function inside drawIcon() method, you are supposed to use the marker's position on the map instead of the latitude and longitude properties.
The specific method is called getScreenPosition(UnfoldingMap map) of AbstractMarker. Please refer to the javadoc for the details. http://unfoldingmaps.org/javadoc/de/fhpotsdam/unfolding/marker/AbstractMarker.html#getScreenPosition(de.fhpotsdam.unfolding.UnfoldingMap)
The reason behind it is that (I think) the markers are added to the map with the map.addMarker method, then rendered together with the map.draw() method, where the latitude and longitude are transferred to their screen positions at the backstage.
Because you are trying to add the country icons on top of the country markers after the map.draw() method, you should try to associate the icon's position to the marker's screen position.
public void draw() {
background(200);
map.draw();
for (Marker m: countryMarkers) {
image(countryIcon, (((AbstractMarker) m).getScreenPosition(map).x,
((AbstractMarker) m).getScreenPosition(map).y);
}
}
It would also help the code look more organized and clean if you make a CountryMarker class extends SimplePointMarker class, which is available in the unfolding maps library.
I'am new new to JavaFX, and I got a problem. I'm trying to move Nodes with UP,DOWN,LEFT,RIGHT, if I just move my "Player" node, it's work perfectly, but I wanna make a game like sokoban, so my Player node can move "Crate" node, the problem is if I press the RIGHT next to the Crate, it swap the places, but not working correctly here is the moving method :
private void lepes(int i, int j, int target_i, int target_j){
int ai, aj;
int bi, bj;
ai = i;
aj = j;
bi = target_i;
bj = target_j;
MyNode nodeA = playfield[ai][aj];
nodeA.toFront();
MyNode nodeB = playfield[bi][bj];
nodeB.toFront();
playfield[ai][aj] = nodeB;
playfield[bi][bj] = nodeA;
Path pathA = new Path();
pathA.getElements().add (new MoveTo ( nodeA.getTranslateX() + nodeA.getBoundsInParent().getWidth() / 2.0, nodeA.getTranslateY() + nodeA.getBoundsInParent().getHeight() / 2.0));
pathA.getElements().add (new LineTo( nodeB.getTranslateX() + nodeB.getBoundsInParent().getWidth() / 2.0, nodeB.getTranslateY() + nodeB.getBoundsInParent().getHeight() / 2.0));
PathTransition pathTransitionA = new PathTransition();
pathTransitionA.setDuration(Duration.millis(1));
pathTransitionA.setNode( nodeA);
pathTransitionA.setPath(pathA);
pathTransitionA.play();
Path pathB = new Path();
pathB.getElements().add (new MoveTo ( nodeB.getTranslateX() + nodeB.getBoundsInParent().getWidth() / 2.0, nodeB.getTranslateY() + nodeB.getBoundsInParent().getHeight() / 2.0));
pathB.getElements().add (new LineTo( nodeA.getTranslateX() + nodeA.getBoundsInParent().getWidth() / 2.0, nodeA.getTranslateY() + nodeA.getBoundsInParent().getHeight() / 2.0));
PathTransition pathTransitionB = new PathTransition();
pathTransitionB.setDuration(Duration.millis(1));
pathTransitionB.setNode( nodeB);
pathTransitionB.setPath(pathB);
pathTransitionB.play();
pathTransitionA.setOnFinished( new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if( (pathTransitionB.getStatus() == Status.RUNNING))
return;
}
});
pathTransitionB.setOnFinished( new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if( (pathTransitionA.getStatus() == Status.RUNNING))
return;
}
});
}
and here is the eventHandler
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode()==KeyCode.RIGHT) {
if(jatekosX < 8 && playfield[jatekosX+1][jatekosY].getHisNumber() == 2){
lepes(jatekosX, jatekosY, jatekosX+1, jatekosY);
jatekosX++;
lepesek++;
}
else if(jatekosX < 8 && playfield[jatekosX+1][jatekosY].getHisNumber() == 1 ){
lepes(jatekosX+1, jatekosY, jatekosX+2, jatekosY);
lepes(jatekosX, jatekosY, jatekosX+1, jatekosY);
jatekosX++;
lepesek++;
}
System.out.println("Jobbra");
System.out.println("X: " + jatekosX + "Y: " + jatekosY + " lépés: " + lepesek + "\n");
}
}
});
Here is the picture next to crate node, https://postimg.org/image/7qkqxnxs5/
And here is after a Right step, https://postimg.org/image/t1ib1xfwl/
I Don't know what causes this.
I have an arraylist of points which are drawn onto a canvas. I have made a method (drawLine) which draws a path/line from one point to another according to the points the user clicks on.
The order in which the points are clicked are put into an arraylist called userPath.
The drawLine method then captures the last two values of userPath and stores them in another arraylist called realPath, and draws a line between these two points and can be seen below.
//this class draws a line
public void drawLine(float x, float y)
{
mPath.reset();
if (userPath.size()>=2);
{
realPath.add(userPath.get(userPath.size()-1));
realPath.add(userPath.get(userPath.size()-2));
}
// start point
Point p = realPath.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
// end point
p = realPath.get(mLastPointIndex + 1);
//this goes through every point in realPath array list
mPath.lineTo(p.x, p.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
++mLastPointIndex;
isPathStarted = false;
}
When I call the method (drawLine(x,y)) however, it throws an error.
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// this will draw the path
//mContext = this.mContext;
float Cox = event.getX();
float Coy = event.getY();
double CoX = (double) Cox;
double CoY = (double) Coy;
//the euclid method only accepts double numbers therefore the coordinates of the
//points the user is clicking on need to be converted from float to double
Double NearestDistance = 1000.12; //this is hardcoded for the sake of declaring the variable.
Point NearestPoint = null;
for (int i = 0; i < mPoints.size(); i++)
{
Point current = mPoints.get(i);
double xi = current.x;
double yi = current.y;
double dis = Euclid(CoX, CoY, xi, yi);
if (dis < NearestDistance)
{
NearestPoint = current;
NearestDistance = dis;
}
}
String text = "the closest point to where you clicked is: " + NearestPoint + " and the coordinates are: " + NearestPoint.x + ", "+ NearestPoint.y;
Toast.makeText(mContext, text, LENGTH_SHORT).show();
if (userPath.contains(NearestPoint))
{
String pickPoint = "Pick another point";
Toast.makeText(mContext, pickPoint, LENGTH_SHORT).show();
}
else
{
userPath.add(NearestPoint);
Toast.makeText(mContext, userPath + "", LENGTH_SHORT).show();
drawLine(x,y);
//need to call the drawLine method here to draw the line between the last 2 elements in the arraylist. this throws an error!!!
}
invalidate();
break;
}
return true;
}