I looked up how to draw a star in Java, and I found the following code:
public void paint(Graphics g) {
drawStar(g,Color.BLACK,5,300,300,100,1…
drawStar(g,Color.RED,6,100,100,20,20);
drawStar(g,Color.BLUE,9,200,400,40,40)…
drawStar(g,Color.YELLOW,27,400,200,10,…
drawStar(g,Color.GREEN,400,300,300,250…
}
public double circleX(int sides, int angle) {
double coeff = (double)angle/(double)sides;
return Math.cos(2*coeff*Math.PI-halfPI);
}
public double circleY(int sides, int angle) {
double coeff = (double)angle/(double)sides;
return Math.sin(2*coeff*Math.PI-halfPI);
}
public void drawStar(Graphics g, Color c, int sides, int x, int y, int w, int h) {
Color colorSave = g.getColor();
g.setColor(c);
for(int i = 0; i < sides; i++) {
int x1 = (int)(circleX(sides,i) * (double)(w)) + x;
int y1 = (int)(circleY(sides,i) * (double)(h)) + y;
int x2 = (int)(circleX(sides,(i+2)%sides) * (double)(w)) + x;
int y2 = (int)(circleY(sides,(i+2)%sides) * (double)(h)) + y;
g.drawLine(x1,y1,x2,y2);
}
}
}
halfPI is defined as a private static variable outside the body
I don't quite get the logic behind these methods. Could someone offer an explanation?
You can follow the graphics object carefully line by line and see what happens to it. It looks like the writer's algorithm uses sine and cosine the evenly split the circle at the same sized angles depending on the number of sides. Then for each side, it draws the line. It is a good beginner program to test and make it work and don't worry if you can't make the basic math work, those are just rather easy trigonometric expressions depending on the arguments that are passed to the drawing method and the helper methods.
Related
I have a polygon I've made with GeneralPath, and I've made a basic stroke with line thickness of 8 and set the join type to JOIN_MITER. When I try to paint this shape like so:
g2d.setStroke(stroke);
g2d.draw(generalPath);
It paints the shape with the correct line thickness, but it treats each line like it's own, giving it whatever type of cap end I define in the stroke. CAP_ROUND looks the best like this, but I would much prefer the if lines properly joined with JOIN_MITER. Can this be done? Am I using the right class when I use GeneralPath? Any help or advice would be much appreciated.
For context, here's the class stripped down to just the pertinent info. the paintComponent method is called from the paintComponent method of the JPanel which I'm drawing on, it has an arrayList of these which it iterates through and calls each their paintComponent methods at a time:
public class RShape extends RComponent{
GeneralPath linkedLines;
Stroke stroke;
public RShape(int x, int y, int sides, Stroke stroke, int defaultLineLength) {
this.stroke = stroke;
linkedLines = new GeneralPath();
double angle = ((double)360)/sides;//find what the angles would need to be to make a shape with that many sides
double dStartX = x;
double dStartY = y;
double nextAngle;
for(int i=0;i<sides;i++) {
nextAngle = angle*i;
nextAngle = nextAngle * Math.PI / 180;//convert to radians
double dEndX = dStartX + defaultLineLength * Math.sin(nextAngle);//find where the end of the line should be for the given angle and line length
double dEndY = dStartY + defaultLineLength * Math.cos(nextAngle);
int endX = (int) Math.round(dEndX);//round to the nearest int
int endY = (int) Math.round(dEndY);
int startX = (int) Math.round(dStartX);
int startY = (int) Math.round(dStartY);
linkedLines.moveTo(startX, startY);//add the next segment of the GeneralPath
linkedLines.lineTo(endX, endY);
dStartX = dEndX;//move the starting point to the end point so it's ready for the next loop
dStartY = dEndY;
}
linkedLines.closePath();//close the last gap.
}
public void paintComponent(Graphics2D g2d) {
g2d.setStroke(stroke);
g2d.draw(linkedLines);
}
}
This is called like this:
ComponentList components = new ArrayList<RComponent>();
components.add(new RShape(50,50,5,new BasicStroke(8,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER),60));
I am currently working on a project called Rectangle project in which I am supposed to do the following on Java:
Make the following methods:
setOrigin
area
move
Also make a method that determines if two rectangles intersect and returns a new intersection Rectangle. Test all your methods in the ObjectDemo program for the following rectangles:
A: Origin 0,0: width 10: height 20
B: Origin 5,5: width 15, height 15
C: Origin 20,12: width 10: height 20
What is the area of each? Test if each of them intersect with the other two and what is the intersection area. Move A by 5,5; B by -5,-5: and C by -20, 0. Now give the intersection area of each.
I need to finish this by Monday but I keep getting a ton of errors like unrecognized variables, etc., and I'm not sure how to fix them. Please let me know!
I have three files: Point, RectangleTest, and Rectangle.
Here are their codes:
Point code:
public class Point
{
//Class variables
private int xCoord; //Private (instead of Public) because we are going to use this class in the other file
//We don't want people changing the values unless we let them
private int yCoord; //Variables are not in a function so will maintain their value
//Constructor
Point()
{
xCoord = 0;
yCoord = 0;
}
//Constructor
Point(int startX, int startY)
{
xCoord = startX;
yCoord = startY;
}
public int getX()
{
return xCoord;
}
public int getY()
{
return yCoord;
}
public void setX(int newX)
{
xCoord = newX;
}
public void setY(int newY)
{
yCoord = newY;
}
public void move(int moveX, int moveY)
{
xCoord+=moveX;
yCoord+=moveY;
}
Point(Point p)
{
xCoord = p.getX();
yCoord = p.getY();
}
}
RectangleTest Code:
public class RectangleTest
{
public static void main(String [] args)
{
Rectangle A = new Rectangle(0,0,10,20);
Rectangle B = new Rectangle(5,5,15,15);
Rectangle C = new Rectangle(20,12,10,20);
//Move rectangles
A.moveby(5,10);
B.moveby(-5,-5);
C.moveby(-20,0);
int areaA = A.getarea;
System.out.println("The area of rectangle A is " +areaA);
int areaB = B.getarea;
System.out.println("The area of rectangle B is " +areaB);
int areaC = C.getarea;
System.out.println("The area of rectangle C is " +areaC);
Rectanlge iAB = A.intersect(B);
Rectangle iAC = A.intersect(C);
Rectangle iBC = B.intersect(C);
if(iab != null)
{
System.out.println("The area of intersection rectangle iab = " +iAB.area());
}
if(iac != null)
{
System.out.println("The area of intersection rectangle iac = " +iAC.area());
}
if (ibc != null)
{
System.out.println("The area of intersection area ibc = " +iBC.area());
}
}
}
Rectangle Code:
public class Rectangle
{
Point origin;
int height;
int width;
//Constructor for rectangle object
Public Rectangle(int startX, int startY, int startW, int startH)
{
origin = new Point (startX, startY);
width = startW;
height = startH;
}
//Set origin point for NEW rectangle origins
//FIX
public void setOrigin(int newX, int newY)
{
origin.setX(newX);
origin.setY(newY);
}
public int moveBy(int moveX, int moveY)
{
origin.move(moveX, moveY);
}
public int getArea()
{
int recArea = height*width;
return recArea;
}
public Rectangle intersect(Rectangle testR)
{
int meTRX = origin.getX() + width;
int meTRY = origin.getY() + height;
int testTRX = testR.origin.getX() + width;
int testTRY = testR.origin.getY() + height;
//Boolean to get iTRX
if(meTRX>testTRX)
{
int iTRX = testTRX;
}
else
{
int iTRX = meTRX;
}
//Boolean to get iTRY
if(meTRY>testTRY)
{
int iTRY = testTRY;
}
else
{
int iTRY = meTRY;
}
//Boolean to get iBLX
if(testBLX>meBLX)
{
int iBLX = testBLX;
}
else
{
int iBLX = meBLX;
}
//Boolean to get iBLY
if(testBLY>meBLY)
{
int iBLY = testBLY;
}
else
{
int iBLY = meBLY;
}
//Testing for whether or not there is an intersection rectangle
if(iTRX-iBLX<0 || iTRY-iBLY<0)
{
return null;
}
int iH = iTRY - iBLY;
int iW = iTRX - iBLX;
int intersectArea = iH * iW;
}
}
Please point out any problems! I'm rather new to programming, so I usually make a lot of simple mistakes. Also, I would appreciate if there are no newly introduced commands or anything because my teacher is pretty strict about doing it this way.
Thanks!
P.S. I would appreciate any extra knowledge or info on code improvement (just in general). Thanks!
Couple of Issues:
Java is case sensitive so Public is not same as public in your rectangle class.
When your method doesnt return anything you should use void as return type. So in your method public int moveBy(int moveX, int moveY), you should change it to public void moveBy(int moveX, int moveY)
You need to define variables before using them. So variables like testBLX, meBLX, testBLY, meBLY, iTRX, iTRY, iBLX, iBLY are undefined. I am not sure from where the values will get populated. But you could avoid the compilation error by defining them as int testBLX = 0; and similarly the others.
In your Rectangle class:
In the constructor your wrote Public Rectangle(int startX, int startY, int startW, int startH), but you actually want public Rectangle(int startX, int startY, int startW, int startH). In Java keywords start always with a lower case.
Your method for changing the origin of a rectangle public int moveBy(int moveX, int moveY) has int as a return type, so the compiler wants you to return an integer value. I suppose you did not want to return anything at all so you can change the return type to void.
In your intersect method public Rectangle intersect(Rectangle testR) you declare your variables (iTRX, iTRY, iBLX, iBLY) such as int iTRX = testTRX; only in the scope of your if/else statements which means that after every if/else statement these variables are not available anymore. To learn more about the different scopes of variables: Variable scopes
In your RectangleTest class:
You forgot a part of your task: What is the area of each? Test if each of them intersect with the other two and what is the intersection area.
Some general leads:
The use of more descriptive variable names improves the readability. For example the variable name meTRX does not have any meaning for me as person who did not work on your code or maybe for you if you review your code two months later.
Before you start coding, you could check if Java has built-in classes which you can use. In your case Java provides a Point class in the package java.awt.Point. You do not have to reinvent the wheel.
I would also recommend to read the Java Code Conventions Code Conventions which can bring you and others who read your code on a common denominator in the future.
I am trying to implement some movement of points. This movement should go by ellipse path.
Something like this:
I know formula of ellipse:
(x-x0)^2/a^2+(y-y0)^2/b^2=1 where (x0,y0) - center of ellipse, a - length of semi-major axis, b - length of semi-minor axis.
I used Maple to get y from this:
y = (y0*a+sqrt(-x^2*b^2+2*b^2*x*x0-b^2*x0^2+a^2*b^2))/a,
y = (y0*a-sqrt(-x^2*b^2+2*b^2*x*x0-b^2*x0^2+a^2*b^2))/a
For example, I'm using following parameters to get this ellipse:
x randomly from 100 to 800, a=500, b=150, x0=500, y0=500.
But in any cases my points form simple line, not ellipse.
Code snippet:
public static int getYElipse(int a, int b, int x, int x0, int y0){
return (int) ((y0*a-Math.sqrt(-x^2*b^2+2*b^2*x*x0-b^2*x0^2+a^2*b^2))/a);
}
public static int getYElipse2(int a, int b, int x, int x0, int y0){
return (int) ((y0*a+Math.sqrt(-x^2*b^2+2*b^2*x*x0-b^2*x0^2+a^2*b^2))/a);
}
...
int x = randomInt(100, 800);
int y = randomBoolean() ? getYElipse(500,150,x,500,500) : getYElipse2(500,150,x,500,500);
What am I doing wrong? Any example will be appreciated.
I would like to draw line using Bresenham Algorithm but I have problem. I dont know, what should I use instead putPixel() method in my code:
public void Line(int x0, int y0, int x1, int y1){
int deltaX = x1-x0;
int deltaY = y1-y0;
double error = 0;
double realError = deltaY/(double) deltaX;
double j = y0;
for(int i = x0; i<= x1; i++){
putpixel(i,(int)j);
j += realError;
}
}
All tutorials have putpixel() method. What can I use instead of this method?
There is no method in Java (awt or Swing) that deliberately paints a single pixel.
You need to use one of these:
drawLine() with starting and final coordinates equal to each other
fillRect() with width and length equal to 1.
Or draw the line as an image, if that's plausible for you. You could use BufferedImage#setRGB().
OK, so I'm trying to make a simple asteroids clone. Everything works fine, except for the collision detection.
I have two different versions, the first one uses java.awt.geom.Area:
// polygon is a java.awt.Polygon and p is the other one
final Area intersect = new Area();
intersect.add(new Area(polygon));
intersect.intersect(new Area(p.polygon));
return !intersect.isEmpty();
This works like a charm... if you don't care about 40% CPU for only 120 asteroids :(
So I searched the net for the famous separating axis theorem, since I'm not thaaaaaat good a the math I took the implementation from here and converted it to fit my Java needs:
public double dotProduct(double x, double y, double dx, double dy) {
return x * dx + y * dy;
}
public double IntervalDistance(double minA, double maxA, double minB,
double maxB) {
if (minA < minB) {
return minB - maxA;
} else {
return minA - maxB;
}
}
public double[] ProjectPolygon(double ax, double ay, int p, int[] x, int[] y) {
double dotProduct = dotProduct(ax, ay, x[0], y[0]);
double min = dotProduct;
double max = dotProduct;
for (int i = 0; i < p; i++) {
dotProduct = dotProduct(x[i], y[i], ax, ay);
if (dotProduct < min) {
min = dotProduct;
} else if (dotProduct > max) {
max = dotProduct;
}
}
return new double[] { min, max };
}
public boolean PolygonCollision(Asteroid ast) {
int edgeCountA = points;
int edgeCountB = ast.points;
double edgeX;
double edgeY;
for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) {
if (edgeIndex < edgeCountA) {
edgeX = xp[edgeIndex] * 0.9;
edgeY = yp[edgeIndex] * 0.9;
} else {
edgeX = ast.xp[edgeIndex - edgeCountA] * 0.9;
edgeY = ast.yp[edgeIndex - edgeCountA] * 0.9;
}
final double x = -edgeY;
final double y = edgeX;
final double len = Math.sqrt(x * x + y * y);
final double axisX = x / len;
final double axisY = y / len;
final double[] minMaxA = ProjectPolygon(axisX, axisY, points, xp,
yp);
final double[] minMaxB = ProjectPolygon(axisX, axisY, ast.points,
ast.xp, ast.yp);
if (IntervalDistance(minMaxA[0], minMaxA[1], minMaxB[0], minMaxB[1]) > 0) {
return false;
}
}
return true;
}
It works... kinda. Actually it seems that the "collision hull" of the asteroids is too big when using this code, it's like 1.2 times the size of the asteroid. And I don't have any clue why.
Here are two pictures for comparison:
http://www.spielecast.de/stuff/asteroids1.png
http://www.spielecast.de/stuff/asteroids2.png
As you can hopefully see, the asteroids in picture one are much denser than the ones in picture 2 where is use the SAT code.
So any ideas? Or does anyone knows a Polygon implementation for Java featuring intersection tests that I could use?
It looks like your second result is doing collision detection as if the polygons were circles with their radius set to the most distant point of the polygon from the center. Most collision detection stuff I've seen creates a simple bounding box (either a circle or rectangle) into which the polygon can fit. Only if two bounding boxes intersect (a far simpler calculation) do you continue on to the more detailed detection. Perhaps the appropriated algorithm is only intended as a bounding box calculator?
EDIT:
Also, from wikipedia
The theorem does not apply if one of the bodies is not convex.
Many of the asteroids in your image have concave surfaces.