import java.awt.*;
import java.awt.image.*;

public class Raster {
    protected int width, height;
    protected int pixel[];

    ///////////////////////// Constructors //////////////////////

    /**
     *  This constructor, which takes no arguments,
     *  allows for future extension.
     */
    public Raster()
    {
    }

    /**
     *  This constructor creates an uninitialized
     *  Raster Object of a given size (w x h).
     */
    public Raster(int w, int h)
    {
        width = w;
        height = h;
        pixel = new int[w*h];
    }

    /**
     *  This constructor creates an Raster initialized
     *  with the contents of an image.
     */
    public Raster(Image img)
    {
        try {
            PixelGrabber grabber = new PixelGrabber(img, 0, 0, -1, -1, true);
            if (grabber.grabPixels()) {
                width = grabber.getWidth();
                height = grabber.getHeight();
                pixel = (int []) grabber.getPixels();
            }
        } catch (InterruptedException e) {
        }
    }

    ////////////////////////// Methods //////////////////////////

    /**
     *  Returns the number of pixels in the Raster
     */
    public final int size( )
    {
        return pixel.length;
    }

    /**
     *  Fills a Raster with a solid color
     */
    public final void fill(Color c)
    {
        int s = size();
        int rgb = c.getRGB();
        for (int i = 0; i < s; i++)
            pixel[i] = rgb;
    }

    /**
     *  Converts Rasters to Images
     */
    public final Image toImage(Component root)
    {
        return root.createImage(new MemoryImageSource(width, height, pixel, 0, width));
    }

    /**
     *  Gets a pixel from a Raster
     */
    public final int getPixel(int x, int y)
    {
        return pixel[y*width+x];
    }

    /**
     *  Gets a color from a Raster
     */
    public final Color getColor(int x, int y)
    {
        return new Color(pixel[y*width+x]);
    }

    /**
     *  Sets a pixel to a given value
     */
    public  boolean setPixel(int pix, int x, int y)
    {
        pixel[y*width+x] = pix;
        return true;
    }

    /**
     *  Sets a pixel to a given color
     */
    public  boolean setColor(Color c, int x, int y)
    {
        pixel[y*width+x] = c.getRGB();
        return true;
    }
    
    
//	----	Different methods to draw a line	---------------------------
//	-----------------------------------------------------------------------    
    /**
     *  Simple and defficient algo to draw a line
     */
    public void lineSimple(int x0, int y0, int x1, int y1, Color color) {
		int pix = color.getRGB();
		int dx = x1 - x0;
		int dy = y1 - y0;
		setPixel(pix, x0, y0);
		if (dx != 0) {
			float m = (float) dy / (float) dx;
			float b = y0 - m*x0;
			dx = (x1 > x0) ? 1 : -1;
			while (x0 != x1) {
				x0 += dx;
				y0 = Math.round(m*x0 + b);
				setPixel(pix, x0, y0);
			}
		}
	}
    public void lineSimple(Point P0, Point P1, Color color) {
		lineSimple(P0.x, P0.y, P1.x, P1.y, color);
	}
	
    /**
     *  Corrected (symetrie) simple algo to draw a ligne
     */
	public void lineImproved(int x0, int y0, int x1, int y1, Color color)          {
		int pix = color.getRGB();
		int dx = x1 - x0;
		int dy = y1 - y0;
		setPixel(pix, x0, y0);
		if (Math.abs(dx) > Math.abs(dy)) { // slope < 1
			float m = (float) dy / (float) dx; // compute slope
			float b = y0 - m*x0;
			dx = (dx < 0) ? -1 : 1;
	
			while (x0 != x1) {
				x0 += dx;
				setPixel(pix, x0, Math.round(m*x0 + b));
			}
		} else	if (dy != 0) { // slope >= 1
			float m = (float) dx / (float) dy; // compute slope
			float b = x0 - m*y0;
			dy = (dy < 0) ? -1 : 1;
			while (y0 != y1) {
				y0 += dy;
				setPixel(pix, Math.round(m*y0 + b), y0);
			}
		}
	}

    public void lineImproved(Point P0, Point P1, Color color) {
		lineImproved(P0.x, P0.y, P1.x, P1.y, color);
	}
	
	public void lineDDA(int x0, int y0, int x1, int y1, Color color) {
		int pix = color.getRGB();
		int dy = y1 - y0;
		int dx = x1 - x0;
		float t = (float) 0.5; // offset for rounding
		setPixel(pix, x0, y0);
		
		if (Math.abs(dx) > Math.abs(dy)) { // slope < 1
			float m = (float) dy / (float) dx; // compute slope
			t += y0;
			dx = (dx < 0) ? -1 : 1;
			m *= dx;
			while (x0 != x1) {
				x0 += dx; // step to next x value
				t += m; // add slope to y value
				setPixel(pix, x0, (int) t);
			}
		} else { // slope >= 1
			float m = (float) dx / (float) dy; // compute slope
			t += x0;
			dy = (dy < 0) ? -1 : 1;
			m *= dy;
			while (y0 != y1) {
				y0 += dy; // step to next y value
				t += m; // add slope to x value
				setPixel(pix, (int) t, y0);
			}
		}
	}

    public void lineDDA(Point P0, Point P1, Color color) {
		lineDDA(P0.x, P0.y, P1.x, P1.y, color);
	}

	public void lineBresenham(int x0, int y0, int x1, int y1, Color color) {
		int pix = color.getRGB();
		int dy = y1 - y0;
		int dx = x1 - x0;
		int stepx, stepy;
		if (dy < 0) { dy = -dy; stepy = -1; 
		} else { stepy = 1; 
		}
		if (dx < 0) { dx = -dx; stepx = -1; 
		} else { stepx = 1; 
		}
		dy <<= 1; 							// dy is now 2*dy
		dx <<= 1; 							// dx is now 2*dx
	 
		setPixel(pix, x0, y0);
	
		if (dx > dy) {
			int fraction = dy - (dx >> 1);	// same as 2*dy - dx
			while (x0 != x1) {
				if (fraction >= 0) {
					y0 += stepy;
					fraction -= dx; 		// same as fraction -= 2*dx
				}
			x0 += stepx;
			fraction += dy; 				// same as fraction -= 2*dy
			setPixel(pix, x0, y0);
			}
		} else {
			int fraction = dx - (dy >> 1);
			while (y0 != y1) {
				if (fraction >= 0) {
					x0 += stepx;
					fraction -= dy;
				}
			y0 += stepy;
			fraction += dx;
			setPixel(pix, x0, y0);
			}
		}
	} 
    public void lineBresenham(Point P0, Point P1, Color color) {
		lineBresenham(P0.x, P0.y, P1.x, P1.y, color);
	}

 public void lineTwoStep(int x0, int y0, int x1, int y1, Color color) {
        int pix = color.getRGB();
        int dy = y1 - y0;
        int dx = x1 - x0;
        int stepx, stepy;

        if (dy < 0) { dy = -dy;  stepy = -1; } else { stepy = 1; }
        if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }

        setPixel(pix, x0, y0);
        setPixel(pix, x1, y1);
        if (dx > dy) {
            int length = (dx - 1) >> 2;
            int extras = (dx - 1) & 3;
            int incr2 = (dy << 2) - (dx << 1);
            if (incr2 < 0) {
                int c = dy << 1;
                int incr1 = c << 1;
                int d =  incr1 - dx;
                for (int i = 0; i < length; i++) {
                    x0 += stepx;
                    x1 -= stepx;
                    if (d < 0) {                                               // Pattern:
                        setPixel(pix, x0, y0);                          //
                        setPixel(pix, x0 += stepx, y0);                 //  x o o
                        setPixel(pix, x1, y1);                          //
                        setPixel(pix, x1 -= stepx, y1);
                        d += incr1;
                    } else {
                        if (d < c) {                                           // Pattern:
                            setPixel(pix, x0, y0);                      //      o
                            setPixel(pix, x0 += stepx, y0 += stepy);    //  x o
                            setPixel(pix, x1, y1);                      //
                            setPixel(pix, x1 -= stepx, y1 -= stepy);
                        } else {
                            setPixel(pix, x0, y0 += stepy);             // Pattern:
                            setPixel(pix, x0 += stepx, y0);             //    o o 
                            setPixel(pix, x1, y1 -= stepy);             //  x
                            setPixel(pix, x1 -= stepx, y1);             //
                        }
                        d += incr2;
                    }
                }
                if (extras > 0) {
                    if (d < 0) {
                        setPixel(pix, x0 += stepx, y0);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1);
                    } else
                    if (d < c) {
                        setPixel(pix, x0 += stepx, y0);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1);
                    } else {
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1 -= stepy);
                    }
                }
            } else {
                int c = (dy - dx) << 1;
                int incr1 = c << 1;
                int d =  incr1 + dx;
                for (int i = 0; i < length; i++) {
                    x0 += stepx;
                    x1 -= stepx;
                    if (d > 0) {
                        setPixel(pix, x0, y0 += stepy);                      // Pattern:
                        setPixel(pix, x0 += stepx, y0 += stepy);             //      o
                        setPixel(pix, x1, y1 -= stepy);                      //    o
                        setPixel(pix, x1 -= stepx, y1 -= stepy);		        //  x
                        d += incr1;
                    } else {
                        if (d < c) {
                            setPixel(pix, x0, y0);                           // Pattern:
                            setPixel(pix, x0 += stepx, y0 += stepy);         //      o
                            setPixel(pix, x1, y1);                           //  x o
                            setPixel(pix, x1 -= stepx, y1 -= stepy);         //
                        } else {
                            setPixel(pix, x0, y0 += stepy);                  // Pattern:
                            setPixel(pix, x0 += stepx, y0);                  //    o o
                            setPixel(pix, x1, y1 -= stepy);                  //  x
                            setPixel(pix, x1 -= stepx, y1);                  //
                        }
                        d += incr2;
                    }
                }
                if (extras > 0) {
                    if (d > 0) {
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1 -= stepy);
                    } else
                    if (d < c) {
                        setPixel(pix, x0 += stepx, y0);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1);
                    } else {
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0);
                        if (extras > 2) {
                            if (d > c)
                                setPixel(pix, x1 -= stepx, y1 -= stepy);
                            else
                                setPixel(pix, x1 -= stepx, y1);
                        }
                    }
                }
            }
        } else {
            int length = (dy - 1) >> 2;
            int extras = (dy - 1) & 3;
            int incr2 = (dx << 2) - (dy << 1);
            if (incr2 < 0) {
                int c = dx << 1;
                int incr1 = c << 1;
                int d =  incr1 - dy;
                for (int i = 0; i < length; i++) {
                    y0 += stepy;
                    y1 -= stepy;
                    if (d < 0) {
                        setPixel(pix, x0, y0);
                        setPixel(pix, x0, y0 += stepy);
                        setPixel(pix, x1, y1);
                        setPixel(pix, x1, y1 -= stepy);
                        d += incr1;
                    } else {
                        if (d < c) {
                            setPixel(pix, x0, y0);
                            setPixel(pix, x0 += stepx, y0 += stepy);
                            setPixel(pix, x1, y1);
                            setPixel(pix, x1 -= stepx, y1 -= stepy);
                        } else {
                            setPixel(pix, x0 += stepx, y0);
                            setPixel(pix, x0, y0 += stepy);
                            setPixel(pix, x1 -= stepx, y1);
                            setPixel(pix, x1, y1 -= stepy);
                        }
                        d += incr2;
                    }
                }
                if (extras > 0) {
                    if (d < 0) {
                        setPixel(pix, x0, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1, y1 -= stepy);
                    } else
                    if (d < c) {
                        setPixel(pix, stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1, y1 -= stepy);
                    } else {
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1 -= stepy);
                    }
                }
            } else {
                int c = (dx - dy) << 1;
                int incr1 = c << 1;
                int d =  incr1 + dy;
                for (int i = 0; i < length; i++) {
                    y0 += stepy;
                    y1 -= stepy;
                    if (d > 0) {
                        setPixel(pix, x0 += stepx, y0);
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        setPixel(pix, x1 -= stepy, y1);
                        setPixel(pix, x1 -= stepx, y1 -= stepy);
                        d += incr1;
                    } else {
                        if (d < c) {
                            setPixel(pix, x0, y0);
                            setPixel(pix, x0 += stepx, y0 += stepy);
                            setPixel(pix, x1, y1);
                            setPixel(pix, x1 -= stepx, y1 -= stepy);
                        } else {
                            setPixel(pix, x0 += stepx, y0);
                            setPixel(pix, x0, y0 += stepy);
                            setPixel(pix, x1 -= stepx, y1);
                            setPixel(pix, x1, y1 -= stepy);
                        }
                        d += incr2;
                    }
                }
                if (extras > 0) {
                    if (d > 0) {
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1 -= stepx, y1 -= stepy);
                    } else
                    if (d < c) {
                        setPixel(pix, x0, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 2) setPixel(pix, x1, y1 -= stepy);
                    } else {
                        setPixel(pix, x0 += stepx, y0 += stepy);
                        if (extras > 1) setPixel(pix, x0, y0 += stepy);
                        if (extras > 2) {
                            if (d > c)
                                setPixel(pix, x1 -= stepx, y1 -= stepy);
                            else
                                setPixel(pix, x1, y1 -= stepy);
                        }
                    }
                }
            }
        }
    }

    public void lineTwoStep(Point P0, Point P1, Color color) {
		lineTwoStep(P0.x, P0.y, P1.x, P1.y, color);
	}





}