/** * 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; }
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; } }
//------------------------------------------------------------------------------ // 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)); } } }
// ------------------------------------------------------------------------------------------------ // 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]; } } }
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; }
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; }
//---------------------------------------------------------------------------- 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); }