I am working with the OSMDroid API and I'm wondering if there's a way to limit the map in north and south. I mean, is this possible to prevent the map from endlessly repeating itself on the Y-Axis.
I found this issue on the Github's "osmdroid" project but the code of the patch is too old and cannot be applied to the new version of osmdroid (4.2)
EDIT
I tried the setScrollableAreaLimit method but there is a bug (maybe) in the upper-left point. The map jump on the other side when I come close to its end.
Thank you by advance
I modified two lines in the class MapView.
I replaced x += worldSize; by x=0; and y += worldSize; by y=0;
public void scrollTo(int x, int y) {
final int worldSize = TileSystem.MapSize(this.getZoomLevel(false));
while (x < 0) {
//x += worldSize;
x=0;
}
while (x >= worldSize) {
x -= worldSize;
}
while (y < 0) {
// y += worldSize;
y=0;
}
while (y >= worldSize) {
y -= worldSize;
}
[...]
}
I was extend MapView and override to scrollTo()
public void scrollTo(int x, int y) {
final int worldSize = TileSystem.MapSize(this.getZoomLevel(false));
if(y < 0) { // when over north pole
y = 0; // scroll to north pole
}else if(y + getHeight() >= worldSize) { // when over south pole
y = worldSize-getHeight() - 1; // scroll to south pole
}
super.scrollTo(x,y);
}
I was able to overcome this by expanding on #kenji's answer. With the subclass approach, I found that rapidly zooming out would sometimes reset the map to the south pole. To prevent this, the y-value needs to be downscaled first (just as the super class implementation does in v5.6.5).
#Override
public void scrollTo(int x, int y) {
final int worldSize = TileSystem.MapSize(this.getZoomLevel(false));
final int mapViewHeight = getHeight();
// Downscale the y-value in case the user just zoomed out.
while (y >= worldSize) {
y -= worldSize;
}
if (y < 0) {
y = 0;
} else if ((y + mapViewHeight) > worldSize) {
y = worldSize - mapViewHeight;
}
super.scrollTo(x, y);
}
use setScrollableAreaLimit.
BoundingBoxE6 bbox_bariloche = new BoundingBoxE6(-41.033770, -71.591065, -41.207056,-71.111444);
map.setScrollableAreaLimit(bbox_bariloche);
Related
The animation I am working on achieving is shown below in Figure 1.
1)I have a list containing points on a 2D plane(left) that I am working on animating.
2)A touch is made at location x, and an invisible circle is drawn (middle). I want all of the points contained in that circle to move away from the center (x).
3) A final result example (right)
I am planning on applying this in a way that I can supply any list of points, touch location, numFrames, and force applied on each point per frame. An array of length numFrames is returned, each array item being an already animated list.
Since I plan on implementing this on screen touch, it is possible for another touch to happen while the first touch animation is already in progress. How can I handle these collisions?
Figure 1:
here's my 2 cents, you need a list of points, these points should have a position, a velocity and a method to update the position. something like this
public class Point {
public float x, y;
public boolean isMoving;
private float dx,dy;
public Point(float x, float y){
this.x = x;
this.y = y;
}
public boolean move(float maxWidth, float maxHeight){
if(!isMoving) return false;
// update the position
x += dx;
y += dy;
dx /= FRICTION;
dy /= FRICTION;
// bounce...?
if(x < 0 || x > maxWidth){
dx *= -1;
}
if(y < 0 || y > maxHeight){
dy *= -1;
}
if(Math.abs(dx) < MOVEMENT_THRESHOLD && Math.abs(dy) < MOVEMENT_THRESHOLD){
isMoving = false;
}
return isMoving;
}
}
on every touch event you apply a force to every point within the radius and set their velocity
for(Point point : mPoints){
float distance = point.distance(x,y);
if(distance > mTouchRange) continue;
float force = (float) Math.pow(1 - (distance / mTouchRange), 2) * mForceFactor;
float angle = point.angle(x,y);
point.dx -= Math.cos(angle) * force;
point.dy -= Math.sin(angle) * force;
point.isMoving = true;
}
then you need an animation that call move on every frame and eventully stops when there are no moving points
you can find the full example here
I am trying to create a pad-like view in android. I got a circle that follows user's gestures and I am using distance to keep the circle of going outside the main circle of the pad control.
My problem is I want the circle to keep following the gesture, but to stay inside of the main circle. I am using the formula for finding a point using angle and radius, but it does some funky stuff.
I am translating the canvas, so that the center of the main circle is at 0, 0.
Here is the code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(this.mainRadius, this.mainRadius);
canvas.drawCircle(0, 0, this.mainRadius, this.debugPaint);
canvas.drawCircle(this.handleX, this.handleY, this.handleRadius, this.handlePaint);
}
private void translateHandle(MotionEvent event) {
int x = (int) (event.getX() - this.mainRadius);
int y = (int) (event.getY() - this.mainRadius);
double distance = distanceFromCenter(x, y);
if (distance <= this.maxDistance) {
this.handleX = x;
this.handleY = y;
} else {
float angle = (float) Math.toDegrees(Math.atan2(y, x));
if (angle < 0)
angle += 360;
this.handleX = (int) ((this.mainRadius - this.handleRadius) * Math.cos(angle));
this.handleY = (int) ((this.mainRadius - this.handleRadius) * Math.sin(angle));
}
//onTranslateHandle(distance);
}
And here is the funky stuff in a gif image:
I cannot verify this change into your code snippet but do hope it gives some idea how to proceed further anyway;
private void translateHandle(MotionEvent event) {
float x = event.getX() - this.mainRadius;
float y = event.getY() - this.mainRadius;
double distance = distanceFromCenter(x, y);
if (distance > this.maxDistance) {
// If distance is i.e 2.0 and maxDistance is 1.0 ==> adjust is 0.5
// which repositions x and y making distance 1.0 maintaining direction
double adjust = this.maxDistance / distance;
x = (float)(x * adjust);
y = (float)(y * adjust);
}
this.handleX = (int)x;
this.handleY = (int)y;
}
I can update the answer where needed if this does not give any useful results.
Using the example with the bucket I am trying instead of using the
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
to use touchUp and touchDown.
So, in order to use them ,I define :
Vector2 position = new Vector2();
Vector2 velocity = new Vector2();
and then :
public boolean touchDown(int x, int y, int pointer, int button) {
if (x < 800 / 2 && y > 480 / 2) {
//here?? for left movement
}
if (x > 800 / 2 && y > 480 / 2) {
//here?? for right movement
}
return true;
}
Generally , I understand that I have a position and a velocity.And I must update the position related to velocity ,but I can't figure how.
You must update the position of your object every frame using the deltatime and the velocity vector.
Something like this(in render):
position.set(position.x+velocity.x*delta, position.y+velocity.y*delta);
And:
public boolean touchDown(int x, int y, int pointer, int button) {
if (x < 800 / 2 && y > 480 / 2) {
//here?? for left movement
velocity.x = -10;
}
if (x > 800 / 2 && y > 480 / 2) {
//here?? for right movement
velocity.x = 10;
}
return true;
}
public boolean touchUp(int x, int y, int pointer, int button) {
velocity.x = 0;
}
public void hatdraw(Canvas canvas,float x,float y) {
mBitmaps = BitmapFactory.decodeResource(this.getResources(),
R.drawable.hat);
srcRect=new Rect(0,0,60,60);
xrect=(int)x;
yrect=(int)y;
Log.d("hatdraw","xrect,yrect"+xrect +yrect);
desRect=new Rect(xrect,yrect, xrect+ (srcRect.right - srcRect.left),
yrect + (srcRect.bottom -srcRect.top));
canvas.drawBitmap(mBitmaps,srcRect,desRect, null);
}
I don't know what the posted code has to do with the title to this question, but take a look at Rect.contains(int x, int y) (or an equivalent method in RectF) for that test.
Get touch on bitmap ...
if (x >= xOfYourBitmap && x < (xOfYourBitmap + yourBitmap.getWidth())
&& y >= yOfYourBitmap && y < (yOfYourBitmap + yourBitmap.getHeight()))
{
// if this is true, you've started your click inside your bitmap
}
I need an advice how to achieve the following functionality under Android:
I need an image that represents something like a graph (from discrete math), with vertices and edges, where I can click every vertice or edge and fire a different action.
Please advise me how to achieve this (maybe with imagebuttons) or another approach to represent this functionality.
I was bored, so I coded up this crude example...
It assumes straight edges between points.
public class App extends Activity
{
PlotView plot;
#Override
public void onCreate(Bundle sis)
{
super.onCreate(sis);
plot = new PlotView(this);
setContentView(plot);
}
public class PlotView extends View
{
Paint paint1 = new Paint();
Paint paint2 = new Paint();
Point[] points = new Point[10];
public PlotView(Context context)
{
super(context);
paint1.setColor(Color.RED);
paint2.setColor(Color.BLUE);
for (int i = 0; i < points.length; i++)
{
points[i] = new Point();
points[i].x = (float) (Math.random() * 320);
points[i].y = (float) (Math.random() * 480);
}
Arrays.sort(points);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color.WHITE);
for (int i = 0; i < points.length; i++)
{
if (i < points.length - 1)
{
canvas.drawLine(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, paint2);
}
canvas.drawCircle(points[i].x, points[i].y, 5, paint1);
}
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
float x = event.getX();
float y = event.getY();
int hitPoint = -1;
int closestLeft = -1;
int closestRight = -1;
for (int i = 0; i < points.length; i++)
{
float dx = x - points[i].x;
float dy = y - points[i].y;
if(i < points.length - 1)
{
if(points[i].x < x && x < points[i + 1].x)
{
closestLeft = i;
closestRight = i + 1;
}
}
if (Math.abs(dx) <= 16.0f && Math.abs(dy) <= 16.0f)
{
hitPoint = i;
break;
}
}
if (hitPoint != -1)
{
Toast.makeText(getContext(), "Hit Point: " + hitPoint, Toast.LENGTH_SHORT).show();
}
else
if(closestLeft != -1 && closestRight != -1)
{
float dx = points[closestLeft].x - points[closestRight].x;
float dy = points[closestLeft].y - points[closestRight].y;
final float u = ((x - points[closestLeft].x) * dx + (y - points[closestLeft].y) * dy) / (dx * dx + dy * dy);
float px = points[closestLeft].x + u * dx;
float py = points[closestLeft].y + u * dy;
if (Math.abs(x - px) <= 16.0f && Math.abs(y - py) <= 16.0f)
{
Toast.makeText(getContext(), "Hit Line Between: " + closestLeft + " & " + closestRight, Toast.LENGTH_SHORT).show();
}
}
}
}
return super.onTouchEvent(event);
}
public class Point implements Comparable<Point>
{
float x;
float y;
#Override
public int compareTo(Point other)
{
if (x < other.x) return -1;
if (x > other.x) return 1;
return 0;
}
}
}
}
I can imagine how to do this with SurfaceView:
create a Vertex class, which among other things, has an x,y coordinate representing where to draw the vertex. If your vertex was a png image of a circle, then the top-left x,y coordinates of the image are stored in the Vertex class.
Have all your verticies in a List, and iterate through and draw each vertex.
the edges are more complicated since they might criss-cross or curve around.
assuming they are straight lines, then you can have a Edge class that contains the starting x,y and ending x,y coordinates.
you can iterate through a List of Edges and draw the lines accordingly
In order to detect when a user clicks on them, you should override the onTouch method and check the event.rawX() and event.rawY() values to see if they match up to a Vertex or Edge class.
for a Vertex class, you can check if x <= event.rawX <= x + image_width and y <= event.rawY <= y + image_height
for an Edge, you can check if the event.rawX, event.rawY coordinates are found in the line formed by the two sets of coordinates you stored in the Edge class.
I've used a similar method to draw a set of nodes in a game. I'm not so sure how to do the edges though - the method I outline would only work if they were straight and do not criss-cross.
I am sure there is a better way to do this using openGL, but I have not used openGL before.
Hopefully you can get some ideas out of this.
I think you might be best off with a SurfaceView:
http://developer.android.com/reference/android/view/SurfaceView.html
And handling the onTouchEvent() as a whole for the surface, and mapping that to underlying entities in the image. If you're calculating the drawing the graph as you go should be easy to also create a map of tapable areas and grabbing the X and Y of the touch event to figure out if it corresponds to an element in the image.
If you literally have an image, as an already processed PNG for example, you would need some way to also carry in the touch event areas. Depends where that image comes in from.
According to android help, "drawing to a View, is your best choice when you want to draw simple graphics that do not need to change dynamically and are not part of a performance-intensive game." This is the right way to go when making a snake or a chess game, for instance. So I don't see a point in suggesting using a SurfaceView for this, it will just overcomplicate things.
For clickable areas you override public boolean onTouchEvent(MotionEvent event) where you manage x and y coordinates of the click for identifying the clicked area.