I am trying to implement DDA algorithm in Java to draw a line. The Line Rasterizer implements an interface. Then I call the rasterizeLine function in class named Canva. The LineRasterizes successfully gets x and y points. No errors are thrown up, however there has to be some logical problem with the algorithm, because the line is not being drawed. Can you help me find the logical mistake?
Interface
package rasterops;
import rasterdata.RasterImage;
public interface LineRasterizer<PixelType> {
RasterImage<PixelType> rasterizeLine(RasterImage<PixelType> img,
double x1, double y1, double x2, double y2,
PixelType value);
}
Line Rasterizer
package rasterops;
import rasterdata.RasterImage;
public class LineRasterizerDDA<PixelType> implements LineRasterizer <PixelType> {
#Override
public RasterImage<PixelType> rasterizeLine(RasterImage<PixelType> img, double x1, double y1, double x2, double y2, PixelType value) {
double dy = y2-y1;
double dx = x2-x1;
double k = dy/dx;
double y = y1;
RasterImage<PixelType> result = img;
for( double x = x1; x <= x2; x++ ){
result = result.withPixel((int)x, (int)Math.round(y), value);
y = y1 + k;
}
return result;
}
}
Canva - calling the function
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
previousX = e.getX();
previousY = e.getY();
}
});
panel.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
final double startX = previousX / (panel.getWidth() - 1.0); //k zamysleni: proc 1.0 a ne 1?
final double startY = 1 - previousY / (panel.getHeight() - 1.0);
final double endX = e.getX() / (panel.getWidth() - 1.0);
final double endY = 1 - e.getY() / (panel.getHeight() - 1.0);
clear(); // zkuste zakomentovat
rasterImage = liner.rasterizeLine(rasterImage,
startX, startY, endX, endY,
0xffff00);
panel.repaint();
}
});
This line:
y = y1 + k;
keeps assigning the same value to y, because y1 and k aren't changing.
Example output, drawing line between (0,0) and (10, 10):
O..........
.OOOOOOOOOO
...........
...........
...........
...........
...........
...........
...........
...........
...........
You may mean:
y = y + k;
or y += k;.
Example output, drawing line between (0,0) and (10, 10):
O..........
.O.........
..O........
...O.......
....O......
.....O.....
......O....
.......O...
........O..
.........O.
..........O
Related
i was wondering how can I edit this DDA.
When I have this values: (x1 = 150,y1 = 20,x2 = 100,y2 = 80) it works perfectly fine, because it is in first quadrant.
But if I want to rasterize line from another qudrant
for example with value of (x1 = 10,y1 = 20,x2 = 100,y2 = 80)
this will make just straight line
So I'm having trouble with editing this algorithm to all 4 quadrants.
public void rasterize(int x1, int y1, int x2, int y2, int color) {
int x, y, krok;
float dy, dx;
dx = x2 - x1;
dy = y2 - y1;
if(Math.abs(dx)>Math.abs(dy)){
krok=(int)(Math.abs(dx));
} else {
krok=(int)(Math.abs(dy));
}
dx = dx / (float)krok;
dy = dy/ (float)krok;
x=x1;
y=y1;
for(int i=1;i<=krok;i++){
raster.setPixel(x, y, 0xffff00);
x+=dx;
y+=dy;
}
}
I really have no idea why the x and y values wont go to the drawLines function
float x, x1, x2;
float y, y1, y2;
float rad; //radius
int lines = 30; //number of lines
int colorNumber = 1;
void setup() {
background(#FFFFFF);
size (800, 600);
rad = 8;
}
void draw() {
}
This creates the three dots or vertices of the mathematical envelope
void mouseClicked() {
float x = mouseX;
float x1 = mouseX;
float x2 = mouseX;
float y = mouseY;
float y1 = mouseY;
float y2 = mouseY;
if (colorNumber == 1) {
fill(#9393ff);
ellipse(x, y, rad, rad);
} else if (colorNumber == 2) {
fill(#FF9393);
ellipse(x1, y1, rad, rad);
} else if (colorNumber == 3) {
fill(#93ff93);
ellipse(x2, y2, rad, rad);
}
}
This is supposed to draw the envelope using the coordinates of the vertices
void drawLines(int numLines) {
for (int i = 0; i < numLines; i = i + 1) {
float x = mouseX;
float x1 = mouseX;
float x2 = mouseX;
float y = mouseY;
float y1 = mouseY;
float y2 = mouseY;
float t = (float) i/(numLines-1);
float startX = x + t * (x1 - x);
float startY = y + t * (y1 - y);
float endX = x1 + t * (x2 - x1);
float endY = y1 + t * (y2 - y1);
line (startX, startY, endX, endY);
}
}
void mouseReleased() {
colorNumber++;
if (colorNumber == 4) {
colorNumber = 1;
}
println(colorNumber);
}
void keyPressed() {
if (keyPressed == true) {
background(#FFFFFF);
}
}
this last stuff just tells the code if you press a key, it will reset the backround
I understand your intention with using mouseX and mouseY to specify the coordinates of one of the 3 points of the envelope on click. The current issue is that all 3 points are being set to the same coordinate with each click. You need to introduce a variable to keep track of which coordinate to set on-click, such that only one pair is set. Then, only once all 3 coordinates are set, drawLines() can be called.
I propose the following:
Introduce 2 variables, one to keep track of which point is being modified; the other an array of PVectors (just to make it cleaner).
int index = 0;
PVector[] coords = new PVector[3];
Modify mouseClicked() to include the following:
void mouseClicked() {
ellipse(mouseX, mouseY, 8, 8);
coords[index] = new PVector(mouseX, mouseY);
index += 1;
if (index == 3) {
drawLines(lines);
}
index %= 3;
}
drawLines() becomes:
void drawLines(int numLines) {
for (int i = 0; i < numLines; i = i + 1) {
x = coords[0].x;
x1 = coords[1].x;
x2 = coords[2].x;
y = coords[0].y;
y1 = coords[1].y;
y2 = coords[2].y;
float t = (float) i / (numLines - 1);
float startX = x + t * (x1 - x);
float startY = y + t * (y1 - y);
float endX = x1 + t * (x2 - x1);
float endY = y1 + t * (y2 - y1);
line(startX, startY, endX, endY);
}
}
Finally, since your drawing on a black background, and the default stroke colour is black, use strokeColour() to change the colour of the lines so that you can see the envelope once its drawn.
I have tried to follow the Wikipedia page on 3d projection to draw my own 3d line using java and AWT with Swing.
The output file that is created as a result of the rendering doesn't contain anything.
What have I done wrong?
Why isn't this producing an image file that has points on it?
Are my formulas off?
I was following this Wikipedia page as my reference: https://en.wikipedia.org/wiki/3D_projection#Perspective_projection
I have a set of points which are generated using a loop.
I then calculate the position of the 3d coordinate to 2d without using matrices, like one of the suggested method in the link.
Have I miss-interpreted something or not implemented something?
Any help and feedback are welcome.
I known nothing is drawn to the window. That isn't a priority at the moment. The priority it's getting the algorithms to work.
public class Window {
JFrame f = new JFrame();
public Window() {
JPanel p = new JPanel();
render();
f.add(p);
f.setSize(500, 500);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
Window w = new Window();
}
void render() {
BufferedImage image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(Color.red);
for (int i = 0; i < 10; i++) {
Vector3 point = new Vector3(1 + i, 2, 1 + i);
int x = calculateBX(point, new Vector3(0, 0, 0));
int y = calculateBY(point, new Vector3(1, 1, 1));
g.drawLine(x, y, x, y);
}
try {
File outputfile = new File("saved.png");
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
e.printStackTrace();
}
}
double calculatDX(Vector3 v, Vector3 camera) {
double cx = Math.cos(0);
double cy = Math.cos(0);
double cz = Math.cos(0);
double sx = Math.sin(0);
double sy = Math.sin(0);
double sz = Math.sin(0);
int x = v.getX() - camera.getX();
int y = v.getY() - camera.getY();
int z = v.getZ() - camera.getZ();
double dx = cy * ((sz) * (y) + (cz) * (x)) - (sy) * (z);
return dx;
}
double calculatDY(Vector3 v, Vector3 camera) {
double cx = Math.cos(0);
double cy = Math.cos(0);
double cz = Math.cos(0);
double sx = Math.sin(0);
double sy = Math.sin(0);
double sz = Math.sin(0);
int x = v.getX() - camera.getX();
int y = v.getY() - camera.getY();
int z = v.getZ() - camera.getZ();
double dy = sx * ((cy) * (z) + (sy) * ((sz) * (y) + (cz) * (x))) + (cx) * (cz * (y) - sz * x);
return dy;
}
double calculatDZ(Vector3 v, Vector3 camera) {
double cx = Math.cos(0);
double cy = Math.cos(0);
double cz = Math.cos(0);
double sx = Math.sin(0);
double sy = Math.sin(0);
double sz = Math.sin(0);
int x = v.getX() - camera.getX();
int y = v.getY() - camera.getY();
int z = v.getZ() - camera.getZ();
double dz = cx * ((cy) * (z) + (sy) * ((sz) * (y) + (cz) * (x))) - (sx) * (cz * (y) - sz * x);
return dz;
}
int calculateBX(Vector3 v, Vector3 camera) {
int ez = camera.getZ();
int ex = camera.getX();
double dz = calculatDZ(v, camera);
double dx = calculatDX(v, camera);
return (int) ((ez / dz) * dx) - ex;
}
int calculateBY(Vector3 v, Vector3 camera) {
int ez = camera.getZ();
int ey = camera.getY();
double dz = calculatDZ(v, camera);
double dy = calculatDY(v, camera);
return (int) ((ez / dz) * dy) - ey;
}
}
Vector Class
public class Vector3 {
private int x, y, z;
public Vector3(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
}
I need to create a GUI for a game and I will need to display on the screen the weapon and the shield. I need to modify the program so it displays the weapon and shield, however their properties are in another class. I know I will have to extend the JPanel class and overrite its paintComponent() method.
public class GraphicsUtil {
private static final int MUZZLE_FRACTION = 3;
private static final Color MUZZLE_COLOR = Color.MAGENTA;
public static void drawShield(IShield shield, Graphics g, GameSpace gameSpace, double origHealth) {
drawPiece(shield, g, gameSpace, origHealth);
}
public static void drawWeapon(IWeapon weapon, Graphics g,
GameSpace gameSpace, double origHealth) {
Color oldColor = g.getColor();
drawPiece(weapon, g, gameSpace, origHealth);
double orientation = weapon.getOrientation();
int x1 = gameSpace.convertToScreenX(weapon.getXPos());
int y1 = gameSpace.convertToScreenY(weapon.getYPos());
int radius = gameSpace.convertToScreenDistance(weapon.getRadius());
int x2 = gameSpace.convertToScreenX(weapon.getXPos()
+ weapon.getRadius() * Math.cos(weapon.getOrientation()));
int y2 = gameSpace.convertToScreenY(weapon.getYPos()
+ weapon.getRadius() * Math.sin(weapon.getOrientation()));
double frac = 1 - 1f / MUZZLE_FRACTION;
int muzzleCentreX
= x1 + (int) Math.round(frac * radius * Math.cos(orientation));
int muzzleCentreY
= y1 - (int) Math.round(frac * radius * Math.sin(orientation));
int muzzleRadius = radius / MUZZLE_FRACTION;
int topMuzzleX = muzzleCentreX - muzzleRadius;
int topMuzzleY = muzzleCentreY - muzzleRadius;
g.setColor(MUZZLE_COLOR);
g.fillOval(topMuzzleX, topMuzzleY, 2 * muzzleRadius, 2 * muzzleRadius);
g.setColor(Color.BLACK);
g.drawLine(x1, y1, x2, y2);
g.setColor(oldColor);
}
public static boolean isInMuzzle(IPiece piece, double x, double y) {
boolean result;
if (piece instanceof IWeapon) {
IWeapon weapon = (IWeapon) piece;
double radius = weapon.getRadius();
double orientation = weapon.getOrientation();
double frac = 1 - 1f / MUZZLE_FRACTION;
double cx = piece.getXPos() + frac * radius * Math.cos(orientation);
double cy = piece.getYPos() + frac * radius * Math.sin(orientation);
double dx = x - cx;
double dy = y - cy;
double dist = Math.sqrt(dx * dx + dy * dy);
result = dist <= radius / MUZZLE_FRACTION;
} else {
result = false;
}
return result;
}
public static double getAngle(double x1, double y1, double x2, double y2) {
double dx = x2 - x1;
double dy = y2 - y1;
double hypotenuse = Math.sqrt(dx * dx + dy * dy);
double angle;
if (dy > 0) {
angle = Math.acos(dx / hypotenuse);
} else {
angle = 2 * Math.PI - Math.acos(dx / hypotenuse);
}
return angle;
}
private static void drawPiece(IPiece piece, Graphics g, GameSpace gameSpace,
double maxHealth) {
Color oldColor = g.getColor();
int centreX = gameSpace.convertToScreenX(piece.getXPos());
int centreY = gameSpace.convertToScreenY(piece.getYPos());
int displayRadius = gameSpace.convertToScreenDistance(piece.getRadius());
int topX = centreX - displayRadius;
int topY = centreY - displayRadius;
if (piece.getOwner() == 0) {
g.setColor(Color.CYAN);
} else {
g.setColor(Color.PINK);
}
g.drawOval(topX, topY, 2 * displayRadius, 2 * displayRadius);
int healthRadius
= (int) Math.round(displayRadius * piece.getHealth() / maxHealth);
int topHealthX = centreX - healthRadius;
int topHealthY = centreY - healthRadius;
g.fillOval(topHealthX, topHealthY, 2 * healthRadius, 2 * healthRadius);
String name = piece.getName();
if (name != null) {
g.setColor(Color.BLACK);
g.drawString(name, centreX, centreY);
}
g.setColor(oldColor);
}
}
This is my main method:
public class Main extends JPanel {
public Main(){
setSize(new Dimension(400,400));
setPreferredSize(new Dimension(400,400));
GraphicsUtil object = new GraphicsUtil();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
}
public static void main(String[] args) {
Main window = new Main();
JFrame frame = new JFrame("RICOCHET");
frame.add(window);
frame.pack();
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
How do I call those methods? What do I need to do in order to they appear in my frame? Thanks.
Presumably you have created one or more weapons or pieces. In your paintComponent() method, just call
GraphicsUtil.drawWeapon( myWeapon, g, ... );
I'm trying to draw Sierpinski's Triangle recursively in Java, but it doesn't work, though to me the logic seems fine. The base case is when the triangles are within 2 pixels of each other, hence the use of the Distance Formula.
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Font;
import java.awt.Canvas;
public class Triangle extends Canvas implements Runnable
{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
public Triangle()
{
setBackground(Color.WHITE);
}
public void paint( Graphics window )
{
window.setColor(Color.BLUE);
window.setFont(new Font("ARIAL",Font.BOLD,24));
window.drawString("Serpinski's Gasket", 25, 50);
triangle(window, (WIDTH-10)/2, 20, WIDTH-40, HEIGHT-20, 40, HEIGHT-20, 4);
}
public void triangle(Graphics window, int x1, int y1, int x2, int y2, int x3, int y3, int r)
{
//if statement base case
//midpoint = (x1 + x2 / 2), (y1 + y2/ 2)
if(Math.sqrt((double)(Math.pow(x2-x1, 2)) + (double)(Math.pow(y2-y1, 2))) > 2)
//if(r==0)
{
window.drawLine(x1, y1, x2, y2);
window.drawLine(x2, y2, x3, y3);
window.drawLine(x3, y3, x1, y1);
}
int xa, ya, xb, yb, xc, yc; // make 3 new triangles by connecting the midpoints of
xa = (x1 + x2) / 2; //. the previous triangle
ya = (y1 + y2) / 2;
xb = (x1 + x3) / 2;
yb = (y1 + y3) / 2;
xc = (x2 + x3) / 2;
yc = (y2 + y3) / 2;
triangle(window, x1, y1, xa, ya, xb, yb, r-1); // recursively call the function using the 3 triangles
triangle(window, xa, ya, x2, y2, xc, yc, r-1);
triangle(window, xb, yb, xc, yc, x3, y3, r-1);
}
public void run()
{
try{
Thread.currentThread().sleep(3);
}
catch(Exception e)
{
}
}
}
The Runner is
import javax.swing.JFrame;
public class FractalRunner extends JFrame
{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
public FractalRunner()
{
super("Fractal Runner");
setSize(WIDTH+40,HEIGHT+40);
getContentPane().add(new Triangle());
setVisible(true);
}
public static void main( String args[] )
{
FractalRunner run = new FractalRunner();
}
}
To me this should work but it causes a runtime/StackOverFlow error that I don't know how to correct. Any help?
You need to move the recursive calls to triangle, and the associated math, inside the conditional check on the separation. Right now, it will always call it and therefore you get the stack overflow.
Chances are your base case might not be working properly- what if the distance between two triangles is never two pixels? say we star with y1 and x1 being 0 and 200. their midpoint would be 100, then 50, 25, 12, 6, 3, 1<--- never hits the 2 pixel base case...
"StdDraw" was taken from here:
public class Sierpinski {
public static void sierpinski(int n) {
sierpinski(n, 0, 0, 1);
}
public static void sierpinski(int n, double x, double y, double size) {
if (n == 0) return;
//compute triangle points
double x0 = x;
double y0 = y;
double x1 = x0 + size;
double y1 = y0;
double x2 = x0 + size / 2;
double y2 = y0 + (Math.sqrt(3)) * size / 2;
// draw the triangle
StdDraw.line(x0, y0, x1, y1);
StdDraw.line(x0, y0, x2, y2);
StdDraw.line(x1, y1, x2, y2);
StdDraw.show(100);
//recursive calls
sierpinski(n-1, x0, y0, size / 2);
sierpinski(n-1, (x0 + x1) / 2, (y0 + y1) / 2, size / 2);
sierpinski(n-1, (x0 + x2) / 2, (y0 + y2) / 2, size / 2);
}
// read in a command-line argument n and plot an order Sierpinski Triangle
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
StdDraw.setPenRadius(0.005);
sierpinski(n);
}
}
Guy