I am creating an Android app where useres can draw and write using an active pen on a tablet.
The user can choose between different modes (e.g. pen, eraser, line, circle...) which offers them different tools.
The line and circle tools let the user draw a line/circle with the length/radius and direction where the user draws it. This is working quite well, but every time the user moves the pen another line/circle is drawn and it fills up the screen.
Image:
Code:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
canvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas c){
c.drawBitmap(mBitmap, 0, 0, bitmapPaint);
}
private float mX, mY, firstX, firstY;
private void touch_start(float x, float y) { //called from MotionEvent.ACTION_DOWN
path.moveTo(x, y);
firstX = x;
firstY = y;
mX = x;
mY = y;
}
private void touch_move(float x, float y) { //called from MotionEvent.ACTION_MOVE
path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
switch(mode){
case "line":
canvas.drawLine(firstX, firstY, x, y, paint);
break;
case "circle":
canvas.drawCircle(firstX, firstY, (Math.abs(firstX-x) + Math.abs(firstY-y))/1.5f, paint); // divisor 1.5 just a rough value
break;
default:
canvas.drawPath(path, paint);
break;
}
mX = x;
mY = y;
}
Has anyone an idea how I could fix this?
Thanks in advance.
I found a solution by myself.
I created a new Canvas animationCanvas with its own animationBitmap for showing the circle while it is drawn.
The final circle is drawn in the method at MotionEvent.ACTION_UP.
This is the new touch_move:
private void touch_move(float x, float y) { //called from MotionEvent.ACTION_MOVE
path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
switch(mode){
case "line":
animationCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // clear previously drawn line (for animation)
animationCanvas.drawLine(firstX, firstY, x, y, paint);
break;
case "circle":
animationCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // clear previously drawn circle (for animation)
animationCanvas.drawCircle(firstX, firstY, (Math.abs(firstX-x) + Math.abs(firstY-y))/1.5f, paint); // divisor 1.5 just a rough value
break;
default:
canvas.drawPath(path, paint);
break;
}
mX = x;
mY = y;
}
Maybe not the best solution but it works :)
Related
I am trying to draw a text on curved path. But when I scale up the canvas, text gets blurred.
Here's the code I've tried
public void draw(Canvas canvas) {
float midX = (maxX + minX) / 2;
float midY = (maxY + minY) / 2;
canvas.save();
canvas.translate(minX, minY);
canvas.scale(this.scaleX, this.scaleY);
if (curvingAngle != 0) {
drawCurveText(canvas, 0f, 0f, 1f);
} else
canvas.drawText(text, mOrigin[0], mOrigin[1], textPaint);
canvas.restore();
}
private void drawCurveText(Canvas canvas,float offsetX, float offsetY, float scale) {
// Path Calculation
Path textPath;
canvas.drawTextOnPath(text, this.textPath, hOffset, 0.0f, this.getPaint());
}
It gives following results
Before Scale
After Scale
The same code without curvingAngle (canvas.drawText) works perfectly with scaling.
Any help would be appreciated...
I'am doing a simple app which displays compas rose + two arrows which represents current and mean wind direction.
What I want is to rotate compas rose + two arrows after they are drawed on canvas.
Here is my example:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//compass rose
canvas.drawBitmap(broza, crozax, crozay, null);
// Draw current wind arrow + rotate for currentwinddirection from json
matrix.reset();
matrix.setRotate(180 + (float) currentWindDirection, bkazalec.getWidth() / 2, bkazalec.getHeight() / 2);
matrix.postTranslate(ckazalecx, ckazalecy);
canvas.drawBitmap(bkazalec, matrix, mPaint);
//Draw mean wind arrow + rotate for meanwinddirection from json
matrix.reset();
matrix.setRotate(180 + (float) meanWindDirection, bkazalecmean.getWidth() / 2, bkazalecmean.getHeight() / 2);
matrix.postTranslate(mkazalecx, mkazalecy);
canvas.drawBitmap(bkazalecmean, matrix, mPaint);
//here I want to rotate canvas (compas rose + two arrows) for certain degree number which I obtain from sensor.
.
.
//after this I must "draw" some text for certain datas
canvas.drawText(getResources().getString(R.string.pod_smer_vetra) + getCurrentWindDirection() + "°", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_hitrost_vetra) + getCurrentWindSpeed() + " m/s", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_povp_smer_vetra) + getMeanWindDirection() + "°", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_pov_hitrost_vetra) + getMeanWindSpeed() + " m/s", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_beaufort) + getMeanWindBeaufort(), x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_temp_povrsina_voda) + getTemperatureSeaSurface() + "°C", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_temp_zraka) + getTemperatureAir() + "°C", x, y, mPaint);
}
int saveCount = canvas.save(); // save canvas state
try { // just for case if some exceptions
canvas.rotate(angle, centerX, centerY);
if (needScale) canvas.scale(scaleX, scaleY, centerX, centerY);
// draw here what you want
} finally {
canvas.restoreToCount(saveCount); // restore previous state, further draw is unrotated
}
Can someone explain exactly how rotation of the canvas about a point works ?
I have lines and I want to draw text parallel to each line. I have worked out the trigonometry required to calculate the angle of the line and it`s centre point.
When I try rotate the canvas about the start point of the line, then draw the text and restore, I am always getting strange offsets which obviously means I do not quiet get how the rotation is working ...
Can someone explain what happens when you rotate the canvas about a point and how the then drawing on co-ords X,Y translates back ?
see the following class:
class V extends View {
private Paint mPaint;
public V(Context context) {
super(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xffeeeeee);
mPaint.setTextSize(24);
}
#Override
protected void onDraw(Canvas canvas) {
float x = 100;
float y = 50;
float dx = 60;
float dy = 40;
canvas.drawLine(x, y, x + dx, y + dy, mPaint);
canvas.save();
float degrees = (float) (180 * Math.atan2(dy, dx) / Math.PI);
canvas.rotate(degrees, x, y);
canvas.drawText("text", x, y, mPaint);
canvas.restore();
}
}
now i hope everything should be clear how canvas rotation works...
I'm newbee in android-game developing and I would appreciate your help. I'd like to paint some graphics on the canvas which is supposed to be way larger than screen. So some scaling and moving would be great. I've read some questions but they usually answers only some details - not the whole concept.
I've tried use Camera
cam.save();
cam.translate(0f, 0f, -8f);
cam.applyToCanvas(canvas);
cam.restore();
This scales perfectly, but I am unable to decode the real touch coord.
I don't want to use openGL (it's overkill and also I'd like to start with sth simple)
Anyway, I tried canvas.scale(int, int) as well, but didn't work. I believe the Camera is the right way, but I'm lost.
So the question is: how to determinate real coord? Furthermore, It would be nice if some could share a piece of tutorial etc. or some concept of using canvas transformation. (Or maybe there more appropriate ways how to solve it)
Thanks in advance
you have to override the onTouchEvent
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
I want to rotate the canvas circularly on its center axis based on user touch.
Like a old phone dialer .
i want to rotate based on center
but
Now its rotating based on top left corner .so i am able to see only 1/4 for rotation of image.
I have tried like as follows
onDraw(Canvas canvas){
canvas.save();
// do my rotation
canvas.rotate(rotation,0,0);
canvas.drawBitmap( ((BitmapDrawable)d).getBitmap(),0,0,p );
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
updateRotation(x,y);
mPreviousX = x;
mPreviousY = y;
invalidate();
}
private void updateRotation(float x, float y) {
double r = Math.atan2(x - centerX, centerY - y);
rotation = (int) Math.toDegrees(r);
}
You need to add this to your custom view methods
#Override
public void onSizeChanged (int w, int h, int oldw, int oldh){
super.onSizeChanged(w, h, oldw, oldh);
screenW = w;
screenH = h;
}
This method will give you the canvas size then use
canvas.rotate(rotation, screenW / 2, screenH / 2);
Pass the point of rotation to rotate api:
canvas.rotate(rotation, 0, centerY);
Instead of rotating the Canvas you can use
x=0;
x=x+50;
yourview.setRotation(x);
use this on touch event and
x=x-50 for rotating backword
I think it will help