I have a diamond drawn on a panel and I'm trying to calculate if the mouse position is within its bounds. The problem is trying to the diamond, it needs four coordinates making up four lines to create the shape.
The easy thing to do is to create/fit a square within the bounds of the diamond, but I want to account for the remaining triangular areas outside. I initially thought I trying to calculate the slope between two points and figuring out if the x and y of the mouse intersects the line by adding the slope into the the equation, but it proved to be a lot more difficult when it comes to the lines that make up the TOP->RIGHT, RIGHT->BOTTOM and BOTTOM->LEFT given that the center of the diamond is not zero.
Is there an easier implementation to check if the mouse's x,y is within the bounds of the diamond?
In pseudo-code (to be more readable):
Point org = new Point(64, 32); // Center.
Point radii = new Point(32, 16); // Half the size.
Point mousePos = ...
mousePos -= org; // Relative to the center.
boolean inside = Math.abs(mousePos.x) * radii.y + Math.abs(mousePos.y) * radii.x
<= radii.x * radii.y;
Of math one knows (0, radii.y) and (radii.x, 0) determine the border line in the positive quadrant.
That comes down to the formula above.
static boolean isInsideDiamond(int x, int y, int[] xs, int[] ys) {
int minX = xs[0];
int maxX = minX;
int minY = ys[0];
int maxY = minY;
for (int i = 1; i < 4; ++i) {
minX = Math.min(minX, xs[i]);
maxX = Math.max(maxX, xs[i]);
minY = Math.min(minY, ys[i]);
maxY = Math.max(maxY, ys[i]);
}
int orgX = (minX + maxX) / 2;
int orgY = (minY + maxY) / 2;
int radX = (maxX - minX) / 2;
int radY = (maxY - minY) / 2;
return isInsideDiamond(x, y, orgX, orgY, radX, radY);
}
static boolean isInsideDiamond(int x, int y, int orgX, int orgY, int radX,
int radY) {
x -= orgX;
x = Math.abs(x);
y -= orgY;
y = Math.abs(y);
return x * radY + y * radX <= radX * radY;
}
By the way:
Polygon diamond = new Polygon(xs, ys, 4);
boolean inside = diamond.contains(x, y);
Related
I have to draw a ring using lines (drawLine) in Java that should look like the attached picture. We are provided with the classDrawingPanel that can be found here.
I've made a regular circle using lines, but I'm unsure how to get the ring shape. I'm new to programming and this is my first post, so apologies if I've missed something important.
This is my code so far:
public static int panelSize = 400;
public static void drawCircle()
{
double radius = 200;
int x2 = 200;
int y2 = 200;
DrawingPanel dp = new DrawingPanel(panelSize, panelSize);
dp.setBackground(Color.CYAN);
Graphics dpGraphics = dp.getGraphics();
dpGraphics.setColor(Color.RED);
for (int circle = 0; circle <= 360; circle++)
{
int x = (int)(x2 + Math.sin(circle * (Math.PI / 180)) * radius);
int y = (int)(y2 + Math.cos (circle * (Math.PI / 180)) * radius);
dpGraphics.drawLine(x, y, x2, y2);
}
}
This is what the final result should look like:
Such a figure can be drawn by drawing a line from one point to a point farther away on the circle, passing the starting point several times.
This is what I came up with:
// Radius
int radius = 200;
// center of the circle
int centerX = 300, centerY = 300;
// The number of edges. Set to 5 for a pentagram
int mod = 136;
// The number of "points" to skip - set to 2 for a pentagram
int skip = 45;
// Precalculated multipier for sin/cos
double multi = skip * 2.0 * Math.PI / mod;
// First point, calculated by hand
int x1 = centerX; // sin(0) = 0
int y1 = centerY + radius; // cos(0) == 1
for (int circle = 1; circle <= mod; circle++)
{
// Calculate the end point of the line.
int x2 = (int) (centerX + radius * Math.sin(circle * multi));
int y2 = (int) (centerY + radius * Math.cos(circle * multi));
dpGraphics.drawLine(x1, y1, x2, y2);
// Next start point for the line is the current end point
x1 = x2;
y1 = y2;
}
The result looks like this:
I am unable to create several instances of the waveClock object even though I have put it in an array and marked the centre positions for each object. I would like to create 4 objects in one window, all responding to different sound frequencies/beat onsets etc
Could someone shed some light on how to go about this? I believe it may be an issue with the centerX and centerY variables in the waveClock class
ArrayList<waveClock> waveClocks = new ArrayList<waveClock>();
//global variables
float angnoise, radiusnoise;
float xnoise, ynoise;
float angle = -PI/6;
float radius;
float strokeCol = 254;
int strokeChange = -1;
int speed; //changes speed of visualisation once beat is detected?
void setup()
//for every waveClock we need 180 pixels width, then add 20 pixels for first gap
size(740, 650);
background(255);
//code is called
waveClocks.add(new waveClock(100, height/2, minRadius, bassColour, lowBassBand, highBassBand, numberOfLowOnsetsThreshold));
waveClocks.add(new waveClock(280, height/2, minRadius, midColour, lowMidBand, highMidBand, numberOfMidOnsetsThreshold));
waveClocks.add(new waveClock(460, height/2, minRadius, highColour, lowHighBand, highHighBand, numberOfHighOnsetsThreshold));
waveClocks.add(new waveClock(640, height/2, minRadius, veryHighColour, lowVeryHighBand, highVeryHighBand, numberOfVeryHighOnsetsThreshold));
//set the min and max radius of each of the viz circles
/* for (int i = 0; i < waveClocks.size(); i++) {
//go through the arraylist of waveClocks and set the min and max radius of each circle
waveClocks.get(i).setMinMaxRadius(minRadius, maxRadius);
}*/
song.play();
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
bl = new BeatListener(beat, song);
}
void draw() {
//clear the screen by painting it black
//background(0);
for (int i = 0; i < waveClocks.size(); i++) {
//has there been a beat in the range? get(circle ID).low band, high band etc.
if (beat.isRange(waveClocks.get(i).getLowBand(), waveClocks.get(i).getHighBand(), waveClocks.get(i).getOnsetThreshold())) {
waveClocks.get(i).setMaxRadius();
}
//waveClocks.get(i).drawCircle();
waveClocks.get(i).drawWaveClock();
}
}
waveClock class in a separate tab
//class is an architecture blueprint
//objects are the actual buildings built from the methods (can make as many as you like)
//constructor is the builder/constructor literally
class waveClock {
float centerX; //co-ordinates of circle's position
float centerY; //co-ordinates of circle's position
float radius; //avg radius
// float minRadius; //smallest size it can be
// float maxRadius; //biggest size it can be
color col; //colour
int onsetThreshold; //
int lowBand; //looks at lowest band of frequency and makes circle sensitive to it
int highBand; //looks at highest band of frequency and makes circle sensitive to it
boolean onset; //has there been an onset (beat has occurred or not?)
//the constructor
waveClock(float x, float y, float r, color c, int lb, int hb, int t) {
centerX = x;
centerY = y;
radius = r;
col = c;
lowBand = lb;
highBand = hb;
onsetThreshold = t;
}
void drawWaveClock() {
radiusnoise += 0.005;
radius = (noise(radiusnoise)*350) + 1;
angnoise += 0.005;
angle += (noise(angnoise)*6) - 3;
if (angle > 360) {
angle -= 360;
} else if (angle < 0) {
angle += 360;
}
xnoise += 0.01;
ynoise =+ 0.01;
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
float rad = radians(angle);
float x1 = centerX + (radius*cos(rad));
float y1 = centerY + (radius*sin(rad));
float opprad = rad + PI;
float x2 = centerX + (radius*cos(opprad));
float y2 = centerY + (radius*sin(opprad));
strokeCol += strokeChange;
if (strokeCol > 354) {
strokeChange = -1;
} else if (strokeCol < 0) {
strokeChange = 1;
}
stroke(strokeCol, 60);
strokeWeight(1);
line(x1, y1, x2, y2);
}
}
You aren't ever using the class-level centerX and centerY variables. Instead, you're recalculating a new centerX and centerY in the drawWaveClock() function.
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
These are all drawn from the center of the screen, so the waves will end up in the same position.
In the future, please try to narrow your problem down to a MCVE that demonstrates the problem. Also please use proper naming conventions- classes start with an upper-case letter, for example. Good luck.
I am going to try my best to give context for the below code. This is a method used to draw a circle and its center point in a 50x50 white square background. The following variables were used:
xc,yx - the center coordinates used to compute the circle
r - the radius of the circle
STEP - how often a new point is drawn on the circumference of the circle
x,y - the coordinates of each point that will make up the circle
Right now, my method uses a for loop to compute each points R,G, and B coordinates along the circumference of the circle based on the center point and the radius. What I am trying to do is anti-alias my output circle so that the round parts are not as jagged. However, I want to do this using only math and variables and I do not want to use any of Java's build in methods. Thank you to anyone who can help or point me in the right direction.
Below is my routine:
protected void proc_21() {
info = "Draw anti-aliased circle";
int xc = (int) rand(1, imgW - 2);
int yc = (int) rand(1, imgH - 2);
int r = (int) rand(4, 0.35f * (imgW + imgH));
int STEP = (2 * (int) Math.PI * r) * 57;
System.out.printf("circle centered at (%d,%d), radius = %d, draw in %d steps. \n", xc,yc,r,STEP);
for (int i = 0; i < STEP; i++) {
int x = (int) Math.round(xc + r * Math.cos(i));
int y = (int) Math.round(yc + r * Math.sin(i));
if (0 <= x && x < imgW) {
if ( 0 <= y && y < imgH) {
imgNew.setR(x, y, 0);
imgNew.setG(x, y, 0);
imgNew.setB(x, y, 1);
}
}
}
// set center to red
imgNew.setR(xc, yc, 1);
imgNew.setG(xc, yc, 0);
imgNew.setB(xc, yc, 0);
}
I'm trying to draw waves onto the sea, but I got no idea how to moves those from top to bottom. No matter what I change, they stay at the top of the picture.
Here's the code I'm using to draw the waves:
Dimension d = getSize();
int x, y, winWidth = d.width, winHeight = d.height;
int halfHeight = 10;
int lastX = 0, lastY = halfHeight;
double trajectory = 2 * Math.PI;
double factor = trajectory / 100;
for (x = 1; x <= winWidth; x++) {
double sine = Math.sin (x * factor) * halfHeight;
y = halfHeight - (int)sine;
graafika.drawLine (x, y, lastX, lastY);
lastX = x; lastY = y;
}
Here's a picture, how it looks at the moment.
Thanks for the help!
Use height?
graafika.drawLine (x, y+winHeight-20, lastX, lastY+winHeight-20);
You can just "mirror" the placement of the wave by replacing
y = halfHeight - (int)sine;
with
y = winHeight - (halfHeight - (int)sine);
This first places your sine wave at the very bottom, then moving it up a half sine wave, allowing the whole wave to be visible.
I'm new to animation in android. I'm working with a tutorial I have found on youtube. The app draws a picture of a ball on a canvas and then moves diagonally. I'd like to make the ball move in a circle. I've found some information about the basic math of circular motion but I'm having trouble implementing it. Could someone look at my code and tell me what I'm doing wrong. Thanks.
Here is my code:
public class DrawingTheBall extends View {
Bitmap bball;
int x,y;
public DrawingTheBall(Context context) {
super(context);
// TODO Auto-generated constructor stub
bball = BitmapFactory.decodeResource(getResources(), R.drawable.blueball);
x = 0;
y = 0;
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
Rect ourRect = new Rect();
ourRect.set(0, 0, canvas.getWidth(), canvas.getHeight()/2);
float a = 10;
float b = 10;
float r = 20;
double theta = 0;
theta = Math.toRadians(45);
Paint blue = new Paint();
blue.setColor(Color.BLUE);
blue.setStyle(Paint.Style.FILL);
canvas.drawRect(ourRect, blue);
if(x < canvas.getWidth()){
//x += 10;
x = (int) (a +r*Math.cos(theta));
}else{
x = 0;
}
if(y < canvas.getHeight()){
//y += 10;
y = (int) (b +r*Math.sin(theta));
}else{
y = 0;
}
Paint p = new Paint();
canvas.drawBitmap(bball, x, y, p);
invalidate();
}
}
Basically you need to use the Sine and Cosine trigonometric functions, which given the angle will give you the ratios of the corresponding x, and y coordinates on your screen.
something along:
double x = a + r * sin(angle);
double y = b + r * cos(angle);
should work.
where:
r - is the radius of the circle
(a,b) - is the center of the circle
angle - is the desired angle
Of course you need to increment the angle, in order for your object to move.
Mathematically a point on the circle is defined by an angle theta and a distance from the center radius. In your code the angle is a constant 100 so it never moves on the circle. What you want to do is increase the angle in your update.
theta = theta + Math.toRadians(10);
x = a + r*Math.cos(theta);
y = b + r*Math.sin(theta);
This will let you move on a circle that centers on (a,b) with radius r, 10 degrees at a time.
To your comment, add theta as a field and don't set it to 45 inside onDraw, if you want to start at 45 degrees you can initialize it to 45 inside your constructor.
int x,y;
to
int x,y, theta;
To your comment
int x,y, theta;
public DrawingTheBall(Context context) {
super(context);
bball = BitmapFactory.decodeResource(getResources(), R.drawable.blueball);
x = 0;
y = 0;
theta = 45;
}
And
public void onDraw(Canvas canvas){
super.onDraw(canvas);
Rect ourRect = new Rect();
ourRect.set(0, 0, canvas.getWidth(), canvas.getHeight()/2);
float a = 10;
float b = 10;
float r = 20;
// double theta = 0; //You are using a local variable that shadows the field, it starts at 0 everytime
// theta = Math.toRadians(45); //You are setting it to 45 degrees everytime, instead:
theta = theta + Math.toRadians(10); //Increase of 10 degrees
Paint blue = new Paint();
blue.setColor(Color.BLUE);
blue.setStyle(Paint.Style.FILL);
canvas.drawRect(ourRect, blue);
if(x < canvas.getWidth()){
//x += 10;
x = (int) (a +r*Math.cos(theta));
}else{
x = 0;
}
if(y < canvas.getHeight()){
//y += 10;
y = (int) (b +r*Math.sin(theta));
}else{
y = 0;
}
Paint p = new Paint();
canvas.drawBitmap(bball, x, y, p);
invalidate();
}
Take a look at this post from another SO ticket, seems very similar.
Android - Moving an object in circle