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;
}
Related
what the method needs to do: to put it simply, we receive any number of points(from class Point) like (1,4)...(7,2) and there can be anywhere from 3 to 10 (if less then 3 it returns null) and the methods needs to return the rectangle(which needs to be from class Polygon) that blocks the Polygon created from the given points, (in other words we get points that create a polygon and we need to find the rectangle that blocks the polygon),
the problem: I believe the code i created should work? but my main problem is I don't know how to write the return command to return those values that are from class Point and print them in this method which is supposed to be class Polygon, I have a toString command that prints out everything i just don't know how can i take those point values from SW,SE,NE,NW and insert return them with toString inside the getBoundingBox() method
Thanks if you can help i will add the code below, the method i am having trouble with in the return command is public Polygon getBoundingBox()
//tester
Polygon boundingBox = polygon.getBoundingBox();
String boundingBoxStr = boundingBox.toString();
if (boundingBoxStr.equals("The polygon has 4 vertices:\n((1,0),(7,0),(7,6),(1,6))"))
System.out.println("\ngetBoundingBox - OK");
else
{
System.out.println("\nError in getBoundingBox or in toString");
System.out.println("Your bounding box is:\n" + boundingBox + "\nExpected bounding box is:\nThe polygon has 4 vertices:\n((1,0),(7,0),(7,6),(1,6))");
}
// instance variables -
private Point [] _vertices;
private int _noOfVertices;
private final int MAX_VERTICES = 10;
// constructor
public Polygon()
{
_vertices = new Point[MAX_VERTICES];
_noOfVertices = 0;
}
// add vertex(or point)
public boolean addVertex(int x, int y)
{
if (_noOfVertices == MAX_VERTICES)
return false;
_vertices[_noOfVertices++] = new Point(x,y);
return true;
}
//toString
public String toString()
{
String str = "";
if(_noOfVertices == 0)
{
str = "The polygon has 0 vertices.";
}
int i;
if(_noOfVertices > 0)
{
str += "The polygon has " + _noOfVertices + " vertices:" + "\n";
str += "" + ("(");
for(i=0; i < _noOfVertices; i++)
if (i == _noOfVertices-1)
{
str += "" + _vertices[i];
}
else
{
str += "" + _vertices[i] + ",";
}
if(i ==_noOfVertices)
{
str += "" + (")");
}
}
return str;
}
public Polygon getBoundingBox()
{
Polygon rectangle = new Polygon();
String str = "";
if(_noOfVertices < 3)
return null;
Point SW = _vertices[0];
Point SE = _vertices[0];
Point NE = _vertices[0];
Point NW = _vertices[0];
for (int i=1; i<_noOfVertices; i++)
{
if(_vertices[i].isLeft(SW) && _vertices[i].isUnder(SW))
{
SW = _vertices[i];
}
if(_vertices[i].isRight(SE) && _vertices[i].isUnder(SE))
{
SE = _vertices[i];
}
if(_vertices[i].isRight(NE) && _vertices[i].isAbove(NE))
{
NE = _vertices[i];
}
if(_vertices[i].isLeft(NW) && _vertices[i].isAbove(NW))
{
NW = _vertices[i];
}
}
return new Polygon(SW,SE,NE,NW); // if i try to add the points SW,SE,NE,NW to Polygon i get an error "constructor polygon in class polygon can't be
// to given types
// I am suppsoed to print it out like this using toString command:
// The polygon has 5 vertices:
// ((SW,SE,NE,NW))
}
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 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!
this code is double while loop ! but not double... only one loop > The end..
plz help me..
i want a double loop for while..
do not double loop for hasNext()?
---------------------------edit--------------
I'm sorry. I've made a mistake Clumsy English.
"Do not make a double loop (While) as HasNext ()?" What I'm asking.
Sorry, I did not polite.
Put the "While" he "HasNext ()" not been able to repeat the first loop.
I'd like to create like multiplication like. Please help me.
import java.io.IOException;
import java.net.MalformedURLException;
import org.geotools.data.shapefile.files.ShpFiles;
import org.geotools.data.shapefile.shp.ShapefileException;
import org.geotools.data.shapefile.shp.ShapefileReader;
import org.geotools.data.shapefile.shp.ShapefileReader.Record;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
class Point {
double x;
double y;
Point(double x2, double y2) {
this.x = x2;
this.y = y2;
}
static double distance(Point p1, Point p2) {
double dist;
dist = Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
return dist;
}
}
public class KFunction {
private static double X;
private static double Y;
private static double X1;
private static double Y1;
public static void main(String[] args) {
ShapefileReader r = null;
ShapefileReader r2 = null;
try {
ShpFiles shpFile = new ShpFiles("Juvenile_Offenders_in_Cardiff.shp");
ShpFiles shpFile2 = new ShpFiles("Juvenile_Offenders_in_Cardiff.shp");
GeometryFactory geometryFactory = new GeometryFactory();
r = new ShapefileReader(shpFile, true, false, geometryFactory);
r2 = new ShapefileReader(shpFile2, true, false, geometryFactory);
Record record2 = r2.nextRecord();
Geometry shape2 = (Geometry) record2.shape();
com.vividsolutions.jts.geom.Point centroid2 = shape2.getCentroid();
int i = 0;
boolean A = r2.hasNext();
while (A) {
X = centroid2.getX();
Y = centroid2.getY();
while (r.hasNext()) {
System.out.println("No." + i);
Record record = r.nextRecord();
Geometry shape = (Geometry) record.shape();
com.vividsolutions.jts.geom.Point centroid = shape.getCentroid();
X1 = centroid.getX();
Y1 = centroid.getY();
Point p1 = new Point(X, Y);
Point p2 = new Point(X1, Y1);
double result = Point.distance(p1, p2);
System.out.println("X : " + X + " Y : " + Y + " X1 : " + X1 + " Y1 : " + Y1);
System.out.println("두 점 사이의 거리 : " + result);
System.out.println("---------------------------");
i++;
}
break;
}
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (ShapefileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
To me it looks like the outer loop while(A) would either be done not at all or forever since it appears the A never changes inside of it.
I am using JXmapkit in order to display a map with way points of openstreetmaps in a frame where the co-ordinates of the waypoint are stored within a database. When a location is clicked, the application will check whether the co-ordinates of the area is within the area around a waypoint, if true than an internal frame will open. The problem is that the co-ordinates of the clicked location are always returned incorrect example, the correct co-ordinates(35.9097,14.4259) are returned as (85.05012,-179.96198). I tried to add the difference but it does not work as I cannot determine the exact difference between the co-ordinates since each time I click the same location, the co-ordinates always differ. Am I missing something or am I doing something wrong?
public static ArrayList<StopBS> GetBusStopByCoordinates(float x, float y, float radius)
{
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try
{
ArrayList<StopBS> stops = new ArrayList<StopBS>();
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection(ConnectionString);
statement = connection.createStatement();
// Added value
// x -= 49.1401725;
// y += 194.4150295;
float x1 = x - radius;
float x2 = x + radius;
float y1 = y - radius;
float y2 = y + radius;
String command = "SELECT StopID, StopNumber, Tag, Latitude, Longitude FROM StopTable WHERE (Latitude BETWEEN %f AND %f) AND (Longitude BETWEEN %f AND %f)" ;
command = String.format(command, x1,x2,y1,y2);
resultSet = statement.executeQuery(command);
while (resultSet.next())
{
StopBS newStop = new StopBS();
newStop.StopID = resultSet.getInt("StopID");
newStop.StopNumber = resultSet.getInt("StopNumber");
newStop.Tag = resultSet.getString("Tag");
newStop.Lat = resultSet.getFloat("Latitude");
newStop.Long = resultSet.getFloat("Longitude");
stops.add(newStop);
}
return stops;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
try
{
resultSet.close();
statement.close();
connection.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
mainMap.getMainMap().addMouseListener(new MouseInputAdapter()
{
public void mouseClicked(MouseEvent e)
{
//Get mouse click position in screen values
Point point = e.getPoint();
//get map component
JXMapViewer map = mainMap.getMainMap();
//calculate x, y for map as the point is relative to the whole screen
Rectangle bounds = getBounds();
int x = (int)(point.getX() - bounds.getX());
int y = (int)(point.getY() - bounds.getY());
//Get the lat and long from the x and y mouse position
Point2D pixelcoord1 = point;
GeoPosition mappos = map.getTileFactory().pixelToGeo(pixelcoord1, map.getZoom());
Point2D QALLA = map.getTileFactory().geoToPixel(mappos, map.getZoom());
//check in database for busstops in that area 0.0015F
ArrayList<StopBS> stops = DataAccess.GetBusStopByCoordinates((float)mappos.getLatitude(),(float)mappos.getLongitude(), 0.0015F);
}
});
}
jXMapKit1.getMainMap().convertPointToGeoPosition(pixelcoord1)