Draw Text on scaled Canvas on Android - android

i am drawing a text on a scaled canvas like this:
Rect bounds = new Rect();
paint.getTextBounds(fct.getText(), 0, fct.getText().length(), bounds);
float scaleX = postcard.getWidth() / fct.getContainerWidth();
float scaleY = postcard.getHeight() / fct.getContainerHeight();
float textXpos = fct.getPositionX();
float textYpos = fct.getPositionY();
float rotateX = textXpos + bounds.exactCenterX();
float rotateY = textYpos + bounds.exactCenterY();
canvas.save();
canvas.scale(scaleX, scaleY);
canvas.rotate(fct.getRotation(), rotateX, rotateY);
canvas.drawText(fct.getText(), textXpos, textYpos, paint);
canvas.restore();
The X position of the drawn text is completly correct but the Y position is wrong.
The text is drawn above the expected position.
So how to draw it correctly?

Related

How do I draw a resizable pentagon shape with user touch events?

I am trying to create a pentagon shaped polygon which can be resized by dragging one of its vertices. I tried some code from this question on SO but later realised that the code is specifically written for a rectangle shape. I tried modifying the code in the onDraw() method but later refactored it to the way it was earlier after realising that it is of no use.
Any help?
So here's a code I just wrote to draw a pentagon in the canvas. You pretty much have the vertices which you can edit on the onTouchEvent.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int heigth = getHeight();
// not required, but just to move it to the middle
float centerX = width / 2.f;
float centerY = heigth / 2.f;
// vertices
float p1x = 100.f + centerX;
float p1y = 0.f + centerY;
float p2x = 0.f + centerX;
float p2y = -80.f + centerY;
float p3x = -100.f + centerX;
float p3y = 0.f + centerY;
float p4x = -80.f + centerX;
float p4y = 80f + centerY;
float p5x = 80.f + centerX;
float p5y = 80.f + centerY;
Path path = new Path();
path.moveTo(p1x, p1y);
path.lineTo(p2x, p2y);
path.lineTo(p3x, p3y);
path.lineTo(p4x, p4y);
path.lineTo(p5x, p5y);
path.lineTo(p1x, p1y);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawPath(path, paint);
}

Draw circle on start and end point of an Arc

Hi im having difficulties on drawing dots on arc's both ends (start and end)
Although I can draw arc on canvas. Heres my sample code for drawing arc.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = (float) getWidth();
float height = (float) getHeight();
float radius;
if (width > height) {
radius = height / 4;
} else {
radius = width / 4;
}
float center_x, center_y;
final RectF oval = new RectF();
center_x = width / 2;
center_y = height / 2;
oval.set(center_x - radius,
center_y - radius,
center_x + radius,
center_y + radius);
float percent = 25;
float arcRadius = 360;
float angle = arcRadius * (percent/100);
canvas.drawArc(oval, 270, 360, false, trackpaint);
canvas.drawArc(oval, 270, angle, false, arcPaint);
}
the only missing is putting circles on start and end points of the arc. I've tried this link but it doest work Calculate Arc Center Point, Knowing It's Start and End Degrees. Any help will be much appreciated. Thank you
the coordinate of the start point is:
double startX = Math.cos(Math.toRadians(270)) * radius + center_x;
double startY = Math.sin(Math.toRadians(270)) * radius + center_y;
the coordinate of the end point is:
double endX = Math.cos(Math.toRadians(270 + angle)) * radius + center_x;
double endY = Math.sin(Math.toRadians(270 + angle)) * radius + center_y;
and then you can draw circle using the start point and end point:
canvas.drawCircle(startX, startY, 10, paint);
canvas.drawCircle(endX, endY, 10, paint);
Get path from the ARC
Use PathMeasure class to retrieve Path length and path TAN, using starting or Ending X and Y coordinates of the ARC
Use this X and Y coordinates to draw circle.
Example for circle at the start of the ARC:
final Path mPath = new Path();
mPath.addArc(oval, startAngle, sweepAngle);
PathMeasure pm = new PathMeasure(mPath, false);
float[] xyCoordinate = { arcStarting.x , arcStarting.y };
float pathLength = pm.getLength();
pm.getPosTan(0, xyCoordinate, null);//"0 for starting point"
PointF point = new PointF(xyCoordinate[0], xyCoordinate[1]);
canvas.drawCircle(point.x, point.y, 10, YourPaintHere)

How to draw circle on canvas that will not be affected by the scaling

Does anyone know how to make the radius of the circle be fixed although other stuff in the same canvas be scaled. I don't really know how to get the scale factor of the circle dynamically. Thanks
Canvas c = new Canvas(image);
c.drawColor(Color.TRANSPARENT, Mode.CLEAR);
c.drawBitmap(bm, 0, 0, null);
c.drawCircle(cx, cy, radius, mPaint);
Canvas c = new Canvas(image); // This image has a matrix that every time I scaled on the image the cursor will also change. I want the cursor size to stay as 13.0f.
Code:
public void draw(Canvas canvas, Paint paint) { //This is access from the main onDraw();
paint.setColorFilter(colorFilter);
// scaled bitmap base on the scaling of the bitmap
canvas.drawBitmap(bitmap, matrix, paint);
if(activateCursor == true){
if(isTouched == true && ActivityMainEditor.IS_ERASING == true){
RectF r = new RectF();
matrix.mapRect(r);
// sol1
float scaledX = (lastX - r.left) + 48;
float scaledY = (lastY - r.top) - 137;
float[] values = new float[9];
matrix.getValues(values);
// mScalingFactor shall contain the scale/zoom factor
float scalex = values[Matrix.MSCALE_X];
float skewy = values[Matrix.MSKEW_Y];
float scale = (float) Math.sqrt(scalex * scalex + skewy * skewy);
scaledX /= scale;
scaledY /= scale;
// cursor adjustment
I have used this lines to make the circle radius will always be the same although scaling the bitmap, but it's not accurate when not scaled yet is okay but when scaled bigger the cursor will got bigger also.
float scaleCursor = (float) Math.sqrt((scalex - 5) * (scalex - 5) + (skewy - 2) * (skewy - 2));
float cursorSize = (13.0f / scaleCursor); // 13.0f fixed circle radius
drawACircle(canvas, bitmap, scaledX, scaledY, cursorSize);
}
}
}
private Bitmap drawACircle(Canvas c, Bitmap bm, float cx, float cy, float radius)
{
Bitmap bmOverlay = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
Canvas cd = new Canvas(bmOverlay);
cd.drawColor(Color.TRANSPARENT, Mode.CLEAR);
cd.drawBitmap(bm, 0, 0, null);
// the line in which the circle will also get scaled :(
cd.drawCircle(cx, cy, radius, mPaint);
// update the main bitmap
bitmap = bmOverlay;
if(saveNow == true){
imageHistory.add(bitmap);
saveNow = false;
}
return bmOverlay;
}
It's simple:
c.scale(x,y); // scales the whole canvas (preconcat the matrix with the scale factor)
c.save(); // saves this matrix
// Do all your drawing here except the `drawCircle`.
c.restore(); // restores the original matrix
c.drawCircle(cx, cy, radius, mPaint);
Once you call restore(), the matrix is returned to the original one. You can now draw the circle in the normal fashion.
UPDATE:
Make x and y as fields in the CustomView, that way you can modify them outside the onDraw method. So in the onTouch or onTouchEvent, you can modify the x and y and call invalidate(). This will call onDraw and here it will scale. This will get you what you are looking for. In case of global scaling, always go with the canvas.scale() rather than scaling individual draw elements. This will keep things simple.

Find new coordinates of overlay object on the canvas after modifying on matrix in Android

I'm working on Android project and I'm using View class to drawing image and overlays.
I'm using this code to drawing image and circle (it is working fine):
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (!isInitialized) {
w = getWidth();
h = getHeight();
position.set(w / 2, h / 2);
// Scaling image to be fit screen
if(width<=height) { scale=((float)w)/width; } else { scale=((float)h)/height; }
isInitialized = true;
}
Paint paint = new Paint();
matrix.reset();
matrix.postTranslate(-width / 2.0f, -height / 2.0f);
matrix.postRotate((float)(angle*180/Math.PI));
matrix.postScale(scale, scale);
matrix.postTranslate(position.getX(), position.getY());
canvas.drawBitmap(bitmap, matrix, paint);
canvas.concat(matrix);
canvas.drawCircle(testPoint.x, testPoint.y, 20, paint );
}
Now I want to show PopupWindow windows as a tip on the image and on the same position of circle (testPoint). but the PopupWindows is not drawable object, so how can I find the new coordinates of testPoint after scaling, rotation and translating to put the coordinates of the PopupWindow same.
I'm trying to write code and it working fine, but for rotation and translating only without scaling, this is the code I wrote:
int offsetX=(int) (-(width / 2.0f)+position.getX())+rc.left;
int offsetY=(int) (-(height / 2.0f)+position.getY())+rc.top;
Point RotatedPoint = RotatePoint(testPoint, centerPoint, angle);
RotatedPoint.x +=offsetX;
RotatedPoint.y +=offsetY;
popup.update(RotatedPoint.x, RotatedPoint.y, -1, -1);
Where rc is the offset difference between bitmap view coordinates and the screen coordinates.
And I'm tested RotatePoint function and it working correctly.
Note: when the scale is equal 1 (disable scaling) the position of popup window is updating correctly if I rotate or move the image.
How can I merged the scale (if not equal 1 only) with equations?
Or there is another way to find new coordinates of overlay object on the canvas after modifying on matrix?
Please help me to solved this problem.
I will be grateful for the help.
Thank you.
try to use matrix.mapPoints()
u must have the absolute coordinates of the image
how to absolute coord?
void calculaCoordenadasImagen(MotionEvent e){
float []m = new float[9];
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X] * -1;
float transY = m[Matrix.MTRANS_Y] * -1;
float scaleX = m[Matrix.MSCALE_X];
float scaleY = m[Matrix.MSCALE_Y];
lastTouchX = (int) ((e.getX() + transX) / scaleX);
lastTouchY = (int) ((e.getY() + transY) / scaleY);
lastTouchX = Math.abs(lastTouchX);
lastTouchY = Math.abs(lastTouchY);
}
then use 2 different arrays to save the points
int [] absolute = new int[2];
absolute[0]=lastTouchX;
absolute[1]=lastTouchY;
int [] points = new int[2];
points = matrix.mapPoints(absolute)
in absolute u have the absolute coordinates and in points u have the points u want know
i wish it help!

Number inside circle

What is the best way for draw a number inside circle drawed on canvas by drawCircle?
Then this circle can be dragged by user, when circle is empty I donĀ“t have problems.
This will draw text centered at centerX, centerY
Rect rect = new Rect();
paint.getTextBounds(text, 0, text.length(), rect);
float x = centerX - rect.width() / 2;
FontMetrics fm = paint.getFontMetrics();
float y= centerY - (fm.descent + fm.ascent) / 2;
canvas.drawText(text, x, y, paint);

Categories

Resources