I have Path that I'm creating once, and adding Rect to it.
On some event I'm offsetting the path by Path.offset(...) or Path.transform(...)
and then invalidating my canvas for redrawing the path.
But the path is not redrawing in the new place.
I checked the path bounds by using Path.computeBounds(...) and I see that the rectangle moved. So I don't understand why Canvas.drawPath(...) is not redrawing the path in the new place.
The only way I managed to make the path redrawn in the new place is to make new path and add the transformed path to it, but I don't really want to do it every time.
m_objPath.offset(p_fltDx, p_fltDy);
//////////////////////////////
// With this lines it makes the path redrawn in the right place - but why should i ??
Path objPath = new Path();
objPath.addPath(m_objPath);
m_objPath = objPath;
//////////////////////////////
m_objCanvas.invalidate();
.
.
.
m_objCanvas.drawPath(m_objPath, m_objPaint);
Any suggestions?
I tested the issue with Path.offset(..) against Android 4.1 and Android 2.3:
On Android 2.3 offset(..) works ok.
On Android 4.1 it fails to show new position of the path. Still it is moved! If I return to main screen (central hardware button on my Samsung) and start app again - it shows correct position.
So just drop using Path...
Related
Currently, I am adding a list of annotations to a mapview with code similar to the following:
// Add to map view
SKAnnotation annotation = new SKAnnotation(i++);
annotation.getLocation().setLongitude(result.longitude);
annotation.getLocation().setLatitude(result.latitude);
annotation.setMininumZoomLevel(1);
annotation.setAnnotationType(SKAnnotation.SK_ANNOTATION_TYPE_PURPLE);
mapView.addAnnotation(annotation, SKAnimationSettings.ANIMATION_POP_OUT);
Yet whenever I view the annotations on the map, they disappear after I zoom out to anything under zoom level 4.0. Looking at the docs for the Annotation class (as well as confirming in the code), I see that the default zoom level is set to 4, yet it seems that my call to .setMinimumZoomLevel is ignored.
Does anyone have any insight into what is happening or if this might be a known bug within the SDK?
I'm using Skobbler 2.5 on Android.
Thanks for any help in the matter!
Based off Ando's comment on the original question and referencing the documentation here, I updated the code to use the workaround he described to allow annotations to show up down to zoom level 2.
Original code:
SKAnnotation annotation = new SKAnnotation(i++);
annotation.getLocation().setLongitude(result.longitude);
annotation.getLocation().setLatitude(result.latitude);
annotation.setMininumZoomLevel(1); // Note: this does not work
annotation.setAnnotationType(SKAnnotation.SK_ANNOTATION_TYPE_PURPLE);
mapView.addAnnotation(annotation, SKAnimationSettings.ANIMATION_POP_OUT);
Updated code:
SKAnnotation annotation = new SKAnnotation(i++);
annotation.getLocation().setLongitude(result.longitude);
annotation.getLocation().setLatitude(result.latitude);
annotation.setMininumZoomLevel(2);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (metrics.densityDpi < DisplayMetrics.DENSITY_HIGH) {
annotation.setImagePath(SKMaps.getInstance().getMapInitSettings().
getMapResourcesPath() + "/.Common/icon_greypin#2x.png");
// set the size of the image in pixel
annotation.setImageSize(128);
} else {
annotation.setImagePath(SKMaps.getInstance().getMapInitSettings().
getMapResourcesPath()+ "/.Common/icon_greypin#3x.png");
// set the size of the image in pixels
annotation.setImageSize(256);
}
mapView.addAnnotation(annotation, SKAnimationSettings.ANIMATION_POP_OUT);
A couple things to note:
.setImagePath() and .setImageSize() are both deprecated methods in the latest SDK even though they're still referenced in the documentation above. Not sure if that means there is another alternative to displaying images via an absolute path approach, or if they're simply phasing this functionality out.
In my particular example, we're using the purple pin to display annotations, but the absolute path file name for that pin is actually called icon_greypin. It looks like the other pin image file name are named appropriately however.
Anyways, this served as a solution for my particular problem until the SDK is updated, so I'm marking it as the answer and I hope it helps someone else! Thanks to Ando for the step in the right direction!
On ICS device, I tried the following code to draw two rectangles.
Path p1 = new Path();
p1.moveTo(0, 0);
p1.lineTo(0, 100);
p1.lineTo(100, 100);
p1.lineTo(100, 0);
p1.close;
Path p2 = new Path();
Matrix scaling = new Matrix();
scaling.preScale(2, 2);
p1.transform(scaling, p2);
canvas.drawPath(p1);
canvas.drawPath(p2);
Running the above code on ICS device with hardware acceleration enabled (as it is by default), p1 is drawn where as p2 is not.
In general, what happened to me is, as long as a Path is not hand-wired (i.e. by calling lineTo(), quadTo(), etc.), but obtained by copying or transforming (i.e. by calling the copy constructor, transform(matrix, dest), translate(x, y, dest), etc.), it is not drawn.
I found a "widely known" issue that is similar but not exactly the same as my problem: https://groups.google.com/forum/#!msg/android-developers/eTxV4KPy1G4/tAe2zUPCjMcJ
Therefore, can anyone tell me what is the issue I am running into? In my case, I have to resort to path transformation otherwise code complexity will be greatly increase. Thanks!
try setting android:layerType="software" in xml on the view to see if that fixes it. some methods aren't available with hardware acceleration on all apis.
the list is here:
http://developer.android.com/guide/topics/graphics/hardware-accel.html
note that if changing the layer type fixes it, you should create a separate layout for the newer APIs for optimal performance
With Unity, the CardboardHead script is added to the main camera and that handles everything quite nicely, but I need to be able to "recenter" the view on demand and the only option I see so far is to rorate the entire scene and it seems like this is something the would address first-hand and I can't find anything in the docs.
With Oculus Mobile SDK (GearVR), it would be OVRCamera.ResetCameraPositionOrientation(Vector3.one, Vector3.zero, Vector3.up, Vector3.zero); though they handle it nicely each time the viewer is put on so it's rarely needed there.
There's a "target" parameter on the CardboardHead that lets you use to another gameobject as a reference for rotation. Or you can use a dummy parent gameobject. Either way, when you want to recenter, you set this reference object's rotation so that the CardboardHead is now pointing forward. Add this function to an script on the CardboardHead (or just add it into that script):
public void Recenter() {
Transform reference = target != null ? target : transform.parent;
if (reference != null) {
reference.rotation = Quaternion.Inverse(transform.rotation) * reference.rotation;
// next line is optional -- try it with and without
reference.rotation = Quaternion.FromToRotation(reference.up, Vector3.up) * reference.rotation;
}
}
Cardboard.SDK.Recenter (); should do the trick.
Recenter orientation Added Recenter() function to Cardboard.SDK, which resets the head tracker so the phone's current heading becomes the forward direction (+Z axis).
Couldn't find the docs for the API/SDK but it's in the release notes for the v0.4.5 Update.
You can rotate the Cardboard Main to point in a certain direction.
This is what worked for me when I wanted the app to start up pointing a certain way. Since the CardboardHead points at Vector3.zero on startup if no target is assigned, I ran a function during Start() for the CardboardMain that would point in the direction I wanted.
Of course, if you're already rotating CardboardMain for some other reason, it may be possible to use this same method by creating a parent of the CardboardHead (child of CardboardMain) and doing the same thing.
This question is a bit old but for Google VR SDK 1.50+ you can do
transform.eulerAngles = new Vector3(newRot.x, newRot.y, newRot.z);
UnityEngine.VR.InputTracking.Recenter();
also, if you don't want to get confused you also need to catch the GvrEditorEmulator instance and Recenter it as well.
#if UNITY_EDITOR
gvrEditorEmulator.Recenter();
#endif
Recentering GvrEditorEmulator though doesn't seem to work very well at the moment but if you disable it you'll see the recentering works for the main camera.
In a toy graphics app I'm playing with I have something like this:
Path p = new Path();
p.addCircle(40,40,40,Path.Direction.CW);
canvas.drawPath(p);
This works as expected on both emulator and phone. But now I try this:
Path p = new Path();
p.addCircle(40,40,40,Path.Direction.CW);
Path q = new Path(p);
canvas.drawPath(q);
This works as expected on the emulator, but does nothing whatsoever on my Nexus S running 4.04.
Similarly, if I try:
Path p = new Path();
p.addCircle(40,40,40,Path.Direction.CW);
Matrix m = new Matrix();
m.setTranslate(50,50);
Path q = new Path();
p.transform(m,q);
canvas.drawPath(q);
Again this only works on the emulator, not on my phone. What is the problem here? No exceptions, nothing useful in the logs, execution runs right through the relevant code.
I expect this is failing because of hardware acceleration. Try switching it off as a quick test.
I have just come across a similare issue in a ploting library I use. The issue looks to be related to the multiple new Path() calls it had in it's drawing code. I have pulled them out to the constructor where they really belong and things are now working OK.
I'd previously managed to incorporate OpenStreetMaps into my application using osmdroid-android-3.0.1.jar with the great assistance of the answer to my question
Porting a Google Maps app to Osmdroid - problem with overlay
I've now upgraded to using the 3.0.3 jar and can't get my overlay to display.
My app can switch display from Google Maps to OSM and display the same overlay consisting of lines and texts on top of either. The alternative displays each run in their own activity for now, as the classes are similar but do not have absolutely identical methods, or at least they didn't have in 3.0.1. (Ultimately I'd like to use the Osmdroid wrapper jar to combine them in one activity and reduce the duplicate code, but that's a question for a later date) Right now I'd like to get the same functionality as I had with the now deprecated 3.0.1 jar using the new 3.0.3 version.
With the new jar, I still get the mapview displayed OK but the overlay has disappeared. I've had to make some changes to the code, as the 3.0.1 onDraw() method has now been replaced with draw() (just like Google) in the MapOverlay extends org.osmdroid.views.overlay.Overlay class.
All the code in the previous onDraw() (now draw) method has been copied verbatim from the answer to the question referred to above, It worked fine, although I confess to not fully understanding the concepts of worldsize, bounding boxes and the transformation described.
I notice that the method
final Point upperLeft = org.osmdroid.views.util.Mercator
.projectGeoPoint(boundingBox.getLatNorthE6(), boundingBox.getLonWestE6(),
zoomLevel + tileZoom, null);
is now deprecated, and I had to remove tileZoom and
final int tileZoom = projection.getTileMapZoom();
to get it to compile.
When I get to the code in the draw() method, I can see in the debugger that all the data necessary to draw the overlay is still present and correct. The drawing is done by lines such as canvas.drawLine(....) and canvas.drawText(....). I've not used the extra parameter to the function (boolean shadow) at all.
My redrawOverlay() method remains as:
private void redrawOverlay() {
mGpt = mMapVw.getMapCenter();
if (mmapOverlay == null)
mmapOverlay = new MapOverlay(this);
mmapOverlay.setEnabled(true);
List<Overlay> listOfOverlays = mMapVw.getOverlays();
int ovlSize = listOfOverlays.size();
if (ovlSize > 1)
listOfOverlays.remove(1);
listOfOverlays.add(mmapOverlay);
mMapVw.invalidate();
}
(The Google listofOverlays.clear() shouldn't be used as osmdroid 3.0.1 had element 0 as the map itself - hence the remove(1))
I'm wondering what I have to do to modify the existing 3.0.1 code to work with 3.0.3? I'm hoping that one of the authors of might read this question.
Update
By adapting the Minimap overaly as suggested in the answer to the question referred to above, the draw() method for drawing an overlay from top left to bottom right, now becomes:
#Override
protected void draw(Canvas pC, MapView pOsmv, boolean shadow) {
if(shadow)
return;
Paint lp3;
lp3 = new Paint();
lp3.setColor(Color.RED);
lp3.setAntiAlias(true);
lp3.setStyle(Style.STROKE);
lp3.setStrokeWidth(1);
lp3.setTextAlign(Paint.Align.LEFT);
lp3.setTextSize(12);
// Calculate the half-world size
final Rect viewportRect = new Rect();
final Projection projection = pOsmv.getProjection();
final int zoomLevel = projection.getZoomLevel();
int mWorldSize_2 = TileSystem.MapSize(zoomLevel) / 2;
// Save the Mercator coordinates of what is on the screen
viewportRect.set(projection.getScreenRect());
// DON'T set offset with either of below
//viewportRect.offset(-mWorldSize_2, -mWorldSize_2);
//viewportRect.offset(mWorldSize_2, mWorldSize_2);
// Draw a line from one corner to the other
pC.drawLine(viewportRect.left, viewportRect.top, viewportRect.right, viewportRect.bottom, lp3);
}
This works OK
Let me try to suggest a few things:
In the new jar build, calling getOverlays().clear() will no longer remove the map tile overlay. Calling remove(1) may be incorrect now since the map tile overlay is no longer in position 0.
The projection has a method that will get you the screen coordinate rectangle of what is currently on the screen. You can check the coordinates you use to draw your lines with against this rectangle to make sure they intercept it.
Take a look at the new TileSystem class. Anything that was deprecated can be recreated using these functions.