JFreechart & Servlet: How to compute datapoint from mouse position - java

I'm drawing within a servlet a ScatterPlot and serve it to the browser.
The user can now click somewhere on the plot and I want to determine what
datapoint of the scatter plot the user has pointed. From the mouse click of the
user I can determine on which pixel of the image he has clicked, but how can
I get from this info to the coordinates on the domain and range axis?
I found tipps how to do it, which uses the ChartPanel. But for serving it directly
to the browser I only use an instance of a JFreeChar object.
Anybody has a clue or an example how to do it?
Thanks,
Dieter

I think I have found a solution. For the solution I need to get my chart again,
so I either have to create it a new or to save it somehow. But when I have a reference
to that chart the solution is as following:
JFreeChart chart = functionWhichRetrievesTheChart();
ChartRenderingInfo info = new ChartRenderingInfo();
// PLOT_SIZE is the size if the graph and has to be the same size as the original drawn chart.createBufferedImage(PLOT_SIZE, PLOT_SIZE, info);
graph, otherwise the pixel position points to somewhere else
PlotRenderingInfo plotInfo = info.getPlotInfo();
XYPlot plot = (XYPlot)chart.getPlot();
Point p = new Point(x,y); // x and y are the pixel positions
// this is the domain value which belongs to the pixel position x
double domain = plot.getDomainAxis().java2DToValue(p.getX(), plotInfo.getDataArea(), plot.getDomainAxisEdge());
// this is the range value which belongs to the pixel position y
double range = plot.getRangeAxis().java2DToValue(p.getY(), plotInfo.getDataArea(), plot.getRangeAxisEdge());

Related

JFreeChart XYTextAnnotation Location with AutoRange

I have a realtime time series chart where I add vertical value markers when certain events occur. I want to also label those markers with XYTextAnnotation (also vertically). I tried to locate the label along the right side and top of the marker. However, the Y axis of chart uses AutoRange but the annotation is in an absolute X,Y location. The result is that it moves off the chart in the Y axis and disappears as the range increases. How can I add the label so it stays on the chart relative to the changing range? TIA.
Here is my current code:
public void addMarker(String id_,String name_) {
Functions.logger("Adding open door marker for "+id_+" "+name_,false);
Long tod=new Date().getTime();
ValueMarker marker=new ValueMarker(tod);
XYTextAnnotation label=new XYTextAnnotation("Door Open: "+name_,tod-1,360);
label.setRotationAnchor(TextAnchor.BASELINE_CENTER);
label.setTextAnchor(TextAnchor.BASELINE_CENTER);
label.setRotationAngle(-Math.PI/2);
label.setPaint(Color.BLACK);
marker.setStroke(new BasicStroke(2));
marker.setPaint(Color.BLACK);
chart.addDomainMarker(marker);
chart.addAnnotation(label);
}

Android: Rotating an image and setting X,Y position at the same time dynamically

so i'm trying to make an app to display the current position of a LEGO Robot in a Path, i'm receiving the data with another existing project and i just have to move dynamically the position of the image in the screen. I have managed to do it (like in a cartesian plane) with setX and setY, and my 'origin' is in the coordinates 'pixels' x= 70, y= 300 of the screen. However when I try to do the rotation (the rotation has to be made counterclockwise, with the origin previously mentioned) it doesn't show me what I expected, doesn't keep the x y coordinates i want. Here is the code for the animation:
final View robot = (View) findViewById(R.id.carImg);
//Scale for the X/Y coordinates
float coordX = hmiModule.getPosition().getX();
float coordXScale = coordX*4 + 50 ;
float coordY = hmiModule.getPosition().getY();
float coordYScale = 300-coordY*4;
robot.setX(coordXScale);
robot.setY(coordYScale);
//code for the rotation with origin (70,300)
robot.setPivotX(70);
robot.setPivotY(300);
robot.setRotation(-hmiModule.getPosition().getAngle());
I would really appreciate your help, thanks in advance!

Converting image X,Y coordinates to longitude and latitude?

I have set values of minimum longitude and latitude of a specific static map image. That map image is a cut of some country.
/**
* Maximum longitude value of the map
*/
private float mapLongitudeMax;
/**
* Minimum longitude value of the map
*/
private float mapLongitudeMin;
/**
* Maximum latitude value of the map
*/
private float mapLatitudeMax;
/**
* Minimum latitude value of the map
*/
private float mapLatitudeMin;
And I have a BufferedImage called mapImage.
I have a method that I wrote with a friend that receives longitude and latitude and gives you an X and a Y position approximately on the map so you can draw something on the map.
Now if I want to move my mouse around the map, I want it to show longitude/latitude of my mouse position, that means I need to create a method which converts X and Y of the mouse position to longitude and latitude, which should do the opposite of my other method.
This is my method to convert globe coordinates to image X and Y:
protected Location getCoordinatesByGlobe(float latitude, float longitude) {
/**
* Work out minimum and maximums, clamp inside map bounds
*/
latitude = Math.max(mapLatitudeMin, Math.min(mapLatitudeMax, latitude));
longitude = Math.max(mapLongitudeMin, Math.min(mapLongitudeMax, longitude));
/**
* We need the distance from 0 or minimum long/lat
*/
float adjLon = longitude - mapLongitudeMin;
float adjLat = latitude - mapLatitudeMin;
float mapLongWidth = mapLongitudeMax - mapLongitudeMin;
float mapLatHeight = mapLatitudeMax - mapLatitudeMin;
float mapWidth = mapImage.getWidth();
float mapHeight = mapImage.getHeight();
float longPixelRatio = mapWidth / mapLongWidth;
float latPixelRatio = mapHeight / mapLatHeight;
int x = Math.round(adjLon * longPixelRatio) - 3;// these are offsets for the target icon that shows.. eedit laterrr #oz
int y = Math.round(adjLat * latPixelRatio) + 3; //
// turn it up
y = (int) (mapHeight - y);
return new Location(x, y);
}
Now I tried thinking, the first thought that came into my head is just doing the same in reverse... so I started doing it and I ran into problems like, I can't get the value of adjLon or adjLat without having the longitude or latitude, so this can't be simply done by reversing it. I am all new to coordinates systems so it's all a bit confusing for me but I am starting to catch it up.
Any tips for me?
EDIT (Its not possible?)
According to this answer, you can't really get real results because the earth is not flat, it can't really be converted to a flat map with longitude and latitude without implementing a real mathematical algorithm to make it work with the changes.
There are few reasons in my code why the answer can not be exact:
Because of the reason above
Because my X,Y values are integers and not floats.
So my question now, if it is really impossible with my method?
Sadly, there's not an easy answer to this. While you can write the projection routines yourself, the easiest thing to do is probably to get a GIS library, but since I ended up doing this in C# and not Java, I don't know what's available.
The biggest piece of information you need is exactly which projection your map image uses. The Mercator Projection is quite popular, but it's not the only one. You also need to make sure that your chosen projection works for the range of latitudes and longitudes you want. The Mercator projection kind of breaks if you start going above +-70 N, so if you're doing a lot of positions at the poles that might not be the projection for you.
From what i read in your code, your image is in longitude/latitude coordinates, and you draw it on a canvas to be display on screen. Then you add your listener on this image is that correct ?
if this is correct the response is trival, as you can retrieve the X/Y position in your image via MouseListener method on Canvas and transform it base on the position of the mouse inside the canvas (methode getX/getY from mouseEvent) and the current dimension of the canvas and then translate this position within the bound of longitude/latitude.
longitude = minLongitude + (MouseEvent.getX/Canvas.Width)*maxLongitude
lalitude = minLaltitude + (MouseEvent.getY/Canvas.Height)*maxLatitude
If not then you will have to know as #ginkner say the projection technique use to pass from long/lat to X/Y and take the inverse transformation knowing that you will lost some information.
There is a difference between geography coordinate and geometry coordinate it is quite like the 3D earch surface and a canvas to draw on. The web Mercator projection or other popular projection coordinate systems are used for an abstraction of visualization of the earth surface. So that pixel shift in different location would result in different distances.
If you are looking for a some basic GIS java library to handle this type of problem, Geotools in Java could be one option. GeoTools

Searching JTS STR tree

Hi I've been following this tutorial http://googledevelopers.blogspot.com/2014/12/building-scalable-geofencing-api-on.html , and here's my problem,
I have a list of longitude and latitude coordinates that I've added to a JTS(Java Topology Suite) STR tree as Points.
Now I would like to send an area that is in the shape of a circle to the STR tree to find all of the Points that land in the circle.
Coordinate center = new Coordinate(entity.getLongitude(), entity.getLatitude());
GeometricShapeFactory gsf = new GeometricShapeFactory();
gsf.setCentre(center);
gsf.setNumPoints(20);
**gsf.setSize(320.0);**
Polygon poly = gsf.createCircle();
Coordinate[] coordinates = poly.getCoordinates();
//Create polygon from the coordinates.
GeometryFactory fact = new GeometryFactory();
LinearRing linear_ring = new GeometryFactory().createLinearRing(coordinates);
Polygon polygon = new Polygon(linear_ring, null, fact);
List<STRLeaf> items = strTree.query(polygon.getEnvelopeInternal());
However the result of the search sends back all of the data in the in the tree of longitude and latitude Points. When I lower the size of the circle below 320 then I receive no results from the search of the STR tree. Does anyone have experience with this ideally I would like to create the circle that finds all the points within a circle of ~7miles.
thanks for your time
It turns out that I had a silly mistake in the backend. When I added the items to the tree I mixed up the x and y coords, so that the Lat Longs were reversed. After switching them, I can now set the size of the circle to around 0.1 and it works well.

Screen X,Y co-ordinates translated to map Lon/Lat co-ordinates

Good day.
I would like to convert a screen x,y pixel location (the location a user tapped/clicked) to a lon/lat location on a map.
The current screen location is in a bounding box, of which you have the top left most and bottom right most lon/lat values.
When the screen is not rotated it is quite simple to translate the x/y position to the lon,lat values:
Let mapboudingbox[0,1] contain top left most lat/lon
mapboundingbox[2,3] contains bottom right most lat/lon
Then the degrees per pixel width = abs(lon2 - lon1)/ screenWidthInPixels
Then the degrees per pixel height = abs(lat2 - lat1)/ screenHeightInPixels
From this you can then get Lon/Lat as follow:
float longitude = ((touchXInPixels) * degreesPerPixelWidth) + mapBoundingBox[1];
float latitude = ((touchYPixels) * degreesPerPixelHeight) + mapBoundingBox[0];
This is easy enough. The problem that I have is calculating the Lat/Lon values when the screen is rotated, i.e:
From this, you can see that the screen has now been rotated by an angle Ө. -180 < Ө < 180
So let's assume the user clicks/taps on the screen FQKD at point Sx,Sy. How can I get the new lon/lat values where the user clicked, assuming that we have point Z and R in Lat/Lon, as well as the angle Ө, as well as the screen height and width in pixels?
Any and all help will be much appreciated!
I would just modify standard rotation and scale algorithm for 2D. Read a bit here:
2dTransformations.
The easiest way to achieve this is with matrices.
A 3x3 matrix can describe the rotation, translation & scale in 2D space.
Using this matrix you can project your map image on to the screen area. And using the inverse of the matrix, you can take a point in screen space to map space.
Pseudocode: (as you don't care what language)
Build your matrix:
var matrix = Matrix.newIdentity();
matrix.postAppendTranslate(tx, ty);
matrix.postAppendScale(zoom);
matrix.postAppendRotate(rot);
Render map image using that matrix.
To reverse a press:
var inverseMatrix = matrix.inverse();
var point = new float[]{touchPointX, touchPointY, 1};
var transformedPoint = inverseMatrix.multiply(point);
var mapX = transformedPoint[0];
var mapY = transformedPoint[1];

Categories

Resources