Draw Circle in ImageView when getting current location IndoorAtlas SDK - android

I want to get current location and draw blue dot like picture above. The blue dot is moving when the current location change.
Here is my code :
public void onServiceUpdate(ServiceState state) {
mSharedBuilder.setLength(0);
mSharedBuilder.append("Location: ")
.append(state.getRoundtrip()).append("ms")
.append(state.getGeoPoint().getLatitude())
.append(state.getGeoPoint().getLongitude())
.append(state.getMetricPoint().getX())
.append(state.getMetricPoint().getY())
.append(state.getImagePoint().getI())
.append(state.getImagePoint().getJ())
.append(state.getHeadingDegrees())
.append(state.getUncertainty());
double x1 = state.getMetricPoint().getX();
double y1 = state.getMetricPoint().getY();
float x = (float) x1;
float y = (float) y1;
Paint paint = null;
canvas.drawCircle(x,y,1,paint);
}
Could you help me ? The pictures already in resource folder.

First, in this case it is easier if you use coordinates from ServiceState#getImagePoint() - these (I & J) are coordinates of your location in the original floor plan. I.e. if your original mapped & uploaded floor plan had dimensions 800x600, service might return position I:400,J:300 indicating that you are now in the center of your mapped area.
You cannot however draw a circle like this: canvas.drawCircle(400, 300, radius, paint) - because depending on how your image is currently displayed (e.g. scaled) you might be drawing into incorrect location.
You need to take into account where your image is on the screen and what are it's current dimensions, i.e. scaling ratio. E.g. if you have a display of size 1920x1080 and your floor plan image of size 800x600 is drawn centered and without any scaling into an ImageView that occupies the entire screen real estate (assume full 1920x1080 in portrait here), then you would need to draw your current coordinate (400,300) into canvas at x: ((1080-800)/2)+400, y: ((1920-600/2)+300) = 540,960.
To draw accuracy with the blue dot (the semi-transparent larger circle), use uncertainty to calculate circle radius.

Related

GroundOverlay image not rotated

Regarding positioning an image on a map giving its bounds, Google Maps' documentation states:
When the image is drawn on the map it will be rotated to fit the bounds. If the bounds do not match the original aspect ratio, the image will be skewed.
But in my code I have this:
GroundOverlayOptions goo2 = new GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(imgRes))
.positionFromBounds(new LatLngBounds(
new LatLng(44.415, 8.937),
new LatLng(44.42, 8.942)
));
mMap.addGroundOverlay(goo2);
The image is not rotated, but always drawn straight pointing north, and skewed. Changing the overlay corners just skews more and it never rotates a bit.
How can I set GMaps to rotate it, or does any external tool exist to rotate it?
I solved this by myself.
I think that Google's documentation is not very clear. It states that a GroundOverlay can be positioned using two possible methods:
There are two ways to specify the position of the ground overlay:
Using a LatLng to center the overlay, and dimensions in meters to specify the size of the image.
Using a LatLngBounds to specify the north east and south west corners of the image.
You must specify the position of the ground overlay before it is added to the map.
I was using the second way, or giving it two geo-corners of the image I wanted to apply. What is not clear is that with the second method rotation is not possible, and every discrepancy in proportion will be rendered with a skewed image. Actually the idea I had was exactly that, given two points on a plain, we have exactly one image that can fit those two points without stratching, but just rotating, I was disappointed discovering that does not work.
However, if you have enough patience to calculate by your own size in meters and rotation of your image, you can determine one corner, or the center of the image, and use the first method, using LatLng and explicitly indicate an anchor, for example (0, 0) for upper left corner or (0.5, 0.5) for the center, a height of the picture in meters (here is a good way to find it: How to convert latitude or longitude to meters?), find a rotation by using trigonometry, and that's it.
A way to find the image size in pixels is indicated here.
That's my final code, for memory:
BitmapFactory.Options dimensions = new BitmapFactory.Options();
dimensions.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), imgRes, dimensions);
int imgHeightPixels = dimensions.outHeight;
GroundOverlayOptions goo = new GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(imgRes))
.position(imgBottomLeftCorner, imgHeightInPixels)
.anchor(0, 1)
.bearing(imgRotation);
mMap.addGroundOverlay(goo);
Watch out that the Y coordinates on the map grow bottom up, while on the image grow top down, so the anchor is (0,1).
Given two vectors, here's what I did to find their angle, and consequently the image rotation (using a vector made of two points coordinates on the image versus a vector made of the same two points geographic coordinates):
private static double calcDistance(double x1, double y1, double x2, double y2) {
return (Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)));
}
private static double calcVectorRotation(double x1, double y1, double x2, double y2) {
return Math.asin( (y1-y2) / calcDistance(x1, y1, x2, y2) );
}
As you've already mentioned and based from the documentation, if the bounds do not match the original aspect ratio, the image will be skewed.
You should try using android:adjustViewBounds to preserve the aspect ratio.
Set this to true if you want the ImageView to adjust its bounds to preserve the aspect ratio of its drawable.
Please try adding the following into your XML:
android:adjustViewBounds="true"
android:scaleType="fitCenter"
You may also try the suggested code implementations in this SO post. Hope that helps!

How to convert coordinates on Bitmap to real coordiates on Image View displayed on screen

I have an Image View which displays an image (e.g 2000x1000 pixels) and I have a coordinate (X,Y) on that image (not the image view). The canvas of my Image View is 600x800 for example. How can I convert the point (X,Y) to screen coordinate so that I can draw a path with them on the OnDraw(...) method of Image View. Any help is appreciated! Thank you.
Update: If I use matrix to draw the path between coordinates, it works but the path and objects i draw become really small. Here is the code i used.
final Matrix matrix = canvas.getMatrix();
matrix.preConcat( _view.getImageMatrix() );
matrix.preScale( 1.0f /_inSampleSize, 1.0f / _inSampleSize);
canvas.setMatrix( matrix );
//I draw the path here
Update: I add a picture to show the effect when using matrix to draw the path. I would like to have the 4 line and the 4 corner balls to be in normal size. The red color is the boundary of the Image View which holds the picture.
I think that might depend on how exactly you are displaying your image. Your ImageView (600x800) is not the same aspect ratio as your bitmap (2000x1000).
You are keeping the bitmap's aspect ratio stable as you scale it down? If so, which part (height or width) takes up the full screen and which has black (or whatever else) as padding? This will help you determine your scale factor.
scale_factor = goal_height/height1; //if height is what you are scaling by
scale_factor = goal_width/width1; //if width is what you are scaling by.
I would try:
x_goal = x1 * scale_factor;
y_goal = y1 * scale_factor;
That is, if you have a point (1333, 900) in your image, and your image takes up the full width, you would multiply both x and y by 600/2000 to get (399.9, 270). (you might want to round that decimal).
If you are NOT keeping the bitmaps aspect ratio stable (that is, you're squeezing it to fit), then you'd have a height_scale_factor and a width_scale factor. So you'd take (1333,900) and multiply x by 600/2000 and y by 800/1000 to get (399.9,720).

Android Opencv calculate size of rotated image inside rectangle

I want to calculate rotated image size, Image is inside rectangle. I have rectangle width, height and angle of rotated image. Any one tell me
how to calculate rotated image size?
So you have width, height and angle means you already got RotatedRect.
Now using the method
Rect RotatedRect::boundingRect();
you can easly calculate the bounding box for rotated rect.
for more info see RotatedRect.
Edit:
As per your comment below is the way how to find the width and height of rotated rect.
So you know the four corners of rectangle, lets say (x1,y1),(x2,y2),(x3,y3),(x4,y4), now you need to find the transformed point after rotation by the given angle, let it be (xT1,yT1),(xT2,yT2),etc...
where
xT = x0+(x-x0)*cos(theta)+(y-y0)*sin(theta)
yT = y0-(x-x0)*sin(theta)+(y-y0)*cos(theta)
here (x0,y0) is the center around which you are rotating. and theta = angle * CV_PI / 180.0
Using above calculate four transformed points, finally calculate the height and width by finding the distance between transformed points.

Paths drawn from the same bounding box have different radii

Background
I'm drawing a custom View, which consists of an arc along which images are drawn.
A bit like this "Wheel of Fortune" screenshot, where only part of a large disc is visible and, as the user drags the view, images become visible/hidden as appropriate and are drawn at the appropriate position and angle along the disc's edge.
This works fine; I use the code below to create a large bounding box (four times the width of the view, to get a more subtle arc), which I use with Path.arcTo() to draw the visible top edge of the disc.
Because the bounding box is square, the arc drawn (if I were to draw 360°) would be circular.
// Disc dimensions (based on this View's width/height/padding)
final int radius = width * 2;
final float halfWidth = width / 2f;
final float top = mTopPadding;
// Create a large, square bounding box to draw the disc in.
// Centre horizontally; top edge of the disc == top edge of this View (+ padding)
final RectF discBounds =
new RectF(-radius + halfWidth, top, radius + halfWidth, radius * 2 + top);
// Create an arc along the circumference of the disc,
// but only where it will intersect with this View
double arcSweep = Math.toDegrees(Math.asin(halfWidth / radius)) * 2;
double startAngle = 180 + ((180 - arcSweep) / 2d);
mDiscPath.reset();
mDiscPath.arcTo(discBounds, (float) startAngle, (float) arcSweep);
// Close the shape so that we fill the rest of this View
// (the area underneath the arc) with the disc bg colour
mDiscPath.lineTo(width, height);
mDiscPath.lineTo(0, height);
I then create another Path and again call arcTo(), using the exact same bounding box so that the same arc radius is maintained.
This time the sweep angle of the arc is longer, since there may be only two or three images shown within the View at one time, but an arbitrary number of images off-screen (in my case, up to about ten).
// Create another arc, along which the images should move,
// based on the number and width of the images.
// We will later use a PathMeasure object created from
// this Path to determine where to draw each image
arcSweep = (mTotalWidth * 180) / (radius * Math.PI);
startAngle = 180 + ((180 - arcSweep) / 2d);
mImagePath.reset();
mImagePath.arcTo(discBounds, (float) startAngle, (float) arcSweep);
Problem
In onDraw(), the mDiscPath is drawn as the background (canvas.drawPath(mDiscPath, fillPaint)), and then the appropriate bitmaps are drawn based on a PathMeasure object created from mImagePath and how far the user has dragged.
However, it's noticeable that the images do not precisely follow the expected path as the disc is "rotated". This causes problems, as the images need to align accurately to the edge of the disc.
For troubleshooting, I started drawing mImagePath using canvas.drawPath(mImagePath, strokePaint)) to see why the image path didn't seem to follow the disc path.
In the screenshot below, to make the problem more obvious, the regular bitmaps are not drawn on top of the disc, and mImagePath was translated downwards by 4dp (i.e. the problem is also visible when not translated).
Here we can see three independent instances of the custom View stacked on top of one another.
But it's clear that the black line (mImagePath) does not match the radius of the top of the coloured disc (mDiscPath) in each case. i.e. The radius of the black arc appears to be large than the disc's radius.
The arcs for both Path objects were created using the same bounding box, so I would expect both arcs to have the same radius.
The line on the bottom disc seems to match up well, but the top two discs are clearly wrong.
The only real difference between the discs is the number of images displayed, and therefore the sweep angle of the image path (89°, 169°, 222° respectively for the three views).
Question
Why, if the exact same square RectF bounding box is being used to create two Path objects, why do arcs drawn from these Paths have different radii?
Am I missing something? Should I be using a different API?
Postscript
I've ensured the bounding box is correctly sized and doesn't change between creating the two paths.
The start and sweep angles look correct in all cases (i.e. the midpoint of each arc is at 270°).
Creating brand new Paths or resetting the existing Paths makes no difference.
Using the same arc sweep for both Paths does work as expected.
I've tested on various devices and orientations, with and without software rendering.

Calculate Arc Center Point, Knowing It's Start and End Degrees

The quickest description of this answer is that I am trying to find the coordinates of the white dot. The dark red is a drawn arc over a drawn circle (dark blue).
The longer explanation:
I have a class that is extending View and that is drawing a circle on the canvas (the canvas has equal width and height):
canvas.drawArc(rectF, 0, 360, true, paint); // mOvals is a RectF object with 4 coordinates
Then I draw an arc that is N percent wide (let's say 225 in this case). The arc starts from -90 degrees (because 0 degrees in the canvas means 3'o clocks) and "strays" N degrees (225 in this example).
I am trying to calculate the X/Y coordinates or the center of the remaining arc (the area that is not covered by the red arc; that is between N and 360).
I have the radius of the circle which is canvasWidth/2 if that is of some help.
Here's how I draw the red arc:
long arcEnd = (360 * fractionNumber) / totalNumber;
canvas.drawArc(rectF, -90, arcEnd, true, paint);
(Original answer updated. It may be a bit too verbose now, but I hope it helps.)
You're looking for the XY coordinates (called Cartesian coordinates), but these are difficult to calculate directly. The trick is to go through Polar coordinates first. Polar and Cartesian are two ways of expressing the same thing, namely a point in a grid and can be converted into eachother.
Polar coordinates consist of angle and distance from the center point. You can calculate the desired angle because you know the percentage of the circle that you need to cover and you can calculate the distance from the center because you know the radius of the circle.
Your covering arc is 225 degrees, so the remainder is 135 and half that is 67.5 degrees. The angle for the point you're looking for is therefore 225+67.5 = 292.5 degrees. The radius for that point is half the radius of the circle, so that's canvasWidth/4.
Once you've determined the polar coordinate, (292.5, canvasWidth/4), you convert this to the XY coordinate using the conversion function. There's one thing that's a bit tricky: Math.cos(double) and Math.sin(double) expect their argument to be in radians, not in degrees. You express your 292.5/360 as x/2π before making the conversion, which you do by multiplying the value by π/180, giving 5.1051 in this case.
Assuming that canvasWidth is 400:
double tdeg 292.5d; // Calculated from arc percentage
int r = 100; // Calculated from canvas width
double trad = tdeg * (Math.PI/180d); // = 5.1051
int x = (int) r * Math.cos(trad);
int y = (int) r * Math.sin(trad);

Categories

Resources