consider two circles with (0,0) as center and 110 and 210 as radius respectively...
i.e i have CENTER as (0,0) and CIRCLE 1 radius as 110 and CIRCLE 2 radius as 210.
Now i need to move an object tball in between these two circles.
Here is my code--
public void run() {
while (isitok == true) {
// perform drawing
if (!holder.getSurface().isValid()) {
continue;
}
Canvas canvas = holder.lockCanvas();
canvas.drawARGB(255, 150, 150, 10);
// System.out.println("Canvas matrix -" + canvas.getm));
Paint p = new Paint();
// canvas.drawBitmap(tball, (x - tball.getWidth()) / 2,
// (y - tball.getHeight()) / 2, p);
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.WHITE);
p.setColor(Color.parseColor("#0101DF"));
canvas.drawCircle(canvas.getWidth() / 2,
canvas.getHeight() / 2, 60, p);
canvas.drawCircle(canvas.getWidth() / 2,
canvas.getHeight() / 2, 110, p);
float x = (canvas.getWidth() / 2) - (tball.getWidth() / 2);
float y = (canvas.getHeight() / 2) - 110 + (110 - 60) / 2
- (tball.getHeight() / 2);
canvas.drawBitmap(tball, x, y, p);
float movingpts[];
holder.unlockCanvasAndPost(canvas);
}
}
Circle coordinates are
X = MX + R * cos( angle )
Y = MY + R * sin( angle )
where (MX,MY) is the center or midpoint of the circle and R the radius. For screen coordinates it is sometimes better to use
Y = MY - R * sin( angle )
to get the angle consistent with mathematical conventions on circle orientation.
Related
I tried with following code, But this code is not working as expected. Actually I hesitated to ask help for this simple solution, But I have wasted lots of time, finally I came here.
deltaX = bounds.right - bounds.left;
deltaY = bounds.bottom - bounds.top;
double distance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
float arrowLength= (float) (distance / 3);
float lineAngle = (float) Math.atan2(deltaY, deltaX);
float angle = (float) Math.toRadians(20);
float sinValue = (float) Math.sin(lineAngle - angle);
point_x_1 = bounds.left - 20 * sinValue;
point_y_1 = (float) (bounds.bottom - 0.5 * arrowLength* Math.cos(lineAngle - angle));
angle = (float) Math.toRadians(60);
sinValue = (float) Math.sin(lineAngle + angle);
point_x_3 = bounds.left + 20 * sinValue;
point_y_3 = (float) (bounds.bottom + arrowLength* Math.cos(lineAngle + angle));
path.moveTo(bounds.right, bounds.top);
path.lineTo(bounds.left, bounds.bottom);
path.moveTo(point_x_1, point_y_1);
path.lineTo(bounds.left, bounds.bottom);
path.lineTo(point_x_3, point_y_3);
Note: I have four directions, each will come in different scenarios.
enum PathDirection {
TopLeftToBottomRight,
TopRightToBottomLeft,
BottomLeftToTopRight,
BottomRightToTopLeft
}
Above code I tried for TopRightToBottomLeft.
Sample Outputs
Pic 1: RectF values: [180.0,560.0][820.0,740.0]
Pic 2: RectF values: [240.0,480.0][640.0,980.0]
Update
path.reset();
canvas.save();
canvas.translate(200, 200);
float direction = (float) Math.atan2(400 - 200, 400 - 200);
canvas.rotate(direction);
path.moveTo(0, 0);
float distance = (float) Math.sqrt(200 * 200 + 200 * 200);
path.lineTo(distance, 0);
float x1 = distance - (distance * 20 / 100);
float y1 = -(distance * 15 / 100);
path.moveTo(x1, y1);
path.lineTo(distance, 0);
x1 = distance - (distance * 20 / 100);
y1 = (distance * 15 / 100);
path.lineTo(x1, y1);
canvas.drawPath(path, mPaint);
canvas.restore();
I used this code to draw line from from position 200, 200 to 300, 300. But this draw the line from 0, 0 to distance.
Screenshot
With help from pskink I came to the solution, Sample code, which draw the line with arrow head from 200, 200 to 400, 400
path.reset();
RectF rectF = new RectF(200, 200, 400, 400);
canvas.save();
canvas.translate(rectF.left, rectF.top);
float direction = (float) Math.atan2(rectF.bottom - rectF.top, rectF.right - rectF.left);
float degree = (float) Math.toDegrees(direction);
canvas.rotate(degree);
canvas.drawColor(Color.parseColor("#E3F2FD"));
path.moveTo(0, 0);
float x = rectF.right - rectF.left;
float y = rectF.bottom - rectF.top;
float distance = (float) Math.sqrt(x * x + y * y);
path.lineTo(distance, 0);
float x1 = distance - (distance * 20 / 100);
float y1 = -(distance * 15 / 100);
path.moveTo(x1, y1);
path.lineTo(distance, 0);
float x2 = distance - (distance * 20 / 100);
float y2 = (distance * 15 / 100);
path.lineTo(x2, y2);
canvas.drawPath(path, mPaint);
canvas.restore();
SC:
Note If you don't want to rotate canvas, you can use Helder Sepulveda's answer, it also works as expected.
I am using drawTextOnPath() to create a bent text like in given picture below but I can't figure out how to rotate the text?
What I want is below highlighted in picture with arrow and circle.
What i have been able to achieve is below
So I just want to rotate these texts?
You can achieve the result you want without drawTextOnPath() using:
float radius = 300;
float cx = getWidth() / 2; //Center of the circle
float cy = getHeight() / 2; //Center of the circle
for (int degree = 0; degree < 360; degree += 30) {
canvas.save();
canvas.translate(cx, cy);
canvas.rotate(degree);
String text = "" + degree;
float textCenterX = radius + textPaint.measureText(text) / 2;
float textCenterY = 0 - textPaint.getTextSize() / 2;
if (degree < 180) {
canvas.rotate(-90, textCenterX, textCenterY);
} else {
canvas.rotate(+90, textCenterX, textCenterY);
}
canvas.drawText("" + degree, radius, 0, textPaint);
canvas.restore();
}
You just need to flip the canvas and draw on it
canvas.save()
canvas.scale(1, -1, width / 2, height / 2)
// your drawing code
canvas.restore()
I'm trying to animate a background in a game I'm making.
https://imgur.com/kQGWsLu
Should look like this(terrible recording quality)
My first attempt work well on my phone but a lot of people saw their fps cut in half:
public void draw(Canvas canvas, Paint paint) {
if (mPaint == null) {
mPaint = new Paint();
mPaint.setColor(Color.GRAY);
mPaint.setStrokeWidth(1);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setShader(new RadialGradient(canvas.getWidth() / 4, canvas.getHeight() / 3,
Math.max(1, canvas.getHeight() / 2), Color.rgb(5, 12, 127), Color.rgb(32, 36, 100), Shader.TileMode.REPEAT));
}
width = canvas.getWidth();
height = canvas.getHeight();
canvas.save();
rotation += 4;
if (rotation > 360)
rotation = 0;
canvas.rotate(rotation, width / 2, height / 2);
canvas.drawCircle(width / 2, height / 2, height * 1.3f, mPaint);
canvas.restore();
}
So now I'm thinking about of pre rendering a image and drawing it as a bitmap that covers the screen and rotates instead. I also cut the calculations to only update every other frame instead.
public void draw(Canvas canvas, Paint paint) {
if (!initiated) {
centerX = (int) (canvas.getWidth() / 2);
centerY = (int) (canvas.getHeight() / 2);
width = (int) (canvas.getWidth() * 2f);
height = (int) (canvas.getHeight() * 2f);
map = factory.GFX().getBackground();
initiated = true;
}
if (!skipUpdate) {
x = CalculatorService.getXCircle(rotation, distance, centerX);
y = CalculatorService.getYCircle(rotation, distance, centerY);
body.set((int) x - width / 2,
(int) y - height / 2,
(int) x + (width / 2),
(int) y + (height / 2));
rotation += rotationSpeed;
if (rotation > 360)
rotation = 0;
}
skipUpdate = !skipUpdate;
canvas.drawBitmap(map, null, body, paint);
}
Though since the image is small in size 320*320 I had to scale it up and draw it bigger then the screen to avoid it moving out of bounds and showing the basic black background, and I'm not sure if this is really a improvement, do anyone have a better way of doing it or any advice on how I can improve?
I have view in which, I want to display a heart that is filled based on percentage shown in middle of heart.
I tried canvas, was able to draw heart but could not partial fill, used cliprect,etc but could not achieve this, please see Image
Now if its 30 %, then only 30% area from bottom should be filled with redcolor rest should be white, also the color outside of heart is blue which needs to be same way always as shown in image.
int percentage = 85;
int w = 100;
int h = 100;
Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
Path path = new Path();
// Fill the canvas with background color
canvas.drawColor(Color.BLUE);
paint.setShader(null);
float width = 100.00f;
float height =100.00f;
// Starting point
path.moveTo(width / 2, height / 5);
// Upper left path
path.cubicTo(5 * width / 14, 0,
0, height / 15,
width / 28, 2 * height / 5);
// Lower left path
path.cubicTo(width / 14, 2 * height / 3,
3 * width / 7, 5 * height / 6,
width / 2, height);
// Lower right path
path.cubicTo(4 * width / 7, 5 * height / 6,
13 * width / 14, 2 * height / 3,
27 * width / 28, 2 * height / 5);
// Upper right path
path.cubicTo(width, height / 15,
9 * width / 14, 0,
width / 2, height / 5);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
// draw text percentage
Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(12);
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
//((textPaint.descent() + textPaint.ascent()) / 2) is the distance from the baseline to the center.
canvas.drawText(percentage+" % ", xPos, yPos, textPaint);
int heightOfClip = 100 - percentage;
//clip
canvas.clipRect(0,0,100,heightOfClip, Region.Op.XOR);
// draw heart and color it
canvas.drawPath(path, paint);
// draw text percentage
canvas.drawText(percentage+"%", xPos, yPos, textPaint);
mSampleIv.setImageBitmap(bitmap);
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)