// Copyright (c) 2021. Pascal Syma <pascal@syma.dev> and Antonio Martinez Casadesus <acasadesus@stud.hs-bremen.de>. // All rights reserved. // // Created by Pascal on 17.05.2021. // #include <string> #include <fstream> #include <iostream> #include <iomanip> #include "Mesh.h" #include "Util.h" using namespace std; Mesh::Mesh() { this->tris = {}; this->pts = {}; } void Mesh::saveData(const string& fileName) { ofstream file( fileName); if (!file){ cout << "error opening file" << endl; return; } for (auto vert : pts) { file << "v\t" << vert.p[0] << "\t" << vert.p[1] << "\t" << vert.p[2] << endl; } for (auto triag : tris) { file << "f\t" << triag.iv[0]+1 << "\t" << triag.iv[1]+1 << "\t" << triag.iv[2]+1 << endl; } file.close(); } void Mesh::loadData(const string& fileName) { ifstream file( fileName); if (!file){ cout << "error opening file" << endl; return; } string key; while( file){ //getline( file, line); file >> key; if (key == "v") { float x, y, z; file >> x >> y >> z; Vertex pVertex = *new Vertex(this, x, y, z); pts.push_back(pVertex); } else if (key == "f") { int a, b, c; file >> a >> b >> c; Tri pTriangle = *new Tri(this, a-1, b-1, c-1); tris.push_back(pTriangle); } } file.close(); tris.pop_back(); } void Mesh::connectivityAlgo() { for (auto & pt : pts) { pt.valence = 0; } // Connectivity Algorithm for (int i = 0; i < tris.size(); ++i) { Tri triag = tris[i]; // Search for neighbour for (int ti = 0; ti < tris.size(); ++ti) { if (i == ti) continue; Tri t = tris[ti]; int count = 0; int side = 0; for (int x = 0; x < 3; ++x) { bool hit = false; for (int y : t.iv) { if (triag.iv[x] == y) hit = true; } if (hit) count++; else side = x; } // if two points are the same, they are neighbours if (count == 2) triag.it[side] = ti; } // increase valence for each vertex of triangle ++pts[triag.iv[0]].valence; ++pts[triag.iv[1]].valence; ++pts[triag.iv[2]].valence; tris[i] = triag; } } void Mesh::subDivLoop(int count) { for (int i = 0; i < count; ++i) { this->subDivLoop(); } } void Mesh::subDivLoop() { this->connectivityAlgo(); for (int i = 0; i < tris.size(); ++i) { Tri triag = tris[i]; Vertex a = pts[triag.iv[0]]; Vertex b = pts[triag.iv[1]]; Vertex c = pts[triag.iv[2]]; for (int tI = 0; tI < 3; ++tI) { Tri t = tris[triag.it[tI]]; int otherEI = 0; for (int j = 0; j < 3; ++j) { if (t.it[j] == i) { otherEI = j; break; } } if (i < triag.it[tI]) { Vertex d = pts[t.iv[otherEI]]; Vertex e = (1.0f/8.0f)*((((tI == 1 || tI == 2) ? 3.0f : 1.0f)*a) + (((tI == 0 || tI == 2) ? 3.0f : 1.0f)*b) + (((tI == 1 || tI == 0) ? 3.0f : 1.0f)*c) + d); triag.ie[tI] = pts.size(); pts.push_back(e); } else { // edge-mask already calculated triag.ie[tI] = t.ie[otherEI]; } } tris[i] = triag; } for( int i=0; i< pts.size(); i++){ // multiply every vertex with beta int n = pts[i].valence; // n = valence of v_i if (n < 3) continue; float beta = Util::beta_n( n); // cout << i << " " << n << " " << beta << " " <<endl; pts[i] *= beta; // v_i *= beta(n) } const unsigned long long int amountToSubDiv = tris.size(); for (int i = 0; i < amountToSubDiv; ++i) { Tri triag = tris[i]; int ai = triag.iv[0]; Vertex a = pts[ai]; int bi = triag.iv[1]; Vertex b = pts[bi]; int ci = triag.iv[2]; Vertex c = pts[ci]; Vertex e[3] = {}; for (int tI = 0; tI < 3; ++tI) { e[tI] = pts[triag.ie[tI]]; } // cout << triag.ie[0] << " " << triag.ie[1] << " " << triag.ie[2] << endl; // cout << e[0].p[0] << " " << e[0].p[1] << " " << e[0].p[2] << endl; // cout << e[1].p[0] << " " << e[1].p[1] << " " << e[1].p[2] << endl; // cout << e[2].p[0] << " " << e[2].p[1] << " " << e[2].p[2] << endl << endl; a += (0.5f * ((1-Util::beta_n(a.valence)) / float(a.valence)) * (e[1] + e[2])); b += (0.5f * ((1-Util::beta_n(b.valence)) / float(b.valence)) * (e[0] + e[2])); c += (0.5f * ((1-Util::beta_n(c.valence)) / float(c.valence)) * (e[1] + e[0])); pts[ai] = a; pts[bi] = b; pts[ci] = c; triag.iv[0] = triag.ie[1]; triag.iv[1] = triag.ie[0]; triag.iv[2] = ci; tris[i] = triag; tris.push_back(*new Tri(this, triag.ie[1], triag.ie[2], triag.ie[0])); tris.push_back(*new Tri(this, ai, triag.ie[2], triag.ie[1])); tris.push_back(*new Tri(this, triag.ie[2], bi, triag.ie[0])); } } void Mesh::subDivEdgeMidpoint() { const unsigned long long int amountToSubDiv = tris.size(); for (int i = 0; i < amountToSubDiv; ++i) { Tri triag = tris[i]; Vertex a = pts[triag.iv[0]]; Vertex b = pts[triag.iv[1]]; Vertex c = pts[triag.iv[2]]; // int e = pts.size(); int ei0 = -1; int ei1 = -1; int ei2 = -1; Vertex e0 = 0.5f * (a+b); Vertex e1 = 0.5f * (c+b); Vertex e2 = 0.5f * (a+c); for (int j = 0; j < pts.size(); ++j) { if (pts[j] == e0) ei0 = j; if (pts[j] == e1) ei1 = j; if (pts[j] == e2) ei2 = j; } if (ei0 == -1) { ei0 = pts.size(); pts.push_back(e0); } if (ei1 == -1) { ei1 = pts.size(); pts.push_back(e1); } if (ei2 == -1) { ei2 = pts.size(); pts.push_back(e2); } tris.push_back(*new Tri(this, triag.iv[2], ei2, ei1)); tris.push_back(*new Tri(this, triag.iv[1], ei0, ei1)); tris.push_back(*new Tri(this, ei0, ei1, ei2)); triag.iv[1] = ei0; triag.iv[2] = ei2; tris[i] = triag; } } Mesh* Mesh::copy() { Mesh *copy = new Mesh(); copy->drawWireframe = this->drawWireframe; copy->drawOutline = this->drawOutline; for (auto vert : this->pts) { copy->pts.push_back(*vert.copy(copy)); } for (auto tri : this->tris) { copy->tris.push_back(*tri.copy(copy)); } return copy; }