void TriStripVisitor::stripify(Geometry& geom) { if (geom.containsDeprecatedData()) geom.fixDeprecatedData(); if (osg::getBinding(geom.getNormalArray())==osg::Array::BIND_PER_PRIMITIVE_SET) return; if (osg::getBinding(geom.getColorArray())==osg::Array::BIND_PER_PRIMITIVE_SET) return; if (osg::getBinding(geom.getSecondaryColorArray())==osg::Array::BIND_PER_PRIMITIVE_SET) return; if (osg::getBinding(geom.getFogCoordArray())==osg::Array::BIND_PER_PRIMITIVE_SET) return; // no point tri stripping if we don't have enough vertices. if (!geom.getVertexArray() || geom.getVertexArray()->getNumElements()<3) return; // check for the existence of surface primitives unsigned int numSurfacePrimitives = 0; unsigned int numNonSurfacePrimitives = 0; Geometry::PrimitiveSetList& primitives = geom.getPrimitiveSetList(); Geometry::PrimitiveSetList::iterator itr; for(itr=primitives.begin(); itr!=primitives.end(); ++itr) { switch((*itr)->getMode()) { case(PrimitiveSet::TRIANGLES): case(PrimitiveSet::TRIANGLE_STRIP): case(PrimitiveSet::TRIANGLE_FAN): case(PrimitiveSet::QUADS): case(PrimitiveSet::QUAD_STRIP): case(PrimitiveSet::POLYGON): ++numSurfacePrimitives; break; default: ++numNonSurfacePrimitives; break; } } // nothitng to tri strip leave. if (!numSurfacePrimitives) return; // compute duplicate vertices typedef std::vector<unsigned int> IndexList; unsigned int numVertices = geom.getVertexArray()->getNumElements(); IndexList indices(numVertices); unsigned int i,j; for(i=0;i<numVertices;++i) { indices[i] = i; } VertexAttribComparitor arrayComparitor(geom); std::sort(indices.begin(),indices.end(),arrayComparitor); unsigned int lastUnique = 0; unsigned int numUnique = 1; unsigned int numDuplicate = 0; for(i=1;i<numVertices;++i) { if (arrayComparitor.compare(indices[lastUnique],indices[i])==0) { //std::cout<<" found duplicate "<<indices[lastUnique]<<" and "<<indices[i]<<std::endl; ++numDuplicate; } else { //std::cout<<" unique "<<indices[i]<<std::endl; lastUnique = i; ++numUnique; } } // std::cout<<" Number of duplicates "<<numDuplicate<<std::endl; // std::cout<<" Number of unique "<<numUnique<<std::endl; // std::cout<<" Total number of vertices required "<<numUnique<<" vs original "<<numVertices<<std::endl; // std::cout<<" % size "<<(float)numUnique/(float)numVertices*100.0f<<std::endl; IndexList remapDuplicatesToOrignals(numVertices); lastUnique = 0; for(i=1;i<numVertices;++i) { if (arrayComparitor.compare(indices[lastUnique],indices[i])!=0) { // found a new vertex entry, so previous run of duplicates needs // to be put together. unsigned int min_index = indices[lastUnique]; for(j=lastUnique+1;j<i;++j) { min_index = osg::minimum(min_index,indices[j]); } for(j=lastUnique;j<i;++j) { remapDuplicatesToOrignals[indices[j]]=min_index; } lastUnique = i; } } unsigned int min_index = indices[lastUnique]; for(j=lastUnique+1;j<i;++j) { min_index = osg::minimum(min_index,indices[j]); } for(j=lastUnique;j<i;++j) { remapDuplicatesToOrignals[indices[j]]=min_index; } // copy the arrays. IndexList finalMapping(numVertices); IndexList copyMapping; copyMapping.reserve(numUnique); unsigned int currentIndex=0; for(i=0;i<numVertices;++i) { if (remapDuplicatesToOrignals[i]==i) { finalMapping[i] = currentIndex; copyMapping.push_back(i); currentIndex++; } } for(i=0;i<numVertices;++i) { if (remapDuplicatesToOrignals[i]!=i) { finalMapping[i] = finalMapping[remapDuplicatesToOrignals[i]]; } } MyTriangleIndexFunctor taf; taf._remapIndices.swap(finalMapping); Geometry::PrimitiveSetList new_primitives; new_primitives.reserve(primitives.size()); for(itr=primitives.begin(); itr!=primitives.end(); ++itr) { switch((*itr)->getMode()) { case(PrimitiveSet::TRIANGLES): case(PrimitiveSet::TRIANGLE_STRIP): case(PrimitiveSet::TRIANGLE_FAN): case(PrimitiveSet::QUADS): case(PrimitiveSet::QUAD_STRIP): case(PrimitiveSet::POLYGON): (*itr)->accept(taf); break; default: new_primitives.push_back(*itr); break; } } float minimum_ratio_of_indices_to_unique_vertices = 1; float ratio_of_indices_to_unique_vertices = ((float)taf._in_indices.size()/(float)numUnique); OSG_INFO<<"TriStripVisitor::stripify(Geometry&): Number of indices"<<taf._in_indices.size()<<" numUnique"<< numUnique << std::endl; OSG_INFO<<"TriStripVisitor::stripify(Geometry&): ratio indices/numUnique"<< ratio_of_indices_to_unique_vertices << std::endl; // only tri strip if there is point in doing so. if (!taf._in_indices.empty() && ratio_of_indices_to_unique_vertices>=minimum_ratio_of_indices_to_unique_vertices) { OSG_INFO<<"TriStripVisitor::stripify(Geometry&): doing tri strip"<< std::endl; unsigned int in_numVertices = 0; for(triangle_stripper::indices::iterator itr=taf._in_indices.begin(); itr!=taf._in_indices.end(); ++itr) { if (*itr>in_numVertices) in_numVertices=*itr; } // the largest indice is in_numVertices, but indices start at 0 // so increment to give to the corrent number of verticies. ++in_numVertices; // remap any shared vertex attributes RemapArray ra(copyMapping); arrayComparitor.accept(ra); triangle_stripper::tri_stripper stripifier(taf._in_indices); stripifier.SetCacheSize(_cacheSize); stripifier.SetMinStripSize(_minStripSize); triangle_stripper::primitive_vector outPrimitives; stripifier.Strip(&outPrimitives); if (outPrimitives.empty()) { OSG_WARN<<"Error: TriStripVisitor::stripify(Geometry& geom) failed."<<std::endl; return; } triangle_stripper::primitive_vector::iterator pitr; if (_generateFourPointPrimitivesQuads) { OSG_INFO<<"Collecting all quads"<<std::endl; typedef triangle_stripper::primitive_vector::iterator prim_iterator; typedef std::multimap<unsigned int,prim_iterator> QuadMap; QuadMap quadMap; // pick out quads and place them in the quadMap, and also look for the max for(pitr=outPrimitives.begin(); pitr!=outPrimitives.end(); ++pitr) { if (pitr->Indices.size()==4) { std::swap(pitr->Indices[2],pitr->Indices[3]); unsigned int minValue = *(std::max_element(pitr->Indices.begin(),pitr->Indices.end())); quadMap.insert(QuadMap::value_type(minValue,pitr)); } } // handle the quads if (!quadMap.empty()) { IndexList indices; indices.reserve(4*quadMap.size()); // adds all the quads into the quad primitive, in ascending order // and the QuadMap stores the quad's in ascending order. for(QuadMap::iterator qitr=quadMap.begin(); qitr!=quadMap.end(); ++qitr) { pitr = qitr->second; unsigned int min_pos = 0; for(i=1;i<4;++i) { if (pitr->Indices[min_pos]>pitr->Indices[i]) min_pos = i; } indices.push_back(pitr->Indices[min_pos]); indices.push_back(pitr->Indices[(min_pos+1)%4]); indices.push_back(pitr->Indices[(min_pos+2)%4]); indices.push_back(pitr->Indices[(min_pos+3)%4]); } bool inOrder = true; unsigned int previousValue = indices.front(); for(IndexList::iterator qi_itr=indices.begin()+1; qi_itr!=indices.end() && inOrder; ++qi_itr) { inOrder = (previousValue+1)==*qi_itr; previousValue = *qi_itr; } if (inOrder) { new_primitives.push_back(new osg::DrawArrays(GL_QUADS,indices.front(),indices.size())); } else { unsigned int maxValue = *(std::max_element(indices.begin(),indices.end())); if (maxValue>=65536) { osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(GL_QUADS); std::copy(indices.begin(),indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } else { osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_QUADS); std::copy(indices.begin(),indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } } } } // handle non quad primitives for(pitr=outPrimitives.begin(); pitr!=outPrimitives.end(); ++pitr) { if (!_generateFourPointPrimitivesQuads || pitr->Indices.size()!=4) { bool inOrder = true; unsigned int previousValue = pitr->Indices.front(); for(triangle_stripper::indices::iterator qi_itr=pitr->Indices.begin()+1; qi_itr!=pitr->Indices.end() && inOrder; ++qi_itr) { inOrder = (previousValue+1)==*qi_itr; previousValue = *qi_itr; } if (inOrder) { new_primitives.push_back(new osg::DrawArrays(pitr->Type,pitr->Indices.front(),pitr->Indices.size())); } else { unsigned int maxValue = *(std::max_element(pitr->Indices.begin(),pitr->Indices.end())); if (maxValue>=65536) { osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(pitr->Type); elements->reserve(pitr->Indices.size()); std::copy(pitr->Indices.begin(),pitr->Indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } else { osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(pitr->Type); elements->reserve(pitr->Indices.size()); std::copy(pitr->Indices.begin(),pitr->Indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } } } } geom.setPrimitiveSetList(new_primitives); #if 0 // debugging code for indentifying the tri-strips. osg::Vec4Array* colors = new osg::Vec4Array(new_primitives.size()); for(i=0;i<colors->size();++i) { (*colors)[i].set(((float)rand()/(float)RAND_MAX), ((float)rand()/(float)RAND_MAX), ((float)rand()/(float)RAND_MAX), 1.0f); } geom.setColorArray(colors); geom.setColorBinding(osg::Array::BIND_PER_PRIMITIVE_SET); #endif } else { OSG_INFO<<"TriStripVisitor::stripify(Geometry&): not doing tri strip *****************"<< std::endl; } }
void CouenneProblem::decomposeTerm (expression *term, CouNumber initCoe, CouNumber &c0, LinMap &lmap, QuadMap &qmap) { switch (term -> code ()) { // easy cases //////////////////////////////////////////////////////////////////////// case COU_EXPRCONST: /// a constant c0 += initCoe * term -> Value (); break; case COU_EXPRVAR: /// a variable lmap.insert (term -> Index (), initCoe); break; case COU_EXPROPP: /// the opposite of a term decomposeTerm (term -> Argument (), -initCoe, c0, lmap, qmap); break; case COU_EXPRSUB: /// a subtraction decomposeTerm (term -> ArgList () [0], initCoe, c0, lmap, qmap); decomposeTerm (term -> ArgList () [1], -initCoe, c0, lmap, qmap); break; case COU_EXPRQUAD: { /// a quadratic form exprQuad *t = dynamic_cast <exprQuad *> (term -> isaCopy () ? term -> Copy () : term); exprQuad::sparseQ &M = t -> getQ (); for (exprQuad::sparseQ::iterator row = M.begin (); row != M.end (); ++row) { int xind = row -> first -> Index (); for (exprQuad::sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) { qmap.insert (xind, col -> first -> Index (), initCoe * col -> second); } } } // NO break here, exprQuad generalizes exprGroup case COU_EXPRGROUP: { /// a linear term exprGroup *t = dynamic_cast <exprGroup *> (term -> isaCopy () ? term -> Copy () : term); exprGroup::lincoeff &lcoe = t -> lcoeff (); // for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) for (int n = lcoe.size (), i=0; n--; i++) lmap.insert (lcoe [i].first -> Index (), initCoe * lcoe [i].second); c0 += initCoe * t -> getc0 (); } // NO break here, exprGroup generalizes exprSum case COU_EXPRSUM: { /// a sum of (possibly) nonlinear elements expression **al = term -> ArgList (); for (int i = term -> nArgs (); i--;) decomposeTerm (*al++, initCoe, c0, lmap, qmap); } break; // not-so-easy cases ///////////////////////////////////////////////////////////////// // // cannot add terms as it may fill up the triplet case COU_EXPRMUL: { /// a product of n factors ///////////////////////////////////////// std::map <int, CouNumber> indices; CouNumber coe = initCoe; // return list of variables (some of which auxiliary) flattenMul (term, coe, indices); if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) { printf ("from flattenmul: [%g] ", coe); for (std::map <int, CouNumber>::iterator itt = indices.begin (); itt != indices.end(); ++itt) printf (" %d,%g", itt -> first, itt -> second); printf ("\n"); } // based on number of factors, decide what to return switch (indices.size ()) { case 0: // no variables in multiplication (hmmm...) c0 += coe; break; case 1: { // only one term (may be with exponent != 1) std::map <int, CouNumber>::iterator one = indices.begin (); int index = one -> first; CouNumber expon = one -> second; if (fabs (expon - 1) < COUENNE_EPS) lmap.insert (index, coe); else if (fabs (expon - 2) < COUENNE_EPS) qmap.insert (index, index, coe); else { exprAux *aux = addAuxiliary (new exprPow (new exprClone (Var (index)), new exprConst (expon))); //linsert (lmap, aux -> Index (), initCoe); // which of these three is correct? //linsert (lmap, aux -> Index (), initCoe * coe); lmap.insert (aux -> Index (), coe); } } break; case 2: { // two terms int ind0, ind1; std::map <int, CouNumber>::iterator one = indices.begin (), two = one; ++two; // now "two" points to the other variable // first variable if (fabs (one -> second - 1) > COUENNE_EPS) { exprAux *aux = addAuxiliary (new exprPow (new exprClone (Var (one -> first)), new exprConst (one -> second))); ind0 = aux -> Index (); } else ind0 = one -> first; // second variable if (fabs (two -> second - 1) > COUENNE_EPS) { exprAux *aux = addAuxiliary (new exprPow (new exprClone (Var (two -> first)), new exprConst (two -> second))); ind1 = aux -> Index (); } else ind1 = two -> first; qmap.insert (ind0, ind1, coe); } break; default: { // create new auxiliary variable containing product of 3+ factors expression **al = new expression * [indices.size ()]; std::map <int, CouNumber>::iterator one = indices.begin (); for (int i=0; one != indices.end (); ++one, i++) if (fabs (one -> second - 1) > COUENNE_EPS) { exprAux *aux = addAuxiliary (new exprPow (new exprClone (Var (one -> first)), new exprConst (one -> second))); al [i] = new exprClone (aux); } else al [i] = new exprClone (Var (one -> first)); // TODO: when we have a convexification for \prod_{i \in I}... // exprAux *aux = addAuxiliary (new exprMul (al, indices.size ())); exprMul *mul = new exprMul (al, indices.size ()); exprAux *aux = mul -> standardize (this); lmap.insert (aux -> Index (), coe); } break; } } break; // end of case COU_EXPRMUL case COU_EXPRPOW: { // expression = f(x)^g(x) //////////////////////////////////////////////// expression **al = term -> ArgList (); if (al [1] -> Type () != CONST) { // non-constant exponent, standardize the whole term and add // linear component (single aux) expression *aux = term -> standardize (this); if (!aux) aux = term; lmap.insert (aux -> Index (), initCoe); } else { // this is of the form f(x)^k. If k=2, return square. If // k=1, return var. Otherwise, generate new auxiliary. expression *aux = (*al) -> standardize (this); if (!aux) aux = *al; // it was a simple variable, and was not standardized. CouNumber expon = al [1] -> Value (); int ind = aux -> Index (); if (fabs (expon - 1.) == 0.) lmap.insert (ind, initCoe); else if (fabs (expon - 2.) == 0.) qmap.insert (ind, ind, initCoe); else { exprAux *aux2 = addAuxiliary (new exprPow (new exprClone (aux), new exprConst (expon))); // TODO: FIX! lmap.insert (aux2 -> Index (), initCoe); } } } break; default: { /// otherwise, simply standardize expression expression *aux = term -> standardize (this); if (!aux) aux = term; lmap.insert (aux -> Index (), initCoe); } break; } }