dev-VirtualTexture
wuyize 2022-10-02 22:24:28 +08:00
commit 1ad996c3eb
15 changed files with 830 additions and 36 deletions

View File

@ -87,12 +87,16 @@
<ItemGroup>
<ClCompile Include="BvhTree.cpp" />
<ClCompile Include="Camera.cpp" />
<ClCompile Include="CubicBezier.cpp" />
<ClCompile Include="Light.cpp" />
<ClCompile Include="Line.cpp" />
<ClCompile Include="Mesh.cpp" />
<ClCompile Include="Model.cpp" />
<ClCompile Include="PaintingHelper.cpp" />
<ClCompile Include="PaintingMesh.cpp" />
<ClCompile Include="RendererWidget.cpp" />
<ClCompile Include="ShortCutTree.cpp" />
<ClCompile Include="StraightLine.cpp" />
<QtRcc Include="MainWindow.qrc" />
<QtUic Include="MainWindow.ui" />
<QtMoc Include="MainWindow.h" />
@ -123,12 +127,16 @@
<ItemGroup>
<ClInclude Include="BvhTree.h" />
<ClInclude Include="Camera.h" />
<ClInclude Include="CubicBezier.h" />
<ClInclude Include="Drawable.h" />
<ClInclude Include="Light.h" />
<ClInclude Include="Line.h" />
<ClInclude Include="Mesh.h" />
<ClInclude Include="Model.h" />
<ClInclude Include="PaintingHelper.h" />
<ClInclude Include="PaintingMesh.h" />
<ClInclude Include="ShortCutTree.h" />
<ClInclude Include="StraightLine.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">

View File

@ -67,6 +67,18 @@
<ClCompile Include="Light.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ShortCutTree.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Line.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CubicBezier.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StraightLine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<QtMoc Include="RendererWidget.h">
@ -148,5 +160,17 @@
<ClInclude Include="Light.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ShortCutTree.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Line.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CubicBezier.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StraightLine.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -4,7 +4,7 @@ GLuint BvhTree::getBvhNodeNum() {
return tot;
}
void BvhTree::buildBvhTree(QVector4D initBound[], int len) {
void BvhTree::buildBvhTree(BvhTreeData initBound[], int len) {
tot = 0;
root = subBvhTree(initBound, 0, len-1);
}
@ -18,39 +18,48 @@ QVector4D BvhTree::Union(QVector4D a, QVector4D b) {
);
}
QVector4D BvhTree::calcBound(QVector4D initBound[], int l, int r) {
QVector4D res = initBound[l];
QVector4D BvhTree::calcBound(BvhTreeData initBound[], int l, int r) {
QVector4D res = initBound[l].bound;
for (int i = l + 1; i <= r; i++) {
res = Union(res, initBound[i]);
res = Union(res, initBound[i].bound);
}
return res;
}
bvhPtr BvhTree::subBvhTree(QVector4D initBound[], int l, int r) {
BvhPtr BvhTree::subBvhTree(BvhTreeData initBound[], int l, int r) {
if (l > r) return NULL;
bvhPtr p(new BvhNode());
p.get()->lab = tot++;
p.get()->bound = calcBound(initBound, l, r);
if (l == r) return p;
int dim = p.get()->maximumBound();
BvhPtr p(new BvhNode());
p->lab = tot++;
p->bound = calcBound(initBound, l, r);
if (l == r) {
p->isLeaf = true;
BvhPtr lp(new BvhNode());
lp->lab = initBound[l].leftSon;
p->child[0] = lp;
BvhPtr rp(new BvhNode());
rp->lab = initBound[r].rightSon;
p->child[1] = rp;
return p;
}
int dim = p->maximumBound();
if (dim == 0) {
std::sort(initBound + l, initBound + r+1, BvhNode::x_compare);
} else {
std::sort(initBound + l, initBound + r+1, BvhNode::y_compare);
}
int mid = (l + r) >> 1;
p.get()->child[0] = subBvhTree(initBound, l, mid);
p.get()->child[1] = subBvhTree(initBound, mid+1, r);
p->child[0] = subBvhTree(initBound, l, mid);
p->child[1] = subBvhTree(initBound, mid+1, r);
return p;
}
void BvhTree::traverseBvhTree(bvhPtr now, std::vector<GLuint>& children, std::vector<QVector4D>& bounds) {
void BvhTree::traverseBvhTree(BvhPtr now, std::vector<GLuint>& children, std::vector<QVector4D>& bounds) {
if (now == NULL) return ;
children.push_back(now.get()->getLeftSon(0));
children.push_back(now.get()->getRightSon(1));
bounds.push_back(now.get()->bound);
traverseBvhTree(now.get()->child[0], children, bounds);
traverseBvhTree(now.get()->child[1], children, bounds);
children.push_back(now->getLeftSon(0));
children.push_back(now->getRightSon(1));
bounds.push_back(now->bound);
traverseBvhTree(now->child[0], children, bounds);
traverseBvhTree(now->child[1], children, bounds);
}

View File

@ -9,33 +9,49 @@
#include <memory>
#include <vector>
#include <cmath>
#define bvhPtr std::tr1::shared_ptr<BvhNode>
using std::tr1::shared_ptr;
struct BvhTreeData {
QVector4D bound;
GLuint leftSon, rightSon;
void show() {
printf("Bvh: (%lf, %lf) (%lf, %lf): %d %d\n",
bound.x(), bound.y(), bound.z(), bound.w(),
leftSon, rightSon);
}
BvhTreeData()
: leftSon(0), rightSon(0) {}
~BvhTreeData() {}
};
// BvhTree 节点
struct BvhNode {
GLuint lab;
bool isLeaf;
QVector4D bound;
bvhPtr child[2];
static bool x_compare(QVector4D a, QVector4D b) {
return a.x() < b.x();
shared_ptr<BvhNode> child[2];
static bool x_compare(BvhTreeData a, BvhTreeData b) {
return a.bound.x() < b.bound.x();
}
static bool y_compare(QVector4D a, QVector4D b) {
return a.y() < b.y();
static bool y_compare(BvhTreeData a, BvhTreeData b) {
return a.bound.y() < b.bound.y();
}
GLuint getLeftSon(int k) {
if (child[0] == NULL) {
return INT_MAX;
if (isLeaf) {
return 0x80000000+child[0]->lab;
}
return child[0].get()->lab;
return child[0]->lab;
}
GLuint getRightSon(int k) {
if (child[1] == NULL) {
return 0;
if (isLeaf) {
return child[1]->lab;
}
return child[1].get()->lab;
return child[1]->lab;
}
BvhNode() {
child[0] = child[1] = NULL;
isLeaf = false;
lab = 0;
}
int maximumBound() {
return (std::fabs(bound.x() - bound.w()) < std::fabs(bound.y() - bound.z()));
@ -43,22 +59,25 @@ struct BvhNode {
~BvhNode() {}
};
typedef std::tr1::shared_ptr<BvhNode> BvhPtr;
class BvhTree
{
private:
GLuint tot;
bvhPtr root;
static QVector4D calcBound(QVector4D initBound[], int l, int r);
BvhPtr root;
static QVector4D calcBound(BvhTreeData initBound[], int l, int r);
static QVector4D Union(QVector4D a, QVector4D b);
BvhPtr subBvhTree(BvhTreeData initBound[], int l, int r);
void traverseBvhTree(BvhPtr now, std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
public:
BvhTree() {
tot = 0;
root = NULL;
}
// 根据底层包围盒生成bvh树
void buildBvhTree(QVector4D initBound[], int len);
bvhPtr subBvhTree(QVector4D initBound[], int l, int r);
void traverseBvhTree(bvhPtr now, std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
void buildBvhTree(BvhTreeData initBound[], int len);
// 获得 Bvh rootBvh部分的 children 数组,包围盒数组 vector 传输
void getBvhArray(std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
// 获得 BvhTree 中节点总数

View File

@ -0,0 +1,122 @@
#include "CubicBezier.h"
float CubicBezier::getLineValueByT(float t, bool isY) {
vector<float> p;
if (isY) p = vY;
else p = vX;
float pt = 1 - t;
return pt * pt * pt * p[0] + 3 * t * pt * pt * p[1] + 3 * t * t * pt * p[2] + t * t * t * p[3];
}
point CubicBezier::getPointByT(point a, point b, float t) {
return { a.x * (1 - t) + b.x * t, a.y * (1 - t) + b.y * t };
}
point CubicBezier::calculateControlPoint(point a, point b) {
return {
a.x + 2 * (b.x - a.x) / 3,
a.y + 2 * (b.y - a.y) / 3
};
}
void CubicBezier::findPointsOfDivison(vector<float> &p, vector<float>& res) {
float a = -3 * p[0] + 9 * p[1] - 9 * p[2] + 3 * p[3];
float b = 6 * p[0] - 12 * p[1] + 6 * p[2];
float c = -3 * p[0] + 3 * p[1];
float deta = b * b - 4 * a * c, t = 0;
if (fabs(a) > eps) {
if (deta < eps) return;
deta = sqrt(deta);
t = (-b + deta) / 2 * a;
if (0 < t && t < 1) {
res.push_back(t);
}
if (fabs(deta) <= eps) return;
t = (-b - deta) / 2 * a;
if (0 < t && t < 1) {
res.push_back(t);
}
}
else if(fabs(b) > eps) {
t = -c/b;
if (0 < t && t < 1) {
res.push_back(t);
}
}
}
void CubicBezier::transformToCubic() {
if (siz == 4) return;
point p[3] = {
getPointByIndex(0),
getPointByIndex(1),
getPointByIndex(2)
};
setPointByIndex(1, calculateControlPoint(p[0], p[1]));
setPointByIndex(2, calculateControlPoint(p[1], p[2]));
push_back(p[2]);
siz = 4;
}
void CubicBezier::splitBezierCubic(float t, vector<LinePtr>& res) {
LinePtr Lf(new CubicBezier());
float pt = 1 - t;
point pointE = { getLineValueByT(t, false), getLineValueByT(t, true) };
point pointF = getPointByT(getPointByIndex(0), getPointByIndex(1), t);
point pointG = getPointByT(getPointByIndex(1), getPointByIndex(2), t);
point pointH = getPointByT(getPointByIndex(2), getPointByIndex(3), t);
Lf->push_back(getPointByIndex(0));
Lf->push_back(pointF);
Lf->push_back(getPointByT(pointF, pointG, t));
Lf->push_back(pointE);
res.push_back(Lf);
setPointByIndex(0, pointE);
setPointByIndex(1, getPointByT(pointG, pointH, t));
setPointByIndex(2, pointH);
}
void CubicBezier::monotonization(vector <LinePtr>& res) {
transformToCubic();
vector<float> re;
re.clear();
findPointsOfDivison(vX, re);
findPointsOfDivison(vY, re);
sort(re.begin(), re.end());
float lt = -1, x = 0, y = 0;
for (float &t : re) {
if (fabs(t - lt) <= eps) continue;
splitBezierCubic(t, res);
lt = t;
}
}
float CubicBezier::findTByValue(float value, bool isY) {
float l = 0, r = 1, be = 0;
if (isY) be = vY[0];
else be = vX[0];
while (fabs(r-l) > eps) {
float mid = (l + r) / 2, midValue = getLineValueByT(mid, isY);
if (fabs(midValue - be) > fabs(value - be)) {
r = mid;
}
else {
l = mid;
}
}
return l;
}
int CubicBezier::judgeBoundIntersection(float xy, float l, float r, bool isY) {
float be = *vX.begin(), en = *vX.rbegin();
if (isY) {
be = *vY.begin();
en = *vY.rbegin();
}
if ((be - xy) * (en - xy) > eps) return 0;
float t = findTByValue(xy, isY);
float value = getLineValueByT(t, !isY);
if (l <= value && value <= r && fabs(t) > eps) {
return 1 + direction(isY);
}
return 0;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "Line.h"
#include <memory>
class CubicBezier : public Line
{
using Line::Line;
private:
static point getPointByT(point a, point b, float t);
static point calculateControlPoint(point a, point b);
static void findPointsOfDivison(vector<float> &p, vector<float>& res);
void splitBezierCubic(float t, vector<LinePtr>& res);
public:
virtual float findTByValue(float value, bool isY);
virtual void monotonization(vector <LinePtr>& res);
virtual float getLineValueByT(float t, bool isY);
virtual int judgeBoundIntersection(float xy, float l, float r, bool isY);
void transformToCubic();
};

View File

@ -0,0 +1,73 @@
#include "CubicMonotonization.h"
const double CubicMonotonization::eps = 1e-6;
CubicMonotonization::point CubicMonotonization::getPointByT(point a, point b, double t) const {
return { a.first * (1 - t) + b.first, a.second * (1 - t) + b.second };
}
void CubicMonotonization::findPointsOfDivison(vector<double> p, vector<double>& res) {
double a = -p[0] + 7 * p[1] - 9 * p[2] + 3 * p[3];
double b = 6 * p[0] - 12 * p[1] + 6 * p[2];
double c = -3 * p[0] + 3*p[1];
double deta = b * b - 4*a*c;
if (fabs(deta) < eps) return;
double t = 0;
if (fabs(a) <= eps) {
deta = sqrt(deta);
t = -b + deta;
if (0 < t && t < 1) {
res.push_back(t);
}
if (fabs(deta) <= eps) return ;
t = -b - deta;
if (0 < t && t < 1) {
res.push_back(t);
}
}
}
double CubicMonotonization::getBezierPoint(vector<double> &p, double t) const{
double pt = 1 - t;
return pt * pt * pt * p[0] + 3 * t * pt * pt * p[1] + 3 * t * t * pt * p[2] + t * t * t * p[3];
}
void CubicMonotonization::splitBezierCubic(Line& p, point mid, double t, vector <Line>& res) {
Line Lf; Lf.clear();
double pt = 1 - t;
Lf.push_back(p[0]);
point pointF = getPointByT(p[0], p[1], t);
point pointG = getPointByT(p[1], p[2], t);
point pointH = getPointByT(p[2], p[3], t);
Lf.push_back(pointF);
Lf.push_back(getPointByT(pointF, pointG, t));
Lf.push_back(mid);
res.push_back(Lf);
p[0] = mid;
p[1] = getPointByT(pointG, pointH, t);
p[2] = pointH;
}
void CubicMonotonization::getPointsOfDivision(Line p, vector <Line>& res) {
vector<double> vX, vY, re;
vX.clear();
vY.clear();
re.clear();
for (point now : p) {
vX.push_back(now.first);
vY.push_back(now.second);
}
findPointsOfDivison(vX, re);
findPointsOfDivison(vY, re);
sort(re.begin(), re.end());
double lt = 0, x = 0, y = 0;
for (double &t : re) {
if (fabs(t - lt) <= eps) continue;
x = getBezierPoint(vX, t);
y = getBezierPoint(vY, t);
splitBezierCubic(p, { x, y }, t, res);
lt = t;
}
}

View File

@ -0,0 +1,24 @@
#include <utility>
#include <vector>
#include <algorithm>
#pragma once
using std::pair;
using std::vector;
using std::min;
using std::max;
using std::sort;
class CubicMonotonization
{
typedef pair<double, double> point;
typedef vector<point> Line;
private:
static const double eps;
point getPointByT(point a, point b, double t) const;
void findPointsOfDivison(vector<double> p, vector<double> &res);
double getBezierPoint(vector<double> &p, double t) const;
void splitBezierCubic(Line& p, point mid, double t, vector <Line> &res);
public:
// p 为端点、控制点、控制点、端点, res 为所有导数为0的点
void getPointsOfDivision(Line p, vector <Line> &res);
};

View File

@ -0,0 +1,80 @@
#include "Line.h"
Line::Line(vector<point> Vp) {
siz = Vp.size();
for (point now : Vp) {
vX.push_back(now.x);
vY.push_back(now.y);
}
}
int Line::size() {
return siz;
}
vector<point> Line::toVectorPoint() const {
vector<point> vL;
for (int i = 0; i < siz; i++) {
vL.push_back({vX[i], vY[i]});
}
return vL;
}
point Line::operator[](int index) const {
return { vX[index], vY[index] };
}
point Line::getPointByIndex(int index) const {
return operator[](index);
}
void Line::setPointByIndex(int index, point now) {
vX[index] = now.x;
vY[index] = now.y;
}
void Line::clear() {
vX.clear();
vY.clear();
}
void Line::push_back(point now) {
siz++;
vX.push_back(now.x);
vY.push_back(now.y);
}
bool Line::isLineContained(QVector4D bound) {
float xMi = min(*vX.begin(), *vX.rbegin()), xMx = max(*vX.begin(), *vX.rbegin());
float yMi = min(*vY.begin(), *vY.rbegin()), yMx = max(*vY.begin(), *vY.rbegin());
if (bound.x() <= xMi && xMx <= bound.z() && bound.y() <= yMi && yMx <= bound.w())
return true;
else return false;
}
point Line::getBegin() {
return { *vX.begin(), *vY.begin() };
}
point Line::getEnd() {
return { *vX.rbegin(), *vY.rbegin() };
}
int Line::direction(bool isY) {
float be = *vX.begin(), en = *vX.rbegin();
if (isY) {
be = *vY.begin();
en = *vY.rbegin();
}
if (fabs(en - be) <= eps) return 0;
else if (be < en) return 1;
else return 2;
}
bool Line::judgeIntersection(QVector4D bound) {
return isLineContained(bound)
|| judgeBoundIntersection(bound.y(), bound.x(), bound.z(), true)
|| judgeBoundIntersection(bound.w(), bound.x(), bound.z(), true)
|| judgeBoundIntersection(bound.x(), bound.y(), bound.w(), false)
|| judgeBoundIntersection(bound.z(), bound.y(), bound.w(), false);
}

View File

@ -0,0 +1,63 @@
#pragma once
#include <vector>
#include <utility>
#include <vector>
#include <QVector4D>
#include <algorithm>
#include <memory>
#include <iostream>
using std::vector;
using std::pair;
using std::min;
using std::max;
using std::sort;
using std::tr1::shared_ptr;
using std::tr1::make_shared;
using std::swap;
const float eps = 1e-6;
struct point {
float x, y;
point operator - (const point a) { return { x - a.x, y - a.y }; }
float operator * (const point a) { return x * a.y - y * a.x; }
bool operator== (const point& a) const {
return fabs(x - a.x) <= eps && fabs(y - a.y) <= eps;
}
bool operator< (const point& a) const {
return fabs(x - a.x) <= eps ? y < a.y : x < a.x;
}
void show() {
std::cout << '(' << x << ',' << y << ')' << ' ';
}
};
class Line
{
protected:
vector<float> vX, vY;
int siz;
public:
typedef shared_ptr<Line> LinePtr;
Line() :siz(0) {}
Line(vector<point> Vp);
int size();
void clear();
point getBegin();
point getEnd();
int direction(bool isY);
virtual float getLineValueByT(float t, bool isY) = 0;
virtual void monotonization(vector <LinePtr>& res) = 0;
virtual int judgeBoundIntersection(float xy, float l, float r, bool isY) = 0;
virtual bool judgeIntersection(QVector4D bound);
bool isLineContained(QVector4D bound);
point operator[](int index) const;
point getPointByIndex(int index) const;
vector<point> toVectorPoint() const;
void setPointByIndex(int index, point now);
void push_back(point now);
virtual ~Line() {}
};
typedef shared_ptr<Line> LinePtr;

View File

@ -185,7 +185,7 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
initBound.push_back(QVector4D(-0.8, 0.7, -0.7, 0.8));
initBound.push_back(QVector4D(0.7, -0.8, 0.8, -0.7));
initBound.push_back(QVector4D(0.7, 0.7, 0.8, 0.8));*/
bvhTree.buildBvhTree(initBound.data(), initBound.size());
//bvhTree.buildBvhTree(initBound.data(), initBound.size());
std::vector<GLuint> children;
std::vector<QVector4D> bounds;
bvhTree.getBvhArray(children, bounds);

View File

@ -0,0 +1,238 @@
#include "ShortCutTree.h"
void ShortCutTree::init() {
outTree.clear();
allLine.clear();
pointMap.clear();
lineIndexSet.clear();
numLine = numPoint = 0;
}
int ShortCutTree::getPointIndex(point now) {
auto iter = pointMap.find(now);
if (iter != pointMap.end()) {
return iter->second;
}
else {
++numPoint;
pointMap.insert({ now, numPoint });
return numPoint;
}
}
bool ShortCutTree::isLineEqual(LineIndex& a, LineIndex& b) const {
if (a.size() != b.size())
return false;
for (int i = 0; i < a.size(); i++)
if (a[i] != b[i])
return false;
return true;
}
void ShortCutTree::Monotonization(vector<vLine>& inL, vector<LinePtr>& outL) {
for (vLine &l: inL) {
LinePtr now;
switch(l.size()) {
case 2: now.reset(new StraightLine(l)); break;
case 3: case 4: now.reset(new CubicBezier(l)); break;
default: break;
}
now->monotonization(outL);
outL.push_back(now);
}
}
void ShortCutTree::generateShortCutSegement(ShortCutNode& now) {
point p;
vector<int> v;
for (int &index : now.lineSet) {
int type = allLine[index]->judgeBoundIntersection(now.bound.z(), now.bound.y(), now.bound.w(), false), be, en;
if (type >= 2) {
numLine++;
v.push_back(numLine);
if (type == 2) {
p = allLine[index]->getEnd();
}
if (type == 3) {
p = allLine[index]->getBegin();
}
be = getPointIndex({ p.x, now.bound.w() });
en = getPointIndex(p);
lineIndexSet.push_back(be);
lineIndexSet.push_back(be);
lineIndexSet.push_back(en);
lineIndexSet.push_back(en);
}
}
for (int& index : v) {
now.lineSet.push_back(index);
}
}
bool ShortCutTree::handleShortCutNode(ShortCutNode& fa, ShortCutNode& now, float yValue, vector<ShortCutNode>& v, int& sumIncrement) {
now.windingIncrement = sumIncrement;
for (int &index : fa.lineSet) {
int type = allLine[index]->judgeBoundIntersection(yValue, now.bound.x(), now.bound.z(), true);
if (type == 2)
sumIncrement++;
if (type == 3)
sumIncrement--;
if (allLine[index]->judgeIntersection(now.bound)) {
now.lineSet.push_back(index);
}
}
if (now.lineSet.size() <= RequiredLineMi) {
if (now.lineSet.empty() && now.windingIncrement == 0)
return false;
outTree.push_back(now);
now.divided = false;
v.push_back(now);
return false;
}
else {
v.push_back(now);
return true;
}
}
void ShortCutTree::simplifyLineVector() {
numLine = allLine.size();
for (auto& l : allLine) {
vLine vl = l->toVectorPoint();
for (point& p : vl) {
int index = getPointIndex(p);
lineIndexSet.push_back(index);
if (vl.size() == 2)
lineIndexSet.push_back(index);
}
}
for (auto& now : outTree) {
generateShortCutSegement(now);
}
}
void ShortCutTree::spliteToShortCutTree() {
queue<ShortCutNode> Q;
queue<pair<float, float> > lineBound;
ShortCutNode root;
root.bound = QVector4D(-1, -1, 1, 1);
for (int i = 0; i < allLine.size(); i++) {
root.lineSet.push_back(i);
}
Q.push(root);
lineBound.push({ -1, 1 });
vector<ShortCutNode> v, vn;
while (!lineBound.empty()) {
// 取出一行的所有可行方格
auto seg = lineBound.front();
float yMid = (seg.first + seg.second) / 2;
lineBound.pop();
while (!Q.empty()) {
auto now = Q.front();
if (now.bound.y() <= seg.first && seg.second <= now.bound.w()) {
v.push_back(now);
Q.pop();
}
else {
break;
}
}
int sumIncrement = 0;
bool isDivided = false;
vn.clear();
// 上部分;
for (auto& now : v) {
if (!now.divided) {
for (int& index : now.lineSet) {
int type = allLine[index]->judgeBoundIntersection(yMid, now.bound.x(), now.bound.z(), true);
if (type == 2)
sumIncrement++;
if (type == 3)
sumIncrement--;
}
vn.push_back(now);
}
else {
ShortCutNode nw, ne;
float xMid = (now.bound.x() + now.bound.z()) / 2;
ne.bound = QVector4D(xMid, yMid, now.bound.z(), now.bound.w());
isDivided |= handleShortCutNode(now, ne, yMid, vn, sumIncrement);
nw.bound = QVector4D(now.bound.x(), yMid, xMid, now.bound.w());
isDivided |= handleShortCutNode(now, nw, yMid, vn, sumIncrement);
}
}
if (isDivided) {
lineBound.push({yMid, seg.second});
for (auto& now : vn) {
Q.push(now);
}
}
// 下部分
vn.clear();
sumIncrement = 0;
isDivided = false;
for (auto& now : v) {
if (!now.divided) {
sumIncrement += now.windingIncrement;
vn.push_back(now);
}
else {
ShortCutNode se, sw;
float xMid = (now.bound.x() + now.bound.z()) / 2;
yMid = (now.bound.y() + now.bound.w()) / 2;
se.bound = QVector4D(xMid, now.bound.y(), now.bound.z(), yMid);
isDivided |= handleShortCutNode(now, se, seg.first, vn, sumIncrement);
sw.bound = QVector4D(now.bound.x(), now.bound.y(), xMid, yMid);
isDivided |= handleShortCutNode(now, sw, seg.first, vn, sumIncrement);
}
}
if (isDivided) {
lineBound.push({seg.first, yMid});
for (auto& now : vn) {
Q.push(now);
}
}
}
}
void ShortCutTree::buildShortCutTree(vector<vLine>& lineSet) {
init();
Monotonization(lineSet, allLine);
spliteToShortCutTree();
simplifyLineVector();
}
vector<BvhTreeData> ShortCutTree::getPointLineAndBvhTree(vector<float>& pointSet, vector<int>& lineSet) {
vector<pair<int, point> > vp; vp.clear();
for (auto& now : pointMap) {
vp.push_back({ now.second , now.first});
}
sort(vp.begin(), vp.end());
for (auto& now : vp) {
pointSet.push_back(now.second.x);
pointSet.push_back(now.second.y);
//now.second.show();
//std::cout << '\n';
}
for (auto& now : lineIndexSet) {
lineSet.push_back(now);
//std::cout << now << ' ';
}
std::cout << '\n';
vector<BvhTreeData> v;
for (auto& now : outTree) {
BvhTreeData oneData;
oneData.leftSon = lineSet.size();
//std::cout << now.lineSet.size() << ' ';
lineSet.push_back(now.lineSet.size());
for (auto& index : now.lineSet) {
lineSet.push_back(index);
//std::cout << index << ' ';
}
//std::cout << '\n';
v.push_back(oneData);
}
return v;
}

View File

@ -0,0 +1,56 @@
#pragma once
#include "CubicBezier.h"
#include "StraightLine.h"
#include "BvhTree.h"
#include <queue>
using std::queue;
using std::map;
using std::for_each;
struct ShortCutNode {
typedef vector<point> vLine;
int windingIncrement;
bool divided;
/* type 代表进入广度优先搜索队列的节点种类:
0
1*/
QVector4D bound;
vector<int> lineSet;
ShortCutNode() {
divided = true;
windingIncrement = 0;
lineSet.clear();
bound = { 0, 0, 0, 0 };
}
~ShortCutNode() {}
};
class ShortCutTree
{
typedef vector<point> vLine;
typedef vector<int> LineIndex;
private:
vector<ShortCutNode> outTree;
vector<LinePtr> allLine;
int RequiredLineMi, numPoint, numLine;
map<point, int> pointMap;
vector<int> lineIndexSet;
int getPointIndex(point now);
void generateShortCutSegement(ShortCutNode& now);
bool handleShortCutNode(ShortCutNode& fa, ShortCutNode& now, float yValue, vector<ShortCutNode>& v, int& sumIncrement);
void spliteToShortCutTree();
static void Monotonization(vector<vLine>& inL, vector<LinePtr> &outL);
bool isLineEqual(LineIndex& a, LineIndex& b) const;
void simplifyLineVector();
public:
void init();
ShortCutTree(int lineMi = 3)
:RequiredLineMi(lineMi), numPoint(0), numLine(0) {}
// 传入一个vector<vector<point> > 作为所有输入的线
void buildShortCutTree(vector<vLine>& lineSet);
// 获得点集合和线集合 返回输入BvhTree的数据集合
vector<BvhTreeData> getPointLineAndBvhTree(vector<float> &pointSet, vector<int> &lineSet);
~ShortCutTree() {}
};

View File

@ -0,0 +1,48 @@
#include "StraightLine.h"
float StraightLine::getLineValueByT(float t, bool isY) {
float pBe, pEn;
if (isY) {
pBe = *vY.begin();
pEn = *vY.rbegin();
}
else {
pBe = *vX.begin();
pEn = *vY.rbegin();
}
return t * (pEn - pBe) + pBe;
}
float StraightLine::findTByValue(float value, bool isY) {
point be = getPointByIndex(0), en = getPointByIndex(1);
if (!isY) {
if(fabs(be.x - en.x) <= eps) return 0;
return (value - be.x) / (en.x - be.x);
}
else {
if (fabs(be.y - en.y) <= eps) return 0;
return (value - be.y) / (en.y - be.y);
}
}
int StraightLine::judgeBoundIntersection(float xy, float l, float r, bool isY) {
point be = getBegin(), en = getEnd();
if (isY) {
swap(be.x, be.y);
swap(en.x, en.y);
}
if ((be.x - xy) * (en.x - xy) > eps) return 0;
if (direction(isY)) {
float t = findTByValue(xy, isY);
float value = getLineValueByT(t, !isY);
if (l <= value && value <= r && fabs(t) > eps) {
return 1 + direction(isY);
}
return 0;
} else {
if (be.y <= l && en.y < l) return 0;
if (be.y >= r && en.y > r) return 0;
return 1;
}
return 0;
}

View File

@ -0,0 +1,10 @@
#include "Line.h"
class StraightLine : public Line
{
using Line::Line;
virtual float getLineValueByT(float t, bool isY);
virtual void monotonization(vector <LinePtr>& res) {};
virtual float findTByValue(float value, bool isY);
virtual int judgeBoundIntersection(float xy, float l, float r, bool isY);
};