Draw polygon with equal sides and angles - java

I am using Bresenham line algorithm in order to draw a simple line.
I need help with using this algorithm to create a polygon with equal sides and angles.
The sides will be the line created by the Bresenham algorithm, but how do I use the created line in order to draw a polygon with X number of sides and equal angels?
Here is the line algorithm I am using:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (double t = 0; t < 1; t += 0.01) {
Point2D p = between(p1, p2, t);
g2d.fillRect((int)p.getX(), (int)p.getY(), 5, 5);
}
g2d.dispose();
}
public Point2D between(Point p1, Point p2, double time) {
double deltaX = p2.getX() - p1.getX();
double deltaY = p2.getY() - p1.getY();
double x = p1.getX() + time * deltaX;
double y = p1.getY() + time * deltaY;
return new Point2D.Double(x, y);
}
Thanks in advance.

Let's suppose your (i-1)th edge of N-sided polygon ends at point x(i-1), y(i-1) and is rotated at angle a(i-1) relative to horizontal axis. So the next edge will be rotated at the angle:
a(i) = a(i-1) + pi - (N-2)/N*pi
and will end at the point:
x(i) = x(i-1) + L * cos(a(i))
y(i) = y(i-1) + L * sin(a(i))
where L is length of one edge. So iterating i from 1 to N and connecting points, you will get your polygon.
If you want to build your polygon using its center point x(c), y(c) and radius R of containing circle, calculate point coordinates in the following way:
x(i) = x(c) + R * cos(2*pi*i/N)
y(i) = y(c) + R * sin(2*pi*i/N)

Related

Java - get x,y coordinates after rotating a rectangle

I can't seem to get the standard answer to work. I'm trying to find the new x,y coordinates of a point inside a larger rectangle, after rotating the larger rectangle around its center. (The end goal is to calculate the 4 corners of a collision box inside the larger rectangle.)
The rectangle is 50W x 128H, and the point inside the rectangle is at 15,111. If I rotate this same rectangle 90 degrees clockwise in Photoshop around its center, the point becomes 17,15 inside the rectangle that is now 128W and 50H.
However, if I use the formula I've found 100 times around here for the same question, I get a completely different answer.
import java.awt.*;
public class MyClass {
public static void main(String args[]) {
int width=50;
int height=128;
int cx = width/2;
int cy = height/2;
// should get 17,15
rotateXY(15,111,cx,cy,-90D); // returns 61,85, which is not even inside the image anymore
rotateXY(15,111,cx,cy,90D); // returns -11,66.
}
public static void rotateXY(int x, int y, int cx, int cy, double degrees) {
// x, y - coordinates of a corner point of the square
// cx, cy - center of square coordinates
double angle = Math.toRadians(degrees);
double x1 = x - cx;
double y1 = y - cy;
double x2 = x1 * Math.cos(angle) - y1 * Math.sin(angle);
double y2 = y1 * Math.cos(angle) + x1 * Math.sin(angle);
int rx = (int) x2 + cx;
int ry = (int) y2 + cy;
System.out.println(rx + "," + ry);
}
}
The method I used to rotate the image in java:
public static BufferedImage rotate(BufferedImage bimg, Double angle) {
double sin = Math.abs(Math.sin(Math.toRadians(angle))),
cos = Math.abs(Math.cos(Math.toRadians(angle)));
int w = bimg.getWidth();
int h = bimg.getHeight();
int neww = (int) Math.floor(w*cos + h*sin),
newh = (int) Math.floor(h*cos + w*sin);
BufferedImage rotated = new BufferedImage(neww, newh, bimg.getType());
Graphics2D graphic = rotated.createGraphics();
graphic.translate((neww-w)/2, (newh-h)/2);
graphic.rotate(Math.toRadians(angle), w/2, h/2);
graphic.drawRenderedImage(bimg, null);
graphic.dispose();
return rotated;
}
I assume you created an AffineTransform. With that you need three transformations:
translate the rectangle so it's center point is the origin
rotate the rectangle by some angle
translate the rectangle back to the position where it came from
Now with this you were able to transform the rectangle's coordinates (corners) into new screen coordinates. What you need is a transformation to get from new screen coordinates back to coordinates inside your rectangle. I think it looks like this:
translate the point the same as in step 1
rotate by the negative angle
undo step 1
These AffineTransforms can be applied quite efficiently, compared to your algorightm using trigonometry which even may have a limited range of validity.
See also Rotating Image with AffineTransform

How to rotate a object on the circumference of a circle?

I created a function for drawing a circle in oepnGL java, and I want to rotate another circle on the circumference of a circle ?
This is my function for create circle, how to change it for drawing the circle on circumference?
For example create a new circle using as center coordinates points from first circle ?
private void rotateAroundOz(GL2 gl, int r, double cx, double cy) {
int step = 1;
gl.glLineWidth(5);
gl.glBegin(GL.GL_LINE_LOOP);
for (int i=0; i<360; i+=step) {
gl.glColor3d(1, 0, 0);
gl.glVertex2d(cx + r * Math.cos(Math.toRadians(i)), cy + r * Math.sin(Math.toRadians(i)));
}
gl.glEnd();
}
You just have to draw a circle (with rotateAroundOz()) using a position that you compute from
cx + r * Math.cos(Math.toRadians(i)), cy + r * Math.sin(Math.toRadians(i))
// This is the attributes of the invisible circle: "PositionCircle"
//that will gives you the circumference
float positionCircle_Radius = 1.0;
float positionCircle_CenterX = 0.0;
float positionCircle_CenterY = 0.0;
// This is actually the circle that you want to draw from the
// "PositionCircle"
int positionOnCircumferenceInDegrees = 90;
float drawnCircle_Radius = 2.0;
float drawnCircle_CenterX = positionCircle_CenterX + positionCircle_Radius * Math.cos(Math.toRadians(positionOnCircumferenceInDegrees));
float drawnCircle_CenterY = positionCircle_CenterY + positionCircle_Radius * Math.sin(Math.toRadians(positionOnCircumferenceInDegrees));
rotateAroundOz(gl, drawnCircle_Radius, drawnCircle_CenterX, drawnCircle_CenterY)
So you can add positionOnCircumferenceInDegrees and drawnCircle_Radius as parameters for your new function.
(That's my first response ever on SO :p hope it's comprehensible!)

Rendering 3-d lines in Java?

Ok, I have a little problem: I'm trying to code an engine capable of rendering 3d lines onto a 2d plane, but I'm having some trouble with it.
I have a point3d class, which takes x y and z coords, a line3d class, which takes two point3d endpoints, and I have a world object containing an arraylist of line3d's. I also have point2d and line2d, which are just like their 3d counterparts, except that they lack a z coordinate.
Here's the render method:
public void render(){
for(Line3d line : world.lines){ //for every 3d line in the world
panel.l3d(line, world.main); //render that line
}
panel.repaint(); //repaint the graphic
}
Which calls upon the l3d method:
public void l3d(Line3d line, Camera view){
Point2d start = p3Top2(line.start, view), end = p3Top2(line.end, view); //convert 3d points to 2d points
if(start==null || end==null)return; //if either is null, return
lineAbs(new Line2d(start, end)); //draw the line
}
Which calls upon p3Top2:
public Point2d p3Top2(Point3d point, Camera view){ //convert 3d point to 2d point on screen
int relativeZed = point.z - view.z; //difference in z values between camera and point
if(relativeZed <= 0)return null; //if it's behind the camera, return
int sx, sy, ex, ey, tx, ty; //begin declaring rectangle formed from extending camera angle to the z coord of the point(angle of 1 = 90 degrees)
sx = (int) (view.x - (width / 2) - relativeZed * (width * view.angle)); //starting x of rectangle
ex = (int) (view.x + (width / 2) + relativeZed * (width * view.angle)); //ending x
sy = (int) (view.y - (height / 2) - relativeZed * (height * view.angle)); //starting y
ey = (int) (view.y + (height / 2) + relativeZed * (height * view.angle)); //ending y
tx = point.x - sx; //difference between point's x and start of rectangle
ty = point.y - sy; //same for y
float px = (float)tx / (float)(ex - sx), py = (float)ty / (float)(ey - sy); //px and py are the ratios of the point's x/y coords compared to the x/y of the rectangle their in
return new Point2d((int)(px * width), (int)(py * height)); //multiply it by the width and height to get positions on screen
}
And also on lineAbs:
public void lineAbs(Line2d line){
Point2d start = line.start;
Point2d end = line.end;
if(start.x>end.x){
start = line.end;
end = line.start;
}
int y = start.y; //starting y point
int white = 0xffffff;
for(int x = start.x; x<end.x; x++){ //for each x in the line
if(x < 0 || y < 0 || x > canvas.getWidth() || y > canvas.getHeight())continue; //if the point is outside of the screen, continue
y += line.getSlope().slope; //increment y by the slope
canvas.setRGB(x, y, white); //draw the point to the canvas
}
}
'canvas' is a BufferedImage being drawn to the screen. With an arbitrary camera and angle of 1, as well as a few arbitrary lines thrown in, I do see each line, but they don't appear to be rendered properly. For example, when I have three point3d's as vertices, and three lines, each with a different combination of two of the points, the lines don't appear to meet at all, although each one is visible.
I suspect the issue is in my p3Top2, but I'm not sure where, can you tell?

Java method to find the rectangle that is the intersection of two rectangles using only left bottom point, width and height?

I have found the solution but wanted to ensure my logic is the most efficient. I feel that there is a better way. I have the (x,y) coordinate of the bottom left corner, height and width of 2 rectangles, and i need to return a third rectangle that is their intersection. I do not want to post the code as i feel it is cheating.
I figure out which is furthest left and highest on the graph.
I check if one completely overlaps the other, and reverse to see if the other completely overlaps the first on the X axis.
I check for partial intersection on the X axis.
I basically repeat steps 2 and 3 for the Y axis.
I do some math and get the points of the rectangle based on those conditions.
I may be over thinking this and writing inefficient code. I already turned in a working program but would like to find the best way for my own knowledge. If someone could either agree or point me in the right direction, that would be great!
Why not use JDK API to do this for you?
Rectangle rect1 = new Rectangle(100, 100, 200, 240);
Rectangle rect2 = new Rectangle(120, 80, 80, 120);
Rectangle intersection = rect1.intersection(rect2);
To use java.awt.Rectangle class, the parameters of the constructor are: x, y, width, height, in which x, y are the top-left corner of the rectangle. You can easily convert the bottom-left point to top-left.
I recommend the above, but if you really want to do it yourself, you can follow the steps below:
say (x1, y1), (x2, y2) are bottom-left and bottom-right corners of Rect1 respectively,
(x3, y3), (x4, y4) are those of Rect2.
find the larger one of x1, x3 and the smaller one of x2, x4, say xL,
xR respectively
if xL >= xR, then return no intersection else
find the larger one of y1, y3 and the smaller one of y2, y4, say yT,
yB respectively
if yT >= yB, then return no intersection else
return (xL, yB, xR-xL, yB-yT).
A more Java-like pseudo code:
// Two rectangles, assume the class name is `Rect`
Rect r1 = new Rect(x1, y2, w1, h1);
Rect r2 = new Rect(x3, y4, w2, h2);
// get the coordinates of other points needed later:
int x2 = x1 + w1;
int x4 = x3 + w2;
int y1 = y2 - h1;
int y3 = y4 - h2;
// find intersection:
int xL = Math.max(x1, x3);
int xR = Math.min(x2, x4);
if (xR <= xL)
return null;
else {
int yT = Math.max(y1, y3);
int yB = Math.min(y2, y4);
if (yB <= yT)
return null;
else
return new Rect(xL, yB, xR-xL, yB-yT);
}
As you see, if your rectangle was originally defined by two diagonal corners, it will be easier, you only need to do the // find intersection part.
My variation of determining intersection of two rectangles in a small utility function.
//returns true when intersection is found, false otherwise.
//when returning true, rectangle 'out' holds the intersection of r1 and r2.
private static boolean intersection2(Rectangle r1, Rectangle r2,
Rectangle out) {
float xmin = Math.max(r1.x, r2.x);
float xmax1 = r1.x + r1.width;
float xmax2 = r2.x + r2.width;
float xmax = Math.min(xmax1, xmax2);
if (xmax > xmin) {
float ymin = Math.max(r1.y, r2.y);
float ymax1 = r1.y + r1.height;
float ymax2 = r2.y + r2.height;
float ymax = Math.min(ymax1, ymax2);
if (ymax > ymin) {
out.x = xmin;
out.y = ymin;
out.width = xmax - xmin;
out.height = ymax - ymin;
return true;
}
}
return false;
}
You can also use the Rectangle source code to compare with your own algorithm:
/**
* Computes the intersection of this <code>Rectangle</code> with the
* specified <code>Rectangle</code>. Returns a new <code>Rectangle</code>
* that represents the intersection of the two rectangles.
* If the two rectangles do not intersect, the result will be
* an empty rectangle.
*
* #param r the specified <code>Rectangle</code>
* #return the largest <code>Rectangle</code> contained in both the
* specified <code>Rectangle</code> and in
* this <code>Rectangle</code>; or if the rectangles
* do not intersect, an empty rectangle.
*/
public Rectangle intersection(Rectangle r) {
int tx1 = this.x;
int ty1 = this.y;
int rx1 = r.x;
int ry1 = r.y;
long tx2 = tx1; tx2 += this.width;
long ty2 = ty1; ty2 += this.height;
long rx2 = rx1; rx2 += r.width;
long ry2 = ry1; ry2 += r.height;
if (tx1 < rx1) tx1 = rx1;
if (ty1 < ry1) ty1 = ry1;
if (tx2 > rx2) tx2 = rx2;
if (ty2 > ry2) ty2 = ry2;
tx2 -= tx1;
ty2 -= ty1;
// tx2,ty2 will never overflow (they will never be
// larger than the smallest of the two source w,h)
// they might underflow, though...
if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
}

Oval collision detection not working properly

So I'm trying to implement a test where a oval can connect with a circle, but it's not working.
edist = (float) Math.sqrt(
Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2 ) +
Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2 )
);
and here is the full code (requires Slick2D):
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
public class ColTest extends BasicGame{
float px = 50;
float py = 50;
float pheight = 50;
float pwidth = 50;
float bx = 200;
float by = 200;
float bsize = 200;
float edist;
float pspeed = 3;
Input input;
public ColTest()
{
super("ColTest");
}
#Override
public void init(GameContainer gc)
throws SlickException {
}
#Override
public void update(GameContainer gc, int delta)
throws SlickException
{
input = gc.getInput();
try{
if(input.isKeyDown(Input.KEY_UP))
py-=pspeed;
if(input.isKeyDown(Input.KEY_DOWN))
py+=pspeed;
if(input.isKeyDown(Input.KEY_LEFT))
px-=pspeed;
if(input.isKeyDown(Input.KEY_RIGHT))
px+=pspeed;
}
catch(Exception e){}
}
public void render(GameContainer gc, Graphics g)
throws SlickException
{
g.setColor(new Color(255,255,255));
g.drawString("col: " + col(), 10, 10);
g.drawString("edist: " + edist + " dist: " + dist, 10, 100);
g.fillRect(px, py, pwidth, pheight);
g.setColor(new Color(255,0,255));
g.fillOval(px, py, pwidth, pheight);
g.setColor(new Color(255,255,255));
g.fillOval(200, 200, 200, 200);
}
public boolean col(){
edist = (float) Math.sqrt(Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2) + Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2));
if(edist <= (bsize/2) + (px + (pwidth/2)))
return true;
else
return false;
}
public float rotate(float x, float y, float ox, float oy, float a, boolean b)
{
float dst = (float) Math.sqrt(Math.pow(x-ox,2.0)+ Math.pow(y-oy,2.0));
float oa = (float) Math.atan2(y-oy,x-ox);
if(b)
return (float) Math.cos(oa + Math.toRadians(a))*dst+ox;
else
return (float) Math.sin(oa + Math.toRadians(a))*dst+oy;
}
public static void main(String[] args)
throws SlickException
{
AppGameContainer app =
new AppGameContainer( new ColTest() );
app.setShowFPS(false);
app.setAlwaysRender(true);
app.setTargetFrameRate(60);
app.setDisplayMode(800, 600, false);
app.start();
}
}
Is using ovals an absolute requirement? You can approximate collisions between fancier shapes by representing them with multiple circles. That way you can use very a simple collision detection between circles and still achieve a high level of accuracy for the viewer.
collision(c1, c2) {
dx = c1.x - c2.x;
dy = c1.y - c2.y;
dist = c1.radius + c2.radius;
return (dx * dx + dy * dy <= dist * dist)
}
(source: strd6.com)
Finding the intersection is harder than you think. Your col() method is a bit off, but that approach will at best be able to tell you if a single point is within the circle. It won't be able to really detect intersections.
I Googled up some code for computing the actual intersections. I found one in JavaScript that's really interesting and really complicated. Take a look at the source.
If you wanted something a bit simpler (but less accurate), you could check a few points around the ellipse to see if they're within the circle.
private boolean isInCircle(float x, float y) {
float r = bsize / 2;
float center_x = bx + r;
float center_y = by + r;
float dist = (float) Math.sqrt(Math.pow(x - center_x, 2) + Math.pow(y - center_y, 2));
return dist < r;
}
public boolean col() {
return
isInCircle(px + pwidth / 2, py ) || // top
isInCircle(px + pwidth , py + pheight / 2) || // right
isInCircle(px + pwidth / 2, py + pheight ) || // bottom
isInCircle(px , py + pheight / 2); // left
}
If you plan on implementing more shapes and/or need the minimum distance between your shapes, you could start using GJK : you would only need to implement the support functions for each new shape. If computation time is also critical, GJK is definitely something you should look at, but it would surely require some more programming on your side.
If you can find your foci you can check for collision with the pseudo code below.
WARNING this only works for two ellipse collisions (ellipse and circle collisions work also).
r = length of semi major axis
a_x = x coordinate of foci 1 of the first ellipse
a_y = y coordinate of foci 1 of the first ellipse
b_x = x coordinate of foci 2 of the first ellipse
b_y = y coordinate of foci 2 of the first ellipse
c_x = x coordinate of foci 1 of the second ellipse
c_y = y coordinate of foci 1 of the second ellipse
d_x = x coordinate of foci 2 of the second ellipse
d_y = y coordinate of foci 2 of the second ellipse
p_x = (a_x+b_x+c_x+d_x)/4 // i.e. the average of the foci x values
p_y = (a_y+b_y+c_y+d_y)/4 // i.e. the average of the foci y values
if r >= ( sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) + sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) )
then collision
If you really want the derivation of this let me know and I'll provide it. But it uses the idea that the sum of the distances between the foci of an ellipse and any point on the edge of an ellipse are a set distance apart (the semi major axis). And solves for a point that is on the edge of both ellipsoids and if one exist then their is a collision.

Categories

Resources