#include #include "findopenrect.h" #include //CUT #define MAXTRIALS 10000 // unless time runs out #define MOUSEPENALTY 65536 FindOpenRect::FindOpenRect() { timelimit = 100; iters = 0; xdiv = ydiv = 1; fn = compare_overlapArea; userdata = userdata2 = 0; bsfval = bsfdist = 0; } void FindOpenRect::setCompareRectsFn(compareRectsFn _fn) { fn = _fn; } RECT FindOpenRect::find(const RECT &vr, const PtrList &list, const RECT &prev, unsigned long userdata, unsigned long userdata2) { beginFind(vr, list, prev, userdata, userdata2); return findMore(); } void FindOpenRect::beginFind(const RECT &viewport, const PtrList &_list, const RECT &_prev, unsigned long _userdata, unsigned long _userdata2) { vr = viewport; list.copyFrom(&_list); prev = _prev; userdata = _userdata; userdata2 = _userdata2; // reset best rect found so far //CUT bsf_nooverlap = prev; //CUT found_nooverlap=0; //CUT bsf_overlap = prev; //CUT bsfval_nooverlap = 1e100; //CUT bsfval_overlap = 1e100; bsfrect = prev; bsfval = 10e10; bsfdist = 10e10; //CUT POINT mousepos; //CUT Std::getMousePos(&mousepos); } RECT FindOpenRect::findMore() { int w = prev.right - prev.left, h = prev.bottom - prev.top; int vw = vr.right - vr.left; int vh = vr.bottom - vr.top; if (vw <= w || vh <= h) { DebugStringW(L"findopenrect: window too big for viewport"); } double started = Wasabi::Std::getTimeStampMS(); for (int c = 0; /*CUTc < MAXTRIALS*/; c++) { // too bad = crashy crash :P love, BU if (c != 0 && (vw <= w || vh <= h)) break; // set the trial rect RECT tr; if (iters == 0) { // try prev tr = prev; } else { int x = Wasabi::Std::random32(vw - w) + vr.top; int y = Wasabi::Std::random32(vh - h) + vr.left; if (xdiv != 1) x -= x % xdiv; if (ydiv != 1) y -= y % ydiv; tr = Wasabi::Std::makeRect(x, y, x + w, y + h); } // add up the coverage of trial position trySingleRect(tr, TRUE); if (timelimit > 0 && c > 0 && (int)((Wasabi::Std::getTimeStampMS() - started)*1000.f) > timelimit) { // DebugString("FindOpenRect::find() timeout, %d iters", c); break; } } return getBestRectSoFar(); } typedef Pair RectV; namespace { class Sorter { public: static int compareItem(RectV *p1, RectV* p2) { return -CMP3(p1->b, p2->b); } }; }; double FindOpenRect::trySingleRect(const RECT &tr, int early_out) { #if 0 PtrListQuickSorted candidates(list.getNumItems()); foreach(list) double d = compare_overlapArea(tr, *list.getfor()); candidates.addItem(new RectV(*list.getfor(), d)); endfor candidates.sort(); #else PtrList candidates; candidates.copyFrom(&list); #endif double trarea = 0; foreach(candidates) #if 0 RECT *wr = &candidates.getfor()->a; #else RECT *wr = candidates.getfor(); #endif //CUT double bsf = MIN(found_nooverlap ? 0 : bsfval_nooverlap, bsfval_overlap); trarea += (*fn)(tr, *wr, userdata, userdata2, foreach_index, bsfval); // early quit if not breaking any records if (early_out && trarea >= bsfval) break; endfor #if 0 candidates.deleteAll(); #endif if (trarea < 0.005) trarea = 0; #if 0 // found one that does not overlap! if (trarea == 0) { if (val < bsfval_nooverlap) { // if it's closer than prev closest, save it bsf_nooverlap = tr; bsfval_nooverlap = val; found_nooverlap = 1; } } else { if (trarea < bsfval_overlap) { // overlaps least stuff bsf_overlap = tr; bsfval_overlap = trarea; } } #endif if (trarea == 0) { // find the distance from the previous double val = SQRT(SQR(prev.left - tr.left) + SQR(prev.top - tr.top)); if (bsfdist > val) { bsfrect = tr; bsfdist = val; } } else { if (trarea < bsfval) { bsfrect = tr; bsfval = trarea; } } iters++; return trarea; } double FindOpenRect::compare_overlapArea(const RECT &rect, const RECT &dest, unsigned long userdata, unsigned long userdata2, int index, double bsf) { RECT intersection; if (Wasabi::Std::rectIntersect(rect, dest, &intersection)) { intersection.right -= intersection.left; intersection.bottom -= intersection.top; return intersection.right * intersection.bottom; } return 0; } void FindOpenRect::setTimeLimit(int ms) { timelimit = ms; } int FindOpenRect::getNumIters() { return iters; } void FindOpenRect::resetNumIters() { iters = 0; } double FindOpenRect::getBestValSoFar() { return (bsfval == 10e10) ? 0 : bsfval; } RECT FindOpenRect::getBestRectSoFar() { return bsfrect; } void FindOpenRect::setBestSoFar(double bsf, const RECT &bestrect) { if (bsf > 0 && bsfval > bsf) { bsfval = bsf; bsfrect = bestrect; bsfdist = SQRT(SQR(prev.left - bsfrect.left) + SQR(prev.top - bsfrect.top)); //CUTDebugString("*******************8 better BSF ****************"); } } RECT FindOpenRect::getOriginalRect() { return prev; } void FindOpenRect::setCoordDivisor(int _xdiv, int _ydiv) { xdiv = MAX(_xdiv, 1); ydiv = MAX(_ydiv, 1); }