I am drawing a triangle on canvas:
float x = 540;
float y = 960;
Path path = new Path();
path.moveTo(x, y);
path.lineTo(x+18, y+60);
path.lineTo(x-18, y+60);
path.lineTo(x, y);
canvas.drawPath(path, mPaint);
This canvas has another objects. But I need to rotate only this triangle around center of this triangle on a random angle (between 0 and 360). How to implement it? How to get coordinates vertexes of a triangle after rotation?
Its simple math, if the center of the triangle is (x,y) and the center-vertex distace is A, the three vertex will be
-(A*Math.cos(angle),A*Math.sin(angle))
-(A*Math.cos(angle+2*Math.PI/3),A*Math.sin(angle+2*Math.PI/3))
-(A*Math.cos(angle-2*Math.PI/3),A*Math.sin(angle-2*Math.PI/3))
I solve it by this way:
float angle = (float) Math.toRadians(90); // Angle to rotate
// Size of triangle
final float height = 60;
final float width = 36;
// Display coordinates where triangle will be drawn
float centerX = 540;
float centerY = 960;
// Vertex's coordinates before rotating
float x1 = centerX;
float y1 = centerY - height / 2;
float x2 = centerX + width / 2;
float y2 = centerY + height / 2;
float x3 = centerX - width / 2;
float y3 = y2;
// Rotating
float x1r = (float) ((x1 - centerX) * Math.cos(angle) - (y1 - centerY) * Math.sin(angle) + centerX);
float y1r = (float) ((x1 - centerX) * Math.sin(angle) + (y1 - centerY) * Math.cos(angle) + centerY);
float x2r = (float) ((x2 - centerX) * Math.cos(angle) - (y2 - centerY) * Math.sin(angle) + centerX);
float y2r = (float) ((x2 - centerX) * Math.sin(angle) + (y2 - centerY) * Math.cos(angle) + centerY);
float x3r = (float) ((x3 - centerX) * Math.cos(angle) - (y3 - centerY) * Math.sin(angle) + centerX);
float y3r = (float) ((x3 - centerX) * Math.sin(angle) + (y3 - centerY) * Math.cos(angle) + centerY);
// Drawing
Path path = new Path();
path.moveTo(x1r, y1r);
path.lineTo(x2r, y2r);
path.lineTo(x3r, y3r);
path.lineTo(x1r, y1r);
canvas.drawPath(path, mPaint);
Thanks to Gimka and Nofate for help.
Related
i'm struggling to word the question a little but I am essentially making a game in which the user will have a limited field of view, the game itself is top down but the player will have to interpret their surroundings based off of the interaction of their small field of view and the walls.
I have created the system for the raysy to be created, however I am struggling to work out the math behind, as well as the implementation of making the angle at which my rays come out of be relevant to the mouse position
code:
private LinkedList<Line2D.Float> calcRays(LinkedList<Line2D.Float> lines, int x, int y, int resolution, int maxDist){
LinkedList<Line2D.Float> rays = new LinkedList<>();
//field of view affected by i
for(int i = 0 ; i < resolution; i++) {
float angle = (float) Math.atan2(mosy - player.getY(), mosx - player.getX());
double dir = (Math.PI*2) * (double) i / resolution / 15;
float minDist = maxDist;
for(Line2D.Float line : lines) {
float dist = getRayCast(x, y, (player.getX()+16)+(float) Math.cos(dir) * maxDist, (player.getY()+16)+(float) Math.sin(dir) * maxDist, line.x1, line.y2, line.x2, line.y2);
if(dist < minDist && dist > 0) {
minDist = dist;
}
}
rays.add(new Line2D.Float(x, y, (player.getX()+16)+(float) Math.cos(dir) * minDist, (player.getY()+16)+(float) Math.sin(dir) * minDist));
}
return rays;
}
public static float dist(float x1, float y1, float x2, float y2) {
return (float) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
public static float getRayCast(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y) {
float s1_x, s1_y, s2_x, s2_y;
s1_x = p1_x - p0_x;
s1_y = p1_y - p0_y;
s2_x = p3_x - p2_x;
s2_y = p3_y - p2_y;
float s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
// Collision detected
float x = p0_x + (t * s1_x);
float y = p0_y + (t * s1_y);
return dist(p0_x, p0_y, x, y);
}
return -1; // No collision
}
This is all of the code related to calculating the ray casts, if anyone would be able to show me how I can add this feature i'd be extremely grateful.
Thanks
I am trying to draw a certain type of polygon but i can't manage to get it to work. Are my formula wrong ? And if so, can you help me?
I want to draw a polygon using Java.awt.polygon
TMP = new Polygon();
// this.getX() and this.getY() return an int
// consider getX() and getY() as x0 and y0
int x1,x2,x3,x4;
int y1,y2,y3,y4;
x1 = (int) Math.round(this.getX() - this.getLength() * Math.cos(this.getAngle()));
y1 = (int) Math.round(this.getY() - this.getLength() * Math.sin(this.getAngle()));
x3 = (int) Math.round(x1 - this.getWidth() * Math.cos((Math.PI / 2) - this.getAngle()));
y3 = (int) Math.round(y1 + this.getWidth() * Math.sin((Math.PI/2) - this.getAngle()));
x4 = (int) Math.round(this.getX() - this.getWidth() * Math.cos((Math.PI/2) - this.getAngle()));
y4 = (int) Math.round(this.getX() + this.getWidth() * Math.sin((Math.PI/2) - this.getAngle()));
x2 = (int) Math.round((x1 + x3) / 2 + Math.cos(this.getAngle()) * this.getLength() / 2);
y2 = (int) Math.round((y1 + y3) / 2 + Math.sin(this.getAngle()) * this.getLength() / 2);
TMP.addPoint(this.getX(), this.getY());
TMP.addPoint(x1, y1);
TMP.addPoint(x2, y2);
TMP.addPoint(x3, y3);
TMP.addPoint(x4, y4);
this.setPolygon(TMP);
This is what i expect
https://i.gyazo.com/bdd8510d0128bab6347bb6c110f03c92.png
And i'm getting this
https://i.gyazo.com/55a00ae07d4f31732db12805fa592aec.png
My formulas were right. My values for length and widths were incorrect. My width was my length and mylength was my width. Sorry!
I am experimenting with libgdx trying to make my first simple game. I have managed to make a line rotate.
What I haven't accomplished is adding a perpendicular line, and making it a cross and then rotating this shape.
public void render(ShapeRenderer renderer) {
renderer.set(ShapeType.Line);
renderer.setColor(COLOR);
/**
* finding the angle
*/
float elapsedNanoseconds = TimeUtils.nanoTime() - initialTime;
float elapsedSeconds = MathUtils.nanoToSec * elapsedNanoseconds;
float elapsedPeriods = elapsedSeconds / 2.0f;
float cyclePosition = elapsedPeriods % 1;
float x = WORLD_SIZE / 2 + radius * MathUtils.cos(MathUtils.PI2 * cyclePosition);
float y = WORLD_SIZE / 2 + radius * MathUtils.sin(MathUtils.PI2 * cyclePosition);
//line rotates and moves at the same time.
renderer.line(position.x - x, position.y + y, position.x + x, position.y - y);
}
position is a Vector2() class object which is updated every delta seconds and holds the current center of the line.
I managed to find the solution. I will leave it here in case someone is having similar issues:
public void render(ShapeRenderer renderer) {
/**
* find the angle
*/
float elapsedNanoseconds = TimeUtils.nanoTime() - initialTime;
float elapsedSeconds = MathUtils.nanoToSec * elapsedNanoseconds;
float elapsedPeriods = elapsedSeconds / 2.0f;
float cyclePosition = elapsedPeriods % 1;
float x = WORLD_SIZE / 2 + radius * MathUtils.cos(MathUtils.PI2 * cyclePosition);
float y = WORLD_SIZE / 2 + radius * MathUtils.sin(MathUtils.PI2 * cyclePosition);
float x2 = WORLD_SIZE / 2 + radius * MathUtils.sin(MathUtils.PI2 * -cyclePosition);
float y2 = WORLD_SIZE / 2 + radius * MathUtils.cos(MathUtils.PI2 * -cyclePosition);
renderer.set(ShapeType.Line);
renderer.setColor(COLOR);
renderer.line(position.x - x, position.y + y, position.x + x, position.y - y);
renderer.line(position.x - x2, position.y + y2, position.x + x2, position.y - y2);
}
I wrote a little program which draws a circular chromatic gradation using Andres' algorithm.
Here is the result of an execution :
If the final-user gives the program a shift, in radians, it will use the latter to begin the drawing of the circle at this angle. Thus, the gradation will begin at this angle (and that's what I want).
For example, you can see that the gradation begins at the bottom of the circle and not at its left in the following image.
But as you can see, two problems appear :
First, there are some gaps in the circle ;
Then, the circumference of the circle is quite imprecise.
I think it's a problem of precision. So I asked myself if there were some bad casts but it's not the case.
Well, I don't know what is the reason why my circle is so imprecise. Could you help me please ?
Here is the class that draws each pixel of the circle. It takes on board the specified shift, in radians.
/**
* Constructs a Pixel taking account of a shift and near the position (x0 ; y0)
* #param x
* #param y
* #param color
* #param angle
* #param x0
* #param y0
*/
Pixel(double x, double y, Color color, double angle, double x0, double y0) {
this.x = (int) (x0 + (x-x0) * Math.cos(angle) - (y-y0) * Math.sin(angle));
this.y = (int) (y0 + (y-y0) * Math.cos(angle) + (x-x0) * Math.sin(angle));
this.color = color;
}
Now, the code that draws the circle, using Andres' algorithm and the Pixel class.
case "Andres' algorithm":
w = 2 * Math.PI;
for(double current_thickness = 0; current_thickness < this.thickness; current_thickness++) {
x = 0;
y = (int) (radius + current_thickness);
double d = radius + current_thickness - 1;
while (y >= x) {
double octant_1_x = x0 + x, octant_1_y = y0 + y;
double octant_2_x = x0 + y, octant_2_y = y0 + x;
double octant_3_x = x0 - x, octant_3_y = y0 + y;
double octant_4_x = x0 - y, octant_4_y = y0 + x;
double octant_5_x = x0 + x, octant_5_y = y0 - y;
double octant_6_x = x0 + y, octant_6_y = y0 - x;
double octant_7_x = x0 - x, octant_7_y = y0 - y;
double octant_8_x = x0 - y, octant_8_y = y0 - x;
max_counter++;
double[] rgb_gradation_octant_1 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_1_y - y0, octant_1_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_1_x, octant_1_y,
Color.color(rgb_gradation_octant_1[0], rgb_gradation_octant_1[1], rgb_gradation_octant_1[2]),
circle_gradation_beginning, x0, y0)); // octant n°1
double[] rgb_gradation_octant_2 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_2_y - y0, octant_2_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_2_x, octant_2_y,
Color.color(rgb_gradation_octant_2[0], rgb_gradation_octant_2[1], rgb_gradation_octant_2[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_3 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_3_y - y0, octant_3_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_3_x, octant_3_y,
Color.color(rgb_gradation_octant_3[0], rgb_gradation_octant_3[1], rgb_gradation_octant_3[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_4 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_4_y - y0, octant_4_x - x0) + Math.PI, w);
updates.add(new Pixel(octant_4_x, octant_4_y,
Color.color(rgb_gradation_octant_4[0], rgb_gradation_octant_4[1], rgb_gradation_octant_4[2]),
circle_gradation_beginning, x0, y0)); // octant n°4
double[] rgb_gradation_octant_5 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_5_y-y0, octant_5_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_5_x, octant_5_y,
Color.color(rgb_gradation_octant_5[0], rgb_gradation_octant_5[1], rgb_gradation_octant_5[2]),
circle_gradation_beginning, x0, y0)); // octant n°5
double[] rgb_gradation_octant_6 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_6_y-y0, octant_6_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_6_x, octant_6_y,
Color.color(rgb_gradation_octant_6[0], rgb_gradation_octant_6[1], rgb_gradation_octant_6[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_7 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_7_y-y0, octant_7_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_7_x, octant_7_y,
Color.color(rgb_gradation_octant_7[0], rgb_gradation_octant_7[1], rgb_gradation_octant_7[2]),
circle_gradation_beginning, x0, y0));
double[] rgb_gradation_octant_8 = PhotoRetouchingFormulas.chromatic_gradation(Math.atan2(octant_8_y-y0, octant_8_x-x0) + Math.PI, w);
updates.add(new Pixel(octant_8_x, octant_8_y,
Color.color(rgb_gradation_octant_8[0], rgb_gradation_octant_8[1], rgb_gradation_octant_8[2]),
circle_gradation_beginning, x0, y0)); // octant n°8
if (d >= 2 * x) {
d -= 2 * x + 1;
x++;
} else if (d < 2 * (radius + thickness - y)) {
d += 2 * y - 1;
y--;
} else {
d += 2 * (y - x - 1);
y--;
x++;
}
}
}
gui.getImageAnimation().setMax(max_counter*8);
break;
you don't have to 'rotate' the pixel, you just have to draw them
Pixel(double x, double y, Color color, double angle, double x0, double y0) {
this.x = (int) (x + x0);
this.y = (int) (y + y0);
this.color = getColorForAngle(angle);
}
Bresenham / Andres provide all pixels of the circle, no need to translate/rotate them
I have here a method to draw a rotated scaled bitmap in Android:
public void drawRotatedScaledBitmap(Bitmap b,
float centerX, float centerY, float width, float height, float angle)
{
float scaleX = width / b.getWidth();
float scaleY = height / b.getHeight();
centerX -= (b.getWidth() * scaleX) / 2.0f;
centerY -= (b.getHeight() * scaleY) / 2.0f;
matrix.reset();
matrix.setTranslate(centerX, centerY);
matrix.postRotate(angle * (180.0f / (float)(Math.PI)),
centerX + (b.getWidth() * scaleX) / 2.0f,
centerY + (b.getHeight() * scaleY) / 2.0f);
matrix.preScale(scaleX,scaleY);
canvas.drawBitmap(b, matrix, null);
}
I'm not sure how I could modify this to take in float sourceX, float sourceY, float sourceW, float sourceH.
I want to render tile sets so I need to tell it say 64,64,64,64 on the bitmap.
How could I do this?
Thanks
Maybe you can try canvas.clipRect() to specify the drawing area.
Here is how I solved it:
public void drawRotatedScaledBitmap(Bitmap b,
float centerX, float centerY, float width, float height,
float sourceX, float sourceY,
float sourceWidth, float sourceHeight, float angle)
{
float cx = centerX;
float cy = centerY;
dstRect.left = (int)centerX - (int)(width / 2);
dstRect.top = (int)centerY - (int)(height / 2);
dstRect.right = dstRect.left + (int)width;
dstRect.bottom = dstRect.top + (int)height;
srcRect.left = (int)sourceX;
srcRect.top = (int)sourceY;
srcRect.right = srcRect.left + (int)sourceWidth;
srcRect.bottom = srcRect.top + (int)sourceHeight;
canvas.rotate(angle * (180.0f / (float)(Math.PI)),cx,cy);
canvas.drawBitmap(b, srcRect, dstRect, null);
canvas.rotate(-angle * (180.0f / (float)(Math.PI)),cx,cy);
}