实现解析svg path
parent
e849479236
commit
4f9611c385
|
@ -58,6 +58,16 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
|
||||
<ClCompile>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
|
@ -97,6 +107,7 @@
|
|||
<ClCompile Include="RendererWidget.cpp" />
|
||||
<ClCompile Include="ShortCutTree.cpp" />
|
||||
<ClCompile Include="StraightLine.cpp" />
|
||||
<ClCompile Include="SvgParser.cpp" />
|
||||
<QtRcc Include="MainWindow.qrc" />
|
||||
<QtUic Include="MainWindow.ui" />
|
||||
<QtMoc Include="MainWindow.h" />
|
||||
|
@ -137,6 +148,7 @@
|
|||
<ClInclude Include="PaintingMesh.h" />
|
||||
<ClInclude Include="ShortCutTree.h" />
|
||||
<ClInclude Include="StraightLine.h" />
|
||||
<ClInclude Include="SvgParser.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
|
|
|
@ -79,6 +79,9 @@
|
|||
<ClCompile Include="StraightLine.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SvgParser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="RendererWidget.h">
|
||||
|
@ -172,5 +175,8 @@
|
|||
<ClInclude Include="StraightLine.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SvgParser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -10,7 +10,7 @@
|
|||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
using std::tr1::shared_ptr;
|
||||
using std::shared_ptr;
|
||||
|
||||
struct BvhTreeData {
|
||||
QVector4D bound;
|
||||
|
@ -59,7 +59,7 @@ struct BvhNode {
|
|||
~BvhNode() {}
|
||||
};
|
||||
|
||||
typedef std::tr1::shared_ptr<BvhNode> BvhPtr;
|
||||
typedef std::shared_ptr<BvhNode> BvhPtr;
|
||||
|
||||
class BvhTree
|
||||
{
|
||||
|
|
|
@ -8,11 +8,11 @@ float CubicBezier::getLineValueByT(float t, bool isY) {
|
|||
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) {
|
||||
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) {
|
||||
Point CubicBezier::calculateControlPoint(Point a, Point b) {
|
||||
return {
|
||||
a.x + 2 * (b.x - a.x) / 3,
|
||||
a.y + 2 * (b.y - a.y) / 3
|
||||
|
@ -47,7 +47,7 @@ void CubicBezier::findPointsOfDivison(vector<float> &p, vector<float>& res) {
|
|||
|
||||
void CubicBezier::transformToCubic() {
|
||||
if (siz == 4) return;
|
||||
point p[3] = {
|
||||
Point p[3] = {
|
||||
getPointByIndex(0),
|
||||
getPointByIndex(1),
|
||||
getPointByIndex(2)
|
||||
|
@ -61,10 +61,10 @@ void CubicBezier::transformToCubic() {
|
|||
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);
|
||||
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));
|
||||
|
|
|
@ -6,8 +6,8 @@ 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 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:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "Line.h"
|
||||
|
||||
Line::Line(vector<point> Vp) {
|
||||
Line::Line(vector<Point> Vp) {
|
||||
siz = Vp.size();
|
||||
for (point now : Vp) {
|
||||
for (Point now : Vp) {
|
||||
vX.push_back(now.x);
|
||||
vY.push_back(now.y);
|
||||
}
|
||||
|
@ -12,23 +12,23 @@ int Line::size() {
|
|||
return siz;
|
||||
}
|
||||
|
||||
vector<point> Line::toPointVector() const {
|
||||
vector<point> vL;
|
||||
vector<Point> Line::toPointVector() 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 {
|
||||
Point Line::operator[](int index) const {
|
||||
return { vX[index], vY[index] };
|
||||
}
|
||||
|
||||
point Line::getPointByIndex(int index) const {
|
||||
Point Line::getPointByIndex(int index) const {
|
||||
return operator[](index);
|
||||
}
|
||||
|
||||
void Line::setPointByIndex(int index, point now) {
|
||||
void Line::setPointByIndex(int index, Point now) {
|
||||
vX[index] = now.x;
|
||||
vY[index] = now.y;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ void Line::clear() {
|
|||
vY.clear();
|
||||
}
|
||||
|
||||
void Line::push_back(point now) {
|
||||
void Line::push_back(Point now) {
|
||||
siz++;
|
||||
vX.push_back(now.x);
|
||||
vY.push_back(now.y);
|
||||
|
@ -52,11 +52,11 @@ bool Line::isLineContained(QVector4D bound) {
|
|||
else return false;
|
||||
}
|
||||
|
||||
point Line::getBegin() {
|
||||
Point Line::getBegin() {
|
||||
return { *vX.begin(), *vY.begin() };
|
||||
}
|
||||
|
||||
point Line::getEnd() {
|
||||
Point Line::getEnd() {
|
||||
return { *vX.rbegin(), *vY.rbegin() };
|
||||
}
|
||||
|
||||
|
|
|
@ -12,20 +12,20 @@ using std::pair;
|
|||
using std::min;
|
||||
using std::max;
|
||||
using std::sort;
|
||||
using std::tr1::shared_ptr;
|
||||
using std::tr1::make_shared;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::swap;
|
||||
|
||||
const float eps = 1e-6;
|
||||
|
||||
struct point {
|
||||
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 {
|
||||
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 {
|
||||
bool operator< (const Point& a) const {
|
||||
return fabs(x - a.x) <= eps ? y < a.y : x < a.x;
|
||||
}
|
||||
void show() {
|
||||
|
@ -41,22 +41,22 @@ protected:
|
|||
public:
|
||||
typedef shared_ptr<Line> LinePtr;
|
||||
Line() :siz(0) {}
|
||||
Line(vector<point> Vp);
|
||||
Line(vector<Point> Vp);
|
||||
int size();
|
||||
void clear();
|
||||
point getBegin();
|
||||
point getEnd();
|
||||
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> toPointVector() const;
|
||||
void setPointByIndex(int index, point now);
|
||||
void push_back(point now);
|
||||
Point operator[](int index) const;
|
||||
Point getPointByIndex(int index) const;
|
||||
vector<Point> toPointVector() const;
|
||||
void setPointByIndex(int index, Point now);
|
||||
void push_back(Point now);
|
||||
virtual ~Line() {}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <QtMath>
|
||||
#include "BvhTree.h"
|
||||
#include "ShortCutTree.h"
|
||||
#include "SvgParser.h"
|
||||
|
||||
Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram)
|
||||
: context(context)
|
||||
|
@ -186,11 +187,20 @@ 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());
|
||||
|
||||
//vector<vector<point>> lineSet = { {point{-1,-1}, point{1,-1}},{point{1,-1}, point{1,1}}, {point{1,1}, point{-1,1}},{point{-1,1}, point{-1,-1}} };
|
||||
vector<vector<point>> lineSet = { {point{-1,-1}, point{1,-1}},{point{1,-1}, point{1,1}}, {point{1,1}, point{-1,1}},{point{-1,1}, point{-1,-1}} };
|
||||
ShortCutTree shortCutTree;
|
||||
//bvhTree.buildBvhTree(initBound.data(), initBound.size());
|
||||
|
||||
|
||||
vector<vector<Point>> lineSet = SvgParser::parse("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", 100,100);
|
||||
for (vector<Point> line : lineSet)
|
||||
{
|
||||
for (Point p : line)
|
||||
p.show();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
//vector<vector<Point>> lineSet = { {Point{-1,-1}, Point{1,-1}},{Point{1,-1}, Point{1,1}}, {Point{1,1}, Point{-1,1}},{Point{-1,1}, Point{-1,-1}} };
|
||||
//vector<vector<Point>> lineSet = { {Point{-1,-1}, Point{1,-1}},{Point{1,-1}, Point{1,1}}, {Point{1,1}, Point{-1,1}},{Point{-1,1}, Point{-1,-1}} };
|
||||
ShortCutTree shortCutTree(5);
|
||||
shortCutTree.buildShortCutTree(lineSet);
|
||||
vector<float> pointVector;
|
||||
vector<GLuint> lineVector;
|
||||
|
@ -296,7 +306,7 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
|
|||
3, 0,2,3,
|
||||
//element1
|
||||
//lines
|
||||
0,1,1,2
|
||||
0,1,1,2
|
||||
};
|
||||
|
||||
std::vector<GLfloat> elementData0 = {
|
||||
|
|
|
@ -8,7 +8,7 @@ void ShortCutTree::init() {
|
|||
numLine = numPoint = 0;
|
||||
}
|
||||
|
||||
int ShortCutTree::getPointIndex(point nowPoint) {
|
||||
int ShortCutTree::getPointIndex(Point nowPoint) {
|
||||
auto iter = pointMap.find(nowPoint);
|
||||
if (iter != pointMap.end()) {
|
||||
return iter->second;
|
||||
|
@ -44,7 +44,7 @@ void ShortCutTree::monotonization(vector<PointVector>& inL, vector<LinePtr>& out
|
|||
}
|
||||
|
||||
void ShortCutTree::generateShortCutsegmentement(ShortCutNode& nowTreeNode) {
|
||||
point p = {0, 0};
|
||||
Point p = {0, 0};
|
||||
vector<int> v;
|
||||
for (int & lineIndex : nowTreeNode.lineSet) {
|
||||
int type = allLine[lineIndex]->judgeBoundIntersection(nowTreeNode.bound.z(), nowTreeNode.bound.y(), nowTreeNode.bound.w(), false), be, en;
|
||||
|
@ -112,7 +112,7 @@ void ShortCutTree::simplifyLineVector() {
|
|||
numLine = allLine.size();
|
||||
for (auto& nowLine : allLine) {
|
||||
PointVector pointVector = nowLine->toPointVector();
|
||||
for (point& p : pointVector) {
|
||||
for (Point& p : pointVector) {
|
||||
int pointIndex = getPointIndex(p);
|
||||
lineIndexs.push_back(pointIndex);
|
||||
if (pointVector.size() == 2)
|
||||
|
@ -216,7 +216,10 @@ void ShortCutTree::buildShortCutTree(vector<PointVector>& lineSet) {
|
|||
}
|
||||
|
||||
vector<BvhTreeData> ShortCutTree::getPointLineAndBvhTree(vector<float>& resPoints, vector<GLuint>& resLines) {
|
||||
vector<pair<GLuint, point> > tmpPoints; tmpPoints.clear();
|
||||
vector<pair<GLuint, Point> > tmpPoints; tmpPoints.clear();
|
||||
for (auto& now : restOfTreeNodes) {
|
||||
std::cout << now.windingIncrement << ' ';
|
||||
}
|
||||
for (auto& mapIter : pointMap) {
|
||||
tmpPoints.push_back({ mapIter.second , mapIter.first});
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ using std::map;
|
|||
using std::for_each;
|
||||
|
||||
struct ShortCutNode {
|
||||
typedef vector<point> vectorPoint;
|
||||
typedef vector<Point> vectorPoint;
|
||||
int windingIncrement;
|
||||
bool divided;
|
||||
/* type 代表进入广度优先搜索队列的节点种类:
|
||||
|
@ -27,16 +27,16 @@ struct ShortCutNode {
|
|||
};
|
||||
class ShortCutTree
|
||||
{
|
||||
typedef vector<point> PointVector;
|
||||
typedef vector<Point> PointVector;
|
||||
typedef vector<int> PointIndexVector;
|
||||
private:
|
||||
vector<ShortCutNode> restOfTreeNodes;
|
||||
vector<LinePtr> allLine;
|
||||
int RequiredLineMin, numPoint, numLine;
|
||||
map<point, int> pointMap;
|
||||
map<Point, int> pointMap;
|
||||
vector<int> lineIndexs;
|
||||
|
||||
int getPointIndex(point nowPoint);
|
||||
int getPointIndex(Point nowPoint);
|
||||
void generateShortCutsegmentement(ShortCutNode& nowTreeNode);
|
||||
bool handleShortCutNode(ShortCutNode& fa, ShortCutNode& nowTreeNode, float yValue, vector<ShortCutNode>& v, int& sumIncrement);
|
||||
void spliteToShortCutTree();
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
//lineMin最小线数目,即划分终止条件
|
||||
ShortCutTree(int lineMin = 3)
|
||||
:RequiredLineMin(lineMin), numPoint(0), numLine(0) {}
|
||||
// 传入一个vector<vector<point> > 作为所有输入的线
|
||||
// 传入一个vector<vector<Point> > 作为所有输入的线
|
||||
void buildShortCutTree(vector<PointVector>& lineSet);
|
||||
// 获得点集合和线集合 返回输入BvhTree的数据集合
|
||||
vector<BvhTreeData> getPointLineAndBvhTree(vector<float> &pointSet, vector<GLuint> &lineSet);
|
||||
|
|
|
@ -14,7 +14,7 @@ float StraightLine::getLineValueByT(float t, bool isY) {
|
|||
}
|
||||
|
||||
float StraightLine::findTByValue(float value, bool isY) {
|
||||
point be = getPointByIndex(0), en = getPointByIndex(1);
|
||||
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);
|
||||
|
@ -26,7 +26,7 @@ float StraightLine::findTByValue(float value, bool isY) {
|
|||
}
|
||||
|
||||
int StraightLine::judgeBoundIntersection(float xy, float l, float r, bool isY) {
|
||||
point be = getBegin(), en = getEnd();
|
||||
Point be = getBegin(), en = getEnd();
|
||||
if (isY) {
|
||||
swap(be.x, be.y);
|
||||
swap(en.x, en.y);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#include "SvgParser.h"
|
||||
#include <algorithm>
|
||||
|
||||
vector<vector<Point>> SvgParser::parse(const std::string path, float width, float height)
|
||||
{
|
||||
std::string tmp;
|
||||
vector<float> point;
|
||||
vector<Point> line;
|
||||
vector<vector<Point>> lines;
|
||||
for (char c : path.substr(1))
|
||||
{
|
||||
if ((c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+')
|
||||
{
|
||||
tmp += c;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (tmp != "")
|
||||
{
|
||||
point.push_back(std::stof(tmp));
|
||||
tmp = "";
|
||||
if (point.size() == 2)
|
||||
{
|
||||
line.push_back(Point{ std::clamp(point[0] / width * 2 - 1, -1.f, 1.f) , std::clamp(1 - point[1] / height * 2 , -1.f, 1.f)});
|
||||
point.clear();
|
||||
}
|
||||
}
|
||||
if (c != ',' && c != ' ')
|
||||
{
|
||||
lines.push_back(line);
|
||||
line.erase(line.begin(), line.end() - 1);
|
||||
if (c == 'Z')
|
||||
{
|
||||
line.push_back(lines[0][0]);
|
||||
lines.push_back(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lines.erase(lines.begin());
|
||||
return lines;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Line.h"
|
||||
class SvgParser
|
||||
{
|
||||
public:
|
||||
static vector<vector<Point>> parse(const std::string path, float width, float height);
|
||||
};
|
||||
|
19
README.md
19
README.md
|
@ -1,17 +1,20 @@
|
|||
# ArchitectureColoredPainting
|
||||
|
||||
vs2022项目 qt5.15.2 msvc 2019 64-bit
|
||||
古建筑彩绘计算机辅助设计系统
|
||||
|
||||
采用pbr材质,现在有一个随时间变化的方向光并添加了阴影
|
||||
## 依赖
|
||||
|
||||
把一块布替换成了(待完成的)彩绘管线,见PaintingMesh类以及painting着色器
|
||||
- Qt 5.15.2 (MSVC 2019 64-bit)
|
||||
- Assimp (x64-windows)
|
||||
|
||||
TODO:
|
||||
## 构建
|
||||
|
||||
- [x] 改用延迟渲染
|
||||
使用 Visual Studio 2022 打开项目编译运行。
|
||||
|
||||
- [x] 指定一块材质使用独立管线进行纹理采样
|
||||
## 进度
|
||||
|
||||
- [ ] 彩绘的表示、读取、采样...
|
||||
采用 PBR (金属度-粗糙度) 材质模型,场景中存在一个方向光,可拖动滑动条调整光源方向观察材质效果。
|
||||
|
||||
- [x] PCF Shadow Map
|
||||
已实现BVH加速结构的建立
|
||||
|
||||
基本实现单图元的拆分,即划分网格并生成快捷段和缠绕增量,尚未验证正确性
|
Loading…
Reference in New Issue