void VertexArray::removeDuplicateVertices(VertexArray& varray, IndexArray& iarray) { Log("Starting vertex count: %d", varray.count); // Lets remove duplicate vertices to get a smaller varray, iarray stays the same. // For each vertex, find duplicates after it for(std::size_t i = 0; i < varray.count ; ++i) { // For each i, iterate from i+1 to end for(std::size_t j = i + 1; j < varray.count; ++j) { if(varray.isVertexEqual(i,j)) { // swap two vertices, also swap their references varray.swapVertices(j, varray.count-1); iarray.swapIndices(j, varray.count-1); varray.removeLast(); // whatever indices were pointing at j, which is now gone, now point to i iarray.redirectFromTo(varray.count, i); //Log("%d and %d are duplicates. Redirecting all references of %d to %d.", i, j, j, i); j--; } } } Log("Done removing duplicated. Varray size: %d, IArray size %d", varray.count, iarray.indices.size()); }
bool TopologyRefinerFactory<TopologyDescriptor>::assignFaceVaryingTopology( TopologyRefiner & refiner, TopologyDescriptor const & desc) { if (desc.numFVarChannels>0) { for (int channel=0; channel<desc.numFVarChannels; ++channel) { int numFVarValues = desc.fvarChannels[channel].numValues; int const* srcFVarValues = desc.fvarChannels[channel].valueIndices; createBaseFVarChannel(refiner, numFVarValues); for (int face = 0, srcNext = 0; face < desc.numFaces; ++face) { IndexArray dstFaceFVarValues = getBaseFaceFVarValues(refiner, face, channel); if (desc.isLeftHanded) { dstFaceFVarValues[0] = srcFVarValues[srcNext++]; for (int vert = dstFaceFVarValues.size() - 1; vert > 0; --vert) { dstFaceFVarValues[vert] = srcFVarValues[srcNext++]; } } else { for (int vert = 0; vert < dstFaceFVarValues.size(); ++vert) { dstFaceFVarValues[vert] = srcFVarValues[srcNext++]; } } } } } return true; }
inline bool TopologyRefinerFactory<PXR_NS::Converter>::assignComponentTopology( Far::TopologyRefiner & refiner, PXR_NS::Converter const & converter) { PXR_NAMESPACE_USING_DIRECTIVE PxOsdMeshTopology const topology = converter.topology; int const * vertIndices = topology.GetFaceVertexIndices().cdata(); bool flip = (topology.GetOrientation() != PxOsdOpenSubdivTokens->rightHanded); for (int face=0, idx=0; face<refiner.GetLevel(0).GetNumFaces(); ++face) { IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face); if (flip) { dstFaceVerts[0] = vertIndices[idx++]; for (int vert=dstFaceVerts.size()-1; vert > 0; --vert) { dstFaceVerts[vert] = vertIndices[idx++]; } } else { for (int vert=0; vert<dstFaceVerts.size(); ++vert) { dstFaceVerts[vert] = vertIndices[idx++]; } } } return true; }
void draw(const VertexArray &varray, const IndexArray &iarray) { load_xform_matrices(); bool use_vbo = !varray.get_dynamic() && sys_caps.vertex_buffers; bool use_ibo = false;//!iarray.get_dynamic() && sys_caps.vertex_buffers; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); if(use_vbo) { Vertex v; glBindBuffer(GL_ARRAY_BUFFER_ARB, varray.get_buffer_object()); glVertexPointer(3, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.pos - (char*)&v)); glNormalPointer(GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.normal - (char*)&v)); glColorPointer(4, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.color - (char*)&v)); for(int i=0; i<MAX_TEXTURES; i++) { select_texture_unit(i); glEnableClientState(GL_TEXTURE_COORD_ARRAY); int dim = ttype[i] == TEX_1D ? 1 : (ttype[i] == TEX_3D || ttype[i] == TEX_CUBE ? 3 : 2); glTexCoordPointer(dim, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.tex[coord_index[i]] - (char*)&v)); } glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); } else { glVertexPointer(3, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->pos); glNormalPointer(GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->normal); glColorPointer(4, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->color); for(int i=0; i<MAX_TEXTURES; i++) { select_texture_unit(i); glEnableClientState(GL_TEXTURE_COORD_ARRAY); int dim = ttype[i] == TEX_1D ? 1 : (ttype[i] == TEX_3D || ttype[i] == TEX_CUBE ? 3 : 2); glTexCoordPointer(dim, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->tex[coord_index[i]]); } } if(use_ibo) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, iarray.get_buffer_object()); glDrawElements(primitive_type, iarray.get_count(), GL_UNSIGNED_INT, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } else { glDrawElements(primitive_type, iarray.get_count(), GL_UNSIGNED_INT, iarray.get_data()); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); for(int i=0; i<MAX_TEXTURES; i++) { select_texture_unit(i); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } }
IndexArray HuboDescription::getJointIndices(StringArray joint_names) const { IndexArray result; for(size_t i=0; i < joint_names.size(); ++i) { result.push_back(getJointIndex(joint_names[i])); } return result; }
void BallTree<_Scalar>::split(const IndexArray& indices, const AxisAlignedBoxType& aabbLeft, const AxisAlignedBoxType& aabbRight, IndexArray& iLeft, IndexArray& iRight) { for (std::vector<int>::const_iterator it=indices.begin(), end=indices.end() ; it!=end ; ++it) { unsigned int i = *it; if (vcg::PointFilledBoxDistance(mPoints[i], aabbLeft) < mRadii[i]*mRadiusScale) iLeft.push_back(i); if (vcg::PointFilledBoxDistance(mPoints[i], aabbRight) < mRadii[i]*mRadiusScale) iRight.push_back(i); } }
inline void claim_joints(const IndexArray& joint_indices) { for(size_t i=0; i<joint_indices.size(); ++i) { claim_joint(joint_indices[i]); } }
StringArray HuboDescription::getJointNames(IndexArray joints) const { StringArray result; for(size_t i=0; i<joints.size(); ++i) { result.push_back(getJointName(joints[i])); } return result; }
void getPart(const RealArray& jvalues, const IndexArray& jidx, Vector6d& q) { assert(jidx.size() == 6); for (int i=0; i<6; ++i) { q[i] = jvalues[jidx[i]]; } }
void setPart(RealArray& jvalues, const IndexArray& jidx, const Vector6d& q) { assert(jidx.size() == 6); for (int i=0; i<6; ++i) { jvalues[jidx[i]] = q[i]; } }
EllMatrix(index_t rows, index_t cols, index_t nnz_per_row) : _rows(rows), _cols(cols), nnz_per_row(nnz_per_row) { static constexpr auto step = align_bytes / sizeof(scalar_t); auto aligned_rows = rows; while (aligned_rows % step != 0) { ++aligned_rows; } data.resize(aligned_rows, nnz_per_row); indices.resize(aligned_rows, nnz_per_row); }
const IndexArray &Database::getIndexDefinitions(const String &tableName) const { if(tableName.length() > MAXTABLENAME) { throwSqlError(SQL_INVALID_TABLENAME,_T("Tablename <%s> is too long"), tableName.cstr() ); } const String tmpName = toUpperCase(tableName); IndexArray *indexArrayp = m_indexTableNameCache.get(tmpName); if(indexArrayp == NULL) { IndexArray indexArray; readIndexDefinitions(tmpName,indexArray); m_indexTableNameCache.put(tmpName,indexArray); indexArrayp = m_indexTableNameCache.get(tmpName); for(size_t i = 0; i < indexArrayp->size(); i++) { IndexDefinition *indexDefp = &(*indexArrayp)[i]; m_indexDefIndexNameCache.put(indexDefp->m_indexName,indexDefp); } indexArrayp = m_indexTableNameCache.get(tmpName); } return *indexArrayp; }
bool TopologyRefinerFactory<TopologyDescriptor>::assignComponentTopology( TopologyRefiner & refiner, TopologyDescriptor const & desc) { for (int face=0, idx=0; face<desc.numFaces; ++face) { IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face); if (desc.isLeftHanded) { dstFaceVerts[0] = desc.vertIndicesPerFace[idx++]; for (int vert=dstFaceVerts.size()-1; vert > 0; --vert) { dstFaceVerts[vert] = desc.vertIndicesPerFace[idx++]; } } else { for (int vert=0; vert<dstFaceVerts.size(); ++vert) { dstFaceVerts[vert] = desc.vertIndicesPerFace[idx++]; } } } return true; }
void Database::readIndexDefinitions(const String &tableName, IndexArray &indexArray) const { const String tmpName = toUpperCase(tableName); indexArray.clear(); const TableDefinition &tableDef = getTableDefinition(tmpName); /* just to check the tmpName */ DataFile dataFile( *this, SYSTEM_INDEXDATA_FNAME, DBFMODE_READONLY); KeyFile indexFile(*this, SYSTEM_INDEXKEY1_FNAME, DBFMODE_READONLY); KeyFileDefinition keydef(indexFile); KeyType key; keydef.put(key,0,tmpName); KeyCursor cursor(indexFile, RELOP_EQ, &key, 1, RELOP_EQ, &key, 1, SORT_ASCENDING); while(cursor.hasNext()) { cursor.next(key); SysTableIndexData index; dataFile.readRecord(keydef.getRecordAddr(key),&index, sizeof(SysTableIndexData)); indexArray.add(index); } }
IndexArray Dijkstra::shortestPathTo(Index node) const { IndexArray way; Index parentNode = -1, endNode = node; while (parentNode != root_) { parentNode = pathMatrix_[endNode].start; way.push_back(endNode); endNode = pathMatrix_[endNode].start; } way.push_back(root_); IndexArray rway(way.size()); for (Index i = 0; i < way.size(); i ++) rway[i] = way[way.size() - i - 1]; return rway; }
bool HuboPlus::comIK( KState& state, const vec3& dcom, const Transform3 manipXforms[NUM_MANIPULATORS], const IKMode mode[NUM_MANIPULATORS], const bool globalIK[NUM_MANIPULATORS], Transform3Array& work, real ascl, real fscl, bool* ikvalid ) const { bool ok = false; MatX gT, gpT, gxT, fxT, fpT, lambda, gxxpT(6, 3), deltap; MatX gfT, deltaf; const real alpha = 0.5; IndexArray pdofs; for (size_t i=DOF_POS_X; i<=DOF_ROT_Z; ++i) { pdofs.push_back(i); } IndexArray fdofs; for (int i=0; i<4; ++i) { if (fscl && mode[i] == IK_MODE_FREE) { const IndexArray& jidx = kbody.manipulators[i].jointIndices; for (size_t j=0; j<jidx.size(); ++j) { fdofs.push_back(jidx[j]); } } } for (size_t iter=0; iter<DEFAULT_COM_ITER; ++iter) { // try doing IK ok = stanceIK( state, manipXforms, mode, globalIK, work, ikvalid ); // compute the COM pos kbody.transforms(state.jvalues, work); vec3 com = state.xform() * kbody.com(work); // get the error vec3 comerr = dcom - com; if (comerr.norm() < DEFAULT_COM_PTOL) { debug << "breaking after " << iter << " iterations\n"; break; } else { ok = false; } if (ascl == 0) { state.body_pos += alpha * comerr; } else { // get jacobians ftw kbody.comJacobian(work, pdofs, gpT); gpT.block(3, 0, 3, 3) *= ascl; debug << "gpT=" << gpT << "\n\n"; if (!fdofs.empty()) { kbody.comJacobian(work, fdofs, gfT); debug << "gfT=" << gfT << "\n\n"; } gxxpT.setZero(); for (int i=0; i<4; ++i) { if (mode[i] == IK_MODE_WORLD || mode[i] == IK_MODE_SUPPORT) { const std::string& name = kbody.manipulators[i].name; kbody.comJacobian(work, kbody.manipulators[i].jointIndices, gxT); kbody.manipulatorJacobian(work, i, pdofs, fpT); kbody.manipulatorJacobian(work, i, fxT); lambda = fxT.colPivHouseholderQr().solve(gxT); fpT.block(3, 0, 3, 6) *= ascl; debug << "gxT[" << name << "]=\n" << gxT << "\n\n"; debug << "fpT[" << name << "]=\n" << fpT << "\n\n"; debug << "fxT[" << name << "]=\n" << fxT << "\n\n"; debug << "lambda[" << name << "]=\n" << lambda << "\n\n"; gxxpT += fpT * lambda; } } gT = gpT - gxxpT; Eigen::Vector3d cerr(comerr[0], comerr[1], comerr[2]); deltap = alpha * gT * cerr; debug << "gxxpT = \n" << gxxpT << "\n\n"; debug << "gT = \n" << gT << "\n\n"; debug << "deltap = \n" << deltap.transpose() << "\n\n"; vec3 dp(deltap(0), deltap(1), deltap(2)); vec3 dq(deltap(3), deltap(4), deltap(5)); state.body_pos += dp; state.body_rot = quat::fromOmega(-dq) * state.body_rot; } if (!fdofs.empty()) { Eigen::Vector3d cerr(comerr[0], comerr[1], comerr[2]); deltaf = fscl * gfT * cerr; debug << "deltaf = \n" << deltaf.transpose() << "\n\n"; for (size_t i=0; i<fdofs.size(); ++i) { state.jvalues[fdofs[i]] += deltaf(i); } } } return ok; }
static MStatus convertToMayaMeshData(OpenSubdiv::Far::TopologyRefiner const & refiner, std::vector<Vertex> const & refinedVerts, bool hasUVs, std::vector<FVarVertexUV> const & refinedUVs, bool hasColors, std::vector<FVarVertexColor> const & refinedColors, MFnMesh & inMeshFn, MObject newMeshDataObj) { MStatus status; typedef OpenSubdiv::Far::ConstIndexArray IndexArray; int maxlevel = refiner.GetMaxLevel(); OpenSubdiv::Far::TopologyLevel const & refLastLevel = refiner.GetLevel(maxlevel); int nfaces = refLastLevel.GetNumFaces(); // Init Maya Data // Face Counts MIntArray faceCounts(nfaces); for (int face=0; face < nfaces; ++face) { faceCounts[face] = 4; } // Face Connects MIntArray faceConnects(nfaces*4); for (int face=0, idx=0; face < nfaces; ++face) { IndexArray fverts = refLastLevel.GetFaceVertices(face); for (int vert=0; vert < fverts.size(); ++vert) { faceConnects[idx++] = fverts[vert]; } } // Points int nverts = refLastLevel.GetNumVertices(); int firstOfLastVert = refiner.GetNumVerticesTotal() - nverts - refiner.GetLevel(0).GetNumVertices(); MFloatPointArray points(nverts); for (int vIt = 0; vIt < nverts; ++vIt) { Vertex const & v = refinedVerts[firstOfLastVert + vIt]; points.set(vIt, v.position[0], v.position[1], v.position[2]); } // Create New Mesh from MFnMesh MFnMesh newMeshFn; MObject newMeshObj = newMeshFn.create(points.length(), faceCounts.length(), points, faceCounts, faceConnects, newMeshDataObj, &status); MCHECKERR(status, "Cannot create new mesh"); // Get face-varying set names and other info from the inMesh MStringArray uvSetNames; MStringArray colorSetNames; std::vector<int> colorSetChannels; std::vector<MFnMesh::MColorRepresentation> colorSetReps; int totalColorSetChannels = 0; status = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames, colorSetChannels, colorSetReps, totalColorSetChannels); // Add new UVs back to the mesh if needed if (hasUVs) { MIntArray fvarConnects(faceConnects.length()); int count = 0; for (int f = 0; f < refLastLevel.GetNumFaces(); ++f) { IndexArray faceIndices = refLastLevel.GetFaceFVarValues(f, CHANNELUV); for (int index = 0 ; index < faceIndices.size() ; ++index) { fvarConnects[count++] = faceIndices[index]; } } int nuvs = refLastLevel.GetNumFVarValues(CHANNELUV); int firstOfLastUvs = refiner.GetNumFVarValuesTotal(CHANNELUV) - nuvs - refiner.GetLevel(0).GetNumFVarValues(CHANNELUV); MFloatArray uCoord(nuvs), vCoord(nuvs); for (int uvIt = 0; uvIt < nuvs; ++uvIt) { FVarVertexUV const & uv = refinedUVs[firstOfLastUvs + uvIt]; uCoord[uvIt] = uv.u; vCoord[uvIt] = uv.v; } // Currently, the plugin only supports one UV set int uvSetIndex = 0; if (uvSetIndex > 0) { status = newMeshFn.createUVSetDataMesh( uvSetNames[uvSetIndex] ); MCHECKERR(status, "Cannot create UVSet"); } static MString defaultUVName("map1"); MString const * uvname = uvSetIndex==0 ? &defaultUVName : &uvSetNames[uvSetIndex]; status = newMeshFn.setUVs(uCoord, vCoord, uvname); MCHECKERR(status, "Cannot set UVs for set : "+*uvname); status = newMeshFn.assignUVs(faceCounts, fvarConnects, uvname); MCHECKERR(status, "Cannot assign UVs"); } // Add new colors back to the mesh if needed if (hasColors) { int count = 0; MIntArray fvarConnects2(faceConnects.length()); for (int f = 0 ; f < refLastLevel.GetNumFaces(); ++f) { IndexArray faceIndices = refLastLevel.GetFaceFVarValues(f, CHANNELCOLOR); for (int index = 0 ; index < faceIndices.size() ; ++index) { fvarConnects2[count++] = faceIndices[index]; } } int ncols = refLastLevel.GetNumFVarValues(CHANNELCOLOR); int firstOfLastCols = refiner.GetNumFVarValuesTotal(CHANNELCOLOR) - ncols - refiner.GetLevel(0).GetNumFVarValues(CHANNELCOLOR); MColorArray colorArray(ncols); for (int colIt = 0; colIt < ncols; ++colIt) { FVarVertexColor const & c = refinedColors[firstOfLastCols + colIt]; colorArray.set(colIt, c.r, c.g, c.b, c.a); } // Currently, the plugin only supports one color sets int colorSetIndex = 0; // Assign color buffer and map the ids for each face-vertex // API Limitation: Cannot set MColorRepresentation here status = newMeshFn.createColorSetDataMesh( colorSetNames[colorSetIndex]); MCHECKERR(status, "Cannot create ColorSet"); bool isColorClamped = inMeshFn.isColorClamped( colorSetNames[colorSetIndex], &status); MCHECKERR(status, "Can not get Color Clamped "); status = newMeshFn.setIsColorClamped( colorSetNames[colorSetIndex], isColorClamped); MCHECKERR(status, "Can not set Color Clamped : " + isColorClamped); status = newMeshFn.setColors( colorArray, &colorSetNames[colorSetIndex], colorSetReps[colorSetIndex]); MCHECKERR(status, "Can not set Colors"); status = newMeshFn.assignColors( fvarConnects2, &colorSetNames[colorSetIndex]); MCHECKERR(status, "Can not assign Colors"); } return MS::kSuccess; }
// Compact model void MeshModelAdvancedOp::CompactModel() { CoordArray& vCoord = kernel->GetVertexInfo().GetCoord(); FlagArray& vFlag = kernel->GetVertexInfo().GetFlag(); PolyIndexArray& fIndex = kernel->GetFaceInfo().GetIndex(); FlagArray& fFlag = kernel->GetFaceInfo().GetFlag(); size_t nVertex = vCoord.size(); size_t nFace = fIndex.size(); IndexArray VtxIDMap, FaceIDMap; VtxIDMap.resize(nVertex); FaceIDMap.resize(nFace); size_t i; int index = 0; size_t nNewVtx, nNewFace; for(i = 0; i < nVertex; ++ i) { Flag vf = vFlag[i]; if(util.IsSetFlag(vf, FLAG_INVALID)) { VtxIDMap[i] = -1; printf("Invalid Vertex = %d\n", i); // Debug } else { VtxIDMap[i] = index ++; } } nNewVtx = index; index = 0; for(i = 0; i < nFace; ++ i) { Flag ff = fFlag[i]; if(util.IsSetFlag(ff, FLAG_INVALID)) { FaceIDMap[i] = -1; } else { FaceIDMap[i] = index ++; } } nNewFace = index; for(i = 0; i < nVertex; ++ i) { int idx = VtxIDMap[i]; if(idx != -1 && idx != i) // Invalid and avoid duplicate copy vCoord[idx] = vCoord[i]; } vCoord.erase(vCoord.begin()+nNewVtx, vCoord.end()); for(i = 0; i < nFace; ++ i) { int idx = FaceIDMap[i]; if(idx == -1) continue; IndexArray& newf = fIndex[idx]; IndexArray oldf = fIndex[i]; size_t n = oldf.size(); newf.resize(n); for(size_t j = 0; j < n; ++ j) { VertexID old_vID = oldf[j]; // Debug VertexID vID = VtxIDMap[oldf[j]]; assert(vID != -1); newf[j] = vID; } } fIndex.erase(fIndex.begin()+nNewFace, fIndex.end()); }
static MStatus convertToMayaMeshData(OpenSubdiv::Far::TopologyRefiner const & refiner, std::vector<Vertex> const & vertexBuffer, MFnMesh const & inMeshFn, MObject newMeshDataObj) { MStatus status; typedef OpenSubdiv::Far::ConstIndexArray IndexArray; int maxlevel = refiner.GetMaxLevel(); OpenSubdiv::Far::TopologyLevel const & refLastLevel = refiner.GetLevel(maxlevel); int nfaces = refLastLevel.GetNumFaces(); // Init Maya Data // -- Face Counts MIntArray faceCounts(nfaces); for (int face=0; face < nfaces; ++face) { faceCounts[face] = 4; } // -- Face Connects MIntArray faceConnects(nfaces*4); for (int face=0, idx=0; face < nfaces; ++face) { IndexArray fverts = refLastLevel.GetFaceVertices(face); for (int vert=0; vert < fverts.size(); ++vert) { faceConnects[idx++] = fverts[vert]; } } // -- Points MFloatPointArray points(refLastLevel.GetNumVertices()); Vertex const * v = &vertexBuffer.at(0); for (int level=1; level<=maxlevel; ++level) { int nverts = refiner.GetLevel(level).GetNumVertices(); if (level==maxlevel) { for (int vert=0; vert < nverts; ++vert, ++v) { points.set(vert, v->position[0], v->position[1], v->position[2]); } } else { v += nverts; } } // Create New Mesh from MFnMesh MFnMesh newMeshFn; MObject newMeshObj = newMeshFn.create(points.length(), faceCounts.length(), points, faceCounts, faceConnects, newMeshDataObj, &status); MCHECKERR(status, "Cannot create new mesh"); int fvarTotalWidth = 0; if (fvarTotalWidth > 0) { // Get face-varying set names and other info from the inMesh MStringArray uvSetNames; MStringArray colorSetNames; std::vector<int> colorSetChannels; std::vector<MFnMesh::MColorRepresentation> colorSetReps; int totalColorSetChannels = 0; status = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames, colorSetChannels, colorSetReps, totalColorSetChannels); #if defined(DEBUG) or defined(_DEBUG) int numUVSets = uvSetNames.length(); int expectedFvarTotalWidth = numUVSets*2 + totalColorSetChannels; assert(fvarTotalWidth == expectedFvarTotalWidth); #endif // XXXX fvar stuff here } return MS::kSuccess; }
//---------------------------------------------------------------------------- void Binary2D::ExtractBoundary (int x0, int y0, ImageInt2D& image, IndexArray& boundary) { // Incremental 2D offsets for 8-connected neighborhood of (x,y). const int dx[8] = { -1, 0, +1, +1, +1, 0, -1, -1 }; const int dy[8] = { -1, -1, -1, 0, +1, +1, +1, 0 }; // Insert the initial boundary point. boundary.push_back(image.GetIndex(x0, y0)); // Compute the direction from background (0) to boundary pixel (1). int cx = x0, cy = y0; int nx = 0, ny = 0, dir; for (dir = 0; dir < 8; ++dir) { nx = cx + dx[dir]; ny = cy + dy[dir]; if (image(nx, ny) == 0) { dir = (dir + 1) % 8; break; } } // Traverse boundary in clockwise order. Mark visited pixels with 1. image(cx, cy) = 1; bool notDone = true; while (notDone) { int i, nbr; for (i = 0, nbr = dir; i < 8; ++i, nbr = (nbr + 1) % 8) { nx = cx + dx[nbr]; ny = cy + dy[nbr]; if (image(nx, ny)) { // The next boundary pixel was found. break; } } if (i == 8) { // (cx,cy) is an isolated pixel. notDone = false; continue; } if (nx == x0 && ny == y0) { // The boundary traversal is completed. notDone = false; continue; } // (nx,ny) is the next boundary point, so add the pixel to the list. boundary.push_back(image.GetIndex(nx, ny)); // Mark visited pixels with 1. image(nx, ny) = 1; // Start the search for the next boundary point. cx = nx; cy = ny; dir = (i + 5 + dir) % 8; } }