初步完成了LineTree,待测试

dev-VirtualTexture
yang.yongquan 2022-12-17 11:24:07 +08:00
parent f3b0a3069c
commit 2745e8c47b
11 changed files with 277 additions and 43 deletions

View File

@ -1,6 +1,8 @@
#include "CubicBezier.h"
#include "CubicBezierSignedDistance.h"
using namespace Renderer;
using std::vector;
using std::swap;
double CubicBezier::getLineValueByT(double t, bool isY) {
vector<double> p;
if (isY) p = vY;
@ -101,7 +103,7 @@ double CubicBezier::findTByValue(double value, bool isY) {
return l;
}
int CubicBezier::judgeBoundIntersection(double xy, double l, double r, bool isY) {
int CubicBezier::judgeOneSideIntersection(double xy, double l, double r, bool isY) {
double valueBegin = *vX.begin(), valueEnd = *vX.rbegin();
if (isY) {
valueBegin = *vY.begin();
@ -115,3 +117,7 @@ int CubicBezier::judgeBoundIntersection(double xy, double l, double r, bool isY)
}
return 0;
}
double CubicBezier::getMinDistanceFromPoint(Point p) {
return CubicBezierSignedDistance::cubic_bezier_dis(p, getBegin(), getPointByIndex(1), getPointByIndex(2), getEnd());
}

View File

@ -15,7 +15,8 @@ namespace Renderer
virtual double findTByValue(double value, bool isY);
virtual void monotonization(std::vector <LinePtr>& res);
virtual double getLineValueByT(double t, bool isY);
virtual int judgeBoundIntersection(double xy, double l, double r, bool isY);
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY);
virtual double getMinDistanceFromPoint(Point p);
void transformToCubic();
};
}

View File

@ -81,10 +81,10 @@ int Line::direction(bool isY) {
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);
|| judgeOneSideIntersection(bound.y(), bound.x(), bound.z(), true)
|| judgeOneSideIntersection(bound.w(), bound.x(), bound.z(), true)
|| judgeOneSideIntersection(bound.x(), bound.y(), bound.w(), false)
|| judgeOneSideIntersection(bound.z(), bound.y(), bound.w(), false);
}
void Line::upwardOffsetForY(bool isStart, double offset) {
@ -95,3 +95,57 @@ void Line::upwardOffsetForY(bool isStart, double offset) {
vY[siz - 1] = vY[siz - 1] + offset;
}
}
Point Line::getMinDistancePointOnSide(double xy, double l, double r, bool isY) {
Point pMid = { xy, l }, pMidr = { xy, r };
if (isY) {
swap(pMid.x, pMid.y);
swap(pMidr.x, pMidr.y);
}
double mid, midr;
while (fabs(r - l) > eps) {
mid = (l + r) / 2;
midr = (mid + r) / 2;
if (isY) {
pMid.x = mid;
pMidr.x = midr;
}
else {
pMid.y = mid;
pMidr.y = midr;
}
if (getMinDistanceFromPoint(pMid) > getMinDistanceFromPoint(pMidr)) {
l = mid;
}
else {
r = midr;
}
}
Point ans = { xy, l };
if (isY) swap(ans.x, ans.y);
return ans;
}
int Line::getPointSideOfLine(Point p) {
// 1 Ϊ×ó²à£¬ 2 ΪÓÒ²à
double z = (p.x - vX[0]) * (*vY.rbegin() - vY[0]) - (p.y - vY[0]) * (*vX.rbegin() - vX[0]);
if (z == 0) return 0;
else if(z>0) return 1;
else return 2;
}
bool Line::judgeOneSideIntersectionWithWidth(double xy, double l, double r, bool isY, double width, int type) {
Point p = getMinDistancePointOnSide(xy, l, r, isY);
if (type && getPointSideOfLine(p) != type) {
return false;
}
return getMinDistanceFromPoint(p) <= width;
}
bool Line::judgeIntersectionWithWidth(QVector4D bound, double width, int type) {
return isLineContained(bound)
|| judgeOneSideIntersectionWithWidth(bound.y(), bound.x(), bound.z(), true, width, type)
|| judgeOneSideIntersectionWithWidth(bound.w(), bound.x(), bound.z(), true, width, type)
|| judgeOneSideIntersectionWithWidth(bound.x(), bound.y(), bound.w(), false, width, type)
|| judgeOneSideIntersectionWithWidth(bound.z(), bound.y(), bound.w(), false, width, type);
}

View File

@ -6,6 +6,7 @@
#include <algorithm>
#include <memory>
#include <iostream>
#include <glm/vec2.hpp>
namespace Renderer
{
@ -24,6 +25,9 @@ namespace Renderer
bool operator< (const Point& a) const {
return fabs(x - a.x) <= eps ? y < a.y : x < a.x;
}
operator glm::dvec2() {
return glm::dvec2(x, y);
}
void show() {
std::cout << '(' << x << ',' << y << ')' << ' ';
}
@ -45,8 +49,13 @@ namespace Renderer
int direction(bool isY);
virtual double getLineValueByT(double t, bool isY) = 0;
virtual void monotonization(std::vector <LinePtr>& res) = 0;
virtual int judgeBoundIntersection(double xy, double l, double r, bool isY) = 0;
virtual bool judgeIntersection(QVector4D bound);
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY) = 0;
virtual double getMinDistanceFromPoint(Point p) = 0;
bool judgeOneSideIntersectionWithWidth(double xy, double l, double r, bool isY, double width, int type);
bool judgeIntersectionWithWidth(QVector4D bound, double width, int type);
bool judgeIntersection(QVector4D bound);
int getPointSideOfLine(Point p);
Point getMinDistancePointOnSide(double xy, double l, double r, bool isY);
// virtual double minDistanceToLine(Point uv);
void upwardOffsetForY(bool isStart, double offset);
bool isLineContained(QVector4D bound);
@ -58,3 +67,4 @@ namespace Renderer
virtual ~Line() {}
};
}

View File

@ -1,19 +1,23 @@
#include "LineTree.h"
#include <queue>
#include <set>
#include <utility>
using namespace Renderer;
using std::set;
using std::pair;
using std::vector;
using std::queue;
void LineTree::init() {
restOfTreeNodes.clear();
allLine.clear();
allLines.clear();
pointMap.clear();
lineIndexs.clear();
numLine = numPoint = 0;
}
void LineTree::setLineWidth(int width) {
void LineTree::setLineWidth(double width) {
lineWidth = width;
}
@ -104,8 +108,8 @@ void LineTree::monotonization(vector<PointVector>& inLines, vector<std::shared_p
}
void LineTree::simplifyLineVector() {
numLine = allLine.size();
for (auto& nowLine : allLine) {
numLine = allLines.size();
for (auto& nowLine : allLines) {
PointVector pointVector = nowLine->toPointVector();
for (Point& p : pointVector) {
int pointIndex = getPointIndex(p);
@ -115,3 +119,147 @@ void LineTree::simplifyLineVector() {
}
}
}
bool LineTree::handleShortCutNode(LineTreeNode& fa, LineTreeNode& nowTreeNode, double yValue, std::vector<LineTreeNode>& v) {
for (int& lineIndex : fa.lineSet) {
if (allLines[lineIndex]->judgeIntersectionWithWidth(nowTreeNode.bound, lineWidth, lineType)) {
nowTreeNode.lineSet.push_back(lineIndex);
}
}
if (nowTreeNode.lineSet.size() <= requiredLineMin) {
if (nowTreeNode.lineSet.empty())
return false;
restOfTreeNodes.push_back(nowTreeNode);
nowTreeNode.divided = false;
v.push_back(nowTreeNode);
return false;
}
else {
v.push_back(nowTreeNode);
return true;
}
}
void LineTree::spliteToLineTree() {
// 防止直线的点落在边界上
set<double> xLineSet, yLineSet;
for (int i = 0; i < allLines.size(); i++) {
xLineSet.insert(allLines[i]->getBegin().x);
xLineSet.insert(allLines[i]->getEnd().x);
yLineSet.insert(allLines[i]->getBegin().y);
yLineSet.insert(allLines[i]->getEnd().y);
}
// 生成方格
queue<LineTreeNode> Q;
queue<pair<double, double> > lineBound;
LineTreeNode root;
int nowEastGroup = 0, eastGroupSize = 1;
root.bound = QVector4D(-1, -1, 1, 1);
for (int i = 0; i < allLines.size(); i++) {
root.lineSet.push_back(i);
}
root.eastGroup = eastGroupSize;
Q.push(root);
lineBound.push({ -1, 1 });
vector<LineTreeNode> tmpTreeNodes, upperTreeNodes, lowerTreeNodes;
bool isUpperDivided = false, isLowerDivided = false;
while (!lineBound.empty()) {
// 取出一行的所有可行方格
++nowEastGroup;
auto segment = lineBound.front(); lineBound.pop();
double yMid = (segment.first + segment.second) / 2;
yMid = findBorderValueNotOnLine(yMid, yLineSet);
while (!Q.empty()) {
auto nowTreeNode = Q.front();
if (nowTreeNode.eastGroup == nowEastGroup) {
tmpTreeNodes.push_back(nowTreeNode);
Q.pop();
}
else {
break;
}
}
isUpperDivided = false; isLowerDivided = false;
upperTreeNodes.clear(); lowerTreeNodes.clear();
// 处理方格;
for (auto& nowTreeNode : tmpTreeNodes) {
LineTreeNode nwTreeNode, neTreeNode, seTreeNode, swTreeNode;
double xMid = (nowTreeNode.bound.x() + nowTreeNode.bound.z()) / 2;
xMid = findBorderValueNotOnLine(xMid, xLineSet);
// 上部分
neTreeNode.bound = QVector4D(xMid, yMid, nowTreeNode.bound.z(), nowTreeNode.bound.w());
isUpperDivided |= handleShortCutNode(nowTreeNode, neTreeNode, yMid, upperTreeNodes);
nwTreeNode.bound = QVector4D(nowTreeNode.bound.x(), yMid, xMid, nowTreeNode.bound.w());
isUpperDivided |= handleShortCutNode(nowTreeNode, nwTreeNode, yMid, upperTreeNodes);
// 下部分
seTreeNode.bound = QVector4D(xMid, nowTreeNode.bound.y(), nowTreeNode.bound.z(), yMid);
isLowerDivided |= handleShortCutNode(nowTreeNode, seTreeNode, segment.first, lowerTreeNodes);
swTreeNode.bound = QVector4D(nowTreeNode.bound.x(), nowTreeNode.bound.y(), xMid, yMid);
isLowerDivided |= handleShortCutNode(nowTreeNode, swTreeNode, segment.first, lowerTreeNodes);
}
if (isUpperDivided) {
++eastGroupSize;
lineBound.push({ yMid, segment.second });
for (auto& nowTreeNode : upperTreeNodes) {
nowTreeNode.eastGroup = eastGroupSize;
Q.push(nowTreeNode);
}
}
if (isLowerDivided) {
++eastGroupSize;
lineBound.push({ segment.first, yMid });
for (auto& nowTreeNode : lowerTreeNodes) {
nowTreeNode.eastGroup = eastGroupSize;
Q.push(nowTreeNode);
}
}
tmpTreeNodes.clear();
}
}
void LineTree::buildLineTree(std::vector<PointVector>& lineSet, double width, int type) {
init();
lineWidth = width;
lineType = type;
monotonization(lineSet, allLines);
spliteToLineTree();
simplifyLineVector();
}
vector<BvhTreeData> LineTree::getPointLineAndBvhTree(vector<float>& resPoints, vector<GLuint>& resLines) {
// 点集
vector<pair<GLuint, Point> > tmpPoints; tmpPoints.clear();
for (auto& mapIter : pointMap) {
tmpPoints.push_back({ mapIter.second , mapIter.first });
}
sort(tmpPoints.begin(), tmpPoints.end());
for (auto& vectorIter : tmpPoints) {
resPoints.push_back(vectorIter.second.x);
resPoints.push_back(vectorIter.second.y);
vectorIter.second.show();
std::cout << '\n';
}
// 线集
for (auto& nowLineIndex : lineIndexs) {
resLines.push_back(nowLineIndex);
std::cout << nowLineIndex << ' ';
}
std::cout << '\n';
// 返回构造BvhTree数据
vector<BvhTreeData> resBvhTreeData;
for (auto& nowTreeNode : restOfTreeNodes) {
BvhTreeData oneData;
oneData.leftSon = resLines.size();
//oneData.rightSon = rightSon;
oneData.bound = nowTreeNode.bound;
std::cout << nowTreeNode.lineSet.size() << ' ';
resLines.push_back(nowTreeNode.lineSet.size());
for (auto& lineIndex : nowTreeNode.lineSet) {
resLines.push_back(lineIndex);
std::cout << lineIndex << ' ';
}
std::cout << '\n';
resBvhTreeData.push_back(oneData);
}
return resBvhTreeData;
}

View File

@ -27,10 +27,12 @@ namespace Renderer {
typedef std::vector<int> PointIndexVector;
private:
std::vector<LineTreeNode> restOfTreeNodes;
std::vector<std::shared_ptr<Line>> allLine;
int requiredLineMin, numPoint, numLine, lineWidth;
std::vector<std::shared_ptr<Line>> allLines;
int requiredLineMin, numPoint, numLine;
std::map<Point, int> pointMap;
std::vector<int> lineIndexs;
double lineWidth;
int lineType;
int getPointIndex(Point nowPoint);
void spliteToLineTree();
@ -42,10 +44,10 @@ namespace Renderer {
static void monotonization(std::vector<PointVector>& inL, std::vector<std::shared_ptr<Line>>& outL);
public:
void init();
void setLineWidth(int width);
void setLineWidth(double width);
LineTree(int lineMin = 3, int width = 0.3)
: requiredLineMin(lineMin), lineWidth(width), numLine(0), numPoint(0) {}
void buildLineTree(std::vector<PointVector>& lineSet);
void buildLineTree(std::vector<PointVector>& lineSet, double width, int type = 0);
std::vector<BvhTreeData> getPointLineAndBvhTree(std::vector<float>& pointSet, std::vector<GLuint>& lineSet);
};
}

View File

@ -9,7 +9,7 @@ using std::pair;
using std::vector;
void ShortCutTree::init() {
restOfTreeNodes.clear();
allLine.clear();
allLines.clear();
pointMap.clear();
lineIndexs.clear();
numLine = numPoint = 0;
@ -80,13 +80,13 @@ void ShortCutTree::generateShortCutSegment(ShortCutNode& nowTreeNode) {
Point p = {0, 0};
set<pair<int, int> > pointSet;
for (int & lineIndex : nowTreeNode.lineSet) {
int type = allLine[lineIndex]->judgeBoundIntersection(nowTreeNode.bound.z(), nowTreeNode.bound.y(), nowTreeNode.bound.w(), false), lineIndexBegin, lineIndexEnd;
int type = allLines[lineIndex]->judgeOneSideIntersection(nowTreeNode.bound.z(), nowTreeNode.bound.y(), nowTreeNode.bound.w(), false), lineIndexBegin, lineIndexEnd;
if (type >= 2) {
if (type == 2) {
p = allLine[lineIndex]->getEnd();
p = allLines[lineIndex]->getEnd();
}
if (type == 3) {
p = allLine[lineIndex]->getBegin();
p = allLines[lineIndex]->getBegin();
}
lineIndexBegin = getPointIndex({ nowTreeNode.bound.z(), nowTreeNode.bound.w()});
lineIndexEnd = getPointIndex({ nowTreeNode.bound.z(), p.y });
@ -123,12 +123,12 @@ void ShortCutTree::generateShortCutSegment(ShortCutNode& nowTreeNode) {
bool ShortCutTree::handleShortCutNode(ShortCutNode& fa, ShortCutNode& nowTreeNode, double yValue, vector<ShortCutNode>& v, int& sumIncrement) {
nowTreeNode.windingIncrement = sumIncrement;
for (int & lineIndex : fa.lineSet) {
int type = allLine[lineIndex]->judgeBoundIntersection(yValue, nowTreeNode.bound.x(), nowTreeNode.bound.z(), true);
int type = allLines[lineIndex]->judgeOneSideIntersection(yValue, nowTreeNode.bound.x(), nowTreeNode.bound.z(), true);
if (type == 2)
sumIncrement++;
if (type == 3)
sumIncrement--;
if (allLine[lineIndex]->judgeIntersection(nowTreeNode.bound)) {
if (allLines[lineIndex]->judgeIntersection(nowTreeNode.bound)) {
nowTreeNode.lineSet.push_back(lineIndex);
}
}
@ -149,8 +149,8 @@ bool ShortCutTree::handleShortCutNode(ShortCutNode& fa, ShortCutNode& nowTreeNod
}
void ShortCutTree::simplifyLineVector() {
numLine = allLine.size();
for (auto& nowLine : allLine) {
numLine = allLines.size();
for (auto& nowLine : allLines) {
PointVector pointVector = nowLine->toPointVector();
for (Point& p : pointVector) {
int pointIndex = getPointIndex(p);
@ -167,11 +167,11 @@ void ShortCutTree::simplifyLineVector() {
void ShortCutTree::spliteToShortCutTree() {
// 防止直线的点落在边界上
set<double> xLineSet, yLineSet;
for (int i = 0; i < allLine.size(); i++) {
xLineSet.insert(allLine[i]->getBegin().x);
xLineSet.insert(allLine[i]->getEnd().x);
yLineSet.insert(allLine[i]->getBegin().y);
yLineSet.insert(allLine[i]->getEnd().y);
for (int i = 0; i < allLines.size(); i++) {
xLineSet.insert(allLines[i]->getBegin().x);
xLineSet.insert(allLines[i]->getEnd().x);
yLineSet.insert(allLines[i]->getBegin().y);
yLineSet.insert(allLines[i]->getEnd().y);
}
// 生成方格
queue<ShortCutNode> Q;
@ -179,7 +179,7 @@ void ShortCutTree::spliteToShortCutTree() {
ShortCutNode root;
int nowEastGroup = 0, eastGroupSize = 1;
root.bound = QVector4D(-1, -1, 1, 1);
for (int i = 0; i < allLine.size(); i++) {
for (int i = 0; i < allLines.size(); i++) {
root.lineSet.push_back(i);
}
root.eastGroup = eastGroupSize;
@ -212,13 +212,13 @@ void ShortCutTree::spliteToShortCutTree() {
if (!nowTreeNode.divided) {
for (int& lineIndex : nowTreeNode.lineSet) {
// 上半部分
int type = allLine[lineIndex]->judgeBoundIntersection(yMid, nowTreeNode.bound.x(), nowTreeNode.bound.z(), true);
int type = allLines[lineIndex]->judgeOneSideIntersection(yMid, nowTreeNode.bound.x(), nowTreeNode.bound.z(), true);
if (type == 2)
sumUpperIncrement++;
if (type == 3)
sumUpperIncrement--;
// 下半部分
type = allLine[lineIndex]->judgeBoundIntersection(segment.first, nowTreeNode.bound.x(), nowTreeNode.bound.z(), true);
type = allLines[lineIndex]->judgeOneSideIntersection(segment.first, nowTreeNode.bound.x(), nowTreeNode.bound.z(), true);
if (type == 2)
sumLowerIncrement++;
if (type == 3)
@ -265,7 +265,7 @@ void ShortCutTree::spliteToShortCutTree() {
void ShortCutTree::buildShortCutTree(vector<PointVector>& lineSet) {
init();
monotonization(lineSet, allLine);
monotonization(lineSet, allLines);
spliteToShortCutTree();
simplifyLineVector();
}

View File

@ -31,7 +31,7 @@ namespace Renderer
typedef std::vector<int> PointIndexVector;
private:
std::vector<ShortCutNode> restOfTreeNodes;
std::vector<std::shared_ptr<Line>> allLine;
std::vector<std::shared_ptr<Line>> allLines;
int requiredLineMin, numPoint, numLine;
std::map<Point, int> pointMap;
std::vector<int> lineIndexs;

View File

@ -26,7 +26,7 @@ double StraightLine::findTByValue(double value, bool isY) {
}
}
int StraightLine::judgeBoundIntersection(double xy, double l, double r, bool isY) {
int StraightLine::judgeOneSideIntersection(double xy, double l, double r, bool isY) {
Point pointBegin = getBegin(), pointEnd = getEnd();
if (isY) {
swap(pointBegin.x, pointBegin.y);
@ -47,3 +47,15 @@ int StraightLine::judgeBoundIntersection(double xy, double l, double r, bool isY
}
return 0;
}
double StraightLine::getMinDistanceFromPoint(Point p) {
Point se = { vX[1] - vX[0], vY[1] - vY[0] };
Point dd = { p.x - vX[0], p.y - vY[0] };
double d = se.x * se.x + se.y * se.y;
double t = se.x * dd.x + se.y * dd.y;
if (d > 0) t /= d;
if (t < 0) t = 0;
else if (t > 1) t = 1;
double dx = vX[0] + t * se.x - p.x, dy = vY[0] + t * se.y - p.y;
return dx * dx + dy * dy;
}

View File

@ -5,9 +5,11 @@ namespace Renderer
class StraightLine : public Line
{
using Line::Line;
public:
virtual double getLineValueByT(double t, bool isY);
virtual void monotonization(std::vector <LinePtr>& res) {};
virtual double findTByValue(double value, bool isY);
virtual int judgeBoundIntersection(double xy, double l, double r, bool isY);
virtual int judgeOneSideIntersection(double xy, double l, double r, bool isY);
virtual double getMinDistanceFromPoint(Point p);
};
}

View File

@ -1,6 +1,9 @@
#include "MainWindow.h"
#include <QtWidgets/QApplication>
#include <QGuiApplication>
#include "Renderer/Painting/CubicBezier.h"
using Renderer::CubicBezier;
extern "C" {
_declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
@ -8,10 +11,6 @@ extern "C" {
int main(int argc, char *argv[])
{
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
return 0;
}