Various optimisations to improve obj file performance

pull/170/head
James Ball 2023-01-20 23:41:37 +00:00
rodzic d8256ac812
commit 56eaa48bb1
9 zmienionych plików z 157 dodań i 140 usunięć

Wyświetl plik

@ -18,9 +18,7 @@ bool Connected(const Graph & G)
visited[u] = true; visited[u] = true;
n++; n++;
for(list<int>::const_iterator it = G.AdjList(u).begin(); it != G.AdjList(u).end(); it++) for(int v : G.AdjList(u)) {
{
int v = *it;
L.push_back(v); L.push_back(v);
} }
} }
@ -41,7 +39,7 @@ pair< list<int>, double > ChinesePostman(const Graph& G, const vector<double>& c
throw "Error: Graph is not connected"; throw "Error: Graph is not connected";
//Build adjacency lists using edges in the graph //Build adjacency lists using edges in the graph
vector< list<int> > A(G.GetNumVertices(), list<int>()); vector<vector<int>> A(G.GetNumVertices(), vector<int>());
for(int u = 0; u < G.GetNumVertices(); u++) for(int u = 0; u < G.GetNumVertices(); u++)
A[u] = G.AdjList(u); A[u] = G.AdjList(u);
@ -105,10 +103,7 @@ pair< list<int>, double > ChinesePostman(const Graph& G, const vector<double>& c
vector<int> traversed(G.GetNumEdges(), 0); vector<int> traversed(G.GetNumEdges(), 0);
for(int u = 0; u < G.GetNumVertices(); u++) for(int u = 0; u < G.GetNumVertices(); u++)
{ {
for(list<int>::iterator it = A[u].begin(); it != A[u].end(); it++) for(int v : A[u]) {
{
int v = *it;
//we do this so that the edge is not counted twice //we do this so that the edge is not counted twice
if(v < u) continue; if(v < u) continue;

Wyświetl plik

@ -36,9 +36,7 @@ pair< vector<int>, vector<double> > Dijkstra(const Graph & G, int origin, const
permanent[u] = true; permanent[u] = true;
//Update the heap with vertices adjacent to u //Update the heap with vertices adjacent to u
for(list<int>::const_iterator it = G.AdjList(u).begin(); it != G.AdjList(u).end(); it++) for (int v : G.AdjList(u)) {
{
int v = *it;
if(permanent[v]) if(permanent[v])
continue; continue;

Wyświetl plik

@ -19,21 +19,11 @@ Graph::Graph(int n, const list< pair<int, int> > & edges):
pair<int, int> Graph::GetEdge(int e) const pair<int, int> Graph::GetEdge(int e) const
{ {
if(e > (int)edges.size())
throw "Error: edge does not exist";
return edges[e]; return edges[e];
} }
int Graph::GetEdgeIndex(int u, int v) const int Graph::GetEdgeIndex(int u, int v) const
{ {
if( u > n or
v > n )
throw "Error: vertex does not exist";
if(edgeIndex[u][v] == -1)
throw "Error: edge does not exist";
return edgeIndex[u][v]; return edgeIndex[u][v];
} }
@ -47,15 +37,11 @@ void Graph::AddVertex()
n++; n++;
adjMat.push_back( vector<bool>(n, false) ); adjMat.push_back( vector<bool>(n, false) );
edgeIndex.push_back( vector<int>(n, -1) ); edgeIndex.push_back( vector<int>(n, -1) );
adjList.push_back( list<int>() ); adjList.push_back( vector<int>() );
} }
void Graph::AddEdge(int u, int v) void Graph::AddEdge(int u, int v)
{ {
if( u > n or
v > n )
throw "Error: vertex does not exist";
if(adjMat[u][v]) return; if(adjMat[u][v]) return;
adjMat[u][v] = adjMat[v][u] = true; adjMat[u][v] = adjMat[v][u] = true;
@ -66,7 +52,7 @@ void Graph::AddEdge(int u, int v)
edgeIndex[u][v] = edgeIndex[v][u] = m++; edgeIndex[u][v] = edgeIndex[v][u] = m++;
} }
const list<int> & Graph::AdjList(int v) const const vector<int>& Graph::AdjList(int v) const
{ {
if(v > n) if(v > n)
throw "Error: vertex does not exist"; throw "Error: vertex does not exist";

Wyświetl plik

@ -30,7 +30,7 @@ public:
void AddEdge(int u, int v); void AddEdge(int u, int v);
//Returns the adjacency list of a vertex //Returns the adjacency list of a vertex
const list<int> & AdjList(int v) const; const vector<int>& AdjList(int v) const;
//Returns the graph's adjacency matrix //Returns the graph's adjacency matrix
const vector< vector<bool> > & AdjMat() const; const vector< vector<bool> > & AdjMat() const;
@ -44,11 +44,11 @@ private:
vector< vector<bool> > adjMat; vector< vector<bool> > adjMat;
//Adjacency lists //Adjacency lists
vector< list<int> > adjList; vector<vector<int> > adjList;
//Array of edges //Array of edges
vector< pair<int, int> > edges; vector<pair<int, int> > edges;
//Indices of the edges //Indices of the edges
vector< vector<int> > edgeIndex; vector<vector<int> > edgeIndex;
}; };

Wyświetl plik

@ -1,4 +1,6 @@
#include "Matching.h" #include "Matching.h"
#include <deque>
#include <stack>
Matching::Matching(const Graph & G): Matching::Matching(const Graph & G):
G(G), G(G),
@ -33,14 +35,10 @@ void Matching::Grow()
//w might be a blossom //w might be a blossom
//we have to explore all the connections from vertices inside the blossom to other vertices //we have to explore all the connections from vertices inside the blossom to other vertices
for(list<int>::iterator it = deep[w].begin(); it != deep[w].end(); it++) for(int u : deep[w]) {
{
int u = *it;
int cont = false; int cont = false;
for(list<int>::const_iterator jt = G.AdjList(u).begin(); jt != G.AdjList(u).end(); jt++) for(int v : G.AdjList(u)) {
{
int v = *jt;
if(IsEdgeBlocked(u, v)) continue; if(IsEdgeBlocked(u, v)) continue;
@ -143,10 +141,7 @@ void Matching::Heuristic()
if(mate[outer[u]] == -1) if(mate[outer[u]] == -1)
{ {
int min = -1; int min = -1;
for(list<int>::const_iterator it = G.AdjList(u).begin(); it != G.AdjList(u).end(); it++) for (int v : G.AdjList(u)) {
{
int v = *it;
if(IsEdgeBlocked(u, v) or if(IsEdgeBlocked(u, v) or
(outer[u] == outer[v]) or (outer[u] == outer[v]) or
(mate[outer[v]] != -1) ) (mate[outer[v]] != -1) )
@ -170,12 +165,10 @@ void Matching::DestroyBlossom(int t)
if((t < n) or if((t < n) or
(blocked[t] and GREATER(dual[t], 0))) return; (blocked[t] and GREATER(dual[t], 0))) return;
for(list<int>::iterator it = shallow[t].begin(); it != shallow[t].end(); it++) for(int s : shallow[t]) {
{
int s = *it;
outer[s] = s; outer[s] = s;
for(list<int>::iterator jt = deep[s].begin(); jt != deep[s].end(); jt++) for(int d : deep[s])
outer[*jt] = s; outer[d] = s;
DestroyBlossom(s); DestroyBlossom(s);
} }
@ -186,82 +179,84 @@ void Matching::DestroyBlossom(int t)
mate[t] = -1; mate[t] = -1;
} }
void Matching::Expand(int u, bool expandBlocked = false) void Matching::Expand(int start, bool expandBlocked = false)
{ {
int v = outer[mate[u]]; std::stack<int> Q;
Q.push(start);
int index = m; while (!Q.empty()) {
int p = -1, q = -1; int u = Q.top();
//Find the regular edge {p,q} of minimum index connecting u and its mate Q.pop();
//We use the minimum index to grant that the two possible blossoms u and v will use the same edge for a mate int v = outer[mate[u]];
for(list<int>::iterator it = deep[u].begin(); it != deep[u].end(); it++)
{ int index = m;
int di = *it; int p = -1, q = -1;
for(list<int>::iterator jt = deep[v].begin(); jt != deep[v].end(); jt++) //Find the regular edge {p,q} of minimum index connecting u and its mate
{ //We use the minimum index to grant that the two possible blossoms u and v will use the same edge for a mate
int dj = *jt; for (int di : deep[u]) {
if(IsAdjacent(di, dj) and G.GetEdgeIndex(di, dj) < index) for (int dj : deep[v]) {
{ if (IsAdjacent(di, dj) and G.GetEdgeIndex(di, dj) < index)
index = G.GetEdgeIndex(di, dj); {
p = di; index = G.GetEdgeIndex(di, dj);
q = dj; p = di;
q = dj;
}
} }
} }
}
mate[u] = q;
mate[v] = p;
//If u is a regular vertex, we are done
if(u < n or (blocked[u] and not expandBlocked)) return;
bool found = false; mate[u] = q;
//Find the position t of the new tip of the blossom mate[v] = p;
for(list<int>::iterator it = shallow[u].begin(); it != shallow[u].end() and not found; ) //If u is a regular vertex, we are done
{ if (u < n or (blocked[u] and not expandBlocked)) continue;
int si = *it;
for(list<int>::iterator jt = deep[si].begin(); jt != deep[si].end() and not found; jt++) bool found = false;
//Find the position t of the new tip of the blossom
for (list<int>::iterator it = shallow[u].begin(); it != shallow[u].end() and not found; )
{ {
if(*jt == p ) int si = *it;
found = true; for (vector<int>::iterator jt = deep[si].begin(); jt != deep[si].end() and not found; jt++)
{
if (*jt == p)
found = true;
}
it++;
if (not found)
{
shallow[u].push_back(si);
shallow[u].pop_front();
}
} }
list<int>::iterator it = shallow[u].begin();
//Adjust the mate of the tip
mate[*it] = mate[u];
it++; it++;
if(not found) //
//Now we go through the odd circuit adjusting the new mates
while (it != shallow[u].end())
{ {
shallow[u].push_back(si); list<int>::iterator itnext = it;
shallow[u].pop_front(); itnext++;
mate[*it] = *itnext;
mate[*itnext] = *it;
itnext++;
it = itnext;
}
//We update the sets blossom, shallow, and outer since this blossom is being deactivated
for (int s : shallow[u]) {
outer[s] = s;
for (int d : deep[s])
outer[d] = s;
}
active[u] = false;
AddFreeBlossomIndex(u);
//Expand the vertices in the blossom
for (int s : shallow[u]) {
Q.push(s);
} }
} }
list<int>::iterator it = shallow[u].begin();
//Adjust the mate of the tip
mate[*it] = mate[u];
it++;
//
//Now we go through the odd circuit adjusting the new mates
while(it != shallow[u].end())
{
list<int>::iterator itnext = it;
itnext++;
mate[*it] = *itnext;
mate[*itnext] = *it;
itnext++;
it = itnext;
}
//We update the sets blossom, shallow, and outer since this blossom is being deactivated
for(list<int>::iterator it = shallow[u].begin(); it != shallow[u].end(); it++)
{
int s = *it;
outer[s] = s;
for(list<int>::iterator jt = deep[s].begin(); jt != deep[s].end(); jt++)
outer[*jt] = s;
}
active[u] = false;
AddFreeBlossomIndex(u);
//Expand the vertices in the blossom
for(list<int>::iterator it = shallow[u].begin(); it != shallow[u].end(); it++)
Expand(*it, expandBlocked);
} }
@ -396,14 +391,11 @@ int Matching::Blossom(int u, int v)
} }
//Now we construct deep and update outer //Now we construct deep and update outer
for(list<int>::iterator it = shallow[t].begin(); it != shallow[t].end(); it++) for(int u_ : shallow[t]) {
{
u_ = *it;
outer[u_] = t; outer[u_] = t;
for(list<int>::iterator jt = deep[u_].begin(); jt != deep[u_].end(); jt++) for(int d : deep[u_]) {
{ deep[t].push_back(d);
deep[t].push_back(*jt); outer[d] = t;
outer[*jt] = t;
} }
} }
@ -423,10 +415,16 @@ void Matching::UpdateDualCosts()
int inite1 = false, inite2 = false, inite3 = false; int inite1 = false, inite2 = false, inite3 = false;
for(int i = 0; i < m; i++) for(int i = 0; i < m; i++)
{ {
int u = G.GetEdge(i).first, auto edge = G.GetEdge(i);
v = G.GetEdge(i).second; int u = edge.first,
v = edge.second;
if( (type[outer[u]] == EVEN and type[outer[v]] == UNLABELED) or (type[outer[v]] == EVEN and type[outer[u]] == UNLABELED) ) int outer_u = outer[u];
int outer_v = outer[v];
int type_u = type[outer_u];
int type_v = type[outer_v];
if( (type_u == EVEN and type_v == UNLABELED) or (type_v == EVEN and type_u == UNLABELED) )
{ {
if(!inite1 or GREATER(e1, slack[i])) if(!inite1 or GREATER(e1, slack[i]))
{ {
@ -434,7 +432,7 @@ void Matching::UpdateDualCosts()
inite1 = true; inite1 = true;
} }
} }
else if( (outer[u] != outer[v]) and type[outer[u]] == EVEN and type[outer[v]] == EVEN ) else if( (outer_u != outer_v) and type_u == EVEN and type_v == EVEN )
{ {
if(!inite2 or GREATER(e2, slack[i])) if(!inite2 or GREATER(e2, slack[i]))
{ {
@ -477,18 +475,24 @@ void Matching::UpdateDualCosts()
for(int i = 0; i < m; i++) for(int i = 0; i < m; i++)
{ {
int u = G.GetEdge(i).first, auto edge = G.GetEdge(i);
v = G.GetEdge(i).second; int u = edge.first,
v = edge.second;
if(outer[u] != outer[v]) int outer_u = outer[u];
int outer_v = outer[v];
int type_u = type[outer_u];
int type_v = type[outer_v];
if(outer_u != outer_v)
{ {
if(type[outer[u]] == EVEN and type[outer[v]] == EVEN) if(type_u == EVEN and type_v == EVEN)
slack[i] -= 2.0*e; slack[i] -= 2.0*e;
else if(type[outer[u]] == ODD and type[outer[v]] == ODD) else if(type_u == ODD and type_v == ODD)
slack[i] += 2.0*e; slack[i] += 2.0*e;
else if( (type[outer[v]] == UNLABELED and type[outer[u]] == EVEN) or (type[outer[u]] == UNLABELED and type[outer[v]] == EVEN) ) else if( (type_v == UNLABELED and type_u == EVEN) or (type_u == UNLABELED and type_v == EVEN) )
slack[i] -= e; slack[i] -= e;
else if( (type[outer[v]] == UNLABELED and type[outer[u]] == ODD) or (type[outer[u]] == UNLABELED and type[outer[v]] == ODD) ) else if( (type_v == UNLABELED and type_u == ODD) or (type_u == UNLABELED and type_v == ODD) )
slack[i] += e; slack[i] += e;
} }
} }

Wyświetl plik

@ -65,7 +65,7 @@ private:
list<int> free;//List of free blossom indices list<int> free;//List of free blossom indices
vector<int> outer;//outer[v] gives the index of the outermost blossom that contains v, outer[v] = v if v is not contained in any blossom vector<int> outer;//outer[v] gives the index of the outermost blossom that contains v, outer[v] = v if v is not contained in any blossom
vector< list<int> > deep;//deep[v] is a list of all the original vertices contained inside v, deep[v] = v if v is an original vertex vector< vector<int> > deep;//deep[v] is a list of all the original vertices contained inside v, deep[v] = v if v is an original vertex
vector< list<int> > shallow;//shallow[v] is a list of the vertices immediately contained inside v, shallow[v] is empty is the default vector< list<int> > shallow;//shallow[v] is a list of the vertices immediately contained inside v, shallow[v] is empty is the default
vector<int> tip;//tip[v] is the tip of blossom v vector<int> tip;//tip[v] is the tip of blossom v
vector<bool> active;//true if a blossom is being used vector<bool> active;//true if a blossom is being used

Wyświetl plik

@ -8,10 +8,14 @@ struct pair_hash {
} }
}; };
//
// returns all vertex indices in all connected sub-components of the graph
//
std::vector<std::vector<int>> ConnectedComponents(const Graph& G) { std::vector<std::vector<int>> ConnectedComponents(const Graph& G) {
std::vector<std::vector<int>> components; std::vector<std::vector<int>> components;
std::vector<bool> visited(G.GetNumVertices(), false); std::vector<bool> visited(G.GetNumVertices(), false);
list<int> L; std::list<int> L;
for (int i = 0; i < visited.size(); i++) { for (int i = 0; i < visited.size(); i++) {
// if condition should only be true for the first element in // if condition should only be true for the first element in
@ -38,18 +42,20 @@ std::vector<std::vector<int>> ConnectedComponents(const Graph& G) {
return components; return components;
} }
WorldObject::WorldObject(juce::InputStream& stream) { WorldObject::WorldObject(std::string obj_string) {
tinyobj::ObjReaderConfig reader_config; tinyobj::ObjReaderConfig reader_config;
tinyobj::ObjReader reader; tinyobj::ObjReader reader;
reader.ParseFromString(stream.readEntireStreamAsString().toStdString(), "", reader_config); reader.ParseFromString(obj_string, "", reader_config);
vs = reader.GetAttrib().vertices; vs = reader.GetAttrib().vertices;
numVertices = vs.size() / 3; numVertices = vs.size() / 3;
//
// normalising object vertices
//
double x = 0.0, y = 0.0, z = 0.0; double x = 0.0, y = 0.0, z = 0.0;
double max = 0.0; double max = 0.0;
for (int i = 0; i < numVertices; i++) { for (int i = 0; i < numVertices; i++) {
x += vs[i * 3]; x += vs[i * 3];
y += vs[i * 3 + 1]; y += vs[i * 3 + 1];
@ -74,14 +80,19 @@ WorldObject::WorldObject(juce::InputStream& stream) {
vs[i * 3 + 2] = (vs[i * 3 + 2] - z) / max; vs[i * 3 + 2] = (vs[i * 3 + 2] - z) / max;
} }
//
// getting edges from obj file
//
std::vector<tinyobj::shape_t> shapes = reader.GetShapes(); std::vector<tinyobj::shape_t> shapes = reader.GetShapes();
std::unordered_set<std::pair<int, int>, pair_hash> edge_set; std::unordered_set<std::pair<int, int>, pair_hash> edge_set;
for (auto& shape : shapes) { for (auto& shape : shapes) {
int i = 0; int i = 0;
int face = 0; int face = 0;
while (i < shape.mesh.indices.size()) { while (i < shape.mesh.indices.size()) {
int prevVertex = -1; int prevVertex = -1;
// num_face_vertices stores the number of vertices per face, used to
// iterate through mesh.indices and know when a face starts/ends
for (int j = 0; j < shape.mesh.num_face_vertices[face]; j++) { for (int j = 0; j < shape.mesh.num_face_vertices[face]; j++) {
int vertex = shape.mesh.indices[i].vertex_index; int vertex = shape.mesh.indices[i].vertex_index;
if (prevVertex != -1) { if (prevVertex != -1) {
@ -101,10 +112,19 @@ WorldObject::WorldObject(juce::InputStream& stream) {
} }
Graph graph(numVertices, edge_list); Graph graph(numVertices, edge_list);
std::vector<std::vector<int>> connected_components = ConnectedComponents(graph); std::vector<std::vector<int>> connected_components = ConnectedComponents(graph);
// perform chinese postman on all connected sub-components of graph
for (auto& connected_component : connected_components) { for (auto& connected_component : connected_components) {
// TODO: make this parallel: https://stackoverflow.com/questions/36246300/parallel-loops-in-c
//
// get a mapping to graph vertices that doesn't skip over
// any numbers, allowing the Graph class to be used
//
// we also need a mapping back to the obj vertices so that
// we can construct the path at the end
//
std::vector<bool> present_vertices(graph.GetNumVertices(), false); std::vector<bool> present_vertices(graph.GetNumVertices(), false);
for (int vertex : connected_component) { for (int vertex : connected_component) {
@ -124,6 +144,8 @@ WorldObject::WorldObject(juce::InputStream& stream) {
} }
} }
// generate all edges in sub-component using the vertex
// maps and parent Graph's adjacency list
std::list<std::pair<int, int>> sub_edge_list; std::list<std::pair<int, int>> sub_edge_list;
for (int obj_start : connected_component) { for (int obj_start : connected_component) {
@ -135,9 +157,22 @@ WorldObject::WorldObject(juce::InputStream& stream) {
} }
Graph subgraph(connected_component.size(), sub_edge_list); Graph subgraph(connected_component.size(), sub_edge_list);
pair<list<int>, double> solution = ChinesePostman(subgraph);
std::vector<double> cost(subgraph.GetNumEdges());
for (auto& edge : sub_edge_list) {
int obj_start = graph_to_obj_vertex[edge.first];
int obj_end = graph_to_obj_vertex[edge.second];
double deltax = vs[3 * obj_start] - vs[3 * obj_end];
double deltay = vs[3 * obj_start + 1] - vs[3 * obj_end + 1];
double deltaz = vs[3 * obj_start + 2] - vs[3 * obj_end + 2];
double c = std::sqrt(deltax * deltax + deltay * deltay + deltaz * deltaz);
cost[subgraph.GetEdgeIndex(edge.first, edge.second)] = c;
}
pair<list<int>, double> solution = ChinesePostman(subgraph, cost);
list<int>& path = solution.first; list<int>& path = solution.first;
// traverse CP solution, converting back to obj vertices
int prevVertex = -1; int prevVertex = -1;
for (auto& graph_vertex : path) { for (auto& graph_vertex : path) {
int vertex = graph_to_obj_vertex[graph_vertex]; int vertex = graph_to_obj_vertex[graph_vertex];

Wyświetl plik

@ -1,11 +1,10 @@
#pragma once #pragma once
#include <JuceHeader.h>
#include "Line3D.h" #include "Line3D.h"
class WorldObject { class WorldObject {
public: public:
WorldObject(juce::InputStream&); WorldObject(std::string);
double rotateX = 0.0, rotateY = 0.0, rotateZ = 0.0; double rotateX = 0.0, rotateY = 0.0, rotateZ = 0.0;

Wyświetl plik

@ -5,7 +5,7 @@ FileParser::FileParser() {}
void FileParser::parse(juce::String extension, std::unique_ptr<juce::InputStream> stream) { void FileParser::parse(juce::String extension, std::unique_ptr<juce::InputStream> stream) {
if (extension == ".obj") { if (extension == ".obj") {
object = std::make_unique<WorldObject>(*stream); object = std::make_unique<WorldObject>(stream->readEntireStreamAsString().toStdString());
camera = std::make_unique<Camera>(1.0, 0, 0, 0.0); camera = std::make_unique<Camera>(1.0, 0, 0, 0.0);
camera->findZPos(*object); camera->findZPos(*object);
} }