diff --git a/Source/chinese_postman/ChinesePostman.h b/Source/chinese_postman/ChinesePostman.h index 0e9b8578..398b67bb 100644 --- a/Source/chinese_postman/ChinesePostman.h +++ b/Source/chinese_postman/ChinesePostman.h @@ -18,9 +18,7 @@ bool Connected(const Graph & G) visited[u] = true; n++; - for(list::const_iterator it = G.AdjList(u).begin(); it != G.AdjList(u).end(); it++) - { - int v = *it; + for(int v : G.AdjList(u)) { L.push_back(v); } } @@ -41,7 +39,7 @@ pair< list, double > ChinesePostman(const Graph& G, const vector& c throw "Error: Graph is not connected"; //Build adjacency lists using edges in the graph - vector< list > A(G.GetNumVertices(), list()); + vector> A(G.GetNumVertices(), vector()); for(int u = 0; u < G.GetNumVertices(); u++) A[u] = G.AdjList(u); @@ -105,10 +103,7 @@ pair< list, double > ChinesePostman(const Graph& G, const vector& c vector traversed(G.GetNumEdges(), 0); for(int u = 0; u < G.GetNumVertices(); u++) { - for(list::iterator it = A[u].begin(); it != A[u].end(); it++) - { - int v = *it; - + for(int v : A[u]) { //we do this so that the edge is not counted twice if(v < u) continue; diff --git a/Source/chinese_postman/Dijkstra.h b/Source/chinese_postman/Dijkstra.h index ac94b1f5..bac8f613 100644 --- a/Source/chinese_postman/Dijkstra.h +++ b/Source/chinese_postman/Dijkstra.h @@ -36,9 +36,7 @@ pair< vector, vector > Dijkstra(const Graph & G, int origin, const permanent[u] = true; //Update the heap with vertices adjacent to u - for(list::const_iterator it = G.AdjList(u).begin(); it != G.AdjList(u).end(); it++) - { - int v = *it; + for (int v : G.AdjList(u)) { if(permanent[v]) continue; diff --git a/Source/chinese_postman/Graph.cpp b/Source/chinese_postman/Graph.cpp index 46861e7f..0f46a091 100644 --- a/Source/chinese_postman/Graph.cpp +++ b/Source/chinese_postman/Graph.cpp @@ -19,21 +19,11 @@ Graph::Graph(int n, const list< pair > & edges): pair Graph::GetEdge(int e) const { - if(e > (int)edges.size()) - throw "Error: edge does not exist"; - return edges[e]; } 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]; } @@ -47,15 +37,11 @@ void Graph::AddVertex() n++; adjMat.push_back( vector(n, false) ); edgeIndex.push_back( vector(n, -1) ); - adjList.push_back( list() ); + adjList.push_back( vector() ); } void Graph::AddEdge(int u, int v) { - if( u > n or - v > n ) - throw "Error: vertex does not exist"; - if(adjMat[u][v]) return; 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++; } -const list & Graph::AdjList(int v) const +const vector& Graph::AdjList(int v) const { if(v > n) throw "Error: vertex does not exist"; diff --git a/Source/chinese_postman/Graph.h b/Source/chinese_postman/Graph.h index 7779db6f..8d61276f 100644 --- a/Source/chinese_postman/Graph.h +++ b/Source/chinese_postman/Graph.h @@ -30,7 +30,7 @@ public: void AddEdge(int u, int v); //Returns the adjacency list of a vertex - const list & AdjList(int v) const; + const vector& AdjList(int v) const; //Returns the graph's adjacency matrix const vector< vector > & AdjMat() const; @@ -44,11 +44,11 @@ private: vector< vector > adjMat; //Adjacency lists - vector< list > adjList; + vector > adjList; //Array of edges - vector< pair > edges; + vector > edges; //Indices of the edges - vector< vector > edgeIndex; + vector > edgeIndex; }; diff --git a/Source/chinese_postman/Matching.cpp b/Source/chinese_postman/Matching.cpp index fb7041fc..6595bf97 100644 --- a/Source/chinese_postman/Matching.cpp +++ b/Source/chinese_postman/Matching.cpp @@ -1,4 +1,6 @@ #include "Matching.h" +#include +#include Matching::Matching(const Graph & G): G(G), @@ -33,14 +35,10 @@ void Matching::Grow() //w might be a blossom //we have to explore all the connections from vertices inside the blossom to other vertices - for(list::iterator it = deep[w].begin(); it != deep[w].end(); it++) - { - int u = *it; + for(int u : deep[w]) { int cont = false; - for(list::const_iterator jt = G.AdjList(u).begin(); jt != G.AdjList(u).end(); jt++) - { - int v = *jt; + for(int v : G.AdjList(u)) { if(IsEdgeBlocked(u, v)) continue; @@ -143,10 +141,7 @@ void Matching::Heuristic() if(mate[outer[u]] == -1) { int min = -1; - for(list::const_iterator it = G.AdjList(u).begin(); it != G.AdjList(u).end(); it++) - { - int v = *it; - + for (int v : G.AdjList(u)) { if(IsEdgeBlocked(u, v) or (outer[u] == outer[v]) or (mate[outer[v]] != -1) ) @@ -170,12 +165,10 @@ void Matching::DestroyBlossom(int t) if((t < n) or (blocked[t] and GREATER(dual[t], 0))) return; - for(list::iterator it = shallow[t].begin(); it != shallow[t].end(); it++) - { - int s = *it; + for(int s : shallow[t]) { outer[s] = s; - for(list::iterator jt = deep[s].begin(); jt != deep[s].end(); jt++) - outer[*jt] = s; + for(int d : deep[s]) + outer[d] = s; DestroyBlossom(s); } @@ -186,82 +179,84 @@ void Matching::DestroyBlossom(int t) 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 Q; + Q.push(start); - int index = m; - int p = -1, q = -1; - //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 - for(list::iterator it = deep[u].begin(); it != deep[u].end(); it++) - { - int di = *it; - for(list::iterator jt = deep[v].begin(); jt != deep[v].end(); jt++) - { - int dj = *jt; - if(IsAdjacent(di, dj) and G.GetEdgeIndex(di, dj) < index) - { - index = G.GetEdgeIndex(di, dj); - p = di; - q = dj; + while (!Q.empty()) { + int u = Q.top(); + Q.pop(); + int v = outer[mate[u]]; + + int index = m; + int p = -1, q = -1; + //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 + for (int di : deep[u]) { + for (int dj : deep[v]) { + if (IsAdjacent(di, dj) and G.GetEdgeIndex(di, dj) < index) + { + index = G.GetEdgeIndex(di, 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; - //Find the position t of the new tip of the blossom - for(list::iterator it = shallow[u].begin(); it != shallow[u].end() and not found; ) - { - int si = *it; - for(list::iterator jt = deep[si].begin(); jt != deep[si].end() and not found; jt++) + mate[u] = q; + mate[v] = p; + //If u is a regular vertex, we are done + if (u < n or (blocked[u] and not expandBlocked)) continue; + + bool found = false; + //Find the position t of the new tip of the blossom + for (list::iterator it = shallow[u].begin(); it != shallow[u].end() and not found; ) { - if(*jt == p ) - found = true; + int si = *it; + for (vector::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::iterator it = shallow[u].begin(); + //Adjust the mate of the tip + mate[*it] = mate[u]; 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); - shallow[u].pop_front(); + list::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 (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::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::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::iterator it = shallow[u].begin(); it != shallow[u].end(); it++) - { - int s = *it; - outer[s] = s; - for(list::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::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 - for(list::iterator it = shallow[t].begin(); it != shallow[t].end(); it++) - { - u_ = *it; + for(int u_ : shallow[t]) { outer[u_] = t; - for(list::iterator jt = deep[u_].begin(); jt != deep[u_].end(); jt++) - { - deep[t].push_back(*jt); - outer[*jt] = t; + for(int d : deep[u_]) { + deep[t].push_back(d); + outer[d] = t; } } @@ -423,10 +415,16 @@ void Matching::UpdateDualCosts() int inite1 = false, inite2 = false, inite3 = false; for(int i = 0; i < m; i++) { - int u = G.GetEdge(i).first, - v = G.GetEdge(i).second; + auto edge = G.GetEdge(i); + 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])) { @@ -434,7 +432,7 @@ void Matching::UpdateDualCosts() 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])) { @@ -477,18 +475,24 @@ void Matching::UpdateDualCosts() for(int i = 0; i < m; i++) { - int u = G.GetEdge(i).first, - v = G.GetEdge(i).second; + auto edge = G.GetEdge(i); + 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; - 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; - 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; - 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; } } diff --git a/Source/chinese_postman/Matching.h b/Source/chinese_postman/Matching.h index 434ab1e0..85584c78 100644 --- a/Source/chinese_postman/Matching.h +++ b/Source/chinese_postman/Matching.h @@ -65,7 +65,7 @@ private: list free;//List of free blossom indices vector 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 > 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 > 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 > shallow;//shallow[v] is a list of the vertices immediately contained inside v, shallow[v] is empty is the default vector tip;//tip[v] is the tip of blossom v vector active;//true if a blossom is being used diff --git a/Source/obj/WorldObject.cpp b/Source/obj/WorldObject.cpp index b561a6dc..43eaa50c 100644 --- a/Source/obj/WorldObject.cpp +++ b/Source/obj/WorldObject.cpp @@ -8,10 +8,14 @@ struct pair_hash { } }; + +// +// returns all vertex indices in all connected sub-components of the graph +// std::vector> ConnectedComponents(const Graph& G) { std::vector> components; std::vector visited(G.GetNumVertices(), false); - list L; + std::list L; for (int i = 0; i < visited.size(); i++) { // if condition should only be true for the first element in @@ -38,18 +42,20 @@ std::vector> ConnectedComponents(const Graph& G) { return components; } -WorldObject::WorldObject(juce::InputStream& stream) { +WorldObject::WorldObject(std::string obj_string) { tinyobj::ObjReaderConfig reader_config; tinyobj::ObjReader reader; - reader.ParseFromString(stream.readEntireStreamAsString().toStdString(), "", reader_config); + reader.ParseFromString(obj_string, "", reader_config); vs = reader.GetAttrib().vertices; numVertices = vs.size() / 3; + // + // normalising object vertices + // double x = 0.0, y = 0.0, z = 0.0; double max = 0.0; - for (int i = 0; i < numVertices; i++) { x += vs[i * 3]; y += vs[i * 3 + 1]; @@ -74,14 +80,19 @@ WorldObject::WorldObject(juce::InputStream& stream) { vs[i * 3 + 2] = (vs[i * 3 + 2] - z) / max; } + // + // getting edges from obj file + // std::vector shapes = reader.GetShapes(); - std::unordered_set, pair_hash> edge_set; + for (auto& shape : shapes) { int i = 0; int face = 0; while (i < shape.mesh.indices.size()) { 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++) { int vertex = shape.mesh.indices[i].vertex_index; if (prevVertex != -1) { @@ -101,10 +112,19 @@ WorldObject::WorldObject(juce::InputStream& stream) { } Graph graph(numVertices, edge_list); - std::vector> connected_components = ConnectedComponents(graph); + // perform chinese postman on all connected sub-components of graph 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 present_vertices(graph.GetNumVertices(), false); 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> sub_edge_list; for (int obj_start : connected_component) { @@ -135,9 +157,22 @@ WorldObject::WorldObject(juce::InputStream& stream) { } Graph subgraph(connected_component.size(), sub_edge_list); - pair, double> solution = ChinesePostman(subgraph); + + std::vector 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, double> solution = ChinesePostman(subgraph, cost); list& path = solution.first; + // traverse CP solution, converting back to obj vertices int prevVertex = -1; for (auto& graph_vertex : path) { int vertex = graph_to_obj_vertex[graph_vertex]; diff --git a/Source/obj/WorldObject.h b/Source/obj/WorldObject.h index cf599ecf..057af427 100644 --- a/Source/obj/WorldObject.h +++ b/Source/obj/WorldObject.h @@ -1,11 +1,10 @@ #pragma once -#include #include "Line3D.h" class WorldObject { public: - WorldObject(juce::InputStream&); + WorldObject(std::string); double rotateX = 0.0, rotateY = 0.0, rotateZ = 0.0; diff --git a/Source/parser/FileParser.cpp b/Source/parser/FileParser.cpp index 8a669add..897eec23 100644 --- a/Source/parser/FileParser.cpp +++ b/Source/parser/FileParser.cpp @@ -5,7 +5,7 @@ FileParser::FileParser() {} void FileParser::parse(juce::String extension, std::unique_ptr stream) { if (extension == ".obj") { - object = std::make_unique(*stream); + object = std::make_unique(stream->readEntireStreamAsString().toStdString()); camera = std::make_unique(1.0, 0, 0, 0.0); camera->findZPos(*object); }