Render Geolocation coordinates into image using Java - java

I need to print a polygon given a set of Longitude and Latitude coordinates.
I am starting with just two coordinate for initial testing. The problem is Java Image API works on pixel points and that Longitude and Latitude are big decimals.
So even if I have this code:
BufferedImage bi = new BufferedImage(500, 500, BufferedImage.OPAQUE);
Graphics2D ig2 = bi.createGraphics();
double[] xArr = toDoubleArray(Arrays.asList(Double.valueOf("121.91359648077058"), Double.valueOf("121.92293884686991")));
double[] yArr = toDoubleArray(Arrays.asList(Double.valueOf("11.995724479140792"), Double.valueOf("11.999118908426375")));
Path2D path = new Path2D.Double();
path.moveTo(xArr[0], yArr[0]);
System.out.println("x[0]=" + xArr[0] + "," + "y[0]=" + yArr[0]);
for(int i = 1; i < xArr.length; ++i) {
path.lineTo(xArr[i], yArr[i]);
System.out.println("x[" + i + "]=" + xArr[i] + "," + "y[" + i + "]" + yArr[i]);
}
path.closePath();
ig2.draw(path);
ImageIO.write(bi, "PNG", new File("polygons.png"));
It will just be a single pixel, which is 121 and 11 inside the 500,500 buffer image.
What can be done to be able to render Geolocation coordinates into an image? I really don't need the lines just plot the points in the image is sufficient, hover the Path2D is the closest one I found since it supports double values.

You could use the GeoTools library which will handle coordinates (in any projection) and render them to a Graphics object which can come from an Image.
There are a number of tutorials to get you started and
these questions will help get you started:
Plot the longitude and latitudes on map using GeoTools
GeoTools - drawing points on image

You can use any of the Java Image API for plotting your lat/lon list on image, the integer input of Image APIs should not be a constraint.
You can first decide the min-max lat/lon that you will be plotting on your image. Then you can map your input data with the image's lat/lon bounds and calculate the plotting pixel.
Below code snippet might help you on how to map and plot on image:
try {
int imagePixelWidth = 500;
int bubble_size = 50;
BufferedImage image = new BufferedImage(imagePixelWidth,
imagePixelWidth, BufferedImage.TYPE_INT_ARGB);
//Position you wish to plot
double lat = 11.995724479140792;
double lon = 121.91359648077058;
// min-max plotting lat/lon of your image
double min_lat = 10.897564874;
double min_lon = 120.8975764;
double max_lat = 13.0975875;
double max_lon = 123.9759874;
Graphics2D graphics = (Graphics2D) image.getGraphics();
double latExtent = max_lat - min_lat;
double lonExtent = max_lon - min_lon;
double ly1 = (imagePixelWidth * (lat - min_lat)) / latExtent;
double lx1 = (imagePixelWidth * (lon - min_lon)) / lonExtent;
int ly = (int) (imagePixelWidth - ly1);/* pixel increases downwards. Latitude increases upwards (north direction). So you need to inverse your mapping.*/
int lx = (int) lx1;
graphics.setColor(new Color(0, 0, 0));
graphics.fillOval(lx - bubble_size / 2, ly - bubble_size / 2,
bubble_size, bubble_size);
ImageIO.write(image, "png", new File("/home/ist/test.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

After you map your coordinates to screen coordinate system, the distinction between big decimals and double should be mostly moot. You can then draw each point as a small circle. To get that done without resorting to integers, you can use e.g.
double final r = 1.0; // radius of dots representing points
for(int i = 1; i < xArr.length; ++i) {
ig2.fill(new Ellipse2D.Double(xArr[i]-r, yArr[i]-r, 2*r, 2*r));
}

Related

Graphics2D placing image with specific corner co-ordinates

I need to place an image onto a canvas with the corners at specific co-ordinates.
// Blank canvas
BufferedImage img = new BufferedImage(2338, 1654, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setBackground(Color.WHITE);
g2d.clearRect(0, 0, width, EXTRA_HEADER_HEIGHT);
I have all 4 corner co-ordinates that the image corners must be placed at on the background canvas. The problem is that the original image might need to be rotated. This is basically what I need to achieve:
I don't have much experience with Graphics2D but based on a quick review of the API I can't see a method to achieve this. I am hoping that I am wrong here and that somebody can save me some time but my current thinking is:
Use the co-ordinates to calculate the rotation of the placed image relative to the supplied image.
Place the image with one of its corners in the correct position.
Rotate the image around that corner (without rotating background canvas).
Any help with the above would be appreciated.
As tucuxi commented, if you really have 4 points and want the transform to place the image corners at these exact points, and affine transform won't do -- you'll need a perspective transform.
However, if you select two points of the four, you can do what you want, but you may have to scale the image. So let's say you just want to place a rotated and scaled version of your image such that its top edge goes from A' to B'. What you'll have to do is compute the affine transform, which involves determining the rotation angle, scaling factor, and translation from the segment AB to A'B'.
Here's a commented method that should do just that. I have not thoroughly tested it, but it shows how to implement the algorithm in Java.
package stackoverflow;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public class ComputeImageTransform
{
public static AffineTransform computeTransform(
Rectangle2D imageBounds, Point2D a2, Point2D b2) {
double dx = b2.getX() - a2.getX();
double dy = b2.getY() - a2.getY();
// compute length of segment
double length = Math.hypot(dx, dy);
// compute scaling factor from image width to segment length
double scaling = length / imageBounds.getWidth();
// compute rotation angle
double rotation = Math.atan2(dy, dx);
// build the corresponding transform
// NOTE: the order of the individual transformations are applied is the
// reverse of the order in which the transform will apply them!
AffineTransform transform = new AffineTransform();
transform.translate(a2.getX(), a2.getY());
transform.rotate(rotation);
transform.scale(scaling, scaling);
transform.translate(-imageBounds.getX(), -imageBounds.getY());
return transform;
}
public static void main(String[] args) {
// transform top edge of image within this axis-aligned rectangle...
double imageX = 20;
double imageY = 30;
double imageWidth = 400;
double imageHeight = 300;
Rectangle2D imageBounds = new Rectangle2D.Double(
imageX, imageY, imageWidth, imageHeight);
// to the line segment a2-b2:
Point2D a2 = new Point2D.Double(100, 30);
Point2D b2 = new Point2D.Double(120, 200);
System.out.println("Transform image bounds " + imageBounds);
System.out.println(" to top edge " + a2 + ", " + b2 + ":");
AffineTransform transform = computeTransform(imageBounds, a2, b2);
// test
Point2D corner = new Point2D.Double();
corner.setLocation(imageX, imageY);
System.out.println("top left: " + transform.transform(corner, null));
corner.setLocation(imageX + imageWidth, imageY);
System.out.println("top right: " + transform.transform(corner, null));
corner.setLocation(imageX, imageY + imageHeight);
System.out.println("bottom left: " + transform.transform(corner, null));
corner.setLocation(imageX + imageWidth, imageY + imageHeight);
System.out.println("bottom right: " + transform.transform(corner, null));
}
}
This is the output:
Transform image bounds java.awt.geom.Rectangle2D$Double[x=20.0,y=30.0,w=400.0,h=300.0]
to top edge Point2D.Double[100.0, 30.0], Point2D.Double[120.0, 200.0]:
top left: Point2D.Double[100.0, 30.0]
top right: Point2D.Double[119.99999999999999, 199.99999999999997]
bottom left: Point2D.Double[-27.49999999999997, 44.999999999999986]
bottom right: Point2D.Double[-7.499999999999986, 214.99999999999997]
As you can see, you'll get some rounding errors due to the nature of floating-point computations.

Need an algorithm to map co-ordinates of a point in images with different dimensions

I am stuck with a problem in my current project. I have 2 copies of same image say image1.tiff and image2.tiff but of different dimensions(Different pixel and DPIs). Suppose a point in image1.tiff lies at co-ordinates (x,y) ,I need to find the co-ordinates of the same point in image2.tiff. I have tried a lot to think of an algorithm. Requesting your help for this ..
You can use AffineTransformOp for this.
As an example:
BufferedImage img1 = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB);
BufferedImage img2 = new BufferedImage(400, 200, BufferedImage.TYPE_INT_ARGB);
double sx = img2.getWidth() / (double) img1.getWidth();
double sy = img2.getHeight() / (double) img1.getHeight();
AffineTransformOp xform =
new AffineTransformOp(AffineTransform.getScaleInstance(sx, sy), null);
Point srcPt = new Point(7, 49);
Point dstPoint = (Point) xform.getPoint2D(srcPt, new Point());
System.err.println("srcPt: " + srcPt);
System.err.println("dstPoint: " + dstPoint);
Will print:
srcPt: java.awt.Point[x=7,y=49]
dstPoint: java.awt.Point[x=14,y=98]
I would suggest the following approach:
double image1_to_image2 = image2.width()/image1.width();
double image2_to_image1 = image1.width()/image2.width();
If you have x1 and y1 as coordinates for the first image, you can calculate the corresponding location for the second image as follows:
int x2 = x1 * image1_to_image2;
int y2 = y1 * image1_to_image2;
If your images have a different aspect ratio, you will need to calculate scaling factors for the height separately.
The basic idea behind the approach is, that you map the coordinates of the images to the interval i_1 = [0;1] by dividing by the width (assuming the width is the larger dimension, but it does not matter if it is smaller than the height). By multiplying the scaled coordinate with the width of the second image, you map the coordinate back to the interval i_2 = [0; x_1 * width_2] which is at most the width of the second image.

Converting an Ellipse2D to Polygon

I have a Java swing application where I can draw hot spots. I am allowing user to draw Rectangle , Polygon and Circle.
For Circle I am using Ellipse2D
Ellipse2D.Double ellipseDouble = new Ellipse2D.Double(x,y,width,height);
g.draw(ellipseDouble);
Above works fine and it does draw an ellipse/circle.
Now the problems when I want the region to be used in HTML Image map.
Html Image map doesn't support Ellipse so I was thinking to use polygon for Ellipse2D but really don't know how would I convert it.
Does anyone know how would I go about it converting an Ellipse2D to Polygon ponits?
Use FlatteningPathIterator.
See e.g. http://java-sl.com/tip_flatteningpathiterator_moving_shape.html where point moves following custom Shape.
You can get list of Points and create Polygon.
Maybe someone will find this one useful: this is pdfbox ellipse or circle (width=height) draw function inside rectangle, it make ellipse as polygon initially to draw.
Code based on math function of ellipse at poin [0 , 0]: x^2/a^2 + y^2/b^2 = 1
private PdfBoxPoligon draw_Ellipse_or_Circle_as_poligon_with_PDFBOX (
PDPageContentStream content, float bottomLeftX, float bottomLeftY,
float width, float height, boolean draw) throws IOException {
PdfBoxPoligon result = new PdfBoxPoligon();
float a = width/2;
float b = height/2;
int points = (int) (a*b/20);
if (DEBUG) {
System.out.println("points=" + points);
}
//top arc
for (float x = -a; x < a; x = x + a / points) {
result.x.add(bottomLeftX + a + x);
float y = (float) Math.sqrt((1-(x*x)/(a*a))*(b*b));
result.y.add(bottomLeftY+b+y);
}
//bottom arc
for (float x = a; x >= -a; x = x - a / points) {
result.x.add(bottomLeftX + a + x);
float y = -(float) Math.sqrt((1-(x*x)/(a*a))*(b*b));
result.y.add(bottomLeftY+b+y);
}
result.x.add(result.x.get(0));
result.y.add(result.y.get(0));
if (draw) {
for (int i=1; i < result.x.size(); i++) {
content.addLine(result.x.get(i-1), result.y.get(i-1), result.x.get(i), result.y.get(i));
}
}
return result;
}

Generate vertices for a polygon

I'm trying to make a useful/generic 2D polygon class for an OpenGL ES renderer.
When I create a polygon, I give it several parameters:
Polygon(Vector3 centerpoint, int numVertices, float inPolySize)
Then, I try to generate the vertices. This is where i'm having a tough time. I need to determine the number of vertices, get an angle, find the x/y position of that angle, someone take the size into account, AND offset by the position.
OpenGL works with big arrays of data. Nothing is nice like Lists of Vector3's. Instead it's float[] arrays, with the first index being X1, second being Y1, third being Z1, fourth being X2, etc...
final int XPOS = 0;
final int YPOS = 1;
final int ZPOS = 2;
int mvSize = 3; // (x, y, z);
float[] vertices = new float[mvSize * mNumVertices];
for (int verticeIndex = 0; verticeIndex < mNumVertices; verticeIndex++)
{
double angle = 2 * verticeIndex * Math.PI / mNumVertices;
vertices[mvSize * verticeIndex + XPOS] = (((float)Math.cos(angle)) * mPolygonSize) + mPosition.GetX();
vertices[mvSize * verticeIndex + YPOS] = (((float)Math.sin(angle)) * mPolygonSize) + mPosition.GetY();
vertices[mvSize * verticeIndex + ZPOS] = mPolygonSize + mPosition.GetZ();
}
Unfortunatley, my triangle is never quite right. It's skewed a lot, the size doesn't seem right...
I figure i'm throwing the size into the wrong formula, can anyone help?
EDIT:
Here's some sample data
Polygon test = new Polygon( new Vector3(0, 1, 0), 3, .5f);
vertices[0] = -0.25
vertices[1] = 1.4330127
vertices[2] = 0.0
vertices[3] = -0.25
vertices[4] = 0.5669873
vertices[5] = 0.0
vertices[6] = 0.5
vertices[7] = 1.0
vertices[8] = 0.0
vertices[9] = -0.25
vertices[10] = 1.4330127
vertices[11] = 0.0
I can't believe I was this stupid. Basically, my render window was smaller than my screen. If my screen is a rectangle, my render window was a square.
This being the case, any triangle I draw that was up was clipped by my render window. To me, it looked like the triangle was skewed. Really, it was just clipped!
The Java math library takes radians as input, not degrees. I didn't see the angles you were using for your calculation, but if you're not converting to radians from degrees, you will get some skewed looking shapes, and would explain that your calculations are correct, but the expected result is off.

Translate Java 3D coordinates to 2D screen coordinates

I'm working with a Java 3D application called "Walrus" that is used to display directed graphs. The code already has a feature to highlight a node and draw label adjacent in graph given its screen coordinates.
Upon rotating the screen, the node is no more highlighted.
What I have is the node coordinates in 3D. I need to draw label to it.
Code for highlight using 3D coordinates
Point3d p = new Point3d();
m_graph.getNodeCoordinates(node, p);
PointArray array = new PointArray(1, PointArray.COORDINATES);
array.setCoordinate(0, p);
m_parameters.putModelTransform(gc);
gc.setAppearance(m_parameters.getPickAppearance());
How can I draw Label with 3D coordinates( Raster graphics throws error Renderer: Error creating immediate mode Canvas3D graphics context )
How can I convert 3D coordinates to 2D screen and use existing code to draw label at 2D screen point
Thanks,
Dakshina
I have an algorithm/method for converting [x,y,z] into [x,y] with the depth parameter:
The x value is : (int) (x - (z / depth * x))
The y value is : (int) (y - (z / depth * y))
Essentially, the depth is the focal point. The vanishing point will be at [0,0,depth].
Here's what i used to convert my 3D coordinates into perspective 2D, x2 and y2 being the 2dimensional coordinates, xyz being the 3D coordinates.
use these formulas:
x2 = cos(30)*x - cos(30)*y
y2 = sin(30)*x + sin(30)*y + z
I picked the angle 30 as it is easy for perspective purposes, also used in Isometric grids for drawing 3D on 2D papers. As the z axe will be the vertical one, x and y are the ones at 60 degrees from it right and left. Isometric Grid Picture.
I'm still working on rotation, but without altering the axes, just coordinate rotation in 3D.
Enjoy.
I found the solution.
This is the function to display Text3D at image 2D coordinates
public void drawLabel(GraphicsContext3D gc, double x, double y, int zOffset, String s) {
boolean frontBufferRenderingState = gc.getFrontBufferRendering();
gc.setBufferOverride(true);
gc.setFrontBufferRendering(true);
Point3d eye = getEye();
double labelZ = zOffset * LABEL_Z_OFFSET_SCALE
+ LABEL_Z_SCALE * eye.z + LABEL_Z_OFFSET;
double xOffset = LABEL_X_OFFSET * m_pixelToMeterScale;
double yOffset = LABEL_Y_OFFSET * m_pixelToMeterScale;
Point3d p = new Point3d(x + xOffset, y + yOffset, 0.0);
{
// Project given (x, y) coordinates to the plane z=labelZ.
// Convert from image-plate to eye coordinates.
p.x -= eye.x;
p.y -= eye.y;
double inversePerspectiveScale = 1.0 - labelZ / eye.z;
p.x *= inversePerspectiveScale;
p.y *= inversePerspectiveScale;
// Convert from eye to image-plate coordinates.
p.x += eye.x;
p.y += eye.y;
}
Transform3D scale = new Transform3D();
scale.set(LABEL_SCALE);
Vector3d t = new Vector3d(p.x, p.y, labelZ);
Transform3D translation = new Transform3D();
translation.set(t);
translation.mul(scale);
Transform3D transform = new Transform3D(m_imageToVworld);
transform.mul(translation);
gc.setModelTransform(transform);
//-----------------
int fontSize=(int)(10*m_magnification);
if(fontSize>20)
fontSize=20;
//---------------
// XXX: Courier may not be available on all systems.
Text2D text = new Text2D(s, new Color3f(1.0f, 1.0f, 1.0f),
"Courier", fontSize, Font.BOLD);
gc.draw(text);
gc.flush(true);
// NOTE: Resetting the model transform here is very important.
// For some reason, not doing this causes the immediate
// following frame to render incorrectly (but subsequent
// frames will render correctly). In some ways, this
// makes sense, because most rendering code assumes that
// GraphicsContext3D has been set to some reasonable
// transform.
gc.setModelTransform(m_objectTransform);
gc.setFrontBufferRendering(frontBufferRenderingState);
}
This is the function to take 3D coordinates and convert them to image 2D coordinates and render using above function
private boolean displayOnScreenLabel(int node, String label) {
boolean success = false;
try {
Transform3D transform = m_parameters.getObjectToEyeTransform();
Point3d nodeC = new Point3d();
m_graph.getNodeCoordinates(node, nodeC);
transform.transform(nodeC);
Point3d eye = m_parameters.getEye();
double perspectiveScale = 1.0 / (1.0 - nodeC.z / eye.z);
double centerX = eye.x + nodeC.x * perspectiveScale;
double centerY = eye.y + nodeC.y * perspectiveScale;
GraphicsContext3D gc = m_canvas.getGraphicsContext3D();
m_parameters.drawLabel(gc, centerX, centerY, m_labelZOffsetCounter++, label);
success = true;
} catch (final java.lang.OutOfMemoryError error) {
JOptionPane.showMessageDialog(m_frame, "The 3D Graphics is unable to find enough memory on your system. Kill the application!", "Out Of Memory!", JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
success = false;
}
return success;
}

Categories