How can I draw a line on the console if I have a 2D array of chars. The function I want to write is something like:
This is my first attempt, but it looks totally wrong
public static void line(char[][] mPixels, int startRow, int startColumn, int endRow, int endColumn)
{
double dY = endRow - startRow;
double dX = endColumn - startColumn;
double slope = dX / dY;
slope = Math.abs(slope);
if(slope >= 1)
{
double progress = -(dY / dX);
for(int i=startColumn; i<=endColumn; i++)
{
double j = startRow - (int) ((i-startColumn) * progress);
int yLoc = (int) (Math.round( j * 100.0 ) / 100.0);
mPixels[i][yLoc] = '*';
}
}
// print array
}
use DDA or Bresenham,...
What you have looks like DDA but you do not handle slopes correctly. You should divide by the axis with bigger amount of pixels and use it as control axis so:
if |dx|>|dy| then for goes through x = x0 -> x1 and y=y0+((x-x0)*dy/dx)
if |dx|<|dy| then for goes through y = y0 -> y1 and x=x0+((y-y0)*dx/dy)
if they are equal then use any of above.
if dx==0 and dy==0 draw just dot and no for is present
Do not forget to handle if main axis is ascending or descending (can be x++,y++ or x--,y--) also can be done on integer only without division or multiplication but that is another story
Related
What I'm trying to do is take 2 mouceclick input which gives me pixel coordinate x[0],y[0] and x[1],y[1]. Then I get a queue of array containing pixels coordinate of every pixel where the line joining these points would make. Don't need the line to be seen at all.
I decided to take the slope prospective such that 1 pixel change in x coordinate would change
(x[1]-x[0])]/(y[1]-y[0]) in y coordinate. I keep getting arithmetic error.
Edit: Used the DDA algorithm and still getting / by zero error even if all values is pre-asigned to something non-zero.
Queue<int[]> queue=new LinkedList<int[]>();
int dx = Math.abs(x[1] - x[0]);
int dy = Math.abs(y[1] - y[0]);
int sx = (x[0] < x[1]) ? 1 : -1;
int sy = (y[0] < y[1]) ? 1 : -1;
int err = dx / dy;
int[] tog= {x[0],y[0]};
queue.add(tog); //1st pixel into queue. nothing else
while(true) {
if (x[0] == x[1] && y[0] == y[1]) {
break;
}
int e2 = 2 * err;
if (e2 > -dy) {
err = err - dy;
x[0] = x[0] + sx;
}
if (e2 < dx) {
err = err + dx;
y[0] = y[0] + sy;
}
tog[0]= x[0];
tog[1]= y[0];
queue.add(tog);
}
System.out.println(queue);
Thanks to the comment on using DDA, the problem I got is now fixed. I have used the following code for the counting of the pixels and storing their coordinates.
I put this code inside the action listener for a mouse click.
private void counter() {//---------counter takes arguments x and y which are array that contain x1x2 and y1y2 coordinates of 1st and 2nd click
int dx = (x[1] - x[0]);
int dy = (y[1] - y[0]);//---------makes it applicable for both inclinations (if we add up there a math.abs it would work on only the positive inclination line )
step = Math.abs(dx) > Math.abs(dy) ? Math.abs(dx) : Math.abs(dy);
//------counts howmany pixels are to be recorded
float Xinc = dx / (float) step;//----slope change with respect to x axis
float Yinc = dy / (float) step;//----slope change with respect to y axis
tog= new int[step][3];
tog[0][0]=x[0]; tog[0][1]=y[0];
tog[0][2]= (black[0]!=0) ? 1 : 0;//------------Tertiary operator where the condition is true, then while is true
//---------------------------------------------------------------send value of x1 and y1 to listOfCoordinates
float xt=x[0],yt=y[0]; int i=0, j=1;
//-------------to get all the coordinates between the 2 points1111
System.out.println(tog[0][0]+" "+tog[0][1]+" "+tog[0][2]);
while (j<step){
if(i==2) i=0;
xt += Xinc;
yt += Yinc;
tog[j][i] = (int)xt;//------tog is the array where you store the coordinates of each pixel that overlaps the line made if the clicked points are connected
tog[j][i+1] = (int)yt;
j++;
}
//-------print tog here to see if it has the coordinates or not for check
}
I have a program that generates a .ppm file with a bunch of black dots on it. What I want to do is to draw lines between these dots to build a graph, but instead of using some swing method I want to know if there is a way to do it by directly manipulating the .ppm's matrix.
I assume it would require some nested loops, but how would I identify which positions I need to change to create the line between two dots?
(for those who don't know, a .ppm file is basically a giant matrix with 3 RGB values for each of it's positions, allowing you to draw stuff pixel by pixel)
Single pixel thickness:
void drawline(Color pixels[][], int width, int height,
int x1, int x2, int y1, int y2, Color line)
{
int dx = x1 - x2;
int dy = y1 - y2;
if (dx != 0 || dy != 0)
{
int n = Math.Max(Math.Abs(dx), Math.Abs(dy));
double inv = 1.0 / (double)(n + 1);
double dxdn = (double)dx * inv;
double dydn = (double)dy * inv;
double x = (double)x1, y = (double)y1;
for (int i = 0; i <= n; i++)
{
int xi = (int)x, yi = (int)y;
if (xi >= 0 || xi < width || yi >= 0 || yi < height)
pixels[yi][xi] = line;
x += dxdn; y += dydn;
}
}
}
(NB this is in C# syntax; you may need minor changes to convert it to Java)
I'm looking to draw a wave. I have this so far:
private void drawWave(int yPos, int xPos, int colour, int length, int amplitude, int alpha) {
int pixelY, pixelX;
for(int i = 0; i < length; i++) {
pixelX = xPos + i;
pixelY = (int) (yPos - Math.sin(Math.toRadians(i)) * amplitude);
Rasterizer2D.drawAlphaPixel(colour, pixelY, 1, 1, alpha, pixelX);
}
}
This draws a wave but I cannot specify a wavelength to use, wasn't so sure how I could do that. Thanks a lot everyone.
To modify the wave length, you could use this formula
F (x) = a * sin ( (1/b)*x )
Where a is amplitude, b is wavelength.
Looking at your code, you have amplitude in there. You just need a new parameter to specify b.
Add an argument like float wavelength and change
pixelY = (int) (yPos - Math.sin( 2.0 * Math.pi * Math.toRadians(i) / wavelength) * amplitude);
You have
y(i) = y0 - A sin(i)
My equation gives you
y = y0 - A sin (2 pi i / L)
where L is the wavelength.
Now, this still may not do what you want. It depends on what you want xPos and yPos to represent. Do you want xPos to give you a phase shift? If so, then you need to include it in your expression for pixelY.
This is a homework assignment.
Work 19 5/16 is the assignment
http://sites.stuycs.org/home/courses/ml2x/dyrland-weaver/work
I am running this in the program processing, which does not require main methods.
Blob was given to us. We had to make BlobRunner on our own.
Any advice on why my code isn't doing what its supposed to would be appreciated.
FIRST FILE BlobRunner
int popSize = 4;
int wobble = 2;
int numSides = 4;
float rad = 100;
int radInt = (int) rad;
float a = sqrt(popSize);
int rootPop = (int) a;
Blob[][] blobs = new Blob[popSize/rootPop][rootPop];
/*=====================================
The trickiest part of setup is to make
the screen an appropriate size for the
grid of blobs. The grid should be just
big enough to contain all of the blobs.
====================================*/
void setup() {
size ((popSize/rootPop)*(2*(radInt+3)), rootPop*(2*(radInt+3)));
populate();
}
/*=====================================
The main purpose of draw is to go through
the array of blobs and display each.
====================================*/
void draw() {
int createdSoFar = 0;
for (int i = 0; i<rootPop; i++){
for (int j = 0; j<popSize/rootPop; j++){
if (createdSoFar < popSize){
blobs[j][i].display();
}
createdSoFar++;
}
}
}
/*=====================================
Populate the array of blobs.
You can use any values for radius, number of sides
and wobble factor that you'd like, but you must
use x and y coordinates that ensure the blobs
are drawn in a grid without overlaping each other.
Your code should work for any reasonable value
of population (i.e. something that would fit on a
normal monitor).
====================================*/
void populate() {
for (int i = 0; i < rootPop; i++){
float y = 1;
for (int j = 0; j < (popSize/rootPop); j++){
float x = 1;
blobs[j][i] = new Blob (x*(rad+3), y*(rad+3), numSides, radInt, wobble, wobble);
x=x+2;}
y=y+2;}
}
SECOND FILE Blob
/*=====================================
A Blob object is a regular polygon variant that
can have various features.
Instance Variables:
numSides: number of sides
rad: distance from the center of the polygon
to any vertext
x: x coordinate of the center
y: y coordinate of the center
xFactor: "wobble" foctor in the x direction
yFactor: "wobble" factor in the y direction
====================================*/
class Blob {
int numSides;
int rad;
float x;
float y;
int xFactor;
int yFactor;
Blob(float cx, float cy, int sides, int r, int xf, int yf ) {
x = cx;
y = cy;
numSides = sides;
rad = r;
xFactor = xf;
yFactor = yf;
}
void display() {
float nx;
float ny;
int rx, ry;
float sy;
strokeWeight(1);
beginShape();
for( float t = 0; t <= 1; t+=( 1.0/numSides ) ) {
/*
"wobble" effect is created by adding a random number to each
x and y coordinate. The larger the x and y factors, the higher
the possible wobble value could be
*/
rx = (int)random(xFactor);
ry = (int)random(yFactor);
nx = rad * cos( 2 * PI * t ) + x + rx;
ny = rad * sin( 2 * PI * t ) + y + ry;
vertex(nx, ny);
}
endShape();
}
}
Your code runs, thus it is doing what you asked it to do and nothing more.
I asked my cat to check it out though and she was all, "the guy is re-initializing his variables inside each pass of the loop, he'll never get a grid of blobs that way. Tell him to start by moving float y = 1; float x = 1; in populate() outside of the bounds of the two for loops and start debugging from there."
Then she rolled over on to her side and I patted her.
I'm trying to move a sprite across the screen in a straight line, towards on the location where've I touched the screen, what i did was upon the update() in each loop , it checks to see if the current sprite's location x y is == to the destination x ,y . if it hasn't sprite's x++ and y++...
the thing is ..it ain't moving in a straight line... as there are cases where the x or y coordinate reaches the destination x or y first... how do i changed it so that the both x and y meets the destination together?
my current pseudo code for the sprite object
destX = destination X
destY = destination Y
posX = current X
posY = current Y
public void update(){
if(destX > posX && destY < posY)
{
posX++;
posY--;
}
else if (destX > posX && destY > posY){
posX++;
posY++;
}
else if(destX < posX && destY > posY)
{
posX--;
posY++;
}
else if(destX < posX && destY < posY){
posX--;
posY--;
}
else if(destX < posX)
posX--;
else if(destX > posX)
posX++;
else if(destY < posY)
posY--;
else if(destY > posY)
posY++;
Check out: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
This simple algorithm will tell you each X,Y coordinate on a line between two points. You could use this algorithm to compute all of the positions it needs to visit, store the coordinates in an array, and iterate over the array as you update the position.
From the Article:
function line(x0, x1, y0, y1)
int deltax := x1 - x0
int deltay := y1 - y0
real error := 0
real deltaerr := abs (deltay / deltax) // Assume deltax != 0 (line is not vertical),
// note that this division needs to be done in a way that preserves the fractional part
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if error ≥ 0.5 then
y := y + 1
error := error - 1.0
This is the most primitive version. The article contains a better generalized algorithm that you should look at.
I am dealing with a similair problem as yours. (I have an arraylist holding the history of positions my player has gone and I want to use that to rewind the game.)
Instead of simply increasing x and y position with 1 you can:
Calculate the angle between the source postion and your destination
position.
Calculate the new direction using a variable which
represents the speed
Update your postion using calculated direction
I made a class of that. I hope it is usefull.
import java.awt.geom.Point2D;
public class MyVelocityCalculator {
public static void main(String[] args) {
Point2D.Double currentPosition = new Point2D.Double();
Point2D.Double destinationPosition = new Point2D.Double();
currentPosition.setLocation(100, 100);
destinationPosition.setLocation(50, 50);
Double speed = 0.5;
Point2D.Double nextPosition = MyVelocityCalculator.getVelocity(currentPosition, destinationPosition, speed);
System.out.println("player was initially at: "+currentPosition);
System.out.println("player destination is at: "+destinationPosition);
System.out.println("half seconds later player should be at: "+nextPosition);
}
public static final Point2D.Double getVelocity(Point2D.Double currentPosition, Point2D.Double destinationPosition, double speed){
Point2D.Double nextPosition = new Point2D.Double();
double angle = calcAngleBetweenPoints(currentPosition, destinationPosition);
double distance = speed;
Point2D.Double velocityPoint = getVelocity(angle, distance);
nextPosition.x = currentPosition.x + velocityPoint.x;
nextPosition.y = currentPosition.y + velocityPoint.y;
return nextPosition;
}
public static final double calcAngleBetweenPoints(Point2D.Double p1, Point2D.Double p2)
{
return Math.toDegrees( Math.atan2( p2.getY()-p1.getY(), p2.getX()-p1.getX() ) );
}
public static final Point2D.Double getVelocity(double angle, double speed){
double x = Math.cos(Math.toRadians(angle))*speed;
double y = Math.sin(Math.toRadians(angle))*speed;
return (new Point2D.Double(x, y));
}
}
Don't use integers. This is a very bad idea to work with ints. Use floats. The main concept is: define the number of steps you want to perform (s). Compute differences in X and Y (diffX and diffY). Don't take absolute values: Compute them this way
float diffX = destX - currentX;
Then compute the xMove and yMove values by dividing diffX and diffY by s (number of steps).
float moveX = diffX / s;
float moveY = diffY / s;
And now you have to add for each iteration the moveX and moveY values to the current position.
And for drawing it, you should use Graphics2D, which supports floating points. If you don't want to use Graphics2D, you can round the floats to ints, using Math.round(float).