/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.shavenpuppy.jglib.algorithms; /** * Bresenham's famous line drawing algorithm. Works for 2D. */ public final class Bresenham { /** Used for calculation */ private int dx, dy, error, x_inc, y_inc, xx, yy, length, count; /** General case algorithm */ private static final Bresenham bresenham = new Bresenham(); /** * Construct a Bresenham algorithm. */ public Bresenham() { } /** * Plot a line between (x1,y1) and (x2,y2). To step through the line use next(). * @return the length of the line (which will be 1 more than you are expecting). */ public int plot(int x1, int y1, int x2, int y2) { // compute horizontal and vertical deltas dx = x2 - x1; dy = y2 - y1; // test which direction the line is going in i.e. slope angle if (dx >= 0) { x_inc = 1; } else { x_inc = -1; dx = -dx; // need absolute value } // test y component of slope if (dy >= 0) { y_inc = 1; } else { y_inc = -1; dy = -dy; // need absolute value } xx = x1; yy = y1; if (dx > 0) { error = dx >> 1; } else { error = dy >> 1; } count = 0; length = Math.max(dx, dy) + 1; return length; } /** * @return true if there is another point to come */ public boolean hasNext() { return count < length; } /** * Get the next point in the line. You must not call next() if the * previous invocation of next() returned false. * * Retrieve the X and Y coordinates of the line with getX() and getY(). * * @return true if there is another point to come. */ public boolean next() { if (count >= length) { throw new RuntimeException("No more points"); } // now based on which delta is greater we can draw the line if (dx > dy) { // adjust the error term error += dy; // test if error has overflowed if (error >= dx) { error -= dx; // move to next line yy += y_inc; } // move to the next pixel xx += x_inc; } else { // adjust the error term error += dx; // test if error overflowed if (error >= dy) { error -= dy; // move to next line xx += x_inc; } // move to the next pixel yy += y_inc; } count ++; return count < length; } /** * @return the current X coordinate */ public int getX() { return xx; } /** * @return the current Y coordinate */ public int getY() { return yy; } /** * Plot a line between (x1,y1) and (x2,y2). The results are placed in x[] and y[], which must be large enough. * @return the length of the line or the length of x[]/y[], whichever is smaller */ public static final int plot(final int x1, final int y1, final int x2, final int y2, final int x[], final int y[]) { int length = Math.min(x.length, Math.min(y.length, bresenham.plot(x1, y1, x2, y2))); for (int i = 0; i < length; i ++) { bresenham.next(); x[i] = bresenham.getX(); y[i] = bresenham.getY(); } return length; /* int dx; // difference in x's int dy; // difference in y's int error = 0; // the discriminant i.e. error i.e. decision variable int x_inc; int y_inc; int index; // used for looping // compute horizontal and vertical deltas dx = x2 - x1; dy = y2 - y1; // test which direction the line is going in i.e. slope angle if (dx >= 0) { x_inc = 1; } else { x_inc = -1; dx = -dx; // need absolute value } // test y component of slope if (dy >= 0) { y_inc = 1; } else { y_inc = -1; dy = -dy; // need absolute value } int xx = x1, yy = y1; // now based on which delta is greater we can draw the line if (dx > dy) { error = dx >> 1; // draw the line for (index = 0; index <= dx && index < x.length; index++) { // remember the point x[index] = xx; y[index] = yy; // adjust the error term error += dy; // test if error has overflowed if (error >= dx) { error -= dx; // move to next line yy += y_inc; } // move to the next pixel xx += x_inc; } return Math.min(x.length, dx); } else { error = dy >> 1; // draw the line for (index = 0; index <= dy && index < y.length; index++) { // remember the point x[index] = xx; y[index] = yy; // adjust the error term error += dx; // test if error overflowed if (error >= dy) { error -= dy; // move to next line xx += x_inc; } // move to the next pixel yy += y_inc; } return Math.min(y.length, dy); } */ } }