So i'm making a custom View that displays some graphs (plots), and in some ocasions i want to rotate the canvas 90 degrees.
All i can guess is that there's a bug in my device (HTC Desire, with android 2.3), i haven't test it yet in another device.
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.rotate((float) 90.0);
canvas.drawPoint(10, 10, pointPaint); /* Sorry about missing that these
* coordinates will fall out after being rotated... it's just an
* example. put 10, -10 and it should work, but it doesn't */
canvas.restore();
}
This won't draw the point, but if we change that 90.0 for a 90.014 (i found that this was the minimum, 90.013 doesn't work either) then the point will show up.
So... is it something i'm doing wrong, or it's just Android's bug? I googled a lot, but couldn't find nothing....
-Victor -
edit: Additional info: Only points doesn't work. Rects, lines and circles work perfect.
edit: screenshot of my app, you can see how the red line has dots on the 90.014 degree version, and the 90.0 doesn't.:
(As you can see, the 90.014 it looks like a little bit flipped (you can see how the Y axis is 'broken')
Setting the Paint of the dots to use a ROUND stroke cap resolves the problem, even though it doesn't yet explain the strange behavior you are experiencing. e.g.:
paint.setStrokeCap(Paint.Cap.ROUND)
The canvas rotates through its origin, so if you rotate your canvas by 90 degrees you are effectively rotating your view out of your screen. You should translate the canvas to the axis you want to rotate on first:
canvas.save();
canvas.translate(-axispointx,-axispointy);
canvas.rotate((float) 90.0);
canvas.translate(axispointx,axispointy);
canvas.drawPoint(10, 10, pointPaint);
canvas.restore();
Related
I've written a custom view that displays text in the center of the screen as seen below.
I've also made it so that if you touch the green box you can rotate and scale the text as seen below.
Heres the problem.
Whenever I rotate the text and let go, then try to rotate again it cant detect that the rect is being touched using myRect.contains(X,Y).
After some time I found that after its rotated, and touch where the original green box was, it allows me to rotate again.
OnTouchEvent is obviously calculating the Rects position correctly since it drawing in the correct location. I just can figure out why the touch coordinates seem to be referencing old positions.
Here's my onDraw() method.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.rotate((float)mAngle, mBorderRect.centerX(), mBorderRect.centerY());
canvas.drawRect(mBorderRect, mTextBorderPaint);
canvas.drawText(mText, mBorderRect.left, mBorderRect.bottom, mTextPaint);
canvas.drawRect(mResizeRect, mBGPaint);
canvas.restore();
}
Remember that you're rotating the canvas, not the Rect. To get this to work you'll have to apply the inverse rotation on the touch position first, then compute myRect.contains(X,Y).
I have a problem that I can not really solve. I have created a graphing app which will contain data with alot of data points. To enable scrolling in the graph i create a bitmap of the graph data, and the shift / move the bitmap to the right or left of the screen depending on the user input. The bitmap is always the graph view height and graph view width. When the user moves the bitmap, i shift the bitmap with:
memoryCanvas.drawBitmap(memoryBitmap, bitmapShift, 0.0f, paint);
where shift is a a float value containing the shifting values.
Now, on most devices i have tried this is, it works very nice. I have tried it on HTC Desire, Galaxy Tab and Galaxy S. When testing this on my own Galaxy S however, i get strange results that i can not explain. Do note that my Galaxy S contains a custom rom (with android 4.0.4), so that is probably the reason why i get this behavior, but i still can not understand it or properly mitigate it.
So in a normal use case behavior, the bitmaps get shifted by bitmapShift number of pixels, and then i fill in the empty space by normal line drawing. But when using my phone, dragging the bitmap either direction slowly, so the bitmapShift values are around 0.5, the bitmap does not move, or only moves sometimes. I have compared the bitmapShift on the other platforms and they are in the same range, 0.5 when dragging slowly. This behavior does of course screw up my drawings a lot. This does also happen when doing fast dragging, but its most visible when doing it slowly.
I can not really figure out what causes this behavior. The bitmap does not move according to my bitmapShift value. It does on all other platforms i have tried. If i skip using bitmaps, and only draw lines according to the shifting values, everything works fine.
Does anyone have any idea on what could cause this behavior? Im kinda running out after sitting some days trying to figure it out. The critical code is below. This code is in my onDraw function.
memoryCanvas.setBitmap(emptyBitmap); //First set another bitmap to clear
memoryCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //Clear it
memoryCanvas.drawBitmap(memoryBitmap, bitmapShift, 0.0f, paint); //Draw shifted bitmap on it
memoryCanvas.drawLines(lineDrawPoints, 0 , cnt, paint); //Draw remaining lines
memoryCanvas.setBitmap(memoryBitmap); //Set the original
memoryCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //Clear original
memoryCanvas.drawBitmap(emptyBitmap, 0.0f, 0.0f, paint); //Draw the final image
canvas.drawBitmap(memoryBitmap, 0, 0.0f, paint); //And finally draw on real canvas
Any help, tips, suggestions are very welcome.
Cheers
Wilhelm
When there is only a simple transform set on Canvas (a simple transform = translate only, no rotate, no scale), Skia, Android's 2D rendering library, aligns bitmaps to the pixel grid. This means that a move by less than 1 pixel might not be visible at all. A silly workaround is to set a very, very small scale or rotate transform on Canvas before drawing your bitmap. This has the side effect of not snapping bitmaps to the pixel grid.
I think I should just add a new API on Paint to let apps do subpixel positioning of bitmaps no matter what transform is set.
I am developing an Android app on eclipse and have been using android.graphics.camera to 3d transform images. In a nutshell, my app takes a 2d image and gives it perspective. My problem is that I also want to rotate the image around the screen while it is being transformed.
final Matrix mMatrix = canvas.getMatrix();
canvas.save();
mCamera.save();
mCamera.rotateX(60);
mCamera.rotateY(0);
mCamera.rotateZ(0);
mCamera.getMatrix(mMatrix);
mMatrix.preTranslate(-this.gridWidth / 2, -this.gridHeight);
mMatrix.postTranslate(this.gridWidth / 2, this.gridHeight);
canvas.concat(mMatrix);
mCamera.restore();
//Draw and move image here
canvas.restore();
When the image gets to the bottom of the screen, where the camera is translated, the image becomes distorted. I see pieces of it on the screen but its like its being drawn backwards or sideways. I've also tried rotating the image using the rotateZ property but the same effect occurs. Once the image gets 'behind' the translation point, it just goes nuts.
I thought it might be an emulator bug so I loaded it on my Droid X and Acer Iconia and the effect remains the same.
I haven't seen anybody else have this problem so i figured someone here might have a clue as to what's going on.
Any Ideas?
This issue can be addressed with newer versions of Android that let you change the camera distance:
http://developer.android.com/reference/android/graphics/Camera.html#setLocation(float, float, float)
Good day,
I have weird problem with drawing image. Code and pictures say more then words.
mCamera.save();
mCamera.rotateX(rotateX);
mCamera.getMatrix(mMatrix);
mCamera.restore();
canvas.save();
canvas.setMatrix(mMatrix);
// here I draw images
...
canvas.restore();
and results are at images below. First picture have angle 0, second around 45 degree and last something more. It depend on size of area (number of bitmaps) I want to draw. I notice that when I draw bitmaps that whole fits canvas bounds, it works fine. But problem is mainly when I draw images with something like (so with part outside of canvas)
canvas.drawBitmap(image, -100, -100, null)
and images (hmm, because I'm new here, I cannot post images directly ...)
ttp://locus.asamm.cz/data/_temp/1311873666794.png
http://locus.asamm.cz/data/_temp/1311873695945.png
http://locus.asamm.cz/data/_temp/1311873782054.png
So question is, if there is any working solution or at least any tip. Also if anyone experienced can tell if drawing with OpenGL can help with this and if so, please point me to any information source that can help me with drawing bitmaps that change a lot (it's map application so user move with map), because I still cannot find any simple and clear source of info.
Thanks to all very much
It's a limitation of the 2D drawing API. To do true 3D you should use OpenGL.
I expect you are trying to produce a google maps tilt/rotate effect which I have successfull done for google maps since they don't think we need an update ;-) and I needed it for my application, even if you are using your own tiles it's basically the same thing.
One thing that helps is realize that the rotations for the Camera Matrix are performed in the upper left corner.
So you should transform to the appropriate location (dependent on axis of rotation and your expected results) and then back, something like ... the effects you are getting were very similar to mine before I read the docs and figured that out.
camera.save();
camera.rotateX(tilt); // tilt forward or backward
camera.rotateY(0);
camera.rotateZ(angle); // Rotate around Z access (similar to canvas.rotate)
camera.getMatrix(cameraMatrix);
// This moves the center of the view into the upper left corner (0,0)
// which is necessary because Matrix always uses 0,0, as it's transform point
// use the center of the canvas, or the bottom center dependent on your results
cameraMatrix.preTranslate(-centerX, -centerY);
// NOTE: Camera Rotations logically happen here when the canvas has the matrix applied
// This happens after the camera rotations are applied, moving the view back to
// where it belongs, allowing us to rotate around the center or any point we choose
// Move it back after the rotations are applied
cameraMatrix.postTranslate(centerX, centerY);
camera.restore();
canvas.concat(cameraMatrix);
The other thing to do is to oversize the container so you don't have empty space (or at least limit it) after your tilt/rotate operations, you can do that by calculating the needed oversize, the diagonal of your display works for basic rotation, + a percentage based on tilt if you are using that.
Playing around with the pre/postTranslate can can give you some interesting results.
As to moving the bitmap I am not really sure why you are doing this, probably panning, but as long as the canvas is getting filled it shouldn't matter
Update
Here is how I oversize the canvas, I tried to use the LayoutParams to do this but didn't have much luck with it so on Measure was the way to go for me.
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (!isInEditMode())
super.onMeasure(View.MeasureSpec.makeMeasureSpec(scaledDimensionsW,
View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(scaledDimensionsH,
View.MeasureSpec.EXACTLY));
else
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
When I call drawCircle (ex. canvas.drawCircle(x, y, r, mPaint);) and I use Paint Style STROKE to initialize the parameter mPaint, the result doesn't quite make a full 360 degrees (2*PI radian) circle in all cases. Sometimes you get a full circle (as I would expect) and sometimes only an arc.
Does someone have an idea what would cause this to happen ?
I don't know what cases work and which don't (yet). I've noticed the ones that don't work seem to be the larger circles I'm drawing (>100.0 radius). Could be size related. I am using floating point for x, y and r. I could try rounding to the nearest int when in the drawing code.
Are you doing anything else to the canvas before the drawCircle? This could happen if, for example you are scaling the canvas or transforming it before you draw the circle.