TriangleList getSurroundingTriangles(QPointF *points, quint32 size, quint32 layers, Vertex v, QPointF *centerPtr) { TriangleList result; if (!v.layer) { for (quint32 i = 0; i < size; ++i) result.append(TRIANGLE(0, i, 0)); return result; } // inner part result.append(TRIANGLE(v.layer - 1, v.sector, 2 * v.index)); if (v.index) { result.append(TRIANGLE(v.layer - 1, v.sector, 2 * v.index - 1)); result.append(TRIANGLE(v.layer - 1, v.sector, 2 * v.index - 2)); } else result.append(TRIANGLE(v.layer - 1, (v.sector + size - 1) % size, 2 * v.layer - 2)); // outer part if (v.layer < layers) { result.append(TRIANGLE(v.layer, v.sector, 2 * v.index)); result.append(TRIANGLE(v.layer, v.sector, 2 * v.index + 1)); if (v.index) { result.append(TRIANGLE(v.layer, v.sector, 2 * v.index - 1)); } else { result.append(TRIANGLE(v.layer, (v.sector + size - 1) % size, 2 * v.layer - 1)); result.append(TRIANGLE(v.layer, (v.sector + size - 1) % size, 2 * v.layer)); } } return result; }
// groupedSliders are in the upper set of sliders void TriangleDensityWidget::groupedSliderChangedSlot(int value) { TriangleList triangles = triangleScene->triangles(); double norm = getNorm(); triangles.at(grouped_slider_idx)->xform()->density = (double)value / 1000. * norm; resetSliders(norm); emit dataChanged(); }
double phiFunction(QPointF *points, quint32 size, quint32 layers, QPointF point, quint32 vertexNumber, QPointF *centerPtr) { Vertex vertex = getVertex(size, vertexNumber); TriangleList triangles = getSurroundingTriangles(points, size, layers, vertex, centerPtr); for (int i = 0; i < triangles.size(); ++i) { if (pointInTriangle(point, triangles.at(i))) return phiFunction(point, triangles.at(i), getPoint(points, size, layers, vertex, centerPtr)); } return 0; }
Deform::Deform(const float *P_data, int P_Num, const AdjList &adj_list, const TriangleList &triangle_list) :at(ORIGIN_HARD), P_data(P_data), P_Num(P_Num), max_iter(10), min_tol(1e-3), lambda(5), adj_list(adj_list) { for (size_t i = 0, i_end = triangle_list.size(); i < i_end; ++ i) { std::vector<int> face = triangle_list[i]; std::sort(face.begin(), face.end()); assert(face.size() == 3); face_list.push_back(Eigen::Vector3i(face[0], face[1], face[2])); } P.resize(3, P_Num); for (int i = 0; i != P_Num; ++i) {P.col(i) << P_data[3*i], P_data[3*i+1], P_data[3*i+2];} P_Prime = P; R = vector<Matrix3f>(P_Num, Matrix3f::Identity()); // Weight build_weight_matrix(); }
void MeshMender::FindNeighbors(Triangle* tri, TriangleList&possibleNeighbors, Triangle** neighbor1, Triangle** neighbor2, std::vector< Vertex >& theVerts) { *neighbor1 = NULL; *neighbor2 = NULL; std::vector<Triangle*> theNeighbors; for(unsigned int n = 0; n < possibleNeighbors.size(); ++n) { TriID tID = possibleNeighbors[n]; Triangle* possible =&(m_Triangles[ tID]); if(possible != tri ) //check for myself { if( SharesEdge(tri, possible, theVerts) ) { theNeighbors.push_back(possible); } } } if(theNeighbors.size()>0) *neighbor1 = theNeighbors[0]; if(theNeighbors.size()>1) *neighbor2 = theNeighbors[1]; }
void KDTree::generateEventList( TriangleList& triList, AABB& parentBox ) { //Start with an empty event list eventList.clear(); //Go through all the triangles passed in. for(unsigned i = 0; i < triList.size(); ++i) { //Clip the triangle to the parent box Triangle tri = triList[i]; clipTriToParentBox(tri, parentBox); //And the box be the AABB of this event AABB* pBox = &parentBox; //Grab the minimum and maximum points of the triangle as per this split axis float pMin = GeometryLibrary::minPos(tri, curAxis); float pMax = GeometryLibrary::maxPos(tri, curAxis); //If the maximum and minimum points are the same, we have a coplanar event if(pMax == pMin) eventList.push_back(KDEvent(Coplanar, &tri, pMin, pBox)); //Otherwise start at the minimum and end at the maximum on this axis else { eventList.push_back(KDEvent(Starting, &tri, pMin, pBox)); eventList.push_back(KDEvent(Ending, &tri, pMax, pBox)); } } //Sort according to the operator < provided so that the events are in ascending order std::sort(eventList.begin(), eventList.end()); }
bool Triangulator::check_triangle(Vertex *first, TriangleList &triangles) { // path is a dot if (first->next == first) return true; // path is a two lines if (first->next->next == first) return true; // path is triangle if (first->next->next->next == first) { triangles.push_back(first->index); triangles.push_back(first->next->index); triangles.push_back(first->next->next->index); return true; } return false; }
void TriangleDensityWidget::reset() { TriangleList triangles = triangleScene->triangles(); // make more sliders if necessary while (sliders.size() < triangles.size()) { GroupedSlider* s = new GroupedSlider(Qt::Horizontal, this, sliders.size()); QLabel* name = new QLabel(QString::number(sliders.size() + 1)); QHBoxLayout* hl = new QHBoxLayout(); hl->addWidget(name); hl->addWidget(s); dynamic_cast<QVBoxLayout*> (m_scrollAreaWidgetContents->layout())->insertLayout(-1,hl,0); s->setRange(0, 1000); s->setVisible(false); sliders.append(s); slider_names.append(name); connect(s, SIGNAL(valueChanged(int)), this, SLOT(groupedSliderChangedSlot(int))); connect(s, SIGNAL(sliderPressed()), this, SLOT(groupedSliderPressedSlot())); connect(s, SIGNAL(undoStateSignal()), this, SIGNAL(undoStateSignal())); } // hide non-used sliders for (int n = triangles.size() ; n < sliders.size() ; n++) { sliders.at(n)->setVisible(false); slider_names.at(n)->setVisible(false); } resetSliders(getNorm()); QStringList items; items << tr("None"); for (int n = 1 ; n <= genome->size() ; n++) items << QString::number(n); int n = m_crossComboBox->currentIndex(); m_crossComboBox->blockSignals(true); m_crossComboBox->clear(); m_crossComboBox->addItems(items); m_crossComboBox->setCurrentIndex(n); m_crossComboBox->blockSignals(false); }
void triangle_tree( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, TriTree & tree, TriangleList & tlist) { assert(F.cols() == 3); tlist.clear(); // Loop over facets for(int f = 0;f<F.rows();f++) { Point3 a(V(F(f,0),0), V(F(f,0),1), V(F(f,0),2)); Point3 b(V(F(f,1),0), V(F(f,1),1), V(F(f,1),2)); Point3 c(V(F(f,2),0), V(F(f,2),1), V(F(f,2),2)); tlist.push_back(Triangle3( a,b,c)); } // constructs AABB tree tree.clear(); tree.insert(tlist.begin(),tlist.end()); }
void KDTree::splitTriList( TriangleList& l, TriangleList& r, TriangleList& p, float pos ) { curAxis = splitAxis; unsigned left, right, coplanar, side; //Go through every triangle in the triangle list for(unsigned i = 0; i < p.size(); ++i) { Triangle& tri = p[i]; left = right = coplanar = 0; CountVertPositions(tri, left, right, coplanar, splitAxis, pos); side = max(left, max(right, coplanar)); if(side == left) l.push_back(tri); else if(side == right) r.push_back(tri); else if(side == coplanar) l.push_back(tri); } }
void KDTree::findMinPlane(TriangleList& triList, AABB& parentBox) { unsigned Nl, Nr, Nc, Vs, Ve, Vc; Vs = Ve = Vc = 0; //Set minimum cost to infinite minCost = FLT_MAX; //For every possible axis, for(unsigned i = 0; i < NumAxes; ++i) { //Generate the event list for this axis curAxis = (SplitAxis)i; generateEventList(triList, parentBox); //All of the triangles are to our right. //These will remain through iterations on positions Nl = 0; Nr = triList.size(); Nc = 0; //For every position for(unsigned j = 0; j < eventList.size(); ) { float curPos = eventList[j].eventPos; Vs = Ve = Vc = 0; //Count the triangles starting, ending, and coplanar with this position //This will advance j to the next event position countTrisOfEvent(Vs, Ve, Vc, j, curPos); Nc = Vc; Nr -= Ve + Vc; //The last index is the positions we care about. calcCostOfPlane(Nl, Nr, Nc, parentBox, curPos); Nl += Vs + Vc; //Update the lowest possible plane if(curCost < minCost) { minCost = curCost; //Save what axis and position we're going to cut at so far... splitPos = curPos; splitAxis = curAxis; } } } }
inline unsigned numSurfaceIntersections(const V3 &voxelPos, const V3 &dir) { unsigned numHits = 0; /********* ASSIGNMENT *********/ /* Check and return the number of times a ray cast in direction dir, * from voxel center voxelPos intersects the surface */ CompFab::Ray r; for (int i = 0; i < triangleList.size(); i++) { r = CompFab::Ray(voxelPos, dir); if (rayTriangleIntersection(r, triangleList[i])) { numHits += 1; } } return numHits; }
void MeshMender::UpdateIndices(const size_t oldIndex , const size_t newIndex , TriangleList& curGroup) { //make any triangle that used the oldIndex use the newIndex instead for( size_t t = 0; t < curGroup.size(); ++t ) { TriID tID = curGroup[ t ]; for(size_t indx = 0 ; indx < 3 ; ++indx) { if(m_Triangles[tID].indices[indx] == oldIndex) { m_Triangles[tID].indices[indx] = newIndex; } } } }
void calculateSplittingOfMesh() { //need to change dividing by also const unsigned dim = 32; //dimension of voxel grid (e.g. 32x32x32) int mass[dim] = {}; int voxcount[dim] = {}; float totalcount = 0; float massheight = 0; float totalmass = 0; int com[dim] = {}; int average = 0; int cut1 = 0; int cut2 = 0; int pointer = 0; CompFab::Mesh tempMesh("bunny.obj", true); triangleList.resize(tempMesh.t.size()); //copy triangles to global list for (unsigned i = 0; i < tempMesh.t.size(); ++i) { triangleList[i].v0 = tempMesh.v[tempMesh.t[i][0]]; triangleList[i].v1 = tempMesh.v[tempMesh.t[i][1]]; triangleList[i].v2 = tempMesh.v[tempMesh.t[i][2]]; } //Create Voxel Grid V3 bbMax, bbMin; BBox(tempMesh, bbMin, bbMax); //Build Voxel Grid Real bbX = bbMax[0] - bbMin[0]; Real bbY = bbMax[1] - bbMin[1]; Real bbZ = bbMax[2] - bbMin[2]; Real spacing; if (bbX > bbY && bbX > bbZ) { spacing = bbX / (Real)(dim - 2); } else if (bbY > bbX && bbY > bbZ) { spacing = bbY / (Real)(dim - 2); } else { spacing = bbZ / (Real)(dim - 2); } V3 hspacing(0.5 * spacing); voxelGrid = CompFab::VoxelGrid(bbMin - hspacing, dim, dim, dim, spacing); V3 voxelPos; V3 direction(1, 0, 0); /********* ASSIGNMENT *********/ /* Iterate over all voxels in voxelGrid and test whether they are inside our outside of the * surface defined by the triangles in triangleList */ for (int i = 0; i < dim; i++) { for (int k = 0; k < dim; k++) { for (int j = 0; j < dim; j++) { //find i-voxel V3 voxeli = V3(i * voxelGrid.spacing, 0, 0); //find j-voxel V3 voxelj = V3(0, j * voxelGrid.spacing, 0); //find k-voxel V3 voxelk = V3(0, 0, k * voxelGrid.spacing); //find the new position from iteration, start from origin then add each dimension voxelPos = voxelGrid.lowerLeft + voxeli + voxelj + voxelk; voxelGrid.isInside(i, j, k) = numSurfaceIntersections(voxelPos, direction) % 2; if (voxelGrid.isInside(i, j, k)) { mass[j]++; voxcount[j]++;} } } } //compilation of all COM after each layer is change to 0.2 mass for (int p = dim-1; p > 0-1; p--) { mass[p] = 0.2*mass[p]; for (int q = 0; q < dim; q++) { totalmass = totalmass + mass[q]; massheight = massheight + (mass[q] * q); } com[p]= ceil(massheight / totalmass); //printf("COM%d is %d\n", p, com[p]); totalmass = 0; massheight = 0; } int cut = dim - 1; for (int p = dim - 1; p > 0; p--) { if (com[cut] >= com[p]) { cut = p; } } for (int i = 0; i < dim; i++) { totalcount = totalcount + voxcount[i]; printf("Layer%d voxcount=%d\n", i, voxcount[i]); } // sorts in ascending order std::sort(std::begin(voxcount), std::end(voxcount)); //percentile calculation pointer = 0.25 * dim; if (floor(pointer) == pointer) average = (voxcount[pointer] + voxcount[pointer + 1]) * 0.5; else average = voxcount[(int) ceil(pointer)]; //printf("cut@ %d, threshold=%d\n", cut,average); for (int q = cut; q < dim; q++) { cut1 = q; if (voxcount[q] > average) { break; } } for (int r = cut; r > 0; r--) { cut2 = r; if (voxcount[r] > average) { break; } } printf("lowestCOM cut@Layer%d with count%d. Threshold=%d therefore cut1@Layer%d with count%d cut2@Layer%d with count%d\n", cut,voxcount[cut],average,cut1,voxcount[cut1],cut2,voxcount[cut2]); cutPoint1 = cut1; cutPoint2 = cut2; inputMeshToCorkMesh(); }
void Triangulator::triangulate(const Contour &contour, TriangleList &triangles, int index_offset) { Path path; build_path(contour, path, index_offset); triangles.reserve(triangles.size() + 3*(path.size() - 2)); split_path(&path.front(), triangles); }
TriangleList getCommonTriangles(QPointF *points, quint32 size, quint32 layers, Vertex v1, Vertex v2, QPointF *centerPtr) { TriangleList result; if (v1.layer > v2.layer) qSwap(v1, v2); if (!v2.layer) return result; if (v1.layer == 0 && v2.layer == 1) { result.append(TRIANGLE(0, v2.sector, 0)); result.append(TRIANGLE(0, (v2.sector + size - 1) % size, 0)); } else if (v1.sector == v2.sector) { if (v1.layer == v2.layer) { if (v2.index == v1.index + 1) { if (v1.layer < layers) result.append(TRIANGLE(v1.layer, v1.sector, v1.index * 2 + 1)); result.append(TRIANGLE(v1.layer - 1, v1.sector, v1.index * 2)); } else if (v2.index == v1.index - 1) { if (v1.layer < layers) result.append(TRIANGLE(v1.layer, v1.sector, v2.index * 2 + 1)); result.append(TRIANGLE(v1.layer - 1, v1.sector, v2.index * 2)); } } else if (v2.layer == v1.layer + 1) { if (v2.index == v1.index) { if (v1.index) result.append(TRIANGLE(v1.layer, v1.sector, v1.index * 2 - 1)); else result.append(TRIANGLE(v1.layer, (v1.sector + size - 1) % size, v1.layer * 2)); result.append(TRIANGLE(v1.layer, v1.sector, v1.index * 2)); } else if (v2.index == v1.index + 1) { result.append(TRIANGLE(v1.layer, v1.sector, v1.index * 2)); result.append(TRIANGLE(v1.layer, v1.sector, v1.index * 2 + 1)); } } } else if ((v2.sector == (v1.sector + 1) % size) && v1.index == v1.layer - 1 && v2.index == 0) { if (v1.layer == v2.layer) { result.append(TRIANGLE(v1.layer - 1, v1.sector, v1.index * 2)); if (v1.layer < layers) result.append(TRIANGLE(v1.layer, v1.sector, v1.index * 2 + 1)); } else if (v1.layer == v2.layer + 1) { result.append(TRIANGLE(v2.layer, v1.sector, v1.index * 2 - 1)); result.append(TRIANGLE(v2.layer, v1.sector, v1.index * 2)); } } else if ((v1.sector == (v2.sector + 1) % size) && v2.index == v2.layer - 1 && v1.index == 0) { if (v1.layer == v2.layer) { result.append(TRIANGLE(v1.layer - 1, v2.sector, v2.index * 2)); if (v1.layer < layers) result.append(TRIANGLE(v1.layer, v2.sector, v2.index * 2 + 1)); } else if (v1.layer == v2.layer - 1) { result.append(TRIANGLE(v1.layer, v2.sector, v2.index * 2 - 1)); result.append(TRIANGLE(v1.layer, v2.sector, v2.index * 2)); } } return result; }
void KDTree::Subdivide(KDTreeNode &node,TriangleList *triangles,aabb& box,int depth) { if(!triangles)return ; int count = triangles->GetCount(); if( count < minTrianglesPerleafNode ||(depth>=20&&count<=maxTrianglesPerleafNode)) { node.SetTriangleList(triangles); node.Type = LEFT; node.box = box; return ; } aabb frontBox,backBox; real splitPosition; bool foundOptimalSplit = findOptimalSplitPositon(triangles,box,depth,splitPosition,frontBox, backBox); if(foundOptimalSplit == true) { node.Type = PATITION; node.SetAxis(depth%Dimension); node.SetSplitPosition(splitPosition); node.box = box; TriangleList *frontTriangles = new TriangleList(); TriangleList *backTriangles = new TriangleList(); for( int i=0; i < count; i++) { //Determine on which side of the split each //triangle belongs. TriangleNode * triangle= triangles->GetHead(); triangles->DeleteHead(); int position = partitionTriangle(triangle,depth,splitPosition); triangle->next = NULL; switch(position) { case kdBefore: frontTriangles->append(triangle); break; case kdAfter: backTriangles->append(triangle); break; case kdIntersection: //frontTriangles->append(triangle); backTriangles->append(triangle); break; } } node.m_lchild = new KDTreeNode(); node.m_rchild = new KDTreeNode(); Subdivide(*node.m_lchild,frontTriangles,frontBox,depth+1); Subdivide(*node.m_rchild,backTriangles,backBox,depth+1); }else { node.SetTriangleList(triangles); node.Type = LEFT; node.box = box; } }
void MeshMender::ProcessBinormals(TriangleList& possibleNeighbors, std::vector< Vertex >& theVerts, std::vector< unsigned int >& mappingNewToOldVert, D3DXVECTOR3 workingPosition) { NeighborGroupList neighborGroups;//a fresh group for each pass //reset each triangle to prepare for smoothing group building unsigned int i; for(i =0; i < possibleNeighbors.size(); ++i ) { m_Triangles[ possibleNeighbors[i] ].Reset(); } //now start building groups CanSmoothBinormalsChecker canSmoothBinormalsChecker; for(i =0; i < possibleNeighbors.size(); ++i ) { Triangle* currTri = &(m_Triangles[ possibleNeighbors[i] ]); assert(currTri); if(!currTri->handled) { BuildGroups(currTri,possibleNeighbors, neighborGroups, theVerts, &canSmoothBinormalsChecker ,MinBinormalsCreaseCosAngle ); } } std::vector<D3DXVECTOR3> groupBinormalVectors; for(i=0; i<neighborGroups.size(); ++i) { D3DXVECTOR3 gbinormal(0,0,0); for(unsigned int t = 0; t < neighborGroups[i].size(); ++t)//for each triangle in the group, { TriID tID = neighborGroups[i][t]; gbinormal+= m_Triangles[tID].binormal; } gbinormal = glm::normalize(gbinormal.GLMvec());//D3DXVec3Normalize( &gbinormal, &gbinormal ); groupBinormalVectors.push_back(gbinormal); } //next step, ensure that triangles in different groups are not //sharing vertices. and give the shared vertex their new group vector std::set<size_t> otherGroupsIndices; for( i = 0; i < neighborGroups.size(); ++i ) { TriangleList& curGroup = neighborGroups[ i ]; std::set<size_t> thisGroupIndices; for( size_t t = 0; t < curGroup.size(); ++t ) //for each tri { TriID tID = curGroup[ t ]; for(size_t indx = 0; indx < 3 ; ++indx)//for each vert in that tri { //if it is at the positions in question if( theVerts[ m_Triangles[tID].indices[indx] ].pos == workingPosition) { //see if another group is already using this vert if(otherGroupsIndices.find( m_Triangles[tID].indices[indx] ) != otherGroupsIndices.end() ) { //then we need to make a new vertex Vertex ov; ov = theVerts[ m_Triangles[tID].indices[indx] ]; ov.binormal = groupBinormalVectors[i]; size_t oldIndex = m_Triangles[tID].indices[indx]; size_t newIndex = theVerts.size(); theVerts.push_back(ov); AppendToMapping( oldIndex , m_originalNumVerts , mappingNewToOldVert); UpdateIndices(oldIndex,newIndex,curGroup); } else { //otherwise, just update it with the new vector theVerts[ m_Triangles[tID].indices[indx] ].binormal = groupBinormalVectors[i]; } //store that we have used this index, so other groups can check thisGroupIndices.insert(m_Triangles[tID].indices[indx]); } } } for(std::set<size_t>::iterator it = thisGroupIndices.begin(); it!= thisGroupIndices.end() ; ++it) { otherGroupsIndices.insert(*it); } } }
void GeometryEngine::initGeometry(TriangleList triangles, QVector<QVector3D> lines, QVector<QVector3D> points) { isTransparent = false; initializeOpenGLFunctions(); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Generate 2 VBOs arrayBuf.create(); indexBuf.create(); arrayBufLines.create(); arrayBufPoints.create(); std::vector<VertexData> vertices; std::vector<GLuint> indices; std::vector<GLuint> tmp(3); // iterate over all triangles for (uint i = 0; i < triangles.size(); i++) { // iterate over all vertices in triangle for (int j = 0; j < 3; j++) { // create vertex with texture coords VertexData vertex = { QVector3D(triangles[i][j][0], triangles[i][j][1], triangles[i][j][2]), QVector2D(abs(((j+1)%2)-1), abs(((j+1)%3)-1)) // tex coords (0,0),(1,1),(0,1) }; // is vertex already in indices? GLuint idx = indexOf(vertices, vertex); if (idx >= vertices.size()) { // no, add it to the end of the list //idx = vertices.size(); vertices.push_back(vertex); } // prime the index of current vertex for insertion tmp[j] = idx; } // insert vertex indices of current triangle indices.insert(indices.end(), tmp.begin(), tmp.end()); // render both sides of triangles, for now as a #define option #if TWO_SIDED std::reverse(tmp.begin(), tmp.end()); indices.insert(indices.end(), tmp.begin(), tmp.end()); #endif } #if DEBUG std::cout << "Vertices:" << std::endl << vertices.size() << std::endl; for (auto i = vertices.begin(); i != vertices.end(); ++i) std::cout << "(" << (*i).position[0] <<"," << (*i).position[1] <<"," << (*i).position[2] <<")" << ' '; std::cout << std::endl; std::cout << "Indices:" << std::endl << indices.size() << std::endl; for (auto i = indices.begin(); i != indices.end(); ++i) std::cout << *i << ' '; std::cout << std::endl; #endif arrayBuf.bind(); arrayBuf.allocate(&vertices[0], vertices.size() * sizeof(VertexData)); indexBuf.bind(); indexBuf.allocate(&indices[0], indices.size() * sizeof(GLuint)); idxLen = indices.size(); if (!lines.empty()) { arrayBufLines.bind(); arrayBufLines.allocate(&lines[0], lines.size() * sizeof(QVector3D)); } if (!points.empty()) { arrayBufPoints.bind(); arrayBufPoints.allocate(&points[0], points.size() * sizeof(QVector3D)); } }
//------------------------------------------------------------------------------------------------ // Name: XMesh // Desc: Constructs the subset geometry for a D3DXMesh //------------------------------------------------------------------------------------------------ bool XMesh::buildGeometryFromD3DXMesh(LPD3DXMESH d3dxMesh, SubsetGeometry* subsetGeometry, DWORD subsets) { // Check parameters if (APP_ERROR(!d3dxMesh || !subsetGeometry)("Invalid parameter to XMesh::buildGeometryFromD3DXMesh")) return false; // Add a reference to the mesh to counteract freeing it at the end d3dxMesh->AddRef(); // Get the device LPDIRECT3DDEVICE9 pd3dDevice = NULL; d3dxMesh->GetDevice(&pd3dDevice); // If this mesh isn't already in the correct format, have D3D do the grunt work of // converting it. bool generate_normals = false; // Whether or not normals need to be generated for this mesh if ((d3dxMesh->GetFVF() != D3DFVF_GEOMETRYVERTEX) || (D3DFMT_GEOMETRYINDEX == D3DFMT_INDEX32) && ((d3dxMesh->GetOptions() & D3DXMESH_32BIT) == 0)) { // Holds the mesh when its converted to the correct format LPD3DXMESH pTemd3dxMesh = NULL; // Duplicate the loaded mesh into the format if (APP_ERROR(d3dxMesh->CloneMeshFVF( D3DXMESH_SYSTEMMEM | ((D3DFMT_GEOMETRYINDEX == D3DFMT_INDEX32) ? D3DXMESH_32BIT : 0), D3DFVF_GEOMETRYVERTEX, pd3dDevice, &pTemd3dxMesh)) ("XMesh couldn't convert the source geometry format")) { d3dxMesh->Release(); pd3dDevice->Release(); return false; } // Generate normals if they didn't exist generate_normals = ((d3dxMesh->GetFVF()&D3DFVF_NORMAL)!=D3DFVF_NORMAL && (D3DFMT_GEOMETRYINDEX&D3DFVF_NORMAL)!=D3DFVF_NORMAL); // Use this mesh instead d3dxMesh->Release(); d3dxMesh = pTemd3dxMesh; } // The mesh must have its attributes sorted before it can be converted to single strips { // Allocate an adjacency buffer DWORD faces = d3dxMesh->GetNumFaces(); DWORD* pAdjacency = new DWORD[faces * 3]; bool failed = false; if (APP_ERROR(FAILED(d3dxMesh->GenerateAdjacency(ADJACENCY_EPSILON, pAdjacency)))("Unable to generate the mesh adjacency")) failed = true; { // Clean up "bowties" in the mesh that prevent lighting from being calculated correctly LPD3DXMESH cleaned_mesh = NULL; DWORD* cleaned_adjacency = new DWORD[faces * 3]; LPD3DXBUFFER errors_and_warnings = NULL; if (!failed && APP_ERROR(FAILED(D3DXCleanMesh(D3DXCLEAN_BOWTIES, d3dxMesh, pAdjacency, &cleaned_mesh, cleaned_adjacency, &errors_and_warnings))) ("Failed to clean mesh")) { failed = true; if (errors_and_warnings) { DEBUG_ERROR("Mesh cleaning error: %s", (const char*)errors_and_warnings->GetBufferPointer()); } } SAFE_RELEASE(errors_and_warnings); // If we successfully cleaned the mesh, use the new mesh and new set of // adjacencies. Otherwise, just delete anything that was allocated and // keep the original. if (failed) { SAFE_DELETE_ARRAY(cleaned_adjacency); SAFE_RELEASE(cleaned_mesh); } else { SAFE_DELETE_ARRAY(pAdjacency); SAFE_RELEASE(d3dxMesh) pAdjacency = cleaned_adjacency; d3dxMesh = cleaned_mesh; } } // Compute mesh normals, if necessary if (!failed && generate_normals && APP_ERROR(FAILED(D3DXComputeNormals(d3dxMesh, pAdjacency)))("Couldn't generate mesh normals")) { failed = true; } // Optimize the mesh if (!failed && APP_ERROR(FAILED(d3dxMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, pAdjacency, NULL, NULL, NULL))) ("Couldn't optimize mesh attributes")) { failed = true; } // Get rid of the temporary adjacency buffer SAFE_DELETE_ARRAY(pAdjacency); // Return if there was an error if (failed) { SAFE_RELEASE(d3dxMesh); SAFE_RELEASE(pd3dDevice); return false; } } // Lock the vertex buffer GeometryVertex* pXVertices = NULL; if (APP_ERROR(d3dxMesh->LockVertexBuffer(D3DLOCK_READONLY, (VOID**)&pXVertices))("Couldn't lock source vertex buffer")) { // Erase this mesh d3dxMesh->Release(); pd3dDevice->Release(); // Failure return false; } // Iterate through all of the materials and copy vertex/index data, and assign material // information for the mesh. for (DWORD subset = 0; subset < subsets; subset++) { // Use D3DX to convert this subset into a nicely indexed form DWORD numStripIndices; LPDIRECT3DINDEXBUFFER9 pSubsetIB; if (APP_ERROR(D3DXConvertMeshSubsetToSingleStrip(d3dxMesh, subset, D3DXMESH_SYSTEMMEM, &pSubsetIB, &numStripIndices))("Couldn't convert mesh subset into indexable strip")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Return the error return false; } D3DINDEXBUFFER_DESC desc; GeometryIndex* pXIndices = NULL; // Check the format of the indices and lock the strip index buffer if (APP_ERROR(pSubsetIB->GetDesc(&desc))("Couldn't get .X mesh IB desc") || (desc.Format != D3DFMT_GEOMETRYINDEX) || APP_ERROR(pSubsetIB->Lock(0, 0, (VOID**)&pXIndices, D3DLOCK_READONLY))("Unable to lock the .X index buffer")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh pSubsetIB->Release(); d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Error! return false; } // This table pairs an index from the .X file to an index in the buffer that // holds the vertices for this subset XIndicesTable xIndicesTable; // For each of the indices in the strip, puts its vertex ID into the indices // table. Use the counter to determine which vertex this is. { GeometryIndex vertexCounter = 0; for (DWORD e = 0; e < numStripIndices; ++e) { // Insert the entry [x-mesh index, subset index] into the table XIndicesTableInsertResult result = xIndicesTable.insert(XIndicesEntry(pXIndices[e], vertexCounter)); // If the result was successful (this isn't a duplicated X-mesh index) increment the vertex counter if (result.second) vertexCounter++; } } // Grab the number of vertices this geometry uses DWORD numVertices = (DWORD)xIndicesTable.size(); // This buffer holds all of the triangles in this subset TriangleList triangles; // This list keeps track of locations in the strip where the winding order changes. This is necessary // because this next part will remove degenerate triangles from the list. std::set<size_t> windingChanges; // Generate the list of triangles from the strip provided for (DWORD t = 0; t < numStripIndices - 2; ++t) { // Build the triangle that will be added to the buffer // CHANGED July 25, 2008: the winding order is wrong here //Triangle tri = { pXIndices[t + 0], pXIndices[t + 1], pXIndices[t + 2] }; Triangle tri = { pXIndices[t + 0], pXIndices[t + 2], pXIndices[t + 1] }; // Convert the triangle into subset-indices by using the lookup table // we generated before. tri.index[0] = xIndicesTable.find(tri.index[0])->second; tri.index[1] = xIndicesTable.find(tri.index[1])->second; tri.index[2] = xIndicesTable.find(tri.index[2])->second; // Check to make sure this triangle isn't degenerate. If it is, we can just skip // this triangle entirely to simplify the geometry. if (tri.index[0] == tri.index[1] || tri.index[1] == tri.index[2] || tri.index[0] == tri.index[2]) { // Try to find the winding in the list std::set<size_t>::iterator currentWinding = windingChanges.find(triangles.size()); // Add this to the winding change list, or remove the change if it's already there if (currentWinding != windingChanges.end()) windingChanges.erase(currentWinding); else windingChanges.insert(triangles.size()); // Don't insert a triangle here continue; } // Add this triangle to the list triangles.push_back(tri); } // Calculate the number of indices we need for the buffer DWORD numGeometryIndices = (DWORD)(triangles.size() * 3); // Allocate the destination geometry Geometry* pGeometry = NULL; if (APP_ERROR(AllocateGeometry(numVertices, numGeometryIndices, &pGeometry))("Couldn't allocate geometry")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh pSubsetIB->Unlock(); pSubsetIB->Release(); d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Error! return false; } // Copy the vertices needed for this subset into the buffer GeometryVertex* pVertices = pGeometry->pVertices; for (XIndicesIterator i = xIndicesTable.begin(); i != xIndicesTable.end(); ++i) { GeometryVertex* pCurrentVertex = &pVertices[i->second]; *pCurrentVertex = pXVertices[i->first]; // Modify the vertex location to make this a unit mesh sitting on the X-Z plane pCurrentVertex->x = pCurrentVertex->x; pCurrentVertex->y = pCurrentVertex->y; pCurrentVertex->z = pCurrentVertex->z; //pVertices[i->second].color = D3DCOLOR_XRGB(255,255,255); // todo: enable color? } // Copy triangles into the indices buffer DWORD index = 0; GeometryIndex* pIndices = pGeometry->pIndices; DWORD windingOrder = 0; for (TriangleIterator t = triangles.begin(); t != triangles.end(); ++t) { // Find this index in the winding list if (windingChanges.find(index / 3) != windingChanges.end()) windingOrder = 1 - windingOrder; // Alternate the winding order so that everything shows up correctly if ((index / 3) % 2 == windingOrder) { pIndices[index + 0] = t->index[0]; pIndices[index + 1] = t->index[1]; pIndices[index + 2] = t->index[2]; } else { pIndices[index + 0] = t->index[1]; pIndices[index + 1] = t->index[0]; pIndices[index + 2] = t->index[2]; } // Increment the index counter index += 3; } // Unlock and delete strip index buffer pSubsetIB->Unlock(); pSubsetIB->Release(); // Store the buffers in the main array std::pair<SubsetGeometry::iterator,bool> result = subsetGeometry->insert(SubsetGeometry::value_type(subset, pGeometry)); if (APP_ERROR(!result.second)("Couldn't insert subset geometry into main array for .X mesh")) { // Get rid of this geometry DeallocateGeometry(pGeometry); DeallocateGeometry(subsetGeometry); // Erase the mesh d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Return error return false; } //DEBUG_MSG("Subset %i has %i vertices %i indices (%i polygons)\n", subset, numVertices, numGeometryIndices, numGeometryIndices / 3); } // Done with the DirectX mesh. This will not erase the outside mesh. d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free the device reference pd3dDevice->Release(); // Success return true; }
void Renderer::Render( void ) { for (unsigned i = 0; i < m_renderUnitList.size(); i++) { RenderUnit* renderUnit = m_renderUnitList[i]; unsigned nVerts = renderUnit->m_vb->Size(); unsigned nTriangles = renderUnit->m_ib->Size() / 3; VsOutList vsOuts(nVerts); TriangleList triangles; // 对每个顶点执行VS for (unsigned j = 0; j < nVerts; j++) { vsOuts[j] = renderUnit->m_vs->Main((*renderUnit->m_vb)[j]); } // triangle setup (trivial-rejection, clipping) for (unsigned j = 0; j < nTriangles; j++) { Triangle tri; tri.iV0 = (*renderUnit->m_ib)[3 * j + 0]; tri.iV1 = (*renderUnit->m_ib)[3 * j + 1]; tri.iV2 = (*renderUnit->m_ib)[3 * j + 2]; if (TrivialReject(tri, vsOuts)) { continue; } else if (RemoveBackface(tri, vsOuts, CULL_MODE_CCW)) { continue; } else if (TrivialAccept(tri, vsOuts)) { triangles.push_back(tri); } else { // TODO: do clipping here triangles.push_back(tri); } } int halfRtWidth = m_renderTarget->GetWidth() >> 1; int halfRtHeight = m_renderTarget->GetHeight() >> 1; for (unsigned j = 0; j < vsOuts.size(); j++) { Vector4& position = vsOuts[j].position; // perspective-divide position.x /= position.w; position.y /= position.w; position.z /= position.w; // 转化到屏幕坐标 position.x = ( position.x + 1.0f) * halfRtWidth; position.y = (-position.y + 1.0f) * halfRtHeight; } // 光栅化每个三角形 for (unsigned j = 0; j < triangles.size(); j++) { VertexShaderOutput& v0 = vsOuts[triangles[j].iV0]; VertexShaderOutput& v1 = vsOuts[triangles[j].iV1]; VertexShaderOutput& v2 = vsOuts[triangles[j].iV2]; if (renderUnit->m_wireFrame) // fill mode: wireframe { int x0 = int(v0.position.x); int y0 = int(v0.position.y); int x1 = int(v1.position.x); int y1 = int(v1.position.y); int x2 = int(v2.position.x); int y2 = int(v2.position.y); DrawLine(x0, y0, x1, y1, 0xFFFFFFFF); DrawLine(x0, y0, x2, y2, 0xFFFFFFFF); DrawLine(x1, y1, x2, y2, 0xFFFFFFFF); } else // fill mode: solid { VertexShaderOutput* sv; VertexShaderOutput* mv; VertexShaderOutput* ev; // 按Y值给三个顶点排序 if (v0.position.y < v1.position.y) { sv = &v0; ev = &v1; } else { sv = &v1; ev = &v0; } if (v2.position.y < sv->position.y) { mv = sv; sv = &v2; } else if (v2.position.y > ev->position.y) { mv = ev; ev = &v2; } else { mv = &v2; } // 扫描线算法 // --begin-- // 这种fill convention会导致由两个三角形共享的边上的像素被重绘一次,而顶点所在的像素会重绘更多次。 // 但是算法实现简单,而且保证没有漏洞(漏洞比重绘更致命) int minY = int(sv->position.y); int maxY = int(ev->position.y); int midY = int(mv->position.y); float esY = ev->position.y - sv->position.y; float msY = mv->position.y - sv->position.y; float emY = ev->position.y - mv->position.y; float subPixelYOffsetS = sv->position.y - int(sv->position.y); float subPixelYOffsetM = mv->position.y - int(mv->position.y); float dx1 = (ev->position.x - sv->position.x) / esY; float dx2 = (mv->position.x - sv->position.x) / msY; float dx2Alt = (ev->position.x - mv->position.x) / emY; float x1 = sv->position.x; float x2 = sv->position.x; for (int y = minY; y < maxY; y++) { if (y == midY) { dx2 = dx2Alt; x2 = mv->position.x; } float fY = y < midY ? y + subPixelYOffsetS : y + subPixelYOffsetM; VertexShaderOutput& va1 = Lerp(*sv, *ev, (ev->position.y - fY) / esY); VertexShaderOutput& va2 = y < midY ? Lerp(*sv, *mv, (mv->position.y - fY) / msY) : Lerp(*mv, *ev, (ev->position.y - fY) / emY); if (x1 < x2) { FillSpan(x1, x2, y, va1, va2, *renderUnit->m_ps); } else { FillSpan(x2, x1, y, va2, va1, *renderUnit->m_ps); } x1 += dx1; x2 += dx2; } // 扫描线算法 // --end-- } } delete renderUnit; } m_renderUnitList.clear(); }
void ProgressiveTriangleGeometry::FindEdgeToCollapse(VertexList& /*org_vertex_list*/, TriangleList& /*org_triangle_list*/, VertexList& vertex_list, TriangleList& triangle_list, Edge& edge) { if (triangle_list.empty()) return; float current_error = 0.0f; float current_max_error = 0.0f; edge.v1_ = 0; edge.v2_ = 0; edge.triangle_list_.clear(); // Calculate mean error. VertexList::iterator v_iter; for (v_iter = vertex_list.begin(); v_iter != vertex_list.end(); ++v_iter) { if (v_iter == vertex_list.begin()) { current_max_error = (*v_iter)->error_; } else if((*v_iter)->error_ > current_max_error) { current_max_error = (*v_iter)->error_; } current_error += (*v_iter)->error_; } current_error /= (float)vertex_list.size(); float min_error = 0.0f; float min_error1 = 0.0f; // Temporary error value storage for _edge->v1_. float min_error2 = 0.0f; // Temporary error value storage for _edge->v2_. bool first = true; // Test vertex collaps on all triangles. TriangleList::iterator tri_iter; for (tri_iter = triangle_list.begin(); tri_iter != triangle_list.end(); ++tri_iter) { Triangle* triangle = *tri_iter; vec3 diff1; vec3 diff2; Vertex mid; // Test V1 and V2. mid.x() = (triangle->v1_->x() + triangle->v2_->x()) * 0.5f; mid.y() = (triangle->v1_->y() + triangle->v2_->y()) * 0.5f; mid.z() = (triangle->v1_->z() + triangle->v2_->z()) * 0.5f; // Calculate the distance between the new, merged position, // and the original vertex position. diff1.Set(mid.x() - triangle->v1_->twin_->x(), mid.y() - triangle->v1_->twin_->y(), mid.z() - triangle->v1_->twin_->z()); diff2.Set(mid.x() - triangle->v2_->twin_->x(), mid.y() - triangle->v2_->twin_->y(), mid.z() - triangle->v2_->twin_->z()); float error1 = diff1.GetLength() + triangle->v1_->error_; float error2 = diff2.GetLength() + triangle->v2_->error_; float error = (error1 + error2 + current_error) / 3.0f; if (first == true || error < min_error) { edge.v1_ = triangle->v1_; edge.v2_ = triangle->v2_; min_error1 = error1; min_error2 = error2; min_error = error; first = false; } // Test V2 and V3. mid.x() = (triangle->v2_->x() + triangle->v3_->x()) * 0.5f; mid.y() = (triangle->v2_->y() + triangle->v3_->y()) * 0.5f; mid.z() = (triangle->v2_->z() + triangle->v3_->z()) * 0.5f; // Calculate the distance between the new, merged position, // and the original vertex position. diff1.Set(mid.x() - triangle->v2_->twin_->x(), mid.y() - triangle->v2_->twin_->y(), mid.z() - triangle->v2_->twin_->z()); diff2.Set(mid.x() - triangle->v3_->twin_->x(), mid.y() - triangle->v3_->twin_->y(), mid.z() - triangle->v3_->twin_->z()); error1 = diff1.GetLength() + triangle->v1_->error_; error2 = diff2.GetLength() + triangle->v2_->error_; error = (error1 + error2 + current_error) / 3.0f; if (error < min_error) { edge.v1_ = triangle->v1_; edge.v2_ = triangle->v2_; min_error = error; min_error1 = error1; min_error2 = error2; } // Test V3 and V1. mid.x() = (triangle->v3_->x() + triangle->v1_->x()) * 0.5f; mid.y() = (triangle->v3_->y() + triangle->v1_->y()) * 0.5f; mid.z() = (triangle->v3_->z() + triangle->v1_->z()) * 0.5f; // Calculate the distance between the new, merged position, // and the original vertex position. diff1.Set(mid.x() - triangle->v3_->twin_->x(), mid.y() - triangle->v3_->twin_->y(), mid.z() - triangle->v3_->twin_->z()); diff2.Set(mid.x() - triangle->v1_->twin_->x(), mid.y() - triangle->v1_->twin_->y(), mid.z() - triangle->v1_->twin_->z()); error1 = diff1.GetLength() + triangle->v1_->error_; error2 = diff2.GetLength() + triangle->v2_->error_; error = (error1 + error2 + current_error) / 3.0f; if (error < min_error) { edge.v1_ = triangle->v1_; edge.v2_ = triangle->v2_; min_error = error; min_error1 = error1; min_error2 = error2; } if (min_error == 0.0f && edge.v1_ != 0 && edge.v2_ != 0) break; } edge.v1_->error_ = min_error1; edge.v2_->error_ = min_error2; // Now add all triangles to _edge that share the two vertices // _edge->v1_ and _edge->v2_. for (tri_iter = triangle_list.begin(); tri_iter != triangle_list.end(); ++tri_iter) { Triangle* triangle = *tri_iter; if (triangle->HaveVertex(edge.v1_) && triangle->HaveVertex(edge.v2_)) { edge.triangle_list_.push_back(triangle); } } }
unsigned int TriangleAdjacencyGraph::calcOptPrim ( unsigned extIteration, bool doStrip, bool doFan, unsigned minFanTriangles ) { int iteration = extIteration; bool sample = iteration > 1 ? true : false; bool checkRevOrder = sample; TriangleList degreeBag[4]; TriangleList *fList = 0; int cost = 0, sampleCost = 0; int stripCost = 0, revCost = 0, fanCost = 0, triCost = 0; int bestCost = 0, worstCost = 0, lowDegree; unsigned int i, n; WalkCase walkCase = START; Triangle *triangle, *next; HalfEdge *twin = 0, *gateEdge = 0, *halfEdge = 0; bool doMainLoop = true; unsigned int seed = 1, bestSeed = 1; int mostDegree = 3; unsigned triangleLeft = _trianglePool.countElem(); srand(1); if (doFan) { n = _temporaryVector.size(); fanCost = 0; // find fans for (i = 0; i < n; i++) if ( (_temporaryVector[i].size() >= minFanTriangles) && (gateEdge = _temporaryVector[i][0].second) && (gateEdge->triangle->valid()) ) { for ( halfEdge = gateEdge->next->next->twin; (halfEdge && halfEdge->triangle->valid() && (halfEdge != gateEdge)); halfEdge = halfEdge->next->next->twin ) ; if (halfEdge == gateEdge) { // fan is closed; mark every triangle triangle = 0; fList = new TriangleList; for ( halfEdge = gateEdge; !triangle || (halfEdge != gateEdge); halfEdge = halfEdge->next->next->twin ) { triangle = halfEdge->triangle; _validTriangleBag.release(*triangle); triangle->drop(); triangle->state = FAN_PART; fList->add(*triangle); } _fanBag.push_back(Primitive(i,fList)); fanCost += (_temporaryVector[i].size() + 2); triangleLeft -= _temporaryVector[i].size(); } } } if (doStrip && iteration) { // push every triangle into the according degree bag degreeBag[mostDegree].paste(_validTriangleBag); for (triangle = degreeBag[mostDegree].first; triangle; triangle = next) { next = triangle->next; if (triangle->valid()) { if (triangle->state != mostDegree) { degreeBag[mostDegree].release(*triangle); _validTriangleBag.release(*triangle); degreeBag[triangle->state].add( *triangle); } } else { cerr << "INVALID TRIANGLE IN VALID TRIANGLE BAG\n" << endl; } } for (iteration--; iteration >= 0; iteration--) { seed = iteration ? rand() : bestSeed; srand (seed); fList = 0; cost = 0; doMainLoop = true; walkCase = START; // run the main loop while (doMainLoop) { switch (walkCase) { case START: stripCost = 0; triangle = 0; for (lowDegree = 1; lowDegree < 4; lowDegree++) if ((degreeBag[lowDegree].empty() == false)) { if (sample) { // pick a random triangle n = degreeBag[lowDegree].countElem() - 1; i = int(float(n) * rand()/float(RAND_MAX)); triangle = degreeBag[lowDegree].first; while (i--) triangle = triangle->next; } else { // pick the first triangle triangle = degreeBag[lowDegree].first; } break; } if (triangle) { // create the new list fList = new TriangleList; // find the best neighbour gateEdge = 0; for (i = 0; i < 3; i++) if ( (twin = triangle->halfEdgeVec[i].twin) && (twin->triangle->state > 0) ) { if ( twin->next->next->twin && (twin->next->next->twin->triangle->state > 0) ) { gateEdge = &triangle->halfEdgeVec[i]; break; } else { if ( twin->next->twin && (twin->next->twin->triangle->state > 0) ) gateEdge = &triangle->halfEdgeVec[i]; else { if ((twin->triangle->state > 0)) gateEdge = &triangle->halfEdgeVec[i]; } } } // release and store the first triangle dropOutTriangle (*triangle,degreeBag); fList->add(*triangle); stripCost += 3; // set the next step if (gateEdge) { walkCase = LEFT; stripCost++; } else walkCase = FINISH; } else doMainLoop = false; break; case LEFT: gateEdge = gateEdge->twin; triangle = gateEdge->triangle; // find the next gate if (triangle->state == DEGREE_0) { gateEdge = 0; walkCase = FINISH; } else if ( (twin = gateEdge->next->next->twin) && (twin->triangle->state > 0) ){ gateEdge = gateEdge->next->next; stripCost++; walkCase = RIGHT; } else { gateEdge = gateEdge->next; stripCost += 2; walkCase = LEFT; } // store the current triangle dropOutTriangle (*triangle,degreeBag); fList->add(*triangle); break; case RIGHT: gateEdge = gateEdge->twin; triangle = gateEdge->triangle; // find the next gate if (triangle->state == DEGREE_0) { gateEdge = 0; walkCase = FINISH; } else if ( (twin = gateEdge->next->twin) && (twin->triangle->state > 0) ) { gateEdge = gateEdge->next; stripCost++; walkCase = LEFT; } else { gateEdge = gateEdge->next->next; stripCost += 2; walkCase = RIGHT; } // store the current triangle dropOutTriangle (*triangle,degreeBag); fList->add(*triangle); break; case FINISH: // try to reverse the strip if ( checkRevOrder && (revCost = calcStripCost(*fList,true)) && (revCost < stripCost) ) { _stripBag.push_back(Primitive(1,fList)); cost += revCost; } else { _stripBag.push_back(Primitive(0,fList)); cost += stripCost; } walkCase = START; fList = 0; break; } } if (sample) { sampleCost = cost + (degreeBag[0].countElem() * 3) + fanCost; if (!bestCost || (sampleCost < bestCost)) { bestCost = sampleCost; bestSeed = seed; } if (sampleCost > worstCost) worstCost = sampleCost; cout << " cost/best/worst: " << sampleCost << '/' << bestCost << '/' << worstCost << endl; } if (iteration) { // reinit the four degree bags degreeBag[mostDegree].paste(degreeBag[0]); n = _stripBag.size(); for (i = 0; i < n; i++) { degreeBag[mostDegree].paste(*_stripBag[i].second); delete _stripBag[i].second; } _stripBag.clear(); for ( triangle = degreeBag[mostDegree].first; triangle; triangle = next) { next = triangle->next; triangle->resetDegreeState(STRIP_PART); if (triangle->valid()) { if (triangle->state != mostDegree) { degreeBag[mostDegree].release(*triangle); degreeBag[triangle->state].add(*triangle); } } else { cerr << "INVALID TRIANGLE IN REINIT\n" << endl; cerr << triangle->state << endl; } } } } } else { // push every valid triangle in degree 0; we don't strip anything degreeBag[0].paste(_validTriangleBag); } if (sample) { cerr << "range: " << bestCost << '/' << worstCost << ' ' << float(100 * (worstCost-bestCost))/float(bestCost) << '%' << endl; } // collect isolated triangles degreeBag[0].paste(_invalidTriangleBag); triCost = degreeBag[0].countElem() * 3; if (triCost) { fList = new TriangleList; fList->paste(degreeBag[0]); _triBag.push_back(Primitive(0,fList)); } return (cost + fanCost + triCost); }