#include "blockviewwavetrace.h" #include BlockViewWavetrace::BlockViewWavetrace(int width, int height) { max_steps = 512; resize(width, height); setPreferredDirection(Horizontal); } void BlockViewWavetrace::resize(int width, int height) { wid = width; hei = height; if (field.size() != wid) field.resize(wid); for (int i = 0; i < wid; ++i) { if (field[i].size() != hei) { field[i].resize(hei); field[i].fill(-1); } } } void BlockViewWavetrace::fill(short val) { QTime tm; tm.restart(); for (int i = 0; i < wid; ++i) { if (i == 0) field[i].fill(val); else memcpy(field[i].data(), field[0].constData(), hei * sizeof(field[0][0])); } } void BlockViewWavetrace::fill(const QRect & rect, short val) { for (int i = rect.left(); i <= rect.right(); ++i) for (int j = rect.top(); j <= rect.bottom(); ++j) field[i][j] = val; } void BlockViewWavetrace::fill(int px, int py, short val) { field[px][py] = val; } bool BlockViewWavetrace::trace(const QPoint & start, const QPoint & finish) { st = start; fn = finish; if (dir_ == NoTrace) return true; //qDebug() << "trace" << start << finish; //return true; int cx, cy; short cl = 0; QRect frect(0, 0, wid - 1, hei - 1); QVector cpnts, npnts; fill(st, cl); jumps.clear(); cpnts.append(st); auto checkAndFill = [this, &npnts, &frect](int x, int y, short c) { if (!frect.contains(x, y)) return; short p = field[x][y]; if (p == (short)Empty || p == (short)Jump) { npnts.append(QPoint(x, y)); fill(x, y, c); } if (p == (short)Jump) { jumps.append(QPoint(x, y)); } }; if (field[fn.x()][fn.y()] < (short)Empty) return false; while (cpnts.size() > 0) { npnts.clear(); cl++; if (cl >= max_steps) return false; for (int i = 0; i < cpnts.size(); ++i) { if (cpnts[i] == fn) { return true; } cx = cpnts[i].x() - 1; cy = cpnts[i].y(); checkAndFill(cx, cy, cl); cx = cpnts[i].x() + 1; checkAndFill(cx, cy, cl); cx = cpnts[i].x(); cy = cpnts[i].y() - 1; checkAndFill(cx, cy, cl); cy = cpnts[i].y() + 1; checkAndFill(cx, cy, cl); } cpnts = npnts; //qDebug() << cl << ": " << cpnts.size(); } return false; } void BlockViewWavetrace::gatherPath() { path_.clear(); path_.push_back(fn); if (dir_ == NoTrace) { path_.push_front(st); return; } int pa = -1, ca = -1; bool first = true; short cl = field[fn.x()][fn.y()]; QRect frect(0, 0, wid, hei); QPoint cpnt = fn; //cout << "start from " << cl << endl; auto checkAndStep = [this, &cpnt, &first, &frect] (int & dir, short c, int & ca_, int pa_)->bool { int cx = cpnt.x() + dps[dir].x(); int cy = cpnt.y() + dps[dir].y(); dir++; if (frect.contains(cx, cy)) { if (field[cx][cy] == c) { if (jumps.contains(QPoint(cx, cy))) { int jx = cx - 1; int jy = cy; if (jumps.contains(QPoint(jx, jy))) fill(jx, jy, (short)Jump); jx = cx + 1; if (jumps.contains(QPoint(jx, jy))) fill(jx, jy, (short)Jump); jx = cx; jy = cy - 1; if (jumps.contains(QPoint(jx, jy))) fill(jx, jy, (short)Jump); jy = cy + 1; if (jumps.contains(QPoint(jx, jy))) fill(jx, jy, (short)Jump); } ca_ = QLineF(QPointF(cx, cy), cpnt).angle(); if (ca_ != pa_ && !first) path_.push_front(cpnt); cpnt = QPoint(cx, cy); first = false; return true; } } return false; }; while (cl > 0) { cl--; pa = ca; int dir = 0; if (checkAndStep(dir, cl, ca, pa)) continue; if (checkAndStep(dir, cl, ca, pa)) continue; if (checkAndStep(dir, cl, ca, pa)) continue; if (checkAndStep(dir, cl, ca, pa)) continue; } path_.push_front(st); //cout << path_.size() << endl; } void BlockViewWavetrace::setPreferredDirection(BlockViewWavetrace::Direction dir) { dir_ = dir; if (dir == Horizontal) { dps[0] = QPoint(0, -1); dps[1] = QPoint(0, 1); dps[2] = QPoint(-1, 0); dps[3] = QPoint(1, 0); } if (dir == Vertical) { dps[2] = QPoint(0, -1); dps[3] = QPoint(0, 1); dps[0] = QPoint(-1, 0); dps[1] = QPoint(1, 0); } } const QVector & BlockViewWavetrace::path() const { /*path_.resize(3); path_[0] = st; path_[1] = (st + fn) / 2; path_[2] = fn;*/ return path_; }