// -------------------------------------------------------------------------- // System Headers // -------------------------------------------------------------------------- #include #include #include #include // -------------------------------------------------------------------------- // Local Headers // -------------------------------------------------------------------------- #include "util.h" #include "svg.h" // -------------------------------------------------------------------------- // Defines // -------------------------------------------------------------------------- #define HOW_MANY (1000) #define MAX_RADIUS_PCT (.1) #define EDGE_MARGIN (0) #define OTHER_MARGIN (0) // -------------------------------------------------------------------------- // Circle // -------------------------------------------------------------------------- typedef struct { int mX; int mY; int mRadius; } Circle; // -------------------------------------------------------------------------- // makeCircle - Construct and return a Circle from 'x', 'y', 'radius' // -------------------------------------------------------------------------- static Circle makeCircle(int x, int y, int radius) { Circle theCircle = { 0 }; theCircle.mX = x; theCircle.mY = y; theCircle.mRadius = radius; return(theCircle); } // -------------------------------------------------------------------------- // getRGB - Create and return a pastel rgb color value // -------------------------------------------------------------------------- static void getRGB(char *dest, int size) { snprintf( dest, size, "rgb(%d, %d, %d)", 128 + utilRandomValue() % 127, 128 + utilRandomValue() % 127, 128 + utilRandomValue() % 127 ); } // -------------------------------------------------------------------------- // drawCircle - Draw 'c' filled with a random color, edge is black // if 'doEdge' is true. // -------------------------------------------------------------------------- static void drawCircle(const Circle *c, SVG *svg, int doEdge) { char buffer[255] = { '\0' }; getRGB(buffer, sizeof(buffer)); svgCircle( svg, c->mX, c->mY, c->mRadius, doEdge ? svg->mColors.black : svg->mColors.none, buffer ); } // -------------------------------------------------------------------------- // intersect - Determine if 'c1' and 'c2' intersect // -------------------------------------------------------------------------- static int intersect(const Circle *c1, const Circle *c2) { double xDelta = (c2->mX - c1->mX); double yDelta = (c2->mY - c1->mY); double distance = sqrt(xDelta * xDelta + yDelta * yDelta); return(distance <= (c1->mRadius + c2->mRadius) + OTHER_MARGIN); } // -------------------------------------------------------------------------- // hitsEdge - Determine if 'c' overlaps any edge // -------------------------------------------------------------------------- static bool hitsEdge(const Circle *c, int width, int height) { return( c->mX - c->mRadius <= EDGE_MARGIN || c->mY - c->mRadius <= EDGE_MARGIN || c->mX + c->mRadius >= (width - EDGE_MARGIN) || c->mY + c->mRadius >= (height - EDGE_MARGIN) ); } // -------------------------------------------------------------------------- // hitsOtherCircle - Determine if 'c' intersects any previous circle // -------------------------------------------------------------------------- static bool hitsOtherCircle(const Circle *c, const Circle *history, int count) { int i = 0; while(i < count) if(intersect(c, history + i++)) return(true); return(false); } // -------------------------------------------------------------------------- // isGood - Determine if 'c' should be drawn, returns true if // 'c' neither hits any edge or existing circle, false otherwise // -------------------------------------------------------------------------- static bool isGood( Circle *c, int width, int height, Circle *history, int count ) { return( !hitsEdge(c, width, height) && !hitsOtherCircle(c, history, count) ); } // -------------------------------------------------------------------------- // doEdgeRequested - Return 1 if '-e' or '-E' was passed as a command-line // argument, 0 otherwise // -------------------------------------------------------------------------- static bool doEdgeRequested(int argc, char **argv) { bool doEdgeFlag = false; int i = 1; while(i < argc && !doEdgeFlag) { if(strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "-E") == 0) { doEdgeFlag = true; } i++; } return(doEdgeFlag); } // -------------------------------------------------------------------------- // main - Invoking with '-e' or '-E' causes the circles to be drawn // with black edges // -------------------------------------------------------------------------- int main(int argc, char **argv) { const int WIDTH = 500; const int HEIGHT = 500; const char *NAME = "circles.html"; SVG *svg = svgOpen(NAME, "Circles", WIDTH, HEIGHT); if(!svg) { printf("Call to 'svgOpen' failed\n"); return(1); } int maxRadius = utilRound( (WIDTH <= HEIGHT ? WIDTH : HEIGHT) * MAX_RADIUS_PCT ); Circle history[HOW_MANY] = { 0 }; int count = 0; int doEdge = doEdgeRequested(argc, argv); svgBorder(svg, svg->mColors.black); while(count < HOW_MANY) { Circle c = makeCircle( utilRandomValue() % WIDTH, utilRandomValue() % HEIGHT, utilRandomValue() % maxRadius ); if(isGood(&c, WIDTH, HEIGHT, history, count)) { drawCircle(&c, svg, doEdge); history[count++] = c; } } svgClose(svg); printf("Successfully wrote file: %s\n", NAME); return(0); }