commit f3fd11ac6a2f4d8ff6823c4a57b67de4f0acf022 Author: mercury Date: Wed Dec 3 17:36:36 2003 +0000 Initial revision diff --git a/GeneratePoints.java b/GeneratePoints.java new file mode 100644 index 0000000..806154f --- /dev/null +++ b/GeneratePoints.java @@ -0,0 +1,55 @@ +import java.awt.*; +import javax.swing.*; +import java.awt.event.*; +import java.util.*; +import java.io.*; + +public class GeneratePoints extends JFrame { + protected Vector points; + protected String fileName; + + public GeneratePoints(String fn) { + super("Point Generator - use mouse!"); + points = new Vector(); + fileName = fn; + getContentPane().setBackground(Color.black); + addWindowListener(new GenerateWindowListener()); + addMouseListener(new PointMouseListener()); + setSize(510, 510); + show(); + } + + protected class GenerateWindowListener extends WindowAdapter { + public void windowClosing(WindowEvent e) { + try { + PrintWriter pw = new PrintWriter(new FileWriter(fileName)); + for (int i = 0; i < points.size(); i++) { + Point pt = (Point) points.elementAt(i); + pw.println((int) pt.getX() + " " + (500 - (int) pt.getY()) ); + } + pw.close(); + } + catch (IOException ioe) { + System.out.println("IO problem"); + } + System.exit(0); + } + } + + protected class PointMouseListener extends MouseAdapter { + public void mouseReleased(MouseEvent e) { + points.add(new Point(e.getX(), e.getY())); + Graphics page = GeneratePoints.this.getGraphics(); + page.setColor(Color.red); + page.fillOval(e.getX(), e.getY(), 3, 3); + } + } + + public static void main(String[] args) { + GeneratePoints gui; + if (args.length > 0) + gui = new GeneratePoints(args[0]); + else + System.out.println("Usage: GeneratePoints filename"); + } +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6eb782a --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +CC=g++ +CFLAGS=-Os -Wall -W -Wwrite-strings +LDFLAGS= +O_TARGET=hull +SRCS=hull.cpp +OBJS=hull.o + +all: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(O_TARGET) $(OBJS) + strip $(O_TARGET) + +$(SRCS): + $(CC) $(CFLAGS) -o $@ $*.c + +clean: + @rm *.o diff --git a/PlotConvexHull.java b/PlotConvexHull.java new file mode 100644 index 0000000..492123f --- /dev/null +++ b/PlotConvexHull.java @@ -0,0 +1,90 @@ +import java.awt.*; +import javax.swing.*; +import java.awt.event.*; +import java.util.*; +import java.io.*; +import com.sun.image.codec.jpeg.*; +import java.awt.image.*; + +public class PlotConvexHull extends JFrame { + protected Vector points; + protected Polygon convexHull; + protected JMenuBar mb; + protected JMenu menu; + protected JMenuItem go; + protected String fileName; + + public PlotConvexHull(String fn) { + super("Convex Hull Plotter - just watch!"); + fileName = fn; + points = new Vector(); + convexHull = new Polygon(); + try { + BufferedReader br = new BufferedReader(new FileReader(fn)); + String line = br.readLine(); + int width = 500; + int height = 500; + while (line != null && line.length() > 1) { + StringTokenizer st = new StringTokenizer(line); + int x = Integer.parseInt(st.nextToken()); + int y = Integer.parseInt(st.nextToken()); + points.add(new Point(x + 5, 500 - y)); + line = br.readLine(); + } + line = br.readLine(); + while (line != null && line.length() > 1) { + StringTokenizer st = new StringTokenizer(line); + int x = Integer.parseInt(st.nextToken()); + int y = Integer.parseInt(st.nextToken()); + convexHull.addPoint(x + 5, 500 - y); + line = br.readLine(); + } + br.close(); + } + catch (IOException e) { + System.out.println("IO Problem"); + System.exit(0); + } + getContentPane().setBackground(Color.white); + addWindowListener(new PlotWindowListener()); + setSize(510, 510); + show(); + } + + public void paint(Graphics g) { + super.paint(g); + getContentPane().setBackground(Color.white); + g.setColor(Color.red); + for (int i = 0; i < points.size(); i++) { + Point pt = (Point) points.elementAt(i); + g.fillOval((int) pt.getX(), (int) pt.getY(), 3, 3); + } + g.setColor(Color.blue); + g.drawPolygon(convexHull); + } + + protected class PlotWindowListener extends WindowAdapter { + public void windowClosing(WindowEvent e) { + Image img = createImage(getWidth(), getHeight()); + Graphics page = img.getGraphics(); + paint(page); + try { + OutputStream out = new FileOutputStream(fileName + ".jpg"); + JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); + encoder.encode((BufferedImage) img); + out.close(); + } + catch (Exception exc) { + } + System.exit(0); + } + } + + public static void main(String[] args) { + PlotConvexHull gui; + if (args.length > 0) + gui = new PlotConvexHull(args[0]); + else + System.out.println("Usage: PlotConvexHull filename"); + } +} diff --git a/hull.cpp b/hull.cpp new file mode 100644 index 0000000..7b02538 --- /dev/null +++ b/hull.cpp @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include + +/* + finds the area in a given set of points. all the arrays will be named points + and i really don't feel like having this thing in several places in my code + + it's huge +*/ +#define AREA(a,b,c) ( points[a].x * points[b].y + points[c].x * points[a].y + points[b].x * points[c].y - points[c].x * points[b].y - points[b].x * points[a].y - points[a].x * points[c].y ) + +/* maximum size of coordinate plane */ +#define COORDMAX 500 +/* maximum number of points to compute */ +#define POINTMAX 5000 + +using namespace std; + +ofstream out; + +/* the class that I will use to wrap a coordinate using oo design */ +class Point { +public: + short x, y; + Point() { + Reset(); + } + + Point ( short one, short two ) { + x = one; y = two; + } + + void Reset() { + x = -1; + y = -1; + } + + double Slope ( const Point &end ) { + double result = 0.0; + result = ( this->y - end.y ) / ( this->x - end.x ); + return result; + } + + /* overloaded C++ operators for various syntax simplifications */ + friend ostream& operator<< ( ostream &out, const Point &p ) { + out << p.x << " " << p.y; + return out; + } + + friend ostream& operator<< ( ostream &out, const Point *p ) { + out << p->x << " " << p->y; + return out; + } + + Point& operator= ( const Point &p ) { + this->x = p.x; + this->y = p.y; + return *this; + } + + Point& operator= ( const Point *p ) { + this->x = p->x; + this->y = p->y; + return *this; + } + + bool operator== ( const Point &p ) { + return ( this->x == p.x && this->y == p.y ); + } + + bool operator!= ( const Point &p ) { + return ( this->x != p.x && this->y != p.y ); + } +}; + +/* + this function reads in all of the points in a file, up to POINTMAX in size + since we don't include a size field in the input file +*/ +Point *CreateByFile ( const char *name, long *size ) { + + ifstream infile ( name ); + Point *points; + + *size = 0; + points = new Point[POINTMAX]; + if ( points == NULL ) {return NULL;} + + while ( !infile.eof() ) { + short x = 0, y = 0; + infile >> x; + infile >> y; + if ( x != 0 && y != 0 ) { + points[*size].x = x; + points[*size].y = y; + (*size)++; + } + if ( *size >= POINTMAX ) {break;} + } + infile.close(); + return points; +} + +/* this function creates an randomly sized array of Points randomly selected between 1 and COORDMAX */ +Point *CreateByRandom ( long *size, bool flag ) { + Point *hull; + + srand ( time ( NULL ) ); + if ( !flag ) + *size = rand() % POINTMAX + 1; + hull = new Point[*size]; + if ( hull == NULL ) + return hull; + for ( long count = 0; count < *size; count++ ) { + hull[count].x = rand() % COORDMAX + 1; + hull[count].y = rand() % COORDMAX + 1; + } + + return hull; +} + +/* this function checks two coordinates against a set of Points for an edge */ +bool ConvexHullContains ( Point *points, long size, long first, long second ) { + long count = 0; + double d = 0.0; + bool above = false, below = false; + + /* check all the points. points may or may not be sorted */ + for ( count = 0; count < size; count++ ) { + /* don't check the checking points */ + if ( count == first || count == second ) {continue;} + + /* area from the book algorithm */ + d = AREA(first, second, count); + /* + one side or the other. it doesn't matter. + by setting one flag and not the other, you can check to see which + side of the line the points are on; only on *one* side of the line. + */ + if ( d > 0.0 ) { + if ( below ) {return false;} + above = true; + } + else if ( d < 0.0 ) { + if ( above ) {return false;} + below = true; + } + /* + not really sure about this one. doesn't work otherwise. + i don't know why the area would be zero, but it gives me strange + hulls if i don't do this + */ + else + return false; + } + + /* finished the 'gauntlet' of checks, we have a winner */ + return true; +} + +/* + Brute Force convex hull smashing. Figures out which points are on the edge + by generating all possible permutations of the point set +*/ +void SmashHull ( Point *points, long size, bool *mark ) { + long hullpoint = 0, count = 0, firsty = -1; + /* blindly adds any points that are on the edge to the mark array */ + for ( hullpoint = 0; hullpoint < size; hullpoint++ ) { + for ( count = 0; count < size; count++ ) { + if ( hullpoint == count ) {continue;} + if ( ConvexHullContains ( points, size, hullpoint, count ) ) {mark[hullpoint] = true;} + } + } + + /* this doesn't really output the points in order, but it does a generally decent job */ + long b = 0; + for ( count = 0; count < size; count++ ) {b += points[count].y;} + double t = b / size; + for ( count = 0; count < size; count++ ) { + if ( mark[count] && points[count].y >= t ) + out << points[count] << endl; + } + for ( count = size - 1; count >= 0 ; count-- ) { + if ( mark[count] && points[count].y < t ) + out << points[count] << endl; + } +} + +/* + a recursive function that determines the convex hull of a point set using + a method similar to quicksort +*/ +void QuickHull ( Point *points, long left, long right, bool *mark, bool flag ) { + long count = 0, maxindex = 0; + double area = 0.0, maxarea = 0.0; + + for ( count = left; count < right; count++ ) { + area = AREA( left, right, count ); + if ( (area > maxarea && flag) || (area < maxarea && !flag) ) {maxarea = area;maxindex = count;} + } + + if ( maxindex > 0 ) { + mark[maxindex] = true; + if ( flag ) { + QuickHull ( points, left, maxindex, mark, flag ); + out << points[maxindex] << endl; + QuickHull ( points, maxindex, right, mark, flag ); + } + else { + QuickHull ( points, maxindex, right, mark, flag ); + out << points[maxindex] << endl; + QuickHull ( points, left, maxindex, mark, flag ); + } + } +} + +/* + this is a C qsort compatible comparison function + returns -1 when a < b, 1 when a > b, and 0 when a == b +*/ +int ComparePoints ( const void *a, const void *b ) { + Point *one = (Point *)a; + Point *two = (Point *)b; + + if ( one->x < two->x ) {return -1;} + else if ( one->x > two->x ) {return 1;} + else { + if ( one->y < two->y ) {return -1;} + else if ( one->y > two->y ) {return 1;} + else {return 0;} + } +} + +int main ( int argc, char **argv ) { + Point *x = NULL; + short firsty = -1; + bool algorithm = false, comparative = false, outputflag = true; + int arg = 0, argindex = 0; + long size = 0, count = 0, t = 0; + char *outputname = NULL, *inputname = NULL; + + /* hooray for getopt */ + struct option longopts[] = { + {"p", 1, NULL, 'p'}, + {"b", 0, NULL, 'b'}, + {"i", 1, NULL, 'i'}, + {"o", 1, NULL, 'o'}, + {"h", 0, NULL, 'h'}, + {"help", 0, NULL, 'h'}, + {"?", 0, NULL, 'h'} + }; + + while ( 1 ) { + arg = getopt_long ( argc, argv, "p:bi:o:h", longopts, &argindex ); + if ( arg == -1 ) {break;} + + switch ( arg ) { + case 'p': + comparative = true; + size = atol ( optarg ); + break; + case 'b': + algorithm = true; + break; + case 'i': + inputname = optarg; + break; + case 'o': + outputname = optarg; + outputflag = false; + break; + case 'h': + cout << "Usage: " << argv[0] << " [options] --i --o " << endl; + cout << "\tOptions" << endl; + cout << "\t--b\tChanges algorithm to brute force (default is quickhull)" << endl; + cout << "\t--p\tSpecifies problem size of random generation" << endl; + exit ( 0 ); + break; + default: + break; + } + } + /* end getopt */ + + if ( outputflag ) { + outputname = new char[ strlen( argv[0] ) + 5 ]; + strcpy ( outputname, argv[0] ); + strcat ( outputname, ".out" ); + } + + out.open ( outputname ); + + if ( inputname == NULL ) {x = CreateByRandom ( &size, comparative );} + else {x = CreateByFile ( inputname, &size );} + + /* sort and output the point set */ + qsort ( x, size, sizeof( Point ), &ComparePoints ); + for ( count = 0; count < size; count++ ) {out << x[count] << endl;} + out << endl; + + /* calculate convex hull and output results as they are found */ + bool result[size]; + for ( count = 0; count < size; count++ ) {result[count] = false;} + result[0] = true;result[size - 1] = true; + if ( algorithm ) { + SmashHull ( x, size, result ); + } + else { + out << x[0] << endl; + QuickHull ( x, 0, size - 1, result, true ); + out << x[size - 1] << endl; + QuickHull ( x, 0, size - 1, result, false ); + } + + out.close(); + delete [] x; + if ( outputflag ) {delete [] outputname;} + + return 0; +} diff --git a/hullcomp.java b/hullcomp.java new file mode 100644 index 0000000..9503e7e --- /dev/null +++ b/hullcomp.java @@ -0,0 +1,70 @@ +import java.io.*; +import java.lang.Runtime; + +public class hullcomp { + + public static void main ( String[] args ) { + long start = 0, end = 0, count = 0; + long low = 0, high = 0; + String outputname = ""; + Runtime run = Runtime.getRuntime(); + PrintStream output = null; + + if ( args.length < 2 ) { + System.out.println ( "Usage: java hullcomp [output]" ); + System.exit ( 1 ); + } + else { + low = Long.parseLong ( args[0] ); + high = Long.parseLong ( args[1] ); + } + if ( args.length == 3 ) { + outputname = args[2]; + } + else { + outputname = "hullcomp.out"; + } + + try { + output = new PrintStream ( new FileOutputStream ( outputname ) ); + System.setOut ( output); + } + catch ( IOException exception ) {} + + System.out.println ( "Size\tSmash\tQuick" ); + try { + for ( count = low; count < high; count = count * 2 ) { + start = System.currentTimeMillis(); + Process test = run.exec ( "./hull --b --p " + count + "--o b" + count + ".out" ); + test.waitFor(); + end = System.currentTimeMillis(); + System.out.print ( count + "\t" + (end - start) ); + start = System.currentTimeMillis(); + test = run.exec ( "./hull --p " + count + "--o " + count + ".out" ); + test.waitFor(); + end = System.currentTimeMillis(); + System.out.println ( "\t" + (end - start) ); + } + start = System.currentTimeMillis(); + Process test = run.exec ( "./hull --b --p " + high ); + test.waitFor(); + end = System.currentTimeMillis(); + System.out.print ( high + "\t" + (end - start) ); + start = System.currentTimeMillis(); + test = run.exec ( "./hull --p " + high ); + test.waitFor(); + end = System.currentTimeMillis(); + System.out.println ( "\t" + (end - start) ); + } + catch ( Exception exception ) { + exception.printStackTrace(); + } + + try { + output.flush(); + output.close(); + } + catch ( Exception exception ) {} + + } +}