From 081e9a7ffbb795e27a7328b04e9088e5913e0d33 Mon Sep 17 00:00:00 2001 From: "yang.yongquan" <3395816735@qq.com> Date: Tue, 6 Sep 2022 22:16:04 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ArchitectureColoredPainting/BvhTree.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ArchitectureColoredPainting/BvhTree.h b/ArchitectureColoredPainting/BvhTree.h index 0292602..4bc5e2e 100644 --- a/ArchitectureColoredPainting/BvhTree.h +++ b/ArchitectureColoredPainting/BvhTree.h @@ -9,13 +9,13 @@ #include #include #include -#define bvhPtr std::tr1::shared_ptr +using std::tr1::shared_ptr; // BvhTree 节点 struct BvhNode { GLuint lab; QVector4D bound; - bvhPtr child[2]; + shared_ptr child[2]; static bool x_compare(QVector4D a, QVector4D b) { return a.x() < b.x(); } @@ -43,13 +43,18 @@ struct BvhNode { ~BvhNode() {} }; +typedef std::tr1::shared_ptr bvhPtr; + class BvhTree { + private: GLuint tot; bvhPtr root; static QVector4D calcBound(QVector4D 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); public: BvhTree() { tot = 0; @@ -57,8 +62,6 @@ public: } // 根据底层包围盒生成bvh树 void buildBvhTree(QVector4D initBound[], int len); - bvhPtr subBvhTree(QVector4D initBound[], int l, int r); - void traverseBvhTree(bvhPtr now, std::vector& children, std::vector& bounds); // 获得 Bvh (rootBvh部分)的 children 数组,包围盒数组 vector 传输 void getBvhArray(std::vector& children, std::vector& bounds); // 获得 BvhTree 中节点总数 From 79883302ac4e1b85d2afd9adcad78646757304ac Mon Sep 17 00:00:00 2001 From: "yang.yongquan" <3395816735@qq.com> Date: Tue, 13 Sep 2022 21:01:18 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=88=86?= =?UTF-8?q?=E5=89=B2=E7=9A=84=E8=B4=9D=E5=A1=9E=E5=B0=94=E6=9B=B2=E7=BA=BF?= =?UTF-8?q?=E7=9A=84=E6=8E=A7=E5=88=B6=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 2 + ...rchitectureColoredPainting.vcxproj.filters | 6 ++ .../CubicMonotonization.cpp | 73 +++++++++++++++++++ .../CubicMonotonization.h | 24 ++++++ 4 files changed, 105 insertions(+) create mode 100644 ArchitectureColoredPainting/CubicMonotonization.cpp create mode 100644 ArchitectureColoredPainting/CubicMonotonization.h diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index 62c0450..dc95cf0 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -87,6 +87,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index ed08f43..092c1d5 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -67,6 +67,9 @@ Source Files + + Source Files + @@ -148,5 +151,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/ArchitectureColoredPainting/CubicMonotonization.cpp b/ArchitectureColoredPainting/CubicMonotonization.cpp new file mode 100644 index 0000000..8e96f1b --- /dev/null +++ b/ArchitectureColoredPainting/CubicMonotonization.cpp @@ -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 p, vector& 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 &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 & 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 & res) { + vector 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; + } +} diff --git a/ArchitectureColoredPainting/CubicMonotonization.h b/ArchitectureColoredPainting/CubicMonotonization.h new file mode 100644 index 0000000..6531b27 --- /dev/null +++ b/ArchitectureColoredPainting/CubicMonotonization.h @@ -0,0 +1,24 @@ +#include +#include +#include +#pragma once +using std::pair; +using std::vector; +using std::min; +using std::max; +using std::sort; +class CubicMonotonization +{ +typedef pair point; +typedef vector Line; +private: + static const double eps; + point getPointByT(point a, point b, double t) const; + void findPointsOfDivison(vector p, vector &res); + double getBezierPoint(vector &p, double t) const; + void splitBezierCubic(Line& p, point mid, double t, vector &res); +public: + // p 为端点、控制点、控制点、端点, res 为所有导数为0的点 + void getPointsOfDivision(Line p, vector &res); +}; + 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 3/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86BvhTree=20?= =?UTF-8?q?=E5=A2=9E=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