parent
79883302ac
commit
e164042a77
|
@ -87,13 +87,16 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="BvhTree.cpp" />
|
<ClCompile Include="BvhTree.cpp" />
|
||||||
<ClCompile Include="Camera.cpp" />
|
<ClCompile Include="Camera.cpp" />
|
||||||
<ClCompile Include="CubicMonotonization.cpp" />
|
<ClCompile Include="CubicBezier.cpp" />
|
||||||
<ClCompile Include="Light.cpp" />
|
<ClCompile Include="Light.cpp" />
|
||||||
|
<ClCompile Include="Line.cpp" />
|
||||||
<ClCompile Include="Mesh.cpp" />
|
<ClCompile Include="Mesh.cpp" />
|
||||||
<ClCompile Include="Model.cpp" />
|
<ClCompile Include="Model.cpp" />
|
||||||
<ClCompile Include="PaintingHelper.cpp" />
|
<ClCompile Include="PaintingHelper.cpp" />
|
||||||
<ClCompile Include="PaintingMesh.cpp" />
|
<ClCompile Include="PaintingMesh.cpp" />
|
||||||
<ClCompile Include="RendererWidget.cpp" />
|
<ClCompile Include="RendererWidget.cpp" />
|
||||||
|
<ClCompile Include="ShortCutTree.cpp" />
|
||||||
|
<ClCompile Include="StraightLine.cpp" />
|
||||||
<QtRcc Include="MainWindow.qrc" />
|
<QtRcc Include="MainWindow.qrc" />
|
||||||
<QtUic Include="MainWindow.ui" />
|
<QtUic Include="MainWindow.ui" />
|
||||||
<QtMoc Include="MainWindow.h" />
|
<QtMoc Include="MainWindow.h" />
|
||||||
|
@ -124,13 +127,16 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="BvhTree.h" />
|
<ClInclude Include="BvhTree.h" />
|
||||||
<ClInclude Include="Camera.h" />
|
<ClInclude Include="Camera.h" />
|
||||||
<ClInclude Include="CubicMonotonization.h" />
|
<ClInclude Include="CubicBezier.h" />
|
||||||
<ClInclude Include="Drawable.h" />
|
<ClInclude Include="Drawable.h" />
|
||||||
<ClInclude Include="Light.h" />
|
<ClInclude Include="Light.h" />
|
||||||
|
<ClInclude Include="Line.h" />
|
||||||
<ClInclude Include="Mesh.h" />
|
<ClInclude Include="Mesh.h" />
|
||||||
<ClInclude Include="Model.h" />
|
<ClInclude Include="Model.h" />
|
||||||
<ClInclude Include="PaintingHelper.h" />
|
<ClInclude Include="PaintingHelper.h" />
|
||||||
<ClInclude Include="PaintingMesh.h" />
|
<ClInclude Include="PaintingMesh.h" />
|
||||||
|
<ClInclude Include="ShortCutTree.h" />
|
||||||
|
<ClInclude Include="StraightLine.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||||
|
|
|
@ -67,7 +67,16 @@
|
||||||
<ClCompile Include="Light.cpp">
|
<ClCompile Include="Light.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="CubicMonotonization.cpp">
|
<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>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -151,7 +160,16 @@
|
||||||
<ClInclude Include="Light.h">
|
<ClInclude Include="Light.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="CubicMonotonization.h">
|
<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>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -4,7 +4,7 @@ GLuint BvhTree::getBvhNodeNum() {
|
||||||
return tot;
|
return tot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BvhTree::buildBvhTree(QVector4D initBound[], int len) {
|
void BvhTree::buildBvhTree(BvhTreeData initBound[], int len) {
|
||||||
tot = 0;
|
tot = 0;
|
||||||
root = subBvhTree(initBound, 0, len-1);
|
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 BvhTree::calcBound(BvhTreeData initBound[], int l, int r) {
|
||||||
QVector4D res = initBound[l];
|
QVector4D res = initBound[l].bound;
|
||||||
for (int i = l + 1; i <= r; i++) {
|
for (int i = l + 1; i <= r; i++) {
|
||||||
res = Union(res, initBound[i]);
|
res = Union(res, initBound[i].bound);
|
||||||
}
|
}
|
||||||
return res;
|
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;
|
if (l > r) return NULL;
|
||||||
bvhPtr p(new BvhNode());
|
BvhPtr p(new BvhNode());
|
||||||
p.get()->lab = tot++;
|
p->lab = tot++;
|
||||||
p.get()->bound = calcBound(initBound, l, r);
|
p->bound = calcBound(initBound, l, r);
|
||||||
if (l == r) return p;
|
if (l == r) {
|
||||||
int dim = p.get()->maximumBound();
|
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) {
|
if (dim == 0) {
|
||||||
std::sort(initBound + l, initBound + r+1, BvhNode::x_compare);
|
std::sort(initBound + l, initBound + r+1, BvhNode::x_compare);
|
||||||
} else {
|
} else {
|
||||||
std::sort(initBound + l, initBound + r+1, BvhNode::y_compare);
|
std::sort(initBound + l, initBound + r+1, BvhNode::y_compare);
|
||||||
}
|
}
|
||||||
int mid = (l + r) >> 1;
|
int mid = (l + r) >> 1;
|
||||||
p.get()->child[0] = subBvhTree(initBound, l, mid);
|
p->child[0] = subBvhTree(initBound, l, mid);
|
||||||
p.get()->child[1] = subBvhTree(initBound, mid+1, r);
|
p->child[1] = subBvhTree(initBound, mid+1, r);
|
||||||
return p;
|
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 ;
|
if (now == NULL) return ;
|
||||||
children.push_back(now.get()->getLeftSon(0));
|
children.push_back(now->getLeftSon(0));
|
||||||
children.push_back(now.get()->getRightSon(1));
|
children.push_back(now->getRightSon(1));
|
||||||
bounds.push_back(now.get()->bound);
|
bounds.push_back(now->bound);
|
||||||
traverseBvhTree(now.get()->child[0], children, bounds);
|
traverseBvhTree(now->child[0], children, bounds);
|
||||||
traverseBvhTree(now.get()->child[1], children, bounds);
|
traverseBvhTree(now->child[1], children, bounds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,31 +11,47 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
using std::tr1::shared_ptr;
|
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 节点
|
// BvhTree 节点
|
||||||
struct BvhNode {
|
struct BvhNode {
|
||||||
GLuint lab;
|
GLuint lab;
|
||||||
|
bool isLeaf;
|
||||||
QVector4D bound;
|
QVector4D bound;
|
||||||
shared_ptr<BvhNode> child[2];
|
shared_ptr<BvhNode> child[2];
|
||||||
static bool x_compare(QVector4D a, QVector4D b) {
|
static bool x_compare(BvhTreeData a, BvhTreeData b) {
|
||||||
return a.x() < b.x();
|
return a.bound.x() < b.bound.x();
|
||||||
}
|
}
|
||||||
static bool y_compare(QVector4D a, QVector4D b) {
|
static bool y_compare(BvhTreeData a, BvhTreeData b) {
|
||||||
return a.y() < b.y();
|
return a.bound.y() < b.bound.y();
|
||||||
}
|
}
|
||||||
GLuint getLeftSon(int k) {
|
GLuint getLeftSon(int k) {
|
||||||
if (child[0] == NULL) {
|
if (isLeaf) {
|
||||||
return INT_MAX;
|
return 0x80000000+child[0]->lab;
|
||||||
}
|
}
|
||||||
return child[0].get()->lab;
|
return child[0]->lab;
|
||||||
}
|
}
|
||||||
GLuint getRightSon(int k) {
|
GLuint getRightSon(int k) {
|
||||||
if (child[1] == NULL) {
|
if (isLeaf) {
|
||||||
return 0;
|
return child[1]->lab;
|
||||||
}
|
}
|
||||||
return child[1].get()->lab;
|
return child[1]->lab;
|
||||||
}
|
}
|
||||||
BvhNode() {
|
BvhNode() {
|
||||||
child[0] = child[1] = NULL;
|
child[0] = child[1] = NULL;
|
||||||
|
isLeaf = false;
|
||||||
|
lab = 0;
|
||||||
}
|
}
|
||||||
int maximumBound() {
|
int maximumBound() {
|
||||||
return (std::fabs(bound.x() - bound.w()) < std::fabs(bound.y() - bound.z()));
|
return (std::fabs(bound.x() - bound.w()) < std::fabs(bound.y() - bound.z()));
|
||||||
|
@ -43,25 +59,25 @@ struct BvhNode {
|
||||||
~BvhNode() {}
|
~BvhNode() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tr1::shared_ptr<BvhNode> bvhPtr;
|
typedef std::tr1::shared_ptr<BvhNode> BvhPtr;
|
||||||
|
|
||||||
class BvhTree
|
class BvhTree
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLuint tot;
|
GLuint tot;
|
||||||
bvhPtr root;
|
BvhPtr root;
|
||||||
static QVector4D calcBound(QVector4D initBound[], int l, int r);
|
static QVector4D calcBound(BvhTreeData initBound[], int l, int r);
|
||||||
static QVector4D Union(QVector4D a, QVector4D b);
|
static QVector4D Union(QVector4D a, QVector4D b);
|
||||||
bvhPtr subBvhTree(QVector4D initBound[], int l, int r);
|
BvhPtr subBvhTree(BvhTreeData initBound[], int l, int r);
|
||||||
void traverseBvhTree(bvhPtr now, std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
|
void traverseBvhTree(BvhPtr now, std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
|
||||||
public:
|
public:
|
||||||
BvhTree() {
|
BvhTree() {
|
||||||
tot = 0;
|
tot = 0;
|
||||||
root = NULL;
|
root = NULL;
|
||||||
}
|
}
|
||||||
// 根据底层包围盒生成bvh树
|
// 根据底层包围盒生成bvh树
|
||||||
void buildBvhTree(QVector4D initBound[], int len);
|
void buildBvhTree(BvhTreeData initBound[], int len);
|
||||||
// 获得 Bvh (rootBvh部分)的 children 数组,包围盒数组 vector 传输
|
// 获得 Bvh (rootBvh部分)的 children 数组,包围盒数组 vector 传输
|
||||||
void getBvhArray(std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
|
void getBvhArray(std::vector<GLuint>& children, std::vector<QVector4D>& bounds);
|
||||||
// 获得 BvhTree 中节点总数
|
// 获得 BvhTree 中节点总数
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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();
|
||||||
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
|
@ -179,7 +179,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.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.8, 0.8, -0.7));
|
||||||
initBound.push_back(QVector4D(0.7, 0.7, 0.8, 0.8));*/
|
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<GLuint> children;
|
||||||
std::vector<QVector4D> bounds;
|
std::vector<QVector4D> bounds;
|
||||||
bvhTree.getBvhArray(children, bounds);
|
bvhTree.getBvhArray(children, bounds);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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() {}
|
||||||
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
Loading…
Reference in New Issue