Rotated rect changes location - java

I am trying to rotate a rect and i have to rotate the canvas to do so but the rect changes its location for example, if the rect is in the middle of the screen after the rotation it will go to the side and i cannot figure out how to get it back to the middle.
Here is the code i used:
canvas.save();
canvas.rotate(45);
canvas.drawRect(width/2,height/2, width/2+200, height/2+200, paint);
canvas.restore();
Is there a way to rotate the rect without rotating the canvas so its location will stay the same?

Your rectangle's center differs from the pivot point of the canvas. You can try using the other rotate method to specify the x/y coordinates of the pivot point. As in:
int offset = 200;
int left = width/2;
int top = height/2;
int right = left + offset;
int bottom = top + offset;
canvas.save();
canvas.rotate(45, left + offset/2, top + offset/2);
canvas.drawRect(left, top, right, bottom, paint);
canvas.restore();
Edit:
Just tested the code above and verified that it works (given a few tweaks that I just added, above).

'canvas.rotate' rotates the canvas around the origin of canvas. Origin is top left corner of canvas at initial state.
If you want to rotate a rectangle around the center of the rectangle, move origin of canvas to the center of the rectancle before using 'canvas.rotate'.
Try following code:
canvas.save();
canvas.drawRect(width/2,height/2, width/2+200, height/2+200, paint); // drow rectangle
canvas.translate(width/2+100, height/2+100); // move origin of canvas to the center of the rectangle
canvas.rotate(45); // canvas is roteted around the origine that is the center of the rectangle also. As a result, rectangle is roteted around its center.
canvas.translate(-(width/2+100), -(height/2+100)); // restore origin of canvas at original position
canvas.restore();

Related

Why is a Pixmap circle off by 1?

I'm trying to draw a circle using Pixmap. To make the problem clearer, I'm filling the entire Pixmap area in white, then drawing the circle in a different color. Here is the code that I feel should work.
I'm setting the width/height of the Pixmap to twice the size of the radius of the circle.
Then I'm drawing a circle in the middle of the Pixmap at (radius, radius).
public static Texture circle(int radius, Color color) {
Pixmap pixmap = new Pixmap(radius * 2, radius * 2, Pixmap.Format.RGBA4444);
pixmap.setColor(Color.WHITE);
pixmap.fill();
pixmap.setColor(color);
pixmap.fillCircle(radius, radius, radius);
Texture texture = new Texture(pixmap);
pixmap.dispose();
}
Unfortunately, the Pixmap cuts off the circle on the right and bottom sides. For example:
If I increase the size of the Pixmap by 1 in both the width and height, then it looks fine:
I can just arbitrarily add an extra pixel but I'd like to understand why this is necessary. Why does setting the radius of the circle to X result in a diameter that is actually X + 1?
To get the result you want, the location of the circle's center would have to fall between two pixels, so that there are a similar number of whole pixels on either side of that location. My guess is that the Pixmap code defines a pixel's location to mean the center of a pixel. So the point (radius, radius) is closer to the right edge than the left, and (radius-1, radius-1) is closer to the left edge than the right. With this definition of location, the center of your circle should be at location (radius-.5, radius-.5).
If you have to put the center of the circle in the middle of a pixel, then it makes sense that you'd use the location (radius, radius) for the circle and that you'd need the width and height of the Pixmap to be (2*radius + 1, 2*radius+1). This way, there are the same number of pixels, radius+.5 pixels, on either side of the center of the circle. You might at that point want to draw a circle of radius radius + .5 if the library will take that.
Because it draws a circle centered on a pixel, not between pixels.
So the actual radius of the circle drawn is one more than passed in, a circle with radius 1 is drawn as (numbers are coordinates in this example):
012
0 X
1XCX
2 X
This technically has a radius of 1.5, but now it's centered on a pixel (C).
I am guessing this is to allow you to place it accurately, as if it actually had a radius of 2, you wouldn't be able to place the center on a pixel.

Cutting a Portion of Canvas and Saving it as an Image

I'm drawing a Rectangle on a Canvas created from a Bitmap using this method
//void android.graphics.Canvas.drawRect(float left, float top, float right, float bottom, Paint paint)
mycanvas.drawRect(arg1,..arg4,mypaint);
I want to show this rectangular portion of the image in an ImageView.
How can i do it? Do i need to create a new Bitmap?

How to rotate sprite via draw method

I have not found answer for this question anywhere, so let's go.
What i expect:
I want to render rocket. Rocket is flying from given start point with evaluated angle. I'm evaluating angle like this:
getVelocity().angle() - 90f
My problem is to calibrate rocket position on top of the rocket. Image below shows how should it work:
In the top picture is how libgdx render not rotated texture region. In the bottom picture is what i expect: I want to move and rotate texture region with given angle to have (x,y) coordinate on the top of rocket.
What i have:
I tired to write method to draw sprite how i expect but i failed. I think it is caused due to fact that i don't understand documentation of this method.
Following manual:
void com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation)
Draws a rectangle with the bottom left corner at x,y and stretching the region to cover the given width and height. The rectangle is offset by originX, originY relative to the origin. Scale specifies the scaling factor by which the rectangle should be scaled around originX, originY. Rotation specifies the angle of counter clockwise rotation of the rectangle around originX, originY.
My code:
public static void drawRotatedTex(SpriteBatch pmRenderer, TextureRegion pmTex, float pmPosX, float pmPosY, float pmAngle)
{
pmRenderer.begin();
pmRenderer.draw(
pmTex, pmPosX, pmPosY, -pmTex.getRegionWidth()/2, pmTex.getRegionHeight(), pmTex.getRegionWidth(), pmTex.getRegionHeight(), 1f, 1f, pmAngle);
pmRenderer.end();
}
Results:
It is moment of collision. As we can see coordinates are offset in relation to rocket.
I don't ask about full solution. For me will be sufficient if someone explain me (on drawing or something) like this method works.
EDIT
Moderation suggested that this question is duplicate of:
libgdx: Rotate a texture when drawing it with spritebatch
I read this topic, but it is not my solution. I know how to rotate my sprite by i don't have idea why coordinates of rocket are offset in relation to rocket top.
EDIT
Invocation of my drawRotatedTex from rocket class:
#Override
public void render(Renderer pmRenderer, float pmX, float pmY) {
SpriteBatch lvSpritebatch = pmRenderer.getSpriteBatch();
Sprite lvSprite = null;
if(mIsExploding)
{
if((lvSprite = mExplosion.getTexture()) != null)
{
lvSpritebatch.begin();
lvSpritebatch.draw(lvSprite, pmX + lvSprite.getWidth()/2, pmY - lvSprite.getHeight()/2);
lvSpritebatch.end();
}
}
else
{
lvSprite = mAnimation.getTexture();
RendererTools.drawRotatedTex(lvSpritebatch,lvSprite,pmX,pmY,getVelocity().angle() - 90f);
}
}
It is not very clear what you are asking, if it's only about moving the origin you would not need that much text. Anyway, I will take a shot at it.
If you want to accomplish what you have in your picture you setup your sprite like this:
sprite.setOrigin(s.getWidth()/2, s.getHeight()); //Centers sprite on top of image.
If I now rotate it in the draw method it rotates around the top center.
sprite.rotate(5);
sprite.draw(batch);
Despite being rotated around the center top of itself it remains position remains the same. If I would set the origin far away from the image and rotate it then the image would travel very far but the position remains the same. Still if you would move it's position 10 pixels to the right the image (wherever it may be) will be moved to the right.
Hope this helps.

Getting translated coordinates from Android canvas

I am passing in an object for Android to paint using it's canvas. The object to rotated to match the horizon. I am trying to find the translated points which canvas calculates given the point and angle I give it.
For example:
I use the following canvas methods to paint it. Where x,y are the screen coordinates and rotation is the rotation of the screen relative to the horizon.
canvas.save();
canvas.translate(x,y);
canvas.rotate(rotation);
obj.paint(canvas);
canvas.restore();
obj.paint() looks like this (but you probably don't need to know it):
canvas.save();
canvas.translate(-width/2, -height/2);
setFill(true);
setColor(backgroundColor);
paintRect(canvas, x, y, width, height);
setFill(false);
setColor(borderColor);
paintRect(canvas, x, y, width, height);
canvas.restore();
paintRect() looks like this:
canvas.drawRect(x, y, x + width, y + height, paint);
What I am trying to figure out is; what are the corner points of the rectangle (green in this picture) after it has been rotated.
Here is an image of the result which is what I expect.

Marker not showing up in the center of circle

This is my below code which is drawing a Circle within Circle and taking my current location as the center of the circle. And I am showing a Star Sign Marker on my current location.
Problem Statement:-
Below code is working fine, but the only problem I am having is, the Star Sign Marker, it is not coming in the center of circle. I need my Star Sign Marker (android.R.drawable.star_on) always in the center of the circle exactly.
imageNames[0] is the Center of the Circle (Star Sign Marker) in the below code.
Any suggestions will be of great help to me.
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
super.draw(canvas, mapView, shadow);
Point screenPts = new Point();
mapView.getProjection().toPixels(pointToDraw, screenPts);
//--------------draw circle----------------------
Point pt = mapView.getProjection().toPixels(pointToDraw,screenPts);
Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(0x30000000);
circlePaint.setStyle(Style.FILL_AND_STROKE);
int totalCircle=4;
int radius=40;
int centerimagesize=13;
for (int i = 1; i <= totalCircle; i ++) {
canvas.drawCircle(screenPts.x,screenPts.y, i*radius, circlePaint);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),imageNames[i]), ((screenPts.x)+(i*radius)),(screenPts.y), null);
}
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),imageNames[0]), (screenPts.x-(centerimagesize/2)),(screenPts.y-(centerimagesize/2)), null);
super.draw(canvas,mapView,shadow);
return true;
}
Below is the screenshot which I am getting currently in my emulator. I need star sign always to be in the center of circle. I am running android 4.1
To me it seems like you forgot to take your markers size in account. You should probably start to draw somewhere like:
screenPts.x - (centerimagesize + starSignWidth)/2
screenPts.y - (centerimagesize + starSignHeight)/2
All you actually do is to tell the canvas to start drawing your markers top left corner in the middle of the screen. Which means that the star markers center won't be the same as your screens center.
The API for Canvas.drawBitmap(Bitmap bitmap, float left, float top, Paint paint) says:
Draw the specified bitmap, with its top/left corner at (x,y)
http://developer.android.com/reference/android/graphics/Canvas.html#drawBitmap%28android.graphics.Bitmap,%20float,%20float,%20android.graphics.Paint%29
Which is exactly what you do. Your markers top left corner is in the middle of the screen.

Categories