// ---------------------------------------------------------------- // System Headers // ---------------------------------------------------------------- #include #include #include // ---------------------------------------------------------------- // Local Headers // ---------------------------------------------------------------- #include "util.h" #include "svg.h" // ---------------------------------------------------------------- // Using Directives // ---------------------------------------------------------------- using std::vector; // ---------------------------------------------------------------- // Point // ---------------------------------------------------------------- struct Point { Point(int x, int y) : mX(x), mY(y) { } Point() : mX(0), mY(0) { } int mX; int mY; }; // ---------------------------------------------------------------- // drawShape - Draw the outline represented by 'points' // ---------------------------------------------------------------- static void drawShape(const vector &points, SVG *svg) { for(int i = 0, n = points.size(); i < n; i ++) { svg->line( points[i].mX, points[i].mY, points[(i + 1) % n].mX, points[(i + 1) % n].mY, Colors::black ); } } // ---------------------------------------------------------------- // getPoint - Find a point that is 'percent' of the way from // 'p1' to 'p2' // ---------------------------------------------------------------- Point getPoint(const Point &p1, const Point &p2, double percent) { if(percent < 0.0) percent = 0.0; else if(percent > 1.0) percent = 1.0; double xDelta = (p2.mX - p1.mX); double yDelta = (p2.mY - p1.mY); double r = sqrt(xDelta * xDelta + yDelta * yDelta); double theta = atan2(yDelta, xDelta); double xNew = p1.mX + (percent * r) * cos(theta); double yNew = p1.mY + (percent * r) * sin(theta); return(Point(Util::rnd(xNew), Util::rnd(yNew))); } // ---------------------------------------------------------------- // getChild - Given 'points', generate the inscribed child // figure based on 'percent' and 'reverse' // ---------------------------------------------------------------- vector getChild( const vector &points, double percent, bool reverse ) { vector child; for(int i = 0, n = points.size(); i < n; i ++) { int index1 = i; int index2 = (reverse ? (i + n - 1) : (i + 1)) % n; child.push_back(getPoint(points[index1], points[index2], percent)); } return(child); } // ---------------------------------------------------------------- // draw - Render our figure having 'nSides' and to 'depth' // based on 'percent' and 'reverse' // ---------------------------------------------------------------- static void draw( int nSides, int depth, double percent, bool reverse, SVG *svg ) { int w = svg->getWidth(); int h = svg->getHeight(); double radius = .45 * (w <= h ? w : h); int step = (360 / nSides); int xc = (w / 2); int yc = (h / 2); vector pts; for(int degrees = 0; degrees < 360; degrees += step) { double theta = Util::d2r(degrees + step / 2); double x = xc + radius * cos(theta); double y = yc + radius * sin(theta); pts.push_back(Point(Util::rnd(x), Util::rnd(y))); } for(int i = 0; i < depth; i ++, pts = getChild(pts, percent, reverse)) drawShape(pts, svg); } // ------------------------------------- // main // ------------------------------------- int main() { static const int WIDTH = 500; static const int HEIGHT = 500; static const int N_SIDES = 6; static const int DEPTH = 20; static const double PERCENT = .15; static const bool REVERSE = true; SVG svg(WIDTH, HEIGHT); svg.border(Colors::black); draw(N_SIDES, DEPTH, PERCENT, REVERSE, &svg); string fileName = "spiral.html"; string errMsg; if(!svg.write(fileName, errMsg)) std::cout << errMsg << "\n"; else std::cout << "Successfully wrote: " << fileName << "\n"; return(0); }