Mesh *Mesh::parallelSubdivide(TaskQueue *tq, int branch){ int n = numFaces(); int b = branch; cout<< " building winged edges " << endl; EdgeMap *em = new EdgeMap(numVertices()); em->putAll(faces); cout << " forking " << endl; while (n / b < 5 && b > 1){ b /= 2; } if (branch != b){ cerr<<"Warning: branch factor reduced from " << branch << " to " << b << endl; } int range = n / b + 1; //SubdivideTask tasks[b]; SubdivideTask *tasks = new SubdivideTask[b]; for (int i = 0; i < b; i++){ int min = i * range; if (min >= n) {b=i; break;} int max = ((i + 1) *range); if (max > n) max = n; tasks[i] = SubdivideTask(this, em, min, max); tq->enqueue(&tasks[i]); } for (int i = 0; i < b; i++){ tasks[i].join(); } cout << "merging" << endl; Mesh* val = merge(tasks, b); delete em; delete[] tasks; return val; }
// Calculates per edge the neighbour data (= edgeCells) void Foam::FECCellToFaceStencil::calcEdgeBoundaryData ( const boolList& isValidBFace, const labelList& boundaryEdges, EdgeMap<labelList>& neiGlobal ) const { neiGlobal.resize(2*boundaryEdges.size()); labelHashSet edgeGlobals; forAll(boundaryEdges, i) { label edgeI = boundaryEdges[i]; neiGlobal.insert ( mesh().edges()[edgeI], calcFaceCells ( isValidBFace, mesh().edgeFaces(edgeI), edgeGlobals ) ); }
void makeEdgeMap(int num_tris, const int3 tri_ndxs[], int num_verts, const float3 v[]) { for (int i=0; i<num_tris; i++) { for (int j=0; j<3; j++) { Edge e(v[tri_ndxs[i][j]], v[tri_ndxs[i][(j+1)%3]]); EdgeMap::iterator e_iter = edge_map.find(e); if (e_iter != edge_map.end()) { e_iter->second.push_back(i); } else { FaceList face_list(1,i); edge_map[e] = face_list; } } } for (int i=0; i<num_tris; i++) { printf("tri: %d\n", i); for (int j=0; j<3; j++) { printf(" edg: %d\n", j); pair<int,int> ndx(tri_ndxs[i][j], tri_ndxs[i][(j+1)%3]); if (ndx.first > ndx.second) { std::swap(ndx.first, ndx.second); } Edge e(v[ndx.first], v[ndx.second]); FaceList face_list = edge_map[e]; for (FaceList::iterator iter = face_list.begin(); iter != face_list.end(); iter++) { int face = *iter; if (face != i) { printf(" other %d\n", face); bool found_match = false; for (int z=0; z<3; z++) { pair<int,int> ndx2(tri_ndxs[face][z], tri_ndxs[face][(z+1)%3]); if (ndx2.first > ndx2.second) { std::swap(ndx2.first, ndx2.second); } if (ndx == ndx2) { printf("match\n"); found_match = true; break; } } if (!found_match) { int3 ndxs = tri_ndxs[face]; for (int z=0; z<3; z++) { if (all(e.v0 == v[ndxs[z]])) { printf(" ndx=%d\n", z); } else if (all(e.v1 == v[ndxs[z]])) { printf(" ndx=%d\n", z); } } } } } } } }
/** * Return first path found from start vertex to end vertex * as a vector of edges, or NULL of no such path is found. */ bool findDfsVertexPath(vector<Vertex*> &path, Vertex *start, const Vertex *end) const { path.clear(); if (mEdges.find(start) != mEdges.end()) { path.push_back(start); return findDfsVertexPathRec(path, end); } return false; }
/** * Return first path found from start vertex to end vertex * as a vector of edges, or NULL of no such path is found. */ bool findDfsVertexPathMarking(vector<Vertex*> &path, Vertex *start, const Vertex *end) { mMarks.clear(); path.clear(); if (mEdges.find(start) != mEdges.end()) { mMarks.insert(start); path.push_back(start); return findDfsVertexPathMarkingRec(path, end); } return false; }
/** * Gets all adjacent vertices to the parameter vertex. * @param v - the vertex to get neighbors from * @return a vector of vertices */ vector<Vertex> Graph::getAdjacent(Vertex v) const { assertExists(v, "getAdjacent"); vector<Vertex> ret; EdgeMap edges = graph.at(v); EdgeMap::iterator it; for (it = edges.begin(); it != edges.end(); ++it) ret.push_back(it->second.dest); return ret; }
/** * Add an edge if both vertices are non-NULL and distinct */ bool addEdge(Vertex *vertA, Vertex *vertB) { if (vertA == NULL || vertB == NULL || vertA == vertB) return false; // no side effects on failure addVertex(vertA); addVertex(vertB); if (mEdges.find(vertA) == mEdges.end()) { mEdges.insert(EdgeMap::value_type(vertA, new VertSet())); } VertSet *nexts = mEdges.at(vertA); return nexts->insert(vertB).second; }
void edgemapwork(void){ EdgeMap::const_iterator iter; //set up halfedge sym pointer for(iter = edgemap.begin(); iter != edgemap.end(); iter++){ EdgeMap::const_iterator iter1; EdgeMap::const_iterator iter2; Pair p1(iter->first.a,iter->first.b); Pair p2(iter->first.b,iter->first.a); iter1 = edgemap.find(p1); iter2 = edgemap.find(p2); iter2->second->sym = iter1->second; } }
/** * Find best predecessor found so far to the specified node * * @param n Node as destination to find best predecessor for * * @return Predecessor node */ gcc_pure Node GetPredecessor(const Node node) const { // Try to find the given node in the node_parent_map edge_const_iterator it = edges.find(node); if (it == edges.end()) // first entry // If the node wasn't found // -> Return the given node itself return node; else // If the node was found // -> Return the parent node return it->second.parent; }
void triangularizationte(){ int newfacesnum = 0; //number of faces @ the end Face newface; vector<Face> newFaces; int index = 0; HalfEdge mynewhalfedge[3]; for(int i = 0 ; i < numfaces ; ++i){ if(3 == faxes[i].numedges){ ++newfacesnum; } else{ newfacesnum += faxes[i].numedges - 2;} } for(int i = 0; i < newfacesnum; i++) newFaces.push_back(newface); for(int i = 0 ; i< numfaces; i++){ if(3 == faxes[i].numedges){ //triangle newFaces[index].numedges = 3; newFaces[index].ver = new Vertex[3]; for(int k=0 ; k < 3; k++){ newFaces[index].ver[k] = faxes[i].ver[k]; newFaces[index].ver[k].id = faxes[i].ver[k].id; } ++index; } else { //polygon to be split into triangles for(int j = 0 ; j< faxes[i].numedges-2; j++){ newFaces[index+j].numedges = 3; newFaces[index+j].ver = new Vertex[3]; for(int k=0 ; k<3; k++){ if( k==0 ){ newFaces[index+j].ver[k] = faxes[i].ver[0]; newFaces[index+j].ver[k].id = faxes[i].ver[0].id; } else{ newFaces[index+j].ver[k] = faxes[i].ver[k+j]; newFaces[index+j].ver[k].id = faxes[i].ver[k+j].id; } } } index += faxes[i].numedges - 2; } } for(int i = 0; i < newfacesnum; ++i){ newFaces[i].listEdge = &mynewhalfedge[0]; for(int j = 0 ; j < 3; ++j){ mynewhalfedge[j].head = &newFaces[i].ver[(j+1) % 3]; mynewhalfedge[j].thisface = &newFaces[i]; mynewhalfedge[j].next = &mynewhalfedge[(j+1) % 3]; Pair pair(newFaces[i].ver[j].id, newFaces[i].ver[(j+1) % 3].id); edgemap.insert(EdgeMap::value_type(pair, &mynewhalfedge[j])); } } edgemapwork(); numfaces = newfacesnum; faxes = newFaces; }
void * getDirectedEdge(Vector3 const & e0, Vector3 const & e1) const { typedef std::pair<EdgeMap::const_iterator, EdgeMap::const_iterator> IteratorRange; Long3Pair base_key(toGrid(e0), toGrid(e1)); // Every edge within welding distance of the given edge must be inside a neighbor of the grid cell containing the edge for (int dx0 = -1; dx0 <= 1; ++dx0) for (int dy0 = -1; dy0 <= 1; ++dy0) for (int dz0 = -1; dz0 <= 1; ++dz0) for (int dx1 = -1; dx1 <= 1; ++dx1) for (int dy1 = -1; dy1 <= 1; ++dy1) for (int dz1 = -1; dz1 <= 1; ++dz1) { Long3Pair key(Long3(base_key.first.x + dx0, base_key.first.y + dy0, base_key.first.z + dz0), Long3(base_key.second.x + dx1, base_key.second.y + dy1, base_key.second.z + dz1)); IteratorRange nbrs = edge_map.equal_range(key); for (EdgeMap::const_iterator ni = nbrs.first; ni != nbrs.second; ++ni) { if ((ni->second.e0 - e0).squaredLength() <= squared_weld_radius && (ni->second.e1 - e1).squaredLength() <= squared_weld_radius) return ni->second.edge; } } return NULL; }
EdgeMap compute_edge_map(const MatrixIr& faces) { assert(faces.cols() == 3); EdgeMap result; const size_t num_faces = faces.rows(); for (size_t i=0; i<num_faces; i++) { const Vector3I& f = faces.row(i); Triplet e0(f[1], f[2]); Triplet e1(f[2], f[0]); Triplet e2(f[0], f[1]); result.insert(e0, i); result.insert(e1, i); result.insert(e2, i); } return result; }
/** * Clears the queues */ void Clear() { // Clear the search queue q.clear(); // Clear EdgeMap edges.clear(); current_value = 0; }
void PolyMesh::buildEdges( Face* f, osg::Vec3Array* refArray, EdgeMap& emap ) { osg::Vec3 p1, p2; unsigned int size = f->_pts.size(); for ( unsigned int i=0; i<size; ++i ) { unsigned int i1=(*f)(i%size), i2=(*f)((i+1)%size); if ( i1<refArray->size() ) p1 = (*refArray)[i1]; else p1 = (*f)[i%size]; if ( i2<refArray->size() ) p2 = (*refArray)[i2]; else p2 = (*f)[(i+1)%size]; PolyMesh::Segment p = getSegment( p1, p2 ); if ( emap.find(p)==emap.end() ) emap[p] = new PolyMesh::Edge( p.first, p.second ); emap[p]->hasFace( f, true ); } }
//------------------------------------------------------------------------------ // generate display IDs for Hbr edges static void createEdgeNumbers(std::vector<Hface const *> faces) { typedef std::map<Hhalfedge const *, int> EdgeMap; EdgeMap edgeMap; typedef std::vector<Hhalfedge const *> EdgeVec; EdgeVec edgeVec; { // map half-edges into unique edge id's for (int i=0; i<(int)faces.size(); ++i) { Hface const * f = faces[i]; for (int j=0; j<f->GetNumVertices(); ++j) { Hhalfedge const * e = f->GetEdge(j); if (e->IsBoundary() or (e->GetRightFace()->GetID()>f->GetID())) { int id = (int)edgeMap.size(); edgeMap[e] = id; } } } edgeVec.resize(edgeMap.size()); for (EdgeMap::const_iterator it=edgeMap.begin(); it!=edgeMap.end(); ++it) { edgeVec[it->second] = it->first; } } static char buf[16]; for (int i=0; i<(int)edgeVec.size(); ++i) { Hhalfedge const * e = edgeVec[i]; float sharpness = e->GetSharpness(); if (sharpness>0.0f) { Vertex center(0.0f, 0.0f, 0.0f); center.AddWithWeight(e->GetOrgVertex()->GetData(), 0.5f); center.AddWithWeight(e->GetDestVertex()->GetData(), 0.5f); snprintf(buf, 16, "%g", sharpness); g_font->Print3D(center.GetPos(), buf, std::min(8,(int)sharpness+4)); } } }
void Foam::syncTools::combine ( EdgeMap<T>& edgeValues, const CombineOp& cop, const edge& index, const T& val ) { typename EdgeMap<T>::iterator iter = edgeValues.find(index); if (iter != edgeValues.end()) { cop(iter(), val); } else { edgeValues.insert(index, val); } }
/** * Inserts an edge between two vertices. * A boolean is returned for use with the random graph generation. * Hence, an error is not thrown when it fails to insert an edge. * @param u - one vertex the edge is connected to * @param v - the other vertex the edge is connected to * @return whether inserting the edge was successful */ bool Graph::insertEdge(Vertex u, Vertex v) { assertExists(u, __func__); assertExists(v, __func__); EdgeMap uEdges = graph[u]; // "fail" silently for random graph generation if (uEdges.find(v) != uEdges.end()) return false; Edge uEdge(u, v, -1, ""); graph[u].insert(make_pair(v, uEdge)); Edge vEdge(v, u, -1, ""); graph[v].insert(make_pair(u, vEdge)); return true; }
bool findDfsVertexPathRec(vector<Vertex*> &path, const Vertex *end) const { Vertex *lastVert = path.back(); if (lastVert == end) return true; if (mEdges.find(lastVert) != mEdges.end()) { VertSet *nexts = mEdges.at(lastVert); for (auto it = nexts->begin(); it != nexts->end(); ++it) { path.push_back(*it); bool found = findDfsVertexPathRec(path, end); if ( found ) return found; else path.pop_back(); } } return false; }
/** * Clears the queues */ void Clear() { // Clear the search queue while (!q.empty()) q.pop(); // Clear EdgeMap edges.clear(); current_value = 0; }
int findEdgeVertical(int x, int y_start, int y_end, const rgbd::View view, EdgeMap& edge_map) { if (y_end - y_start < min_segment_size) return -1; geo::Vector3 p1_3d, p2_3d; if (!view.getPoint3D(x, y_start, p1_3d) || !view.getPoint3D(x, y_end, p2_3d)) return -1; geo::Vec2 p1(p1_3d.y, -p1_3d.z); geo::Vec2 p2(p2_3d.y, -p2_3d.z); geo::Vec2 n = (p2 - p1).normalized(); int y_edge = -1; float max_dist_sq = 0; for(int y2 = y_start; y2 <= y_end; ++y2) { geo::Vector3 p_3d; if (!view.getPoint3D(x, y2, p_3d)) continue; geo::Vec2 p(p_3d.y, -p_3d.z); // Calculate distance of p to line (p1, p2) geo::Vec2 p1_p = p - p1; float dist_sq = (p1_p - (p1_p.dot(n) * n)).length2(); if (dist_sq > max_dist_sq) { max_dist_sq = dist_sq; y_edge = y2; } } if (y_edge < 0) return -1; float d = view.getDepth(x, y_edge); if (d > max_range) return -1; float th = d * bla; if (max_dist_sq < (th * th)) return -1; // Add edge point edge_map.addEdgePoint(x, y_edge, 0, 1); // Recursively find edges findEdgeVertical(x, y_start, y_edge, view, edge_map); return y_edge; }
/** * Add node to search queue * * @param n Destination node to add * @param pn Previous node * @param e Edge distance (previous to this) * @return false if this link was worse than an existing one */ bool Push(const Node node, const Node parent, unsigned edge_value = 0) { // Try to find the given node n in the EdgeMap edge_iterator it = edges.find(node); if (it == edges.end()) // first entry // If the node wasn't found // -> Insert a new node it = edges.insert(std::make_pair(node, Edge(parent, edge_value))).first; else if (it->second.value > edge_value) // If the node was found and the new value is smaller // -> Replace the value with the new one it->second = Edge(parent, edge_value); else // If the node was found but the new value is higher or equal // -> Don't use this new leg return false; q.push(Value(edge_value, it)); return true; }
int findEdgeHorizontal(int y, int x_start, int x_end, const rgbd::View view, EdgeMap& edge_map) { if (x_end - x_start < min_segment_size) return -1; geo::Vector3 p1_3d, p2_3d; if (!view.getPoint3D(x_start, y, p1_3d) || !view.getPoint3D(x_end, y, p2_3d)) return -1; geo::Vec2 p1(p1_3d.x, -p1_3d.z); geo::Vec2 p2(p2_3d.x, -p2_3d.z); geo::Vec2 n = (p2 - p1).normalized(); int x_edge = -1; float max_dist_sq = 0; for(int x2 = x_start; x2 <= x_end; ++x2) { geo::Vector3 p_3d; if (!view.getPoint3D(x2, y, p_3d)) continue; geo::Vec2 p(p_3d.x, -p_3d.z); // Calculate distance of p to line (p1, p2) geo::Vec2 p1_p = p - p1; float dist_sq = (p1_p - (p1_p.dot(n) * n)).length2(); if (dist_sq > max_dist_sq) { max_dist_sq = dist_sq; x_edge = x2; } } if (x_edge < 0) return -1; float d = view.getDepth(x_edge, y); if (d > max_range) return -1; float th = d * bla; if (max_dist_sq < (th * th)) return -1; // Add edge point edge_map.addEdgePoint(x_edge, y, 1, 0); // Recursively find edges findEdgeHorizontal(y, x_start, x_edge, view, edge_map); return x_edge; }
bool Foam::triSurfaceMesh::addFaceToEdge ( const edge& e, EdgeMap<label>& facesPerEdge ) { EdgeMap<label>::iterator eFnd = facesPerEdge.find(e); if (eFnd != facesPerEdge.end()) { if (eFnd() == 2) { return false; } eFnd()++; } else { facesPerEdge.insert(e, 1); } return true; }
bool findDfsVertexPathMarkingRec(vector<Vertex*> &path, const Vertex *end) { Vertex *lastVert = path.back(); if (lastVert == end) return true; if (mEdges.find(lastVert) != mEdges.end()) { VertSet *nexts = mEdges.at(lastVert); for (VertSet::iterator it = nexts->begin(); it != nexts->end(); ++it) { Vertex *vert = *it; if (mMarks.find(vert) == mMarks.end()) { mMarks.insert(vert); path.push_back(vert); bool found = findDfsVertexPathMarkingRec(path, end); if ( found ) return found; else path.pop_back(); } } } return false; }
/** * Returns whether two vertices are connected in the graph. * @param u - one vertex * @param v - another vertex * @param functionName - the name of the calling function to return * in the event of an error */ void Graph::assertConnected(Vertex u, Vertex v, string functionName) const { EdgeMap uEdges = graph.at(u); if (uEdges.find(v) == uEdges.end()) error(functionName + " called on unconnected vertices"); EdgeMap vEdges = graph.at(v); if (vEdges.find(u) == vEdges.end()) error(functionName + " called on unconnected vertices"); }
void facedeleter(){ if(selectedFace >= 0){ for(int i= selectedFace; i < numfaces-1 ; i++){ // basically assign it to the next face (can't delete last face though) faxes[i].listEdge = faxes[i+1].listEdge; faxes[i].ver = faxes[i+1].ver; faxes[i].numedges = faxes[i+1].numedges; } faxes.pop_back(); // pop one out calling the destructor // delete pointers to this face for(int i = 0; i < faxes[selectedFace].numedges; i++){ Pair p(faxes[selectedFace].ver[(i+1) % (faxes[selectedFace].numedges)].id, faxes[selectedFace].ver[i].id); EdgeMap::const_iterator iter; iter = edgemap.find(p); iter->second->thisface = NULL; } --numfaces; selectedFace = -1; } }
void getAllIntersections(EdgeMap & map, float x, float y, float yaw, float fov, int nBeams, IntersectionMap & ms) { for(int i = 0; i<nBeams; i++) { float cBeamAngle = yaw + ((float)nBeams/2.0f - (float)i) * (fov / (float)nBeams); while(cBeamAngle < -M_PI) cBeamAngle += 2.0f*M_PI; while(cBeamAngle > M_PI) cBeamAngle -= 2.0f*M_PI; for(int j = 0; j<map.size(); j++) { float x0 = map[j].x0; float x1 = map[j].x1; float y0 = map[j].y0; float y1 = map[j].y1; float a = cBeamAngle; float d0 = - cos(a) * (y0+y1) + sin(a) * (x0 + x1); float d1 = (x1 + x) * (y0 + y1) - (y1 + y) * (x0 + x1); float d2 = -cos(a) * (y1 + y) + sin(a) * (x1 + x); float t = d1 / d0; float l = d2 / d0; if( l >= 0.0f && l <= 1.0f) { if(t > 0) { Intersection iSect; iSect.distance = t; iSect.type = map[j].type; iSect.offset = fmod((sqrt((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0)) * l) , map[j].texWidth); ms[i].push_back(iSect); } } } std::sort(ms[i].begin(), ms[i].end(), sorter); } }
void Foam::CV2D::extractPatches ( wordList& patchNames, labelList& patchSizes, EdgeMap<label>& mapEdgesRegion, EdgeMap<label>& indirectPatchEdge ) const { label nPatches = qSurf_.patchNames().size() + 1; label defaultPatchIndex = qSurf_.patchNames().size(); patchNames.setSize(nPatches); patchSizes.setSize(nPatches, 0); mapEdgesRegion.clear(); const wordList& existingPatches = qSurf_.patchNames(); forAll(existingPatches, sP) { patchNames[sP] = existingPatches[sP]; } patchNames[defaultPatchIndex] = "CV2D_default_patch"; for ( Triangulation::Finite_edges_iterator eit = finite_edges_begin(); eit != finite_edges_end(); ++eit ) { Face_handle fOwner = eit->first; Face_handle fNeighbor = fOwner->neighbor(eit->second); Vertex_handle vA = fOwner->vertex(cw(eit->second)); Vertex_handle vB = fOwner->vertex(ccw(eit->second)); if ( (vA->internalOrBoundaryPoint() && !vB->internalOrBoundaryPoint()) || (vB->internalOrBoundaryPoint() && !vA->internalOrBoundaryPoint()) ) { point ptA = toPoint3D(vA->point()); point ptB = toPoint3D(vB->point()); label patchIndex = qSurf_.findPatch(ptA, ptB); if (patchIndex == -1) { patchIndex = defaultPatchIndex; WarningInFunction << "Dual face found that is not on a surface " << "patch. Adding to CV2D_default_patch." << endl; } edge e(fOwner->faceIndex(), fNeighbor->faceIndex()); patchSizes[patchIndex]++; mapEdgesRegion.insert(e, patchIndex); if (!pointPair(*vA, *vB)) { indirectPatchEdge.insert(e, 1); } } } }
// ------------------------------------------------------------------------------------------------ // Note - this is an implementation of the standard (recursive) Cm-Cl algorithm without further // optimizations (except we're using some nice LUTs). A description of the algorithm can be found // here: http://en.wikipedia.org/wiki/Catmull-Clark_subdivision_surface // // The code is mostly O(n), however parts are O(nlogn) which is therefore the algorithm's // expected total runtime complexity. The implementation is able to work in-place on the same // mesh arrays. Calling #InternSubdivide() directly is not encouraged. The code can operate // in-place unless 'smesh' and 'out' are equal (no strange overlaps or reorderings). // Previous data is replaced/deleted then. // ------------------------------------------------------------------------------------------------ void CatmullClarkSubdivider::InternSubdivide ( const aiMesh* const * smesh, size_t nmesh, aiMesh** out, unsigned int num ) { ai_assert(NULL != smesh && NULL != out); INIT_EDGE_HASH_TEMPORARIES(); // no subdivision requested or end of recursive refinement if (!num) { return; } UIntVector maptbl; SpatialSort spatial; // --------------------------------------------------------------------- // 0. Offset table to index all meshes continuously, generate a spatially // sorted representation of all vertices in all meshes. // --------------------------------------------------------------------- typedef std::pair<unsigned int,unsigned int> IntPair; std::vector<IntPair> moffsets(nmesh); unsigned int totfaces = 0, totvert = 0; for (size_t t = 0; t < nmesh; ++t) { const aiMesh* mesh = smesh[t]; spatial.Append(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D),false); moffsets[t] = IntPair(totfaces,totvert); totfaces += mesh->mNumFaces; totvert += mesh->mNumVertices; } spatial.Finalize(); const unsigned int num_unique = spatial.GenerateMappingTable(maptbl,ComputePositionEpsilon(smesh,nmesh)); #define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second+vert_idx) #define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first+face_idx) // --------------------------------------------------------------------- // 1. Compute the centroid point for all faces // --------------------------------------------------------------------- std::vector<Vertex> centroids(totfaces); unsigned int nfacesout = 0; for (size_t t = 0, n = 0; t < nmesh; ++t) { const aiMesh* mesh = smesh[t]; for (unsigned int i = 0; i < mesh->mNumFaces;++i,++n) { const aiFace& face = mesh->mFaces[i]; Vertex& c = centroids[n]; for (unsigned int a = 0; a < face.mNumIndices;++a) { c += Vertex(mesh,face.mIndices[a]); } c /= static_cast<float>(face.mNumIndices); nfacesout += face.mNumIndices; } } { // we want edges to go away before the recursive calls so begin a new scope EdgeMap edges; // --------------------------------------------------------------------- // 2. Set each edge point to be the average of all neighbouring // face points and original points. Every edge exists twice // if there is a neighboring face. // --------------------------------------------------------------------- for (size_t t = 0; t < nmesh; ++t) { const aiMesh* mesh = smesh[t]; for (unsigned int i = 0; i < mesh->mNumFaces;++i) { const aiFace& face = mesh->mFaces[i]; for (unsigned int p =0; p< face.mNumIndices; ++p) { const unsigned int id[] = { face.mIndices[p], face.mIndices[p==face.mNumIndices-1?0:p+1] }; const unsigned int mp[] = { maptbl[FLATTEN_VERTEX_IDX(t,id[0])], maptbl[FLATTEN_VERTEX_IDX(t,id[1])] }; Edge& e = edges[MAKE_EDGE_HASH(mp[0],mp[1])]; e.ref++; if (e.ref<=2) { if (e.ref==1) { // original points (end points) - add only once e.edge_point = e.midpoint = Vertex(mesh,id[0])+Vertex(mesh,id[1]); e.midpoint *= 0.5f; } e.edge_point += centroids[FLATTEN_FACE_IDX(t,i)]; } } } } // --------------------------------------------------------------------- // 3. Normalize edge points // --------------------------------------------------------------------- {unsigned int bad_cnt = 0; for (EdgeMap::iterator it = edges.begin(); it != edges.end(); ++it) { if ((*it).second.ref < 2) { ai_assert((*it).second.ref); ++bad_cnt; } (*it).second.edge_point *= 1.f/((*it).second.ref+2.f); } if (bad_cnt) { // Report the number of bad edges. bad edges are referenced by less than two // faces in the mesh. They occur at outer model boundaries in non-closed // shapes. char tmp[512]; ai_snprintf(tmp, 512, "Catmull-Clark Subdivider: got %u bad edges touching only one face (totally %u edges). ", bad_cnt,static_cast<unsigned int>(edges.size())); DefaultLogger::get()->debug(tmp); }} // --------------------------------------------------------------------- // 4. Compute a vertex-face adjacency table. We can't reuse the code // from VertexTriangleAdjacency because we need the table for multiple // meshes and out vertex indices need to be mapped to distinct values // first. // --------------------------------------------------------------------- UIntVector faceadjac(nfacesout), cntadjfac(maptbl.size(),0), ofsadjvec(maptbl.size()+1,0); { for (size_t t = 0; t < nmesh; ++t) { const aiMesh* const minp = smesh[t]; for (unsigned int i = 0; i < minp->mNumFaces; ++i) { const aiFace& f = minp->mFaces[i]; for (unsigned int n = 0; n < f.mNumIndices; ++n) { ++cntadjfac[maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]; } } } unsigned int cur = 0; for (size_t i = 0; i < cntadjfac.size(); ++i) { ofsadjvec[i+1] = cur; cur += cntadjfac[i]; } for (size_t t = 0; t < nmesh; ++t) { const aiMesh* const minp = smesh[t]; for (unsigned int i = 0; i < minp->mNumFaces; ++i) { const aiFace& f = minp->mFaces[i]; for (unsigned int n = 0; n < f.mNumIndices; ++n) { faceadjac[ofsadjvec[1+maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t,i); } } } // check the other way round for consistency #ifdef ASSIMP_BUILD_DEBUG for (size_t t = 0; t < ofsadjvec.size()-1; ++t) { for (unsigned int m = 0; m < cntadjfac[t]; ++m) { const unsigned int fidx = faceadjac[ofsadjvec[t]+m]; ai_assert(fidx < totfaces); for (size_t n = 1; n < nmesh; ++n) { if (moffsets[n].first > fidx) { const aiMesh* msh = smesh[--n]; const aiFace& f = msh->mFaces[fidx-moffsets[n].first]; bool haveit = false; for (unsigned int i = 0; i < f.mNumIndices; ++i) { if (maptbl[FLATTEN_VERTEX_IDX(n,f.mIndices[i])]==(unsigned int)t) { haveit = true; break; } } ai_assert(haveit); if (!haveit) { DefaultLogger::get()->debug("Catmull-Clark Subdivider: Index not used"); } break; } } } } #endif } #define GET_ADJACENT_FACES_AND_CNT(vidx,fstartout,numout) \ fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx] typedef std::pair<bool,Vertex> TouchedOVertex; std::vector<TouchedOVertex > new_points(num_unique,TouchedOVertex(false,Vertex())); // --------------------------------------------------------------------- // 5. Spawn a quad from each face point to the corresponding edge points // the original points being the fourth quad points. // --------------------------------------------------------------------- for (size_t t = 0; t < nmesh; ++t) { const aiMesh* const minp = smesh[t]; aiMesh* const mout = out[t] = new aiMesh(); for (unsigned int a = 0; a < minp->mNumFaces; ++a) { mout->mNumFaces += minp->mFaces[a].mNumIndices; } // We need random access to the old face buffer, so reuse is not possible. mout->mFaces = new aiFace[mout->mNumFaces]; mout->mNumVertices = mout->mNumFaces*4; mout->mVertices = new aiVector3D[mout->mNumVertices]; // quads only, keep material index mout->mPrimitiveTypes = aiPrimitiveType_POLYGON; mout->mMaterialIndex = minp->mMaterialIndex; if (minp->HasNormals()) { mout->mNormals = new aiVector3D[mout->mNumVertices]; } if (minp->HasTangentsAndBitangents()) { mout->mTangents = new aiVector3D[mout->mNumVertices]; mout->mBitangents = new aiVector3D[mout->mNumVertices]; } for(unsigned int i = 0; minp->HasTextureCoords(i); ++i) { mout->mTextureCoords[i] = new aiVector3D[mout->mNumVertices]; mout->mNumUVComponents[i] = minp->mNumUVComponents[i]; } for(unsigned int i = 0; minp->HasVertexColors(i); ++i) { mout->mColors[i] = new aiColor4D[mout->mNumVertices]; } mout->mNumVertices = mout->mNumFaces<<2u; for (unsigned int i = 0, v = 0, n = 0; i < minp->mNumFaces;++i) { const aiFace& face = minp->mFaces[i]; for (unsigned int a = 0; a < face.mNumIndices;++a) { // Get a clean new face. aiFace& faceOut = mout->mFaces[n++]; faceOut.mIndices = new unsigned int [faceOut.mNumIndices = 4]; // Spawn a new quadrilateral (ccw winding) for this original point between: // a) face centroid centroids[FLATTEN_FACE_IDX(t,i)].SortBack(mout,faceOut.mIndices[0]=v++); // b) adjacent edge on the left, seen from the centroid const Edge& e0 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])], maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a==face.mNumIndices-1?0:a+1]) ])]; // fixme: replace with mod face.mNumIndices? // c) adjacent edge on the right, seen from the centroid const Edge& e1 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])], maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[!a?face.mNumIndices-1:a-1]) ])]; // fixme: replace with mod face.mNumIndices? e0.edge_point.SortBack(mout,faceOut.mIndices[3]=v++); e1.edge_point.SortBack(mout,faceOut.mIndices[1]=v++); // d= original point P with distinct index i // F := 0 // R := 0 // n := 0 // for each face f containing i // F := F+ centroid of f // R := R+ midpoint of edge of f from i to i+1 // n := n+1 // // (F+2R+(n-3)P)/n const unsigned int org = maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])]; TouchedOVertex& ov = new_points[org]; if (!ov.first) { ov.first = true; const unsigned int* adj; unsigned int cnt; GET_ADJACENT_FACES_AND_CNT(org,adj,cnt); if (cnt < 3) { ov.second = Vertex(minp,face.mIndices[a]); } else { Vertex F,R; for (unsigned int o = 0; o < cnt; ++o) { ai_assert(adj[o] < totfaces); F += centroids[adj[o]]; // adj[0] is a global face index - search the face in the mesh list const aiMesh* mp = NULL; size_t nidx; if (adj[o] < moffsets[0].first) { mp = smesh[nidx=0]; } else { for (nidx = 1; nidx<= nmesh; ++nidx) { if (nidx == nmesh ||moffsets[nidx].first > adj[o]) { mp = smesh[--nidx]; break; } } } ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces); const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first]; bool haveit = false; // find our original point in the face for (unsigned int m = 0; m < f.mNumIndices; ++m) { if (maptbl[FLATTEN_VERTEX_IDX(nidx,f.mIndices[m])] == org) { // add *both* edges. this way, we can be sure that we add // *all* adjacent edges to R. In a closed shape, every // edge is added twice - so we simply leave out the // factor 2.f in the amove formula and get the right // result. const Edge& c0 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX( nidx,f.mIndices[!m?f.mNumIndices-1:m-1])])]; // fixme: replace with mod face.mNumIndices? const Edge& c1 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX( nidx,f.mIndices[m==f.mNumIndices-1?0:m+1])])]; // fixme: replace with mod face.mNumIndices? R += c0.midpoint+c1.midpoint; haveit = true; break; } } // this invariant *must* hold if the vertex-to-face adjacency table is valid ai_assert(haveit); if ( !haveit ) { DefaultLogger::get()->warn( "OBJ: no name for material library specified." ); } } const float div = static_cast<float>(cnt), divsq = 1.f/(div*div); ov.second = Vertex(minp,face.mIndices[a])*((div-3.f) / div) + R*divsq + F*divsq; } } ov.second.SortBack(mout,faceOut.mIndices[2]=v++); } } } } // end of scope for edges, freeing its memory // --------------------------------------------------------------------- // 7. Apply the next subdivision step. // --------------------------------------------------------------------- if (num != 1) { std::vector<aiMesh*> tmp(nmesh); InternSubdivide (out,nmesh,&tmp.front(),num-1); for (size_t i = 0; i < nmesh; ++i) { delete out[i]; out[i] = tmp[i]; } } }
int main() { cv::namedWindow("render", cv::WINDOW_NORMAL); // cv::Mat map = cv::imread("test_map.bmp", cv::IMREAD_GRAYSCALE); EdgeMap map; /* map.push_back(Edge(-9.950000f, 8.350000f, -0.400000f, -8.300000f, 150)); map.push_back(Edge(-0.400000f, -8.300000f, 12.400000f, 4.100000f, 150)); map.push_back(Edge(12.400000f, 4.100000f, 1.000000f, 1.800000f, 150)); map.push_back(Edge(1.000000f, 1.800000f, -9.950000f, 8.350000f, 150)); */ map.push_back(Edge(10.0f, 10.0f, 10.0f, -10.0f, 100)); map.push_back(Edge(10.0f, -10.0f, 1.0f, -1.0f, 100)); map.push_back(Edge(1.0f, -1.0f, -10.0f, -10.0f, 100)); map.push_back(Edge(-10.0f, -10.0f, -10.0f, 10.0f, 100)); map.push_back(Edge(-10.0f, 10.0f, 10.0f, 10.0f, 100)); int wndWidth = 1440; int wndHeight = 900; cv::Mat render(wndHeight,wndWidth, CV_8UC3); float df = 0.0f; float ds = 0.0f; float x = 0.0f; float y = 0.0f; float angle = -M_PI/2.0f; float dangle = 0.3f; float fov = M_PI/3.0f; std::vector<Sprite> sprites; Sprite ballSprite; // ballSprite.states.push_back(cv::imread("svidetel.jpg")); // ballSprite.x = 32; // ballSprite.y = -32; // ballSprite.width = 2; sprites.push_back(ballSprite); Texpack texpack; texpack[50] = Texture(cv::imread("wall_window.bmp")); texpack[100] = Texture(cv::imread("wood_wall.jpeg")); texpack[150] = Texture(cv::imread("brick_wall.jpeg")); texpack[200] = Texture(cv::imread("doom_door.jpeg")); for(int i = 1; i<15; i++) { char buf[1000]; sprintf(buf,"doom_door_%d.jpg", i); texpack[200].addFrame(cv::imread(buf)); } for(int i = 14; i>0; i--) { char buf[1000]; sprintf(buf,"doom_door_%d.jpg", i); texpack[200].addFrame(cv::imread(buf)); } texpack[200].animationTime = 2; texpack[200].animationType = Texture::ANIMATION_FRAMES; cv::Mat bgImageRaw = cv::imread("bg.png"); cv::Mat bgImage; cv::resize(bgImageRaw, bgImage, cv::Size(2.0f*M_PI*(float)wndWidth/fov,wndHeight)); double prevTime = getTime(); while(1) { double cTime = getTime(); animateTextures(texpack, cTime); calcNewPosition(map, x, y, angle, df, ds, dangle, cTime - prevTime); moveSprites(sprites); prevTime = cTime; newRenderAt(render, map, bgImage, fov, wndWidth, texpack, sprites, x, y, angle); cv::imshow("render",render); /* cv::Mat mapD; cv::resize(map, mapD, cv::Size(640,640), 0, 0, cv::INTER_NEAREST); cv::line(mapD, cv::Point(x*10.0f,-y*10.0f), cv::Point(x + cos(-angle - fov/2.0f)*1000, y + sin(-angle - fov/2.0f)*1000)*10.0f, cv::Scalar(0,255,0,0),1); cv::line(mapD, cv::Point(x*10.0f,-y*10.0f), cv::Point(x + cos(-angle + fov/2.0f)*1000, y + sin(-angle + fov/2.0f)*1000)*10.0f, cv::Scalar(0,255,0,0),1); cv::imshow("map", mapD); */ int k = cv::waitKey(1); if((char)k == 'q') { break; } else if((char)k == ',') { ds = 5.0f; } else if((char)k == '.') { ds = -5.0f; } else if((char)k == 'a') { dangle = +1.0f; } else if((char)k == 'd') { dangle = -1.0f; } else if((char)k == 's') { df = -5.0f; } else if((char)k == 'w') { df = 5.0f; } else if((char)k == '[') { fov -= M_PI/180.0f; //myLidar = VirtualLidar(fov, render.cols, 0); } else if((char)k == ']') { fov += M_PI/180.0f; //myLidar = VirtualLidar(fov, render.cols, 0); } else if((char)k == 'e'){ ds = 0; df = 0; dangle = 0; } else { if(df > 1) df -= 5; else if(df < -1) df += 5; else df = 0; if(ds > 1) ds -= 5; else if(ds < -1) ds += 5; else ds = 0; if(dangle > 0.5f) { dangle -= 1.0f; } else if(dangle < -0.5f) { dangle += 1.0f; } else { dangle = 0; } } } return 0; }