bool obj_save(const string& filename, Manifold& m) { ofstream os(filename.data()); if(os.bad()) return false; VertexAttributeVector<int> vmap; int k = 0; for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){ Vec3d p = m.pos(*v); os << "v "<< p[0] << " " << p[1] << " " << p[2] << "\n"; vmap[*v] = k++; } for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f){ vector<int> verts; for(Walker w = m.walker(*f); !w.full_circle(); w = w.circulate_face_ccw()){ int idx = vmap[w.vertex()]; assert(static_cast<size_t>(idx) < m.no_vertices()); // move subscript range from 0..size-1 to 1..size according to OBJ standards verts.push_back(idx + 1); } os << "f "; for(size_t i = 0; i < verts.size() ; ++i){ os << verts[i] << " "; } os<<endl; } return true; }
AmbientOcclusionRenderer::AmbientOcclusionRenderer(const Manifold& m, bool smooth, VertexAttributeVector<double>& field, double max_val): SimpleShaderRenderer(vss,fss) { GLint old_prog; glGetIntegerv(GL_CURRENT_PROGRAM, &old_prog); glUseProgram(prog); GLuint scalar_attrib = glGetAttribLocation(prog, "scalar"); glUniform1fARB(glGetUniformLocationARB(prog, "scalar_max"), max_val); glNewList(display_list,GL_COMPILE); for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f) { if(!smooth) glNormal3dv(normal(m, *f).get()); if(no_edges(m, *f)== 3) glBegin(GL_TRIANGLES); else glBegin(GL_POLYGON); for(Walker w = m.walker(*f); !w.full_circle(); w = w.circulate_face_ccw()) { Vec3d n(normal(m, w.vertex())); if(smooth) glNormal3dv(n.get()); glVertexAttrib1d(scalar_attrib, field[w.vertex()]); glVertex3dv(m.pos(w.vertex()).get()); } glEnd(); } glEndList(); glUseProgram(old_prog); }
int WireframeRenderer::maximum_face_valency(const Manifold& m) { int max_val = 0; for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f) max_val = max(max_val, no_edges(m, *f)); return max_val; }
LineFieldRenderer::LineFieldRenderer(const Manifold& m, bool smooth, VertexAttributeVector<Vec3d>& lines, float _r): SimpleShaderRenderer(vss,fss), r(_r) { float noise_scale = 10.0f/r; float line_scale = 0.003f; GLint old_prog; glGetIntegerv(GL_CURRENT_PROGRAM, &old_prog); glUseProgram(prog); glUniform1fARB(glGetUniformLocationARB(prog, "scale_line"),line_scale*noise_scale); glUniform1fARB(glGetUniformLocationARB(prog, "noise_scale"),noise_scale); glUniform1iARB(glGetUniformLocationARB(prog, "noise_tex"),0); GLuint direction = glGetAttribLocation(prog, "direction"); glNewList(display_list,GL_COMPILE); for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f) { if(!smooth) glNormal3dv(normal(m, *f).get()); if(no_edges(m, *f) == 3) glBegin(GL_TRIANGLES); else glBegin(GL_POLYGON); for(Walker w = m.walker(*f); !w.full_circle(); w = w.circulate_face_ccw()) { Vec3d n(normal(m, w.vertex())); if(smooth) glNormal3dv(n.get()); Vec3d d = lines[w.vertex()]; d = normalize(d-n*dot(n,d)); glVertexAttrib3dv(direction, d.get()); glVertex3dv(m.pos(w.vertex()).get()); } glEnd(); } glBindTexture(GL_TEXTURE_3D, 0); glEndList(); glUseProgram(old_prog); }
CircleFieldRenderer::CircleFieldRenderer(const Manifold& m, bool smooth, VertexAttributeVector<Vec2d>& field, float gamma): SimpleShaderRenderer(vss, fss) { GLint old_prog; glGetIntegerv(GL_CURRENT_PROGRAM, &old_prog); glUseProgram(prog); GLuint scalar_attrib = glGetAttribLocation(prog, "circlepos"); // static float& gamma = CreateCVar("display.scalar_field_renderer.gamma",2.2f); glUniform1fARB(glGetUniformLocationARB(prog, "gamma"), gamma); glNewList(display_list,GL_COMPILE); for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f) { if(!smooth) glNormal3dv(normal(m, *f).get()); if(no_edges(m, *f)== 3) glBegin(GL_TRIANGLES); else glBegin(GL_POLYGON); for(Walker w = m.walker(*f); !w.full_circle(); w = w.circulate_face_ccw()) { Vec3d n(normal(m, w.vertex())); if(smooth) glNormal3dv(n.get()); glVertexAttrib2dv(scalar_attrib, field[w.vertex()].get()); glVertex3dv(m.pos(w.vertex()).get()); } glEnd(); } glEndList(); glUseProgram(old_prog); }
int main(int argc, char** argv) { /* * Read and parse a point set. */ /* Open a data stream for reading. * We first open data.txt. There is also kote1.txt which contains height * values in addition to x,y positions. */ ifstream data("data.txt"); vector<Vec2d> pts; if(data.good()) while(!data.eof()) { double x,y; data >> x >> y; if(data.good()) { Vec2d p(x,y); pts.push_back(p); dmin = v_min(p,dmin); dmax = v_max(p,dmax); } } cout << "Loaded " << pts.size() << " points " << endl; Vec2d trans((dmax[0]+dmin[0])/2,(dmax[1]+dmin[1])/2); double skal = 2/max(dmax[0]-dmin[0],dmax[1]-dmin[1]); /* Træk trans fra alle punkter og gang med 'skal'*/ for (int i = 0; i < pts.size(); i++) { pts[i] -= trans; pts[i] *= skal; } /* * Build a triangle mesh with a single triangle consisting of the * first three vertices. */ create_single_triangle_manifold(Vec3f(0, 3, 0), Vec3f(4.5, -1.5, 0), Vec3f(-4.5, -1.5, 0), m); // Initially just split the triangle by inserting the first point VertexID v = m.split_face_by_vertex(*m.faces_begin()); m.pos(v) = Vec3d(pts[0][0], pts[0][1], 0); // Now insert all of the remaining points for (int i = 1; i < pts.size(); i++) { Vec3d insertionPoint = Vec3d(pts[i][0], pts[i][1], 0); VertexID insertionVertex; // Loop over all the faces and find the face that contains the point for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); f++) { Walker w = m.walker(*f); bool isLeftOf = true; while (!w.full_circle()) { // If the point to be inserted is not to the left of the halfedge, then break the while loop and continue to the next face if (!leftOf(m.pos(w.circulate_face_ccw().vertex()), m.pos(w.vertex()), insertionPoint)) { isLeftOf = false; break; } w = w.circulate_face_cw(); } // if we found the face the point belongs to then insert it and break the for loop if (isLeftOf == true) { insertionVertex = m.split_face_by_vertex(*f); m.pos(insertionVertex) = insertionPoint; break; } } // Now loop over all the edges affected by the inserted point. // Note that we are assuming that the point was inserted, if not then this will crash spectacularly. Walker w = m.walker(insertionVertex); // Keep track of the next halfedge pointing TO the inserted vertex HalfEdgeID next_edge = w.circulate_vertex_ccw().opp().halfedge(); HalfEdgeAttributeVector<int> touched; while (!w.full_circle()) { // Iterate over the face of the current halfedge until we reach the next edge pointing TO the inserted vertex if(w.halfedge() != next_edge) { // Check if the current halfedge is locally Delaunay using the inCircle function recursiveDelaunayFlip(m, w, false); // Update the walker to be the next halfedge in the current face. w = w.circulate_face_ccw(); } else { // If we are the next edge pointing to the inserted vertex then go to opposite halfedge. This means we are now looking at the halfedge pointing AWAY from the inserted vertex. w = w.opp(); // Remember to update the next_edge to be the next halfedge pointing to the inserted vertex. next_edge = w.circulate_vertex_ccw().opp().halfedge(); } } } /* * Initialize GLUT, the system used to show OpenGL windows. */ glutInit(&argc, argv); glutInitWindowSize(512,512); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow("Delaunay"); glutDisplayFunc(display); // This function is called from glut to draw glutKeyboardFunc(keyfun); // Parse keyboard input // Pass control to glut glutMainLoop(); return 0; }