/** * 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 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 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)); } } }
/** * 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; }
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); } }
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; }
/** * 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; }
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; }
// ------------------------------------------------------------------------------------------------ // 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]; } } }
//---------------------------------------------------------------------------- CreateEnvelope::CreateEnvelope (int numVertices, const Vector2f* vertices, int numIndices, const int* indices, int& numEnvelopeVertices, Vector2f*& envelopeVertices) { // The graph of vertices and edgeMaps to be used for constructing the // obstacle envelope. SegmentGraph* graph = new0 SegmentGraph(); // Convert the vertices to rational points to allow exact arithmetic, // thereby avoiding problems with numerical round-off errors. RPoint2* ratVertices = new1<RPoint2>(numVertices); int i; for (i = 0; i < numVertices; ++i) { ratVertices[i].X() = RScalar(vertices[i].X()); ratVertices[i].Y() = RScalar(vertices[i].Y()); } // Insert the 2D mesh edgeMaps into the graph. const int* currentIndex = indices; int numTriangles = numIndices/3; for (i = 0; i < numTriangles; ++i) { int v0 = *currentIndex++; int v1 = *currentIndex++; int v2 = *currentIndex++; graph->InsertEdge(ratVertices[v0], ratVertices[v1]); graph->InsertEdge(ratVertices[v1], ratVertices[v2]); graph->InsertEdge(ratVertices[v2], ratVertices[v0]); } delete1(ratVertices); // Represent each edge as a map of points ordered by rational parameter // values, each point P(t) = End0 + t*(End1-End0), where End0 and End1 // are the rational endpoints of the edge and t is the rational // parameter for the edge point P(t). std::set<SegmentGraph::Edge>& edgeSet = graph->GetEdges(); int numEdges = (int)edgeSet.size(); EdgeMap** edgeMaps = new1<EdgeMap*>(numEdges); std::set<SegmentGraph::Edge>::iterator esIter = edgeSet.begin(); for (i = 0; i < numEdges; ++i, ++esIter) { SegmentGraph::Edge edge = *esIter; EdgeMap* edgeMap = new0 EdgeMap(); (*edgeMap)[0] = edge.GetVertex(0)->Position; (*edgeMap)[1] = edge.GetVertex(1)->Position; edgeMaps[i] = edgeMap; } UpdateAllEdges(numEdges, edgeMaps); // Recreate the graph, now using the segmented edgeMaps from the original // graph. delete0(graph); graph = new0 SegmentGraph(); for (i = 0; i < numEdges; ++i) { // Each graph edge is a pair of consecutive edge points. EdgeMap* edgeMap = edgeMaps[i]; // Get first point. EdgeMap::iterator iter = edgeMap->begin(); EdgeMap::iterator end = edgeMap->end(); RPoint2* point0 = &iter->second; // Get remaining points. for (++iter; iter != end; ++iter) { RPoint2* point1 = &iter->second; graph->InsertEdge(*point0, *point1); point0 = point1; } delete0(edgeMap); } delete1(edgeMaps); std::vector<RPoint2> envelope; graph->ExtractEnvelope(envelope); // Convert the vertices back to floating-point values and return to the // caller. numEnvelopeVertices = (int)envelope.size(); envelopeVertices = new1<Vector2f>(numEnvelopeVertices); for (i = 0; i < numEnvelopeVertices; ++i) { const RPoint2& point = envelope[i]; point.X().ConvertTo(envelopeVertices[i].X()); point.Y().ConvertTo(envelopeVertices[i].Y()); } delete0(graph); }
void ShadowMesh::calculateMissingData() { EdgeMap edges; faceNormals = new float[numFaces*3]; for (uint32_t i = 0 ; i < numFaces ; i++) { uint32_t idx1 = indices[i*3]; uint32_t idx2 = indices[i*3 + 1]; uint32_t idx3 = indices[i*3 + 2]; Vector3& v1 = *((Vector3*) (vertices + idx1 * 3)); Vector3& v2 = *((Vector3*) (vertices + idx2 * 3)); Vector3& v3 = *((Vector3*) (vertices + idx3 * 3)); Vector3 normal = (v2-v1).cross(v3-v1); memcpy(faceNormals + i*3, &normal, 3*sizeof(float)); uint32_t e1Idx1, e1Idx2; uint32_t e2Idx1, e2Idx2; uint32_t e3Idx1, e3Idx2; if (idx1 > idx2) { e1Idx1 = idx1; e1Idx2 = idx2; } else { e1Idx1 = idx2; e1Idx2 = idx1; } if (idx2 > idx3) { e2Idx1 = idx2; e2Idx2 = idx3; } else { e2Idx1 = idx3; e2Idx2 = idx2; } if (idx3 > idx1) { e3Idx1 = idx3; e3Idx2 = idx1; } else { e3Idx1 = idx1; e3Idx2 = idx3; } EdgeInfo& e1Info = edges[e1Idx1][e1Idx2]; EdgeInfo::FaceInfo e1fInfo; e1fInfo.index = i; e1fInfo.additionalIndex = 2; e1Info.faceIndices.push_back(e1fInfo); EdgeInfo& e2Info = edges[e2Idx1][e2Idx2]; EdgeInfo::FaceInfo e2fInfo; e2fInfo.index = i; e2fInfo.additionalIndex = 0; e2Info.faceIndices.push_back(e2fInfo); EdgeInfo& e3Info = edges[e3Idx1][e3Idx2]; EdgeInfo::FaceInfo e3fInfo; e3fInfo.index = i; e3fInfo.additionalIndex = 1; e3Info.faceIndices.push_back(e3fInfo); } bool decoupled = false; for (ConstEdgeMapIterator it = edges.begin() ; it != edges.end() && !decoupled ; it++) { for (map<uint32_t, EdgeInfo>::const_iterator iit = it->second.begin() ; iit != it->second.end() ; iit++) { const EdgeInfo& info = iit->second; if (info.faceIndices.size() > 2) { decoupleEdges(edges); decoupled = true; break; } } } float* extendedVertices = new float[2*numVertices * 4]; for (uint32_t i = 0 ; i < numVertices ; i++) { memcpy(extendedVertices + i*4, vertices + i*3, 3*sizeof(float)); extendedVertices[i*4 + 3] = 1.0f; } for (uint32_t i = 0 ; i < numVertices ; i++) { memcpy(extendedVertices + (numVertices+i)*4, vertices + i*3, 3*sizeof(float)); extendedVertices[(numVertices+i)*4 + 3] = 0.0f; } delete[] vertices; vertices = extendedVertices; uint32_t* extendedIndices = new uint32_t[numFaces*6]; // Enter the base indices for all faces into extendedIndices for (uint32_t i = 0 ; i < numFaces ; i++) { extendedIndices[i*6] = indices[i*3]; extendedIndices[i*6 + 2] = indices[i*3 + 1]; extendedIndices[i*6 + 4] = indices[i*3 + 2]; } uint32_t dummyIdx = numVertices*2 - 1; adjacentFaces = new uint32_t[numFaces*3]; for (EdgeMapIterator it = edges.begin() ; it != edges.end() ; it++) { uint32_t idx1 = it->first; for (map<uint32_t, EdgeInfo>::iterator iit = it->second.begin() ; iit != it->second.end() ; iit++) { uint32_t idx2 = iit->first; EdgeInfo& info = iit->second; EdgeInfo::FaceInfo& f1 = info.faceIndices[0]; uint32_t f1ExtendedAdditionalIdx = f1.index*6 + (2*f1.additionalIndex + 3) % 6; if (info.faceIndices.size() == 1) { // f1 has no adjacent face between idx1 and idx2 extendedIndices[f1ExtendedAdditionalIdx] = dummyIdx; // This value is invalid and shall not be used when there is no adjacent face, so we can // basically set it to anything we want adjacentFaces[f1.index*3 + (f1.additionalIndex+1) % 3] = 0; } else { // There are two adjacent faces on edge idx1-idx2 EdgeInfo::FaceInfo& f2 = info.faceIndices[1]; uint32_t f2ExtendedAdditionalIdx = f2.index*6 + (2*f2.additionalIndex + 3) % 6; extendedIndices[f1ExtendedAdditionalIdx] = indices[f2.index*3 + f2.additionalIndex]; extendedIndices[f2ExtendedAdditionalIdx] = indices[f1.index*3 + f1.additionalIndex]; adjacentFaces[f1.index*3 + (f1.additionalIndex+1) % 3] = f2.index; adjacentFaces[f2.index*3 + (f2.additionalIndex+1) % 3] = f1.index; } } } delete[] indices; indices = extendedIndices; }
void ShadowMesh::decoupleEdges(EdgeMap& edges) { vector<float> newVertices; EdgeMap newEdges; for (EdgeMapIterator it = edges.begin() ; it != edges.end() ; it++) { for (map<uint32_t, EdgeInfo>::iterator iit = it->second.begin() ; iit != it->second.end() ; iit++) { uint32_t idx1 = it->first; uint32_t idx2 = iit->first; EdgeInfo& info = iit->second; if (info.faceIndices.size() > 2) { // More than two faces on an edge. We will decouple them here vector<EdgeInfo::FaceInfo>::iterator idxIt = info.faceIndices.begin(); vector<EdgeInfo::FaceInfo>::iterator nextIdxIt; idxIt++; idxIt++; for (; idxIt != info.faceIndices.end() ; idxIt++) { EdgeInfo::FaceInfo& finfo = *idxIt; uint32_t faceIdx = finfo.index; uint32_t newIdx1 = numVertices + newVertices.size()/3; float v11 = vertices[idx1*3]; float v12 = vertices[idx1*3 + 1]; float v13 = vertices[idx1*3 + 2]; newVertices.push_back(v11); newVertices.push_back(v12); newVertices.push_back(v13); uint32_t newIdx2 = newIdx1+1; float v21 = vertices[idx2*3]; float v22 = vertices[idx2*3 + 1]; float v23 = vertices[idx2*3 + 2]; newVertices.push_back(v21); newVertices.push_back(v22); newVertices.push_back(v23); EdgeInfo& newInfo = newEdges[newIdx2][newIdx1]; newInfo.faceIndices.push_back(finfo); if (indices[faceIdx*3] == idx1) { indices[faceIdx*3] = newIdx1; if (indices[faceIdx*3 + 1] == idx2) indices[faceIdx*3 + 1] = newIdx2; else indices[faceIdx*3 + 2] = newIdx2; } else if (indices[faceIdx*3 + 1] == idx1) { indices[faceIdx*3 + 1] = newIdx1; if (indices[faceIdx*3] == idx2) indices[faceIdx*3] = newIdx2; else indices[faceIdx*3 + 2] = newIdx2; } else { indices[faceIdx*3 + 2] = newIdx1; if (indices[faceIdx*3] == idx2) indices[faceIdx*3] = newIdx2; else indices[faceIdx*3 + 1] = newIdx2; } nextIdxIt = idxIt; nextIdxIt++; if (nextIdxIt != info.faceIndices.end()) { // There's another face too much. This is true if we have an even number of faces on // this edge. In this case, we can group two of them together on a new edge so we // do not introduce any new cracks. EdgeInfo::FaceInfo& nextfInfo = *nextIdxIt; uint32_t nextFaceIdx = nextfInfo.index; newInfo.faceIndices.push_back(nextfInfo); if (indices[nextFaceIdx*3] == idx1) { indices[nextFaceIdx*3] = newIdx1; if (indices[nextFaceIdx*3 + 1] == idx2) indices[nextFaceIdx*3 + 1] = newIdx2; else indices[nextFaceIdx*3 + 2] = newIdx2; } else if (indices[nextFaceIdx*3 + 1] == idx1) { indices[nextFaceIdx*3 + 1] = newIdx1; if (indices[nextFaceIdx*3] == idx2) indices[nextFaceIdx*3] = newIdx2; else indices[nextFaceIdx*3 + 2] = newIdx2; } else { indices[nextFaceIdx*3 + 2] = newIdx1; if (indices[nextFaceIdx*3] == idx2) indices[nextFaceIdx*3] = newIdx2; else indices[nextFaceIdx*3 + 1] = newIdx2; } info.faceIndices.erase(nextIdxIt); } vector<EdgeInfo::FaceInfo>::iterator idxItCpy = idxIt; idxIt--; info.faceIndices.erase(idxItCpy); } } } } for (EdgeMapIterator it = newEdges.begin() ; it != newEdges.end() ; it++) { for (map<uint32_t, EdgeInfo>::iterator iit = it->second.begin() ; iit != it->second.end() ; iit++) { edges[it->first][iit->first] = iit->second; } } float* newVertexArr = new float[numVertices*3 + newVertices.size()]; memcpy(newVertexArr, vertices, numVertices*3*sizeof(float)); //copy(newVertices.begin(), newVertices.end(), newVertexArr + numVertices*3); for (uint32_t i = 0 ; i < newVertices.size() ; i++) { newVertexArr[numVertices*3 + i] = newVertices[i]; } delete[] vertices; vertices = newVertexArr; numVertices += newVertices.size() / 3; }