android custom map marker bounds - android

Hello i am using a resized version of this marker( http://www.clker.com/clipart-orange-pin-4.html ) for showing markers in google maps on android.
The problem is i don't know how to make the marker point match the coordinates.
The arrow point is at about 1/5 of the Width coordinates and MAX of the Height.
here is my class
public class GestionaleItemizedOverlay extends com.google.android.maps.ItemizedOverlay {
public GestionaleItemizedOverlay(Drawable defaultMarker, Context context) {
//super(boundCenterBottom(defaultMarker));
super(boundCenter(defaultMarker));
this.mContext = context;
}
...
And this
this.marker_poi = this.getContext().getResources().getDrawable(R.drawable.marker);
this.marker_poi.setBounds(this.marker_poi.getIntrinsicWidth() / 2, this.marker_poi.getIntrinsicHeight(), this.marker_poi.getIntrinsicWidth() / 2, 0);
new GestionaleItemizedOverlay(this.poi, this.context);
Do i need to setBounds on the marker before passing it to the constructor? and why does super(defaultMarker) makes all the markers not to show ?

The previous answer is right, you need to play with the BOUNDS value of your marker.
As I am sure you know the bounding rectangle determines the size of the object... The marker on your map is going to lay itself out with upper left coordinate of your marker at the GPS coordinate if you just would call a normal setbounds on the size of your image.
What you need to do is modify the bounds on your image so that the part of the image you wnat is over the point on the map you want.
So if your resized image is say 20 x 20, and your actual arrow tip (assuming the image is an arrow, and you want it lined up exactly with the point on the map) is at say X=4 and Y=10, you need to modify the bounds of your image accordingly to "move" the image where you want it.
Since 0,0 would put the image 4 pixels to the right, and 10 pixels below the actual point on the map you associate it with, your bounds should not be 0,0,X,Y but should be -4,-10,X size of image-4,Y size of image-10 (in this exampe case the xsize of image and ysize of image are both 20, but should use the values appropriate for your case.)

Yes you need to setBounds but you can do it in the constructor, this is what I do in the constructor to set it to the left bottom corner:
public class CustomOverlay extends ItemizedOverlay<CustomOverlayItem> {
public CustomOverlay(Drawable defaultMarker, Context context) {
super(defaultMarker);
defaultMarker.setBounds(0, -defaultMarker.getIntrinsicHeight(), defaultMarker.getIntrinsicWidth(), 0);
}
You'll need to add a little extra to the left side of the bounds to make center point at the right position. You should remember this is set in px so make some kind of DP converter so it is set properly for your different images for each screen size.
About the second question, you'll need a context in order to know where to add the overlay. Without the context you just create your overlay without giving it any reference to where it should be used (you could add this later if you wanted to).

Related

tricky Android Google Map zoom while maintaining center point

It's not easy explaining my problem but I will try.
I have an android GoogleMap, on top of it, I have an ImageView positioned at its center at all times. If I drag/pan the map, the pin will always be in the center of the GoogleMap.
Now, I add a marker, somewhere on the map. I want to zoom such that the center point remains in the center of the map, and the marker is visible within the map, and to the highest zoom level.
The problem is if I simply check if the marker is within boundaries of the map or not, and then keep zooming in/out till it is, this process will always repeat itself, i.e. trying to zoom in and if the marker became outside, then zoom out.
The problem is I rely on an OnCameraChange listener which will keep calling itself everytime I zoom in or out, hence, the process of zooming in/out will keep occuring indefinitely
journeyGoogleMap.setOnCameraChangeListener(new OnCameraChangeListener()
{
#Override
public void onCameraChange(final CameraPosition position)
{
Basically, what I need is a function where I can provide the center LatLng and the markerLatLng and it will automatically calculate the LatLngBounds making sure my center is within the center of the LatLng bounds, and then I can simply use
public static CameraUpdate newLatLngBounds (LatLngBounds bounds, int width, int height, int padding)
as shown in the link below
https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/CameraUpdateFactory#newLatLngBounds(com.google.android.gms.maps.model.LatLngBounds,int, int,int)
If you need anymore clarification please do tell me
You need to calculate LatLngBounds from two points:
Your marker position and
Place on the opposite side of your current center.
The second is calculated like this:
LatLng other = new LatLng(2 * center.latitude - position.latitude, 2 * center.longitude - position.longitude);
See LatLngBoundsUtils.fromCenterAndPositions for a general solution.
Use googleMap.getProjection().getVisibleRegion() to get all four corners of screen as LatLng values forming trapezium. Calculate where trapezium intersects with line drawn through center and your marker. Scale factor is (distance from center to marker / distance from center to intersection point). Now just scale trapezium with this scale factor relative to center. This is new visible regison.
You may also use getVisibleRegion().latLngBounds to simplify calculation, but note that some areas of returned rectangle are actually not visible.

want to create a semi doughnut shape button clickable in a particular region

I want to create a semi doughnut shaped button which is only clickable in the region where it is visible and not in the the whole rectangular region.
http://i.stack.imgur.com/MKD45.png
I want clicking to affect only this blue region.
You can do this by grabbing the Bitmap representation of the Button, then testing the x/y pixel's alpha value.
To get the bitmap for a button:
Bitmap buttonBmp;
button.setDrawingCacheEnabled(true);
buttonBmp = Bitmap.createBitmap(button.getDrawingCache());
button.setDrawingCacheEnabled(false);
I'd recommend only doing this once, and saving the results, that way you're not creating a new bitmap every time you touch the button.
Then you override the Button's onTouchEvent so you have the local x/y where the user tapped. If the alpha in that spot is 0, you have a non-clickable area. It's not as simple as an onClickListener, but it should do the job.
This way you can use any arbitrary shape, not just a doughnut. Colors, textures, whatever.
I'm not entirely sure on this but I think this scheme would work. Create an image view in your layout to display the picture and make it clickable via an onTouchEvent. This way you can get the coordinates of the click. Check to make sure that the click is within the inner and outer radii and if it is, do the given response.
Here are a few calculations that will need:
Center of circle
-Assuming the center is the very bottom of the image, this will look something like this(not necessarily exact methods)
centerX = img.getX() + img.getWidth()/2;
centerY = img.getY() + img.getHeight()/2;
Remember that screen coordinates go from top to bottom and from left to right.
Find the distance away from the center where the click occurred
Dx = click.getX() - centerX;
Dy = click.getY() - centerY;
D = Math.sqrt(Dx^2 + Dy^2);
Then all you need is to check if the distance is within the radii(not sure how to get the exact radii here, may just need to guess and check. An alternative may be that the top of the semicircle is the top of the picture and then the max height with be the outer radius.)
if(D<=outerR && D>=innerR)
respond();

Touch event for visible part of the Image

I need to apply click/touch events for only visible part of the View. Say for example a image of size 200X200. Apart from center 50X50, remaining part is transparent. I want to get touch events only for that 50X50 visible part Not on remaining transparent part.
In above image (its single image), only inner Diamond has got visible part. Apart from that Diamond is transparent area. So, if I touch Diamond then only I want to do something else ignore.
Edit :
Rachita's link helped me. I gone through that link and got idea how can I implement. But I could not understand some constants like 320, 240 etc while creating Points. In my case, I know the Diamond (in above image) x and y Ponits (hard coded values asctually). So, using those how can I determine, whether I touched inside Diamond or outside?
my Diamond points are as below
pointA = new Point(0, 183);
pointB = new Point(183, 0);
pointC = new Point(366, 183);
pointD = new Point(183, 366);
Edit :
Finally got solution from Luksprog. Its based on checking touched point pixel color. If color is 0 means, you touched transparent layer else you touched some colored part of the image. Simple, but very effective. Have a look at it here.
AFAIK you can not implement this with onclick listener or my any other direct way .You will have to use onTouchListener .
Firstly set your view dynamically at a specific (x,y) position using this How can I dynamically set the position of view in Android?
Calculate the region your diamond will occupy (you should khow the size of image inorder to calculate area of diamond)
3.Trigger a action in onTouchListener only when x, y fall in the required region. Use How to get the Touch position in android?
check this link to calculate if a given point lies in the required square
EDIT
To understand the coordinate system of android refer to this link How do android screen coordinates work?
Display mdisp = getWindowManager().getDefaultDisplay();
int maxX= mdisp.getWidth();
int maxY= mdisp.getHeight();
(x,y) :-
1) (0,0) is top left corner.
2) (maxX,0) is top right corner
3) (0,maxY) is bottom left corner
4) (maxX,maxY) is bottom right corner
here maxX and maxY are screen maximum height and width in pixels, which we have retrieved in above given code.
Remember if you want to support multiple devices with different screen sizes,make sure you use a relative value for x,y ie some ratio of screen height or width ,as different devices have different ppi
Check if touched point lies in the required polygon
I thinks these link might help you determining if the point touched (you can get x,y from onTouch event eg.event.getX()) lies in the required polygon whose points you have mentioned in the question . determine if a given point is inside the polygon and How can I determine whether a 2D Point is within a Polygon?

Android MapView marker shadows move after activity resumes

I have a MapView, with various markers on it. On entering the MapActivity the first time, I set the bounds of drawables set on the markers, and everything appears fine. The markers and shadows all appear correctly. But when I click over to another activity, and return, the shadows, or the markers are no longer bound correctly. Sometimes its only some of the markers that are affected. Can anyone tell me what is going on here? Here is some code. Below is where I set the bounds on the marker drawable:
InputStream is = assetManager.open(imageName);
drawable = Drawable.createFromStream(is, null);
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
drawable.setBounds(-width / 2, -height, width - (width / 2), 0);
And here is how I create/add the overlay item to the map:
GeoPoint point = createGeoPoint(lat, lon);
OverlayItem overlayItem = new OverlayItem(point, character.get_id(), "");
Drawable image = drawable;
overlayItem.setMarker(image);
itemizedOverlay.addOverlay(overlayItem);
From what I can tell, the overlays are not being re-added to the map, this is simply a redraw after an onResume() event. Any ideas?
Update: I've actually figured out, only images of the type tapped move, and its not the shadow, but the image that moves. So, of there are x images of type A, and y images of type B, and I tap on any image of type A, all images of type A are misaligned with their shadows when I return to the MapActivity, while all images of type B are still properly aligned.
Another update: I am outputting the bounds to the log, and see that the bounds are changing after returning to the map screen. When the marker is initially added, its bounds are:
[Rect(-25, -48 - 25, 1)]
But when returning to the map screen, the bounds have changed to:
[Rect(0, 0 - 50, 49)]
...why would this be?
Yet another update: I have a workaround... but I would still like an answer as to why this is happening. The workaround is to override the draw method, and set the bounds (to center bottom) whenever the draw method is called. Here is the code:
#Override
public void draw(Canvas canvas) {
int dWidth = getIntrinsicWidth();
int dHeight = getIntrinsicHeight();
setBounds(-dWidth / 2, -dHeight, dWidth / 2, 0);
super.draw(canvas);
}
I found out what the problem was. You can see from the code in the question, I am reading in BitmapDrawables from an InputStream. To reduce waste, I put all images created in a flyweight and reuse them when I can. That means, when I put 3 'sunshines' on the map, all three are based on the same image. In addition, when I place them on the map via an ItemizedOverlay, I am calling boundCenterBottom() so the shadow will display in the correct place.
When I open a different Activity, that Activity has an ImageView that I was populating with the same image. Turns out, that ImageView must have been resetting the bounds. I know this because, after overriding the draw() method, and setting the bounds on every draw, I was no longer able to see the images in the ImageViews. When I comment out the overridden draw() method, I am able to see the images in the ImageViews, but the images are shifted when I return to the map. This tells me that adding the image to the ImageView must be updating the bounds.
My solution is to create two distinct images for each image type; one for the map, and one for the ImageViews on the other Activities. I can still put them in the flyweight, but they have separate keys so multiple image instances can exist for the same image.
Hope this helps someone. I know there was another question of StackOverflow about this, but I can't find it to link to or to answer.

Android - Set focus on a circle that I have drawn in my onDraw method

Android Question.
I have made a custom ImageView class and inside it I have an onDraw method which will draw a circle on particular pixels (using canvas). When I use this custom imageview and open up my image I would like to set the focus on the circle that I have drawn (e.g like google maps do with your current location. The focus is set to your current point)
What the map server does on google is deliver a customized set of tiles so that the center is displayed properly, the newer version is of course vector based so they simply draw the view so it's centered where they want it.
Without knowing the details of your application you probably need
Create your own container class, probably FrameLayout
public class myMapFrameLayout extends FrameLayout {
The override either onDraw or onDispatchDraw so that you can layout your tile appropriately
Figure out where to draw your bitmap so that the x,y you need will be in the center of the screen, then draw the other tiles that you need to fill in the blank space at the coordinates required dependent on which way the tile was moved to get centered
Think of a virtual screen that is larger than the actual screen with tiles all around it that are the same size
1 2 3
4 X 5
6 7 8
Assuming that X is the size of the display and represents the current tile you need to figure out which way to move the tile, and which other tiles 1,2,3,4,5,6,7 or 8 you need to fill in the empty space caused by move
If you had to draw the tile +x from 0,0 you need some of tile 4, drawing +y from 0,0 means some of 2 and both mean 1,2,4 are all needed and so on, so figure out the combinations and load the tiles you need, and figure out the drawing positions of each. That would give you your new virtual tile with the center displayed.
That's about as efficient as you can get I think with a bitmap drawing method on the client side.
UPDATE
Since your comment indicates you have only one very large image this is going to be a bit of a problem if the x,y you need as anything closer to the edges than the size of the display
None the less you can still draw the image where you need it, just measure the screen and draw the bitmap with the target x,y in the center
So if the screen was 500x500 and your image was 5000x5000 and the center was at position x=1000 y=1000 then
drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
where source rectangle would be 1000-250,1000-250,500,500 and dst rectangle would be 0,0,500,500
The 250 is the center x and center y of the display, 1000 are the target x/y coordinates, and 500 is the size of display.
Again, with targets that are at the edges you are going to have a blank polygon in your screen since you dont have an infinite map tile
Alternatively you could oversize your framelayout using layoutparams and just translate the canvas in the x and y to get the canvas centered to the x,y you need using similar calcs which may be more performant, not really sure
Keep in mind you are going to be using a lot of memory if your image is really big

Categories

Resources