/** * Copyright 2001 Jean-Francois Doue * * This file is part of Asteroid Zone. Asteroid Zone is free software; * you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; * either version 2 of the License, or (at your option) any later version. * Asteroid Zone is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Asteroid Zone; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ package asteroids; /** * Class to group various geometric functions. * @author Jean-Francois Doue * @version 1.4, 2002/10/14 */ public class Geometry extends Object { /** * Scan converts a polygon. * @param pixels * The resulting scan-converted polygon as a 2D boolean array * @param xcoords * The X-coordinates of the polygon vertices. The vertex are ordered clockwise, * and the last vertex equals the first vertex. * @param ycoords * The Y-coordinates of the polygon vertices. The vertex are ordered clockwise, * and the last vertex equals the first vertex. */ public static void scanConvertPolygon(boolean[][] pixels, byte[] xcoords, byte[] ycoords) { // Degenerate cases if (pixels.length == 0) { return; } if (pixels.length == 1) { pixels[0][0] = true; return; } // Index of the polygon segment being scan converted. int top = 0, bottom = xcoords.length - 1; // Parameters used to adapt the Bresenham algorithm. // to the 8 possible octants. (top and bottom lines) boolean isSteepT = false, isSteepB = false; int incrYT = 0, incrYB = 0; // Decision variable of the Bresenham algorithm. // If d <= 0, then the next point ought to be E // If d > 0, then the next point ought to be NE int dT = 0, dB = 0; // Incremental d of the Bresenham algorithm when E is chosen. int incrET = 0, incrEB = 0; // Incremental d of the Bresenham algorithm when NE is chosen. int incrNET = 0, incrNEB = 0; // The x coordinate of the current line point. int x = xcoords[top]; // The y coordinate of the current line point (top and bottom lines). int yT = 0, yB = 0; // Translation int tx = pixels.length >> 1; // Scan convert the top and bottom border of the polygon. // The scan conversion is done once the lines cross. while (top <= bottom) { // Another segment of the top border has been reached. if (x == xcoords[top]) { while (xcoords[top + 1] == xcoords[top] && top < xcoords.length) { top++; } int dxT = xcoords[top + 1] - xcoords[top]; int dyT = ycoords[top + 1] - ycoords[top]; yT = ycoords[top]; top++; incrYT = (dyT >= 0) ? 1 : -1; int absDxT = Math.abs(dxT); int absDyT = Math.abs(dyT); isSteepT = (absDxT <= absDyT); if (isSteepT) { dT = (absDxT << 1) - absDyT; incrET = absDxT << 1; incrNET = (absDxT - absDyT ) << 1; } else { dT = (absDyT << 1) - absDxT; incrET = absDyT << 1; incrNET = (absDyT - absDxT ) << 1; } } else { // Compute the Y coordinate of the next top border point. if (isSteepT) { if (dT <= 0) { while (dT <= 0) { yT += incrYT; dT += incrET; } } yT += incrYT; dT += incrNET; } else { if (dT <= 0) { dT += incrET; } else { yT += incrYT; dT += incrNET; } } } // Another segment of the bottom border has been reached. if (x == xcoords[bottom]) { while (xcoords[bottom - 1] == xcoords[bottom] && bottom >= 0) { bottom--; } int dxB = xcoords[bottom - 1] - xcoords[bottom]; int dyB = ycoords[bottom - 1] - ycoords[bottom]; yB = ycoords[bottom]; bottom--; incrYB = (dyB >= 0) ? 1 : -1; int absDxB = Math.abs(dxB); int absDyB = Math.abs(dyB); isSteepB = (absDxB <= absDyB); if (isSteepB) { dB = (absDxB << 1) - absDyB; incrEB = absDxB << 1; incrNEB = (absDxB - absDyB ) << 1; } else { dB = (absDyB << 1) - absDxB; incrEB = absDyB << 1; incrNEB = (absDyB - absDxB ) << 1; } } else { // Compute the Y coordinate of the next bottom border point. if (isSteepB) { if (dB <= 0) { while (dB <= 0) { yB += incrYB; dB += incrEB; } } yB += incrYB; dB += incrNEB; } else { if (dB <= 0) { dB += incrEB; } else { yB += incrYB; dB += incrNEB; } } } // Fill the line between the top and the bottom border points. int min = (yB <= yT) ? yB : yT; int max = (yB > yT) ? yB : yT; for (int i = min; i <= max; i++) { pixels[pixels.length - 1 - i - tx][x + tx] = true; } x--; } /* for (int i = 0; i < pixels.length; i++) { for (int j = pixels[i].length - 1; j >= 0; j--) { if (pixels[i][j]) { System.out.print("#"); } else { System.out.print("."); } } System.out.println(); } */ } }