From e164042a771e8969a72b70e6f0aab412e5f220e2 Mon Sep 17 00:00:00 2001
From: "yang.yongquan" <3395816735@qq.com>
Date: Fri, 30 Sep 2022 23:45:42 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86BvhTree=20=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0=E4=BA=86ShortCutTree=E6=8B=86=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ArchitectureColoredPainting.vcxproj | 10 +-
...rchitectureColoredPainting.vcxproj.filters | 22 +-
ArchitectureColoredPainting/BvhTree.cpp | 45 ++--
ArchitectureColoredPainting/BvhTree.h | 48 ++--
ArchitectureColoredPainting/CubicBezier.cpp | 122 +++++++++
ArchitectureColoredPainting/CubicBezier.h | 20 ++
ArchitectureColoredPainting/Line.cpp | 80 ++++++
ArchitectureColoredPainting/Line.h | 63 +++++
ArchitectureColoredPainting/Model.cpp | 2 +-
ArchitectureColoredPainting/ShortCutTree.cpp | 238 ++++++++++++++++++
ArchitectureColoredPainting/ShortCutTree.h | 56 +++++
ArchitectureColoredPainting/StraightLine.cpp | 48 ++++
ArchitectureColoredPainting/StraightLine.h | 10 +
13 files changed, 725 insertions(+), 39 deletions(-)
create mode 100644 ArchitectureColoredPainting/CubicBezier.cpp
create mode 100644 ArchitectureColoredPainting/CubicBezier.h
create mode 100644 ArchitectureColoredPainting/Line.cpp
create mode 100644 ArchitectureColoredPainting/Line.h
create mode 100644 ArchitectureColoredPainting/ShortCutTree.cpp
create mode 100644 ArchitectureColoredPainting/ShortCutTree.h
create mode 100644 ArchitectureColoredPainting/StraightLine.cpp
create mode 100644 ArchitectureColoredPainting/StraightLine.h
diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
index dc95cf0..db4a2a9 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
@@ -87,13 +87,16 @@
-
+
+
+
+
@@ -124,13 +127,16 @@
-
+
+
+
+
diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
index 092c1d5..9cb0c67 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
@@ -67,7 +67,16 @@
Source Files
-
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
Source Files
@@ -151,7 +160,16 @@
Header Files
-
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
Header Files
diff --git a/ArchitectureColoredPainting/BvhTree.cpp b/ArchitectureColoredPainting/BvhTree.cpp
index 907ee25..6ebce18 100644
--- a/ArchitectureColoredPainting/BvhTree.cpp
+++ b/ArchitectureColoredPainting/BvhTree.cpp
@@ -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& children, std::vector& bounds) {
+void BvhTree::traverseBvhTree(BvhPtr now, std::vector& children, std::vector& 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);
}
diff --git a/ArchitectureColoredPainting/BvhTree.h b/ArchitectureColoredPainting/BvhTree.h
index 4bc5e2e..0dad260 100644
--- a/ArchitectureColoredPainting/BvhTree.h
+++ b/ArchitectureColoredPainting/BvhTree.h
@@ -11,31 +11,47 @@
#include
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;
shared_ptr child[2];
- static bool x_compare(QVector4D a, QVector4D b) {
- return a.x() < b.x();
+ 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,25 +59,25 @@ struct BvhNode {
~BvhNode() {}
};
-typedef std::tr1::shared_ptr bvhPtr;
+typedef std::tr1::shared_ptr 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(QVector4D initBound[], int l, int r);
- void traverseBvhTree(bvhPtr now, std::vector& children, std::vector& bounds);
+ BvhPtr subBvhTree(BvhTreeData initBound[], int l, int r);
+ void traverseBvhTree(BvhPtr now, std::vector& children, std::vector& bounds);
public:
BvhTree() {
tot = 0;
root = NULL;
}
// 根据底层包围盒生成bvh树
- void buildBvhTree(QVector4D initBound[], int len);
+ void buildBvhTree(BvhTreeData initBound[], int len);
// 获得 Bvh (rootBvh部分)的 children 数组,包围盒数组 vector 传输
void getBvhArray(std::vector& children, std::vector& bounds);
// 获得 BvhTree 中节点总数
diff --git a/ArchitectureColoredPainting/CubicBezier.cpp b/ArchitectureColoredPainting/CubicBezier.cpp
new file mode 100644
index 0000000..459f0ac
--- /dev/null
+++ b/ArchitectureColoredPainting/CubicBezier.cpp
@@ -0,0 +1,122 @@
+#include "CubicBezier.h"
+
+float CubicBezier::getLineValueByT(float t, bool isY) {
+ vector 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 &p, vector& 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& 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 & res) {
+ transformToCubic();
+ vector 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;
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/CubicBezier.h b/ArchitectureColoredPainting/CubicBezier.h
new file mode 100644
index 0000000..835485f
--- /dev/null
+++ b/ArchitectureColoredPainting/CubicBezier.h
@@ -0,0 +1,20 @@
+#pragma once
+#include "Line.h"
+#include
+
+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 &p, vector& res);
+ void splitBezierCubic(float t, vector& res);
+public:
+ virtual float findTByValue(float value, bool isY);
+ virtual void monotonization(vector & res);
+ virtual float getLineValueByT(float t, bool isY);
+ virtual int judgeBoundIntersection(float xy, float l, float r, bool isY);
+ void transformToCubic();
+};
+
diff --git a/ArchitectureColoredPainting/Line.cpp b/ArchitectureColoredPainting/Line.cpp
new file mode 100644
index 0000000..2585b49
--- /dev/null
+++ b/ArchitectureColoredPainting/Line.cpp
@@ -0,0 +1,80 @@
+#include "Line.h"
+
+Line::Line(vector Vp) {
+ siz = Vp.size();
+ for (point now : Vp) {
+ vX.push_back(now.x);
+ vY.push_back(now.y);
+ }
+}
+
+int Line::size() {
+ return siz;
+}
+
+vector Line::toVectorPoint() const {
+ vector 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);
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/Line.h b/ArchitectureColoredPainting/Line.h
new file mode 100644
index 0000000..c1e259d
--- /dev/null
+++ b/ArchitectureColoredPainting/Line.h
@@ -0,0 +1,63 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 vX, vY;
+ int siz;
+public:
+ typedef shared_ptr LinePtr;
+ Line() :siz(0) {}
+ Line(vector 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 & 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 toVectorPoint() const;
+ void setPointByIndex(int index, point now);
+ void push_back(point now);
+ virtual ~Line() {}
+};
+
+typedef shared_ptr LinePtr;
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/Model.cpp b/ArchitectureColoredPainting/Model.cpp
index 31149b6..f32defb 100644
--- a/ArchitectureColoredPainting/Model.cpp
+++ b/ArchitectureColoredPainting/Model.cpp
@@ -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.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 children;
std::vector bounds;
bvhTree.getBvhArray(children, bounds);
diff --git a/ArchitectureColoredPainting/ShortCutTree.cpp b/ArchitectureColoredPainting/ShortCutTree.cpp
new file mode 100644
index 0000000..81b9165
--- /dev/null
+++ b/ArchitectureColoredPainting/ShortCutTree.cpp
@@ -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& inL, vector& 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 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& 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 Q;
+ queue > 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 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& lineSet) {
+ init();
+ Monotonization(lineSet, allLine);
+ spliteToShortCutTree();
+ simplifyLineVector();
+}
+
+vector ShortCutTree::getPointLineAndBvhTree(vector& pointSet, vector& lineSet) {
+ vector > 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 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;
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/ShortCutTree.h b/ArchitectureColoredPainting/ShortCutTree.h
new file mode 100644
index 0000000..d422ba0
--- /dev/null
+++ b/ArchitectureColoredPainting/ShortCutTree.h
@@ -0,0 +1,56 @@
+#pragma once
+#include "CubicBezier.h"
+#include "StraightLine.h"
+#include "BvhTree.h"
+#include
+
+using std::queue;
+using std::map;
+using std::for_each;
+
+struct ShortCutNode {
+ typedef vector vLine;
+ int windingIncrement;
+ bool divided;
+ /* type 代表进入广度优先搜索队列的节点种类:
+ 0:不需要拆开的节点
+ 1:需要拆分*/
+ QVector4D bound;
+ vector lineSet;
+ ShortCutNode() {
+ divided = true;
+ windingIncrement = 0;
+ lineSet.clear();
+ bound = { 0, 0, 0, 0 };
+ }
+ ~ShortCutNode() {}
+};
+class ShortCutTree
+{
+ typedef vector vLine;
+ typedef vector LineIndex;
+private:
+ vector outTree;
+ vector allLine;
+ int RequiredLineMi, numPoint, numLine;
+ map pointMap;
+ vector lineIndexSet;
+
+ int getPointIndex(point now);
+ void generateShortCutSegement(ShortCutNode& now);
+ bool handleShortCutNode(ShortCutNode& fa, ShortCutNode& now, float yValue, vector& v, int& sumIncrement);
+ void spliteToShortCutTree();
+ static void Monotonization(vector& inL, vector &outL);
+ bool isLineEqual(LineIndex& a, LineIndex& b) const;
+ void simplifyLineVector();
+public:
+ void init();
+ ShortCutTree(int lineMi = 3)
+ :RequiredLineMi(lineMi), numPoint(0), numLine(0) {}
+ // 传入一个vector > 作为所有输入的线
+ void buildShortCutTree(vector& lineSet);
+ // 获得点集合和线集合 返回输入BvhTree的数据集合
+ vector getPointLineAndBvhTree(vector &pointSet, vector &lineSet);
+ ~ShortCutTree() {}
+};
+
diff --git a/ArchitectureColoredPainting/StraightLine.cpp b/ArchitectureColoredPainting/StraightLine.cpp
new file mode 100644
index 0000000..4bcbf3c
--- /dev/null
+++ b/ArchitectureColoredPainting/StraightLine.cpp
@@ -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;
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/StraightLine.h b/ArchitectureColoredPainting/StraightLine.h
new file mode 100644
index 0000000..ce45986
--- /dev/null
+++ b/ArchitectureColoredPainting/StraightLine.h
@@ -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 & res) {};
+ virtual float findTByValue(float value, bool isY);
+ virtual int judgeBoundIntersection(float xy, float l, float r, bool isY);
+};
\ No newline at end of file