/***** * bbox.h * Andy Hammerlindl 2002/06/06 * * Stores a rectangle that encloses a drawing object. *****/ #ifndef BBOX_H #define BBOX_H #include "pair.h" #include "settings.h" namespace camp { template inline T min(T a, T b) { return (a < b) ? a : b; } template inline T max(T a, T b) { return (a > b) ? a : b; } // The box that encloses a path struct bbox { bool empty; double left; double bottom; double right; double top; // Start bbox about the origin bbox() : empty(true), left(0.0), bottom(0.0), right(0.0), top(0.0) { } bbox(double left, double bottom, double right, double top) : empty(false), left(left), bottom(bottom), right(right), top(top) { } // Start a bbox with a point bbox(const pair& z) : empty(false), left(z.getx()), bottom(z.gety()), right(z.getx()), top(z.gety()) { } bool nonempty() const { return !empty; } // Add a point to a bbox bbox add(const pair& z) { double x = z.getx(), y = z.gety(); if (empty) { left = right = x; top = bottom = y; empty = false; } else { if (x < left) left = x; else if (x > right) right = x; if (y < bottom) bottom = y; else if (y > top) top = y; } return *this; } // Add a point to a nonempty bbox void addnonempty(const pair& z) { double x = z.getx(), y = z.gety(); if (x < left) left = x; else if (x > right) right = x; if (y < bottom) bottom = y; else if (y > top) top = y; } // Add a point to a nonempty bbox, updating bounding times void addnonempty(const pair& z, bbox& times, double t) { double x = z.getx(), y = z.gety(); if (x < left) { left = x; times.left = t; } else if (x > right) { right = x; times.right = t; } if (y < bottom) { bottom = y; times.bottom = t; } else if (y > top) { top = y; times.top = t; } } bbox operator+= (const pair& z) { add(z); return *this; } bbox operator*= (double x) { left *= x; right *= x; top *= x; bottom *=x; return *this; } // Add two bounding boxes friend bbox operator+ (const bbox& b1, const bbox& b2) { if (b1.empty) return b2; else if (b2.empty) return b1; else return bbox(min(b1.left, b2.left), max(b1.right, b2.right), min(b1.bottom, b2.bottom), max(b1.top, b2.top)); } // Add one bounding box to another void add(const bbox& b) { if (this->empty) *this = b; else if (!b.empty) { left = min(left, b.left); right = max(right, b.right); bottom = min(bottom, b.bottom); top = max(top, b.top); } } bbox operator+= (const bbox& b) { add(b); return *this; } void clip(const bbox& b) { if(this->empty) return; left = max(left, b.left); right = min(right, b.right); bottom = max(bottom, b.bottom); top = min(top, b.top); if(left > right || bottom > top) *this=bbox(); } bbox shift(const pair& p) const { bbox b=*this; b.left += p.getx(); b.right += p.getx(); b.bottom += p.gety(); b.top += p.gety(); return b; } pair Min() const { return pair(left,bottom); } pair Max() const { return pair(right,top); } double diameter() { return (Max()-Min()).length(); } bbox LowRes() const { return bbox(floor(left),floor(bottom),ceil(right),ceil(top)); } friend ostream& operator<< (ostream& out, const bbox& b) { out << b.left << " " << b.bottom << " " << b.right << " " << b.top; return out; } }; // Add results of both bounding boxes, say for a path and a pen. inline bbox pad(bbox b1, bbox b2) { if (b1.empty) return b2; else if (b2.empty) return b1; else { bbox b; b.empty = false; b.left = b1.left + b2.left; b.right = b1.right + b2.right; b.top = b1.top + b2.top; b.bottom = b1.bottom + b2.bottom; return b; } } inline bbox svgbbox(const bbox& B, pair shift=pair(0,0)) { bbox b=B; double height=b.top-b.bottom; double threshold=12.0*settings::tex2ps; if(height < threshold) { double offset=threshold-height; b.top += offset; b.bottom += offset; } return b.shift(pair(1.99*settings::cm,1.9*settings::cm)+shift); } } // namespace camp GC_DECLARE_PTRFREE(camp::bbox); #endif