I'm practicing for an exam, and I'm doing one of the practice problems. I have a method that takes two arguments: one for the radius of a circle, and one for the number of dots to place within that circle. The method is below:
private void drawDots(int radius, int numDots){
double ycord;
double xcord;
for(int q = 0; q < numDots; q++){
ycord = -radius + random()*(radius+radius+1);
xcord = pow((pow(radius,2)-pow(ycord,2)),0.5);
turt.moveTo(xcord,ycord);
turt.penDown();
turt.forward(0);
turt.penUp();
}
}
turt is an object I'm using to draw with, and penDown()/penUp() is placing and removing the object from the canvas respectively.
I'm trying to define the x-coordinate and y-coordinate of the turt object to stay within a radius. Say the radius is 100, and the number of dots is 200, how do I keep the object within that radius?
The question states that:
"To constain the dots to a circle of radius r, a random y-coord in the interval -r, r is chosen. To x-coord is then randomly chosen in the interval -b, b, where b = sqrt(r^2 - y^2)."
I'm just not sure how to make sense of this math. The code above was my best attempt, but the output is strange.
Here is my failed output:
The distance from the center (0,0) to a dot must be less than the radius of the circle, r. The distance can be expressed as sqrt(x² + y²). Therefore, if you choose your y coordinate randomly between [-r, r], you just have to make sure that your x coordinate respects the previous equation, hence your math.
Demonstration
sqrt(x² + y²) < r
x² + y² < r²
x² < r² - y²
x < sqrt(r² - y²)
#
Your algorithm should be as follows. Once you chose the y coordinate, you can randomly choose x as long as it respects the distance constraint.
private void drawDots(int radius, int numDots){
double y;
double x;
double xMax;
for (int q = 0; q < numDots; q++){
// y is chosen randomly
y = -radius + random() * (radius + radius + 1);
// x must respect x² + y² < r²
xMax = pow((pow(radius,2)-pow(ycord,2)), 0.5);
x = random() * 2 * xMax - xMax;
turt.moveTo(x, y);
turt.penDown();
turt.forward(0);
turt.penUp();
}
}
Take a look at the documentation for random, you will see by default it produces a number between 0 and 1.
Basically this means that the expression you are looking for is:
ycord=-radius+random()*(radius*2);
This gives you a point on the y axis between -radius and radius (consider if the random() returns 0 you get -radius, it it returns 1 you get -radius+(2*radius())=radius.
You calculation for the x co-ordinate is correct but it gives you the x coordinate point on the circle (lets call it b). I suspect you want to use a new random to select an x co-ordinate between b and -b.
At present you are drawing points on the circle, not inside it. That is because you are not following the guideline correctly.
b = pow((pow(radius,2)-pow(ycord,2)),0.5); // this should be b
xcord = -b + random()*(b+b);
Related
I'm currently working on a raycaster in Java, and so far, I have the floor correctly textured. The problem, however, is that the floor doesn't scroll. In other words, when I move the camera in the projection, the floor stays the same, yet the walls move as expected. I'm really not sure what I'm doing wrong. I took almost all the code from this reference. Note that I took some liberties when pasting the code in that I used some pseudocode.
I tried applying a player offset to the tileX and tileY variables, e.g., tileX += player.x, and all I got was a floor that scrolls far too quickly and incorrectly.
for every ray:
... // other stuff relating to the walls above here.
int start = (int)(wallY + wallHeight + 1);
double directionCos = cos(rad(ray.getAngle()));
double directionSin = sin(rad(ray.getAngle()));
int textureDim = 16;
for (int y = start; y < screenHeight; y++) {
double distance = screenHeight / (2.f * y - screenHeight);
distance /= cos(rad(player.getAngle()) - rad(ray.getAngle()));
// The source I grabbed the code from actually appends the player's x and y to the tileX and tileY variables, but this completely messes up the textures when I try to.
double tileX = distance * directionCos;
double tileY = distance * directionSin;
int textureX = Math.floorMod((int)(tileX * textureDim), textureDim);
int textureY = Math.floorMod((int)(tileY * textureDim), textureDim);
int rgb = floorTexture.getRGB(textureX, textureY);
projectionFloor.setRGB((int)wallX, y, rgb);
}
Below is an image of the floor.
Below is an animation visualizing the problem.
Below is an animation visualizing what happens if I try to apply a player position offset:
Fixed it on my own. Turns out that, yes, you do have to account for the player's position (shocker!); the source I got the code from just didn't do it correctly.
DTPP = distance to projection plane.
for every pixel y from wallY + wallHeight + 1 to projectionHeight:
double r = y - this.getPreferredSize().height / 2.f;
double d = (CAMERA_HEIGHT * DTPP / r) / ANGLE;
double tileX = CAMERA_X + d * RAY_COSANGLE;
double tileY = CAMERA_Y + d * RAY_SINANGLE;
int textureX = Math.floorMod((int) (tileX * TEXTURE_SIZE /
TEXTURE_SCALE), TEXTURE_SIZE);
int textureY = Math.floorMod((int) (tileY * TEXTURE_SIZE /
TEXTURE_SCALE), TEXTURE_SIZE);
... (drawing occurs here)
i have a mathematical problem. Im making a game where the user is a 12 year old kid. The child's goal is to calculate the area of a drawn shape. In easy and medium mode, the shapes are given and hard coded so they are not hardcore. in the hard mode 5 coordinates are randomly generated and here is where the problem comes. I need to make a shape which area is calculable by a 12 y/o child. With the random coordinates come various hard things, such as intersections, or odd points on a line connecting 2 other points and so. Is there any way to calculate and avoid such problems?
Here is my code which makes the random points + draws it on a dot grid in the application:
private void gameHard ()
{
//distance between points is 65 pixels, the numbers that are generated are 1-8
x1=(genRandomInt())*65;
x2=(genRandomInt())*65;
x3=(genRandomInt())*65;
x4=(genRandomInt())*65;
x5=(genRandomInt())*65;
y1=(genRandomInt())*65;
y2=(genRandomInt())*65;
y3=(genRandomInt())*65;
y4=(genRandomInt())*65;
y5=(genRandomInt())*65;
compareRCoordinates ();
areaImage = new JPanel ()
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
g2.fillRect(0,0,780,650);
g2.setColor(Color.BLACK);
int xnum = 65, ynum = 65;
for(ynum=65;ynum<650;ynum=ynum+65)
{
int x=0, y=0;
for(xnum = 65;xnum<780;xnum=xnum+65)
{
x = xnum-9;
y = ynum-9;
g2.fillOval(x,y,18,18);
}
xnum=xnum+65;
}
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(6));
g2.drawLine(x1,y1,x2,y2);
g2.drawLine(x2,y2,x3,y3);
g2.drawLine(x3,y3,x4,y4);
g2.drawLine(x4,y4,x5,y5);
g2.drawLine(x5,y5,x1,y1);
}
};
areaImage.setBounds(20,20,780,650);
areaImage.setBorder(BorderFactory.createLineBorder(Color.black));
this.add(areaImage);
roundsPlayed++;
}
Here's the outline of a fairly straightforward method.
Choose five distinct random points.
Calculate the centroid of the five points (that is, the average X co-ordinate and the average Y co-ordinate).
Calculate the angle from the centroid to each of the five original points. If one of the points happens to be the centroid, then pick any number at all (such as 0) as the angle.
Arrange the points in order of the angle calculated. Ties can be broken arbitrarily.
OK, the points now make a pentagon in the order you've arranged them (including a line segment from the last point to the first one). It's not necessarily convex, but it won't have any "crossing over". You can draw this on the screen.
And you can calculate the area as
( x1 * y2 + x2 * y3 + x3 * y4 + x4 * y5 + x5 * y1 - y1 * x2 - y2 * x3 - y3 * x4 - y4 * x5 - y5 * x1 ) / 2
My basic idea is I divide your 64 (8 by 8) possible points into 5 disjoint rectangular areas and pick one random point from each area. The areas are picked so that connecting the points in order will never cause any connecting lines to cross. It’s quite simple — maybe too simple?
x1 = genRandomInt(1, 3) * 65;
y1 = genRandomInt(1, 4) * 65;
x2 = genRandomInt(1, 3) * 65;
y2 = genRandomInt(5, 8) * 65;
x3 = genRandomInt(4, 8) * 65;
y3 = genRandomInt(6, 8) * 65;
x4 = genRandomInt(4, 8) * 65;
y4 = genRandomInt(4, 5) * 65;
x5 = genRandomInt(6, 8) * 65;
y5 = genRandomInt(1, 3) * 65;
Write genRandomInt(int from, int to) so that it returns a random int in the interval from from through to inclusive. In the code above I have between 10 and 15 possible points in each of the rectangular areas.
Using arrays for the coordinates facilitates.
One could use a random distance to the prior points so points are not near. I'll be math lazy and simply repeat selecting new random numbers till the random point is no longer near.
Finally I cheat and use java.awt.Polygon to check that the new candidate point is not inside the polygon till that.
Polygon one can draw, and even fill.
The fields:
int[] xs = new int[5]; // xs[0] till xs[4]
int[] ys = new int[5];
Polygon pentagon;
Picking random points:
final int NEAR = 20;
for (int i = 0; i < 5; ++i) {
// Pull random numbers for this i'th point till okay.
for (;;) {
xs[i] = random ...
ys[i] = random ...
// Check that the point is not inside the polygon till now:
if (i >= 3) {
Polygon polygon = new Polygon(xs, ys, i);
if (polygon.contains(xs[i], ys[i]) {
continue; // Inside
}
}
// Check that the point are apart:
boolean near = false;
for (int j = 0; j < i && !near; ++j) {
near = Math.abs(xs[i] - xs[j]) < NEAR
&& Math.abs(ys[i] - ys[j]) < NEAR;
}
if (near) {
continue; // Too near
}
break; // Found point i
}
}
pentagon = new Polygon(xs, ys, 5);
Drawing:
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(6));
g2.draw(pentagon);
g2.setColor(Color.TEAL);
g2.fill(pentagon);
... draw grid
As you might image there might be sufficient looping. Endless when the first four points cover the largest part of the screen.
I need to draw a spider using the Graphics package. The problem though is that its size, number of legs and eyes are specified by the user.
I've got a few questions:
how can I randomly select a point on a circle so I can draw a line (for legs) from there while keeping in mind that drawLine(), for instance, takes only integer arguments?
how can I randomly select a point inside the circle used as a center of an eye so that the circle (eye) fits within the ranges of an outer circle (body)?
Selecting a point on a circle just requires getting a random angle. Java uses radians for it's trigonometric functions so a random double between 0 and 1 is multiplied by 2π.
Random r = new Random();
double angle = r.nextDouble() * Math.PI * 2;
Drawing legs is simple trigonometry which requires finding the x and y of each line. For this sine and cosine functions are used. The line can then be drawn off the center point of the circle (centerX and centerY), ending at a specified length in pixels (legLength).
The process can be repeated to draw multiple legs with a specified offset (legOffset) and repeated and offset again (by π) to draw legs on the other side.
for (int i = 0; i < 4; i++) {
int lineX = (int) radius * Math.cos(angle);
int lineY = (int) radius * Math.sin(angle));
g.drawLine(circleX + lineX , circleY + lineY , circleX + lineX * legLength, circleY + lineY * legLength);
angle += legOffset;
}
Drawing the eyes is essentially the same process as the legs. Each eye can drawn at a specified angle and distance from the center of the circle.
int eyeX = (int) distance * Math.cos(angle);
int eyeY = (int) distance * Math.sin(angle));
g.fillOval(eyeX - eyeRadius, eyeY - eyeRadius, eyeRadius* 2, eyeRadius* 2);
The easiest way to get random integers is to create an instance of Random and with random.nextInt(bound) you get an integer between 0 (inclusive) and bound (exclusive), [0, bound).
Instead of selecting the upper left corner of the spider, I would randomly select the center of the spider and then draw everything in relation to it.
Now let's define the radius r = size / 2.
Selecting a random point with insuring that the spider is fully visible:
x = r + random.nextInt(width - 2 * r);
y = r + random.nextInt(height - 2 * r);
Drawing the body with a diameter of r and not 2r to ensure the legs are visible: g.fillOval(x - r / 2, y - r / 2, r, r);
Drawing the legs and eyes: There are numerous strategies, you could draw lines from the center with length r for the legs and very small circles at distance r/4 from the center for the eyes. After selecting an initial random angle, you can use the golden angle to calculate the position of the next leg / eye, this ensures they are never drawn at the same positon (https://en.wikipedia.org/wiki/Golden_angle).
Note: draw the legs first, then the body and the eyes last.
I am currently working on making a screensaver and I want my ellipse to slowly transform to a rectangle in java. What is the easiest way of doing that?
There are some shapes that are easy to transform into one another. For instance a square is a rectangle with equal side lengths, a circle is an ellipse with equal axes. So it is easy to transform a square into a rectangle since you can just use some drawrectangle function and adjust the parameters the whole way. Ditto for circle to ellipse.
squaretorect(double width,double height)
{
//Transform a square width * width to a rectangle width * height
int n = 100;//Number of intermediate points
int i;
double currentheight;
for(i=0;i<n;i++)
{
currentheight = width + (height-width) * i/(n-1);
drawrectangle(width,currentheight);
}
}
Transforming from a rectangle to an ellipse is harder, since in between the shape is neither a rectangle nor an ellipse. It may be that there is some more general object which can be either a rectangle, an ellipse, or something in between, but I cannot think of one.
So, the easy way is out, but there is a harder way to do it. Suppose if I divide the unit circle into N pieces and write points on an ellipse Ei and a rectangle Ri. Now as the transformation happens the points Ei move into the points Ri. A simple way to do this is to use a linear combination.
Ti = (1-v) * Ei + v * Ri
So to do the transformation we slowly increment v from 0 to 1. And we draw lines(or better yet interpolate) between the points Ti.
ellipsetorectangle(double a, double b, double w, double h)
{
//(x/a)^2+(y/b)^2 = 1
//Polar r = 1/sqrt(cos(phi)^2/a^2 + sin(phi)^2/b^2)
int N = 1000;
int i;
double phi; double r;
double phirect = atan(w/h);//Helps determine which of the 4 line segments we are on
ArrayList<Point> Ei;
ArrayList<Point> Ri;
for(i=0;i<N;i++)
{
//Construct ellipse
phi = 2PI * (double)i/N;
r = 1/sqrt(cos(phi)^2/a^2 + sin(phi)^2/b^2);
Ei.add(new Point(r * cos(phi),r * sin(phi));
//Construct Rectangle (It's hard)
if(phi > 2Pi - phirect || phi < phirect)
{Ri.add(new Point(w/2,w/2 * tan(phi)));}
else if(phi > phirect)
{Ri.add(new Point(h/2 * tan(phi),h/2));}
else if(phi > PI-phirect)
{Ri.add(new Point(-w/2,-w/2 * tan(phi)));}
else if(phi > PI+phirect)
{Ri.add(new Point(-h/2,-h/2 * tan(phi)));}
}
}
Arraylist<Point> Ti;
int transitionpoints = 100;
double v;
int j;
for(j=0;j<transitionpoints;j++)
{
//This outer loop represents one instance of the object. You should probably clear the picture here. This probably belongs in a separate function but it would take awhile to write it that way.
for(i=0;i<N;i++)
{
v = (double)1 * j/(N-1);
Ti = new Point(v * Ri.get(i).getx + (1-v) * Ei.get(i).getx,
v * Ri.get(i).gety + (1-v) * Ei.get(i).gety);
if(i != 0)
drawline(Ti,Tiold);
Tiold = Ti;
}
}
Here is a code segment in java intended to rotate the vertices with coordinates A(10,10),B(20,10),C(20,20),D(10,20) of a square by an angle about the center point of the square. The side of the square is 10 points. The angle of rotation is 90 degree. Ideally after rotation A must become B, B must become C, C must become D and D becomes A.
private Point getRotation(Point start, int side, int rotation){
int x = start.getX();
int y = start.getY();
int pivot_x = x + (side/2);
int pivot_y = y + (side/2);
float angle = (float)Math.toRadians(rotation);
int xR = (int)(pivot_x + (x -pivot_x)*Math.cos(angle) - (y - pivot_y)*Math.sin(angle));
int yR = (int)(pivot_y + (x -pivot_x)*Math.sin(angle) + (y - pivot_y)*Math.cos(angle));
return new Point(xR,yR);
}
public static void main(String[] args) {
Square s = new Square();
Point rotatedPoint1= s.getRotation(new Point(10,10), 10, 90);
System.out.println("{"+rotatedPoint1.getX()+","+rotatedPoint1.getY()+"}");
Point rotatedPoint2= s.getRotation(new Point(20,10), 10, 90);
System.out.println("{"+rotatedPoint2.getX()+","+rotatedPoint2.getY()+"}");
Point rotatedPoint3= s.getRotation(new Point(20,20), 10, 90);
System.out.println("{"+rotatedPoint3.getX()+","+rotatedPoint3.getY()+"}");
Point rotatedPoint4= s.getRotation(new Point(10,20), 10, 90);
System.out.println("{"+rotatedPoint4.getX()+","+rotatedPoint4.getY()+"}");
}
The result that is achieved are not correct
point A(10,10) rotated to (20,10) ---- correct
point B(20,10) rotated to (30,10) ---- INCORRECT
point C(20,20) rotated to (30,20) ---- INCORRECT
point D(10,20) rotated to (20,20) ---- INCORRECT
The formula applied is
if (h,k) are the points about which the point (x,y) needs to be rotated by an angle THETA, then the Coordinates after rotation (xR, yR) are
xR = h + (x-h)cos(THETA) - (y-k)sin(THETA)
yR = k + (x-h)sin(THETA) + (y-k)cos(THETA)
Where is the problem?
The problem is your calculation of the square's centroid.
It's supposed to be the same point for all four vertices. However, you calculate as (x+5,y+5) based on each new pair when you call the function. That is:
Call for (10,10), pivot is (15,15)
Call for (20,10), pivot is (25,15)
Call for (20,20), pivot is (25,25)
Call for (10,20), pivot is (15,25)
And you should have rotated them all around the same pivot (15,15).
So you should calculate the pivot before calling the getRotation() method, and pass the pre-calculated pivot as parameter instead of passing the length of the side.