Having trouble drawing a square grid for an android game - java

I would like for this to display as a 7 x 7 square grid in the centre of the screen, however as you can see with my current code the vertical lines are in the correct positions but the horizontal ones are not. I am sure this is a simple fix and any help would be appreciated -
public class GameGrid extends View {
Paint black = new Paint();
public GameGrid(Context context) {
super(context);
black.setColor(Color.BLACK);
black.setStrokeWidth(8);
}
#Override
public void onDraw(Canvas canvas) {
float startX;
float stopX;
float startY;
float stopY;
int width = canvas.getWidth();
int height = canvas.getHeight();
int gridSize = 7;
int gridSpacing = width / gridSize;
//Vertical Grid-lines
for (int i = 0; i < gridSize; i++) {
startX = width / 2 - height / 2;
stopX = width / 2 + height / 2;
startY = i*gridSpacing;
stopY = i*gridSpacing;
canvas.drawLine(startX, startY, stopX, stopY, black);
}
//Horizontal Grid-lines
for (int i = 0; i < gridSize; i++) {
startX = i*gridSpacing;
stopX = i*gridSpacing;
startY = height / 2 - width / 2;
stopY = height / 2 + width / 2;
canvas.drawLine(startX, startY, stopX, stopY, black);
}
}
Picture of what grid currently looks like

You are missing the offset (on both axis). Why you don't pre-calculate xOffset and yOffset and the start to paint based on the point (xOffset, yOffset)?
something like this:
#Override
public void onDraw(Canvas canvas) {
float startX;
float stopX;
float startY;
float stopY;
int width = canvas.getWidth();
int height = canvas.getHeight();
int gridSize = 7;
int gridSpacing = Math.min(width, height) / gridSize;
int boardSize = gridSize * gridSpacing;
int xOffset = (width - boardSize)/2;
int yOffset = (height - boardSize)/2;
//Vertical Grid-lines
for (int i = 0; i < gridSize; i++) {
startX = xOffset + i*gridSpacing;
startY = yOffset;
stopX = startX;
stopY = startY + boardSize;
canvas.drawLine(startX, startY, stopX, stopY, black);
}
//Horizontal Grid-lines
for (int i = 0; i < gridSize; i++) {
startX = xOffset;
startY = yOffset + i*gridSpacing;
stopX = startX + boardSize;
stopY = startY;
canvas.drawLine(startX, startY, stopX, stopY, black);
}
}
If you want to make sure that will be always centered (e.g. in landscape ) you should set:
int gridSpacing = Math.min(width, height) / gridSize;

I'd GUESS the problem is that the canvas isn't square? Height is greater than width.
Thus in the vertical Gridlines
startX = width / 2 - height / 2;
gives a negative number and puts the starting point to the left off-screen. It looks fine, but the length is wrong.
For the horizontal Gridlines
startY = height / 2 - width / 2;
is a positive number and you start partway down the screen. Similarly, the endY value overshoots by some amount (note the horizontal gridlines are longer than the vertical gridlines as well as being offset downward)
Perhaps try
//Horizontal Y vals
startY = 0;
stopY = height;

Related

(Java / Processing) How to create several instances of an object on different positions on the screen?

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.

What's wrong with image rotation code?

The image rotates with code below, but wrong, some black dots appears on original image. I believe it's something with rotation code. Any solution? Thanks. The image dimensions is 32x32 pixels loaded on center of screen (320x240).
public class RendPanel extends JPanel {
private static final long serialVersionUID = 1L;
int widthe = 320;
int heighte = 240;
double angle = Math.toRadians(220);
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double x0 = 0.5 * (widthe - 1); // point to rotate about
double y0 = 0.5 * (heighte - 1); // center of image
public static BufferedImage fbuffer;
public RendPanel(int width, int height) {
fbuffer = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
BufferedImage in = null;
try { in = ImageIO.read(new File("square.png")); } //32x32 square .png
catch (IOException e) { e.printStackTrace(); }
for (int i = 0; i < in.getWidth(); i++) {
for (int j = 0; j < in.getHeight(); j++) {
fbuffer.setRGB(i + (320 / 2) - 16, j + (240 / 2) - 16, in.getRGB(i, j));
}
}
BufferedImage neww = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < widthe; x++) {
for (int y = 0; y < heighte; y++) {
if(x >= x0 - 32 && x <= x0 + 32 && y >= y0 - 32 && y <= y0 + 32){
double a = x - x0;
double b = y - y0;
int xx = (int) (+a * cos - b * sin + x0);
int yy = (int) (+a * sin + b * cos + y0);
// plot pixel (x, y) the same color as (xx, yy) if it's in bounds
if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
neww.setRGB(xx, yy, fbuffer.getRGB(x, y));
}
}
}
}
fbuffer = neww;
repaint();
setPreferredSize(new Dimension(width, height));
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(fbuffer, 0, 0, null);
}
}
A beginner's mistake (sorry).
Taking every source pixel in turn, transforming the coordinates to the destination and copying the pixel value is not the right way.because the regular input grid will not map to a regular grid, and there will be voids (and overlaps).
The correct way is to scan the destination image (so that every destination pixel is reached) and counter-transform the coordinates to fetch the pixel value from the source.
As a refinement, you can use the four neighboring pixel from where you land in the source and perform bilinear interpolation, to reduce aliasing.
Man, it's strange, because in this code it works properly!
Heres a working code:
public class RendPanel extends JPanel {
private static final long serialVersionUID = 1L;
int widthe = 320;
int heighte = 240;
int ang = 0;
double x0 = 0.5 * (widthe - 1); // point to rotate about
double y0 = 0.5 * (heighte - 1); // center of image
public static BufferedImage fbuffer;
public RendPanel(int width, int height) {
fbuffer = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
BufferedImage in = null;
try { in = ImageIO.read(new File("square.png")); } //32x32 square .png
catch (IOException e) { e.printStackTrace(); }
for (int i = 0; i < in.getWidth(); i++) {
for (int j = 0; j < in.getHeight(); j++) {
fbuffer.setRGB(i + (320 / 2) - 16, j + (240 / 2) - 16, in.getRGB(i, j));
}
}
setPreferredSize(new Dimension(width, height));
}
BufferedImage neww;
public void r(){
neww = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
double angle = Math.toRadians(ang);
double sin = Math.sin(angle);
double cos = Math.cos(angle);
for (int x = 0; x < widthe; x++) {
for (int y = 0; y < heighte; y++) {
if(x >= x0 - 32 && x <= x0 + 32 && y >= y0 - 32 && y <= y0 + 32){
double a = x - x0;
double b = y - y0;
int xx = (int) (+a * cos - b * sin + x0);
int yy = (int) (+a * sin + b * cos + y0);
// plot pixel (x, y) the same color as (xx, yy) if it's in bounds
if (xx >= 0 && xx < widthe && yy >= 0 && yy < heighte) {
neww.setRGB(x, y, fbuffer.getRGB(xx, yy));
}
}
}
}
ang++;
repaint();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(neww, 0, 0, null);
}
}
Thanks for:
https://introcs.cs.princeton.edu/java/31datatype/Rotation.java.html
EDIT:
You have to invert the vars on bf2.setRGB(x, y, fbuffer.getRGB(xx, yy)); to the rotated coordinate.

How to draw bitmap image on top in arc

I want to draw image on Top in each Arc of Canvas
private void drawImage(Canvas canvas, float tempAngle, Bitmap bitmap,String mValue) {
//get every arc img width and angle
int imgWidth = (radius / mWheelItems.size());
//int imgWidth = (radius / 3);
float angle = (float) ((tempAngle + 360 / mWheelItems.size() /2) * Math.PI / 180);
//calculate x and y
int x = (int) (center + radius / 2 / 2 * Math.cos(angle));
int y = (int) (center + radius / 2 / 2 * Math.sin(angle));
int top=y - imgWidth/2;
int bottom=y +imgWidth/2;
int left=x - imgWidth /2;
int right=x + imgWidth / 2;
Rect rect = new Rect(left, top, right, bottom);
final Rect rect1 = new Rect(x - imgWidth /2 , y - imgWidth / 2 , bitmap.getWidth() , bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rect, null);
}
the Arc is made according to the size of items
The Result is shown like that
But I want the image bitmap shown on top like that of rect. Red also want to large size of images or bitmap
Solved by Specific Tab and Big Screen Tablets
Change the X and Y coordination According to Angle
if(tempAngle==0) {
x = x + 50;
}
if(tempAngle==60) {
y = y + 50;
}
if(tempAngle==120) {
imgWidth = imgWidth-12;
y = y + 20;
x = x - 40;
}
if(tempAngle==180) {
imgWidth = imgWidth+12;
x = x - 50;
}
if(tempAngle==240) {
y = y - 50;
}
if(tempAngle==300) {
y = y - 20;
x = x + 40;
}

Java SWT: Getting original X/Y Coordinates from Scaled Image

I have an image where
Height = 1300
Width = 1300
I scaled the image to:
ScaledHeight = 700
ScaledWidth = 700
I am using the following to get the original Coordinates:
public Coordinate GetScaledXYCoordinate(int oldX, int oldY, int width, int height, int scaledWidth, int scaledHeight)
{
int newX = (int)(oldX * width)/scaledWidth;
int newY = (int)(oldY * height)/scaledHeight;
Coordinate retXY = new Coordinate(newX, newY);
return retXY;
}
EDIT:
I have updated to include answer
With
int width = 1300;
int scaledWidth = 700;
the value of (width/scaledWidth) is 1 - you are doing integer arithmetic not floating point.
Use
int newX = (oldX * width) /scaledWidth;
int newY = (oldY * height) /scaledHeight;
to avoid this issue.

Draw line function

I want to create a drawLine function, however I am not able to use any graphics classes (I can set pixels though). I tried this method https://en.wikipedia.org/wiki/Bresenham's_line_algorithm#Method, but this only works when the line is going from top left to bottom right and not for example going from top right to bottom left. Does anyone have a way that does this? The current code I have:
public void drawLine(int startX, int startY, int endX, int endY) {
double deltaX = endX - startX;
double deltaY = endY - startY;
double error = -1;
double deltaError = Math.abs(deltaY / deltaX);
int y = startY;
for (int x = startX; x < endX - 1; x++) {
error += deltaError;
if (error >= 0) {
y++;
error--;
}
drawPixel(x, y);
}
}
Any help is appreciated.
I solved it. The end result is this.
public void drawLine(int startX, int startY, int endX, int endY) {
if (startX > endX && startY > endY) {
int startXCopy = startX;
startX = endX;
endX = startXCopy;
int startYCopy = startY;
startY = endY;
endY = startYCopy;
}
double deltaX = endX - startX;
double deltaY = endY - startY;
double error = -1;
double deltaError = Math.abs(deltaY / deltaX);
if (deltaX == 0) {
for (int y = startY; y < endY; y++)
drawPixel(startX, y);
}
if (deltaY == 0) {
for (int x = startX; x < endX; x++)
drawPixel(x, startY);
}
if (deltaX >= deltaY) {
int y = startY;
int yDirection = endY > startY ? 1 : -1;
for (int x = startX; x < endX - 1; x++) {
error += deltaError;
if (error >= 0) {
y += yDirection;
error--;
}
drawPixel(x, y);
}
} else if (deltaY > deltaX) {
int x = startX;
int xDirection = endX > startX ? 1 : -1;
for (int y = startY; y < endY - 1; y++) {
error += deltaError;
if (error >= 0) {
x += xDirection;
error--;
}
drawPixel(x, y);
}
}
}
To draw a line is a simple Math problem and can be achieved on different ways.
What you need is the basic linear euqation y = f(x) = mx + b
where m is your slope, defined as m=(y2−y1)/(x2−x1), bis your startY value and the x is expressed by x = x_i - startX where x_i is your current point on your line. Then you can compute all y-values for each x_i value on the line between your start point and your end point. The quantity of points depends on a resolution factor.
double slope = (double)(endY - startY) / (endX - startX);
//adjustable resolution factor
double resolution = 1;
double x = startX;
while (x <= endX) {
double y = slope * (x - startX) + startY;
drawPixel(x, y);
x += resolution;
}

Categories