I'm currently developing an radar for android. (Following this tutorial: http://www.androidph.com/2009/02/app-10-beer-radar.html )
I'm getting all users within a range of 5KM around my current location from the server after that I draw in my customview like this:
float xU = (float)(userLocation.getLongitude() + getWidth() / 2 - currentLong);
float yU = (float)(getHeight() / 2 - userLocation.getLatitude() + currentLat);
canvas.drawBitmap(bmpUser,xU,yU,radarPaint);
Now my problem is, that I need to scale the the points / coordinates I draw on the radar, because all users within a distance below 5KM will be drawn like only 2-3 Pixel away from the center. How would I manage to do that?
This is one way to do it. All you need to do is to set the value of the "scale" variable to the required value;
float scale = 3.0f; //set this to any number to change the drawing scale
float xU = (float)(getWidth() / 2 + (userLocation.getLongitude() - currentLong) * scale);
float yU = (float)(getHeight() / 2 - (userLocation.getLatitude() - currentLat) * scale);
canvas.drawBitmap(bmpUser,xU,yU,radarPaint);
Related
I have a map of world.
I need to create a function that gets two double parameters (longitude and latitude) and that function should draw a small circle on that area in the map image.
I have the following info about the map:
The width of the map in pixels
The height of the map in pixels
** I get to pixel X, Y based on that image.
I tried longitude = -106.346771 and latitude = 56.130366;
mapWidth = 3840.0 and mapHeight = 2160.0 ;
double x = (longitude + 180) / 360 * mapWidth;
double y = (1 - Math.log(Math.tan(Math.toRadians(latitude)) + 1 /
Math.cos(Math.toRadians(latitude))) / Math.PI) / 2 * mapHeight;
result : [lon: -106.346771 lat: 56.130366]: X: 785.6344426666666 Y: 671.2084211650845
but not selected in right location.
enter image description here
Unfortunately, this problem is way harder than it seems.
That map is a Projection, so it is distorted from the original (roughly) spherical coordinate system your data is in.
(actually, your lat & long values may themselve be in one of several different projections, but that only really matters if you are doing very precise measurements.)
So your first order of business is to find out exactly what projection the map is using, then start looking for GIS libraries you can use in Java (I think there are several) to perform the translation.
Decide on a radius, r, for your globe model. Your map will be 2πr pixels wide.
Decide on a a latitude cutoff. You can't project a pole to a plane, and at extreme latitudes things get so distorted as to be unusable. 85 degrees is a common choice.
Express your latitude in radians: lat_r
You X coordinate is r * (lat_r+ π). So at 180° W your X coordinate is r * (-π + π) = 0, and at 180° E your X coordinate is r * (π + π) = 2πr
Express your longitude in radians: lon_r
Your Y coordinate is r * tan(lon_r) * (1 - cos(lon_r)). So at 85° N your Y coordinate is r * tan(1.4835) * (1 - cos(1.4835)) = 10.4r
I am trying to center the content of my page after scaling it by a factor X. I have tried using the Matrix.translate function but I always end up getting the wrong position, except when scaling with a factor of 0.5 (which makes totally sense to me).
My current code:
for (int i = 0; i < doc.getNumberOfPages(); i++) {
pdfBuilder.addPage(doc.getPage(i));
PDPage p = pdfBuilder.getDocument().getPage(i);
Matrix matrix = new Matrix();
float scaleFactor = 0.7f;
float pageHeight = p.getMediaBox().getHeight();
float pageWidth = p.getMediaBox().getWidth();
float translateX = pageWidth * (1 - scaleFactor);
float translateY = pageHeight * (1 - scaleFactor);
matrix.scale(scaleFactor, scaleFactor);
matrix.translate(translateX, translateY);
PDPageContentStream str = new PDPageContentStream(pdfBuilder.getDocument(), p, AppendMode.PREPEND,
false);
str.beginText();
str.transform(matrix);
str.endText();
str.close();
}
I have also tried other boxes like the cropBox and bBox but I think I am totally wrong in what I do right now. Please help me! :)
Update
I finally found a solution. The new translation values I am using now look like the following.
float translateX = (pageWidth * (1- scaleFactor)) / scaleFactor / 2;
float translateY = (pageHeight * (1- scaleFactor)) / scaleFactor / 2;
Update I finally found a solution. The new translation values I am using now look like the following.
float translateX = (pageWidth * (1- scaleFactor)) / scaleFactor / 2;
float translateY = (pageHeight * (1- scaleFactor)) / scaleFactor / 2;
First of all, it is important to note what #mkl said.
The crop box may be the box you should use instead of the media box.
The code implicitly assumes that the lower left corner of the (media/crop) box is the origin of the coordinate system. This often is the case but not always.
The code only scales the static content, not annotations.
Now the explanation of the translation (e.G. translation for the page height). PLEASE NOTE THAT I AM NOT A MATHEMATICIAN AND I JUST TRIED DIFFERENT WAYS AND THIS IS THE ONE THAT WORKED FOR ME
Firsly, we multiply the page height with the opposite of the scale factor pageHeight * (1 - scaleFactor). We need the opposite because the smaller we scale something the more it needs to move from a given position. If we use the normal scale factor here, the smaller we scale an image the less it will translate to the centre.
Now the problem is that the translation is still off. Overall it moves the scaled content in the right direction, but just not into the centre. Therefore I tried dividing the calculated factor in the step before through the half of the scale factor. We use the half here because we want the content to appear in the centre. I don't know exactly why it is precisely this value, but as I said it just worked for me!
If you know why this works, feel free to edit this answer :)
I'm working on a game for a game jam right now, and the problem is related to the flight path of a certain game enemy. I'm trying to have several of them fly in formation, and the idea was to have them fly in a wide radius circle around the center of the screen so they essentially box in the player. To do this, I tried to use the following formula...
public Pair<Double> move(Pair<Double> currPos, Pair<Double> playerPos) {
Pair<Double> newPos = new Pair<>(currPos.x, currPos.y);
// The radius used as the distance from the center.
double r = (Framework.CANVAS_WIDTH / 2) - Player.SHIP_SIZE;
// X,Y coords for center of the screen.
double cX = (Framework.CANVAS_WIDTH / 2);
double cY = (Framework.CANVAS_HEIGHT / 2);
// Trigonometric equation for transforming the object in a circle.
newPos.x = cX + (r * Math.cos(Framework.getHypotenuse(currPos, new Pair<Double>(cX, cY)) + (Math.PI / 90)));
newPos.y = cY + (r * Math.sin(Framework.getHypotenuse(currPos, new Pair<Double>(cX, cY)) + (Math.PI / 90)));
return newPos;
}
I can't figure out why the equation doesn't seem to work. When I test the movement pattern, there seem to be two enemies on screen rotating around the center, even though I only spawned one. However, they're blinking really fast, which makes it seem like maybe the ship is jumping back and forth really fast. This is supported by the fact that when I took a screenshot, there was only one ship. Is there something wrong with my trigonometry that would cause this, or does the problem lie elsewhere?
The following pseudocode gives the standard way to make an object move in a circular path:
double r = (...); // Radius of circle
double cX = (...); // x-coordinate of center of rotation
double cY = (...); // y-coordinate of center of rotation
double omega = (...); // Angular velocity, like 1
double t = (...); // Time step, like 0.00, 0.01, 0.02, 0.03, etc.
newPos.x = cX + r * Math.cos(t * omega);
newPos.y = cY + r * Math.sin(t * omega);
So I'm rendering points in 3D space. To find their X position on the screen, I'm using this math:
double sin = Math.sin(viewPointRotX);
double cos = Math.cos(viewPointRotX);
double xx = x - viewPointX;
double zz = z - viewPointZ;
double rotx = xx * cos - zz * sin;
double rotz = zz * cos + xx * sin;
double xpix = (rotx / rotz * height + width / 2);
I'm doing a similar process for Y.
This works fine, but points can render as if they were in front of the camera when they are actually behind it.
How can I work out using the data I've got whether a given point is in front of or behind the camera?
We can tell if a point is in front or behind a camera by comparing coordinates with a little 3D coordinate geometry.
Consider a very simple example: The camera is located at (0,0,0) and pointed straight up. That would mean every point with a positive Z coordinate is "in front" of the camera. Now, we could get more complicated and account for the fact that the field of view of a camera is really a cone with a particular angle.
For instance, if the camera has a 90 degree field of view (45 degrees in both directions of the way it is facing), then we can handle this with some linear math. In 2D space, again with camera at the origin facing up, the field of view would be bound by the lines y = x and y = -x (or all points within y = |x|).
For 3D space, take the line y = x and spin it around the z-axis. We now have the cone:
z = x*x + y*y, so if
if(z < x*x + y*y && z>0)
then the point is in front of the camera and within the field of view.
If the camera is not at the origin, we can just translate the coordinate system so that it is and then run the calculation above. If the viewing angle is not 90 degrees, then we need to trace out some line y = mx (where m = Math.tan(viewAngle/2) ) and spin this line about the z-axis to get the light cone.
The way it looks like you are doing this is transforming the point coordinates so that they are aligned with and relative to the view.
If you do this the right way then you can just check that the rotated z-value is positive and greater than the distance from the focal-point to the "lens".
Find the view direction vector:
V = (cos(a)sin(b), sin(a)sin(b), cos(b)), where a and b are the camera's rotation angles.
Project the offset vector (xx, yy, zz) onto the view direction vector, and find the magnitude, giving the distance along the camera's view axis of the point:
distance = xx * cos(a)sin(b) + yy * sin(a)sin(b) + zz * cos(b)
Now just check that distance > focalLength.
This should work but you have to be careful to set everything up right. You might have to use a different calculation to find the view direction vector depending on how you are representing the camera's orientation.
I'm not all that good with Maths, so i was hoping some of you guys could help?
I'm trying to make a function to convert mouse coordiantes into a particular tile in an isometric view.
It won't let me post images for a stupid reason, so ill just link the image:
Link
All of the algorithms i have seen so far work with the X & Y axes going diagonal, my game is currently set up like this, and i would like to keep it so.
Is there an algorithm so that if the mouse was at the red dot, it would return the coordinates of the tile that it is sitting on? (6,2)
Thanks in advance!
There is a good start : http://www.java-gaming.org/index.php?topic=23656.0
Enjoy :)
EDIT
Full-trusted "DrDobb's" website, full article on this : http://www.drdobbs.com/parallel/designing-isometric-game-environments/184410055
<0;4>
x <0;3> <1;4>
<0;2> <1;3> <2;4>
<0;1> <1;2> <2;3> <3;4>
<0;0> <1;1> <2;2> <3;3> <4;4>
<1;0> <2;1> <3;2> <4;3>
<2;0> <3;1> <4;2>
y <3;0> <4;1>
<4;0>
I rendered the tiles like above.
the sollution is VERY simple!
first thing:
my Tile width and height are both = 32 this means that in isometric view, the width = 32 and height = 16! Mapheight in this case is 5 (max. Y value)
y_iso & x_iso == 0 when y_mouse=MapHeight/tilewidth/2 and x_mouse = 0
when x_mouse +=1, y_iso -=1
so first of all I calculate the "per-pixel transformation"
TileY = ((y_mouse*2)-((MapHeight*tilewidth)/2)+x_mouse/2;
TileX = x_mouse-TileY;
to find the tile coordinates I just devide both by tilewidth
TileY = TileY/32; TileX = TileX/32;
DONE!! never had any problems!
It's quite easy actually once you get your head wrapped around it. All you do is find out where your mouse is relative to the map and then reverse to how you are drawing the tiles.
I draw my map in the double "for" loop like this:
For x coord: x * (TileWidth / 2) - (y * (TileWidth / 2))
For y coord: x * (TileHeight / 2) + (y * (TileHeight / 2))
So my x goes from top left to bottom right and my y goes from top right to bottom left. Mind though, like for the first tile the world coord will be 0,0 but the top pixel starts at x=0 + (tilewidth / 2) so we have to compensate for that when we are looking to find which tile the mouse is over. (or we could do that for the whole world itself by giving it a offset).
Now first we have to find the mouse position in relation to the world since you probably want a moving camera. My camera's centre starts as 0,0 so i have to compensate the mouse by half the screen width like so:
mouseWorldPosX = mouse.x + cam.x - (screen.width / 2)
mouseWorldPosY = mouse.y + cam.y - (screen.height / 2)
This is all we need to calculate the mouse position back to tile position.
For X:
tileX = (mouseWorldPosX + (2 * mouseWorldPosY) - (tileWidth / 2)) / tileWidth
As you can see we divide the whole thing by the tilewidth since we multiplied it in the draw method. The (tileWidth / 2) is just there to compensate for the offset i mentioned earlier.
For Y:
tileY = (mouseWorldPosX - (2 * mouseWorldPosY) - (tileHeight / 2) / -tileWidth
It's practically the same but the other way around. We subtract the Y world position since the Y axis runs the other way around. This time we compensate the offset for the height of the tile and we divide the whole thing by negative tilewidth, again since it runs the other way.
I hope this helps below is a working example of a method i looked up, it returns a vector with the tile coordinates:
public Vector2 MouseTilePosition(Camera cam, GraphicsDevice device)
{
float mPosX = newMouseState.X + (cam.Position.X - (device.Viewport.Width / 2));
float mPosY = newMouseState.Y + (cam.Position.Y - (device.Viewport.Height / 2));
float posx = (mPosX + (2 * mPosY) - (Map.TileWidth / 2)) / Map.TileWidth;
float posy = (mPosX - (2 * mPosY) - (Map.TileHeight / 2)) / -Map.TileWidth;
return new Vector2((int)posx, (int)posy);
}