void end( const TWallVertexVector& vb, TIntVector& polygon, TIntVector& ib ) { assert( polygonCount ); if( polygonCount == 1 ) { // trivial case, just output input polygon polygon.resize( 0 ); polygon.reserve( vertices.size() ); int idx0 = *vertices.begin(); int idx = idx0; do { polygon.push_back( idx ); const TIntVector& vnext = vertexNexts[idx]; assert( vnext.size() == 1 ); idx = vnext[0]; } while( idx != idx0 ); triangulator::process( vb, polygon, ib ); } else { // mark vertex types markVertexTypes(); // trace and triangulate the polygon(s) traceBorder( vb, polygon, ib ); } }
void CWall3D::fracturePiecesInYRange( float t, float y1, float y2, TIntVector& pcs ) { if( !mPiecesInited ) initPieces(); // fetch the pieces pcs.resize( 0 ); // TODO: optimize, right now linear search! float pieceRestoreTime = t + 1.0e6f; int n = mWall2D.getPieceCount(); for( int i = 0; i < n; ++i ) { const CWallPiece2D& p = mWall2D.getPiece( i ); SVector2 c = p.getAABB().getCenter(); float y = c.y; if( mMatrix.getAxisY().y < 0.5f ) { SVector3 wc; D3DXVec3TransformCoord( &wc, &SVector3(c.x,c.y,0), &mMatrix ); y = wc.y; } if( y >= y1 && y <= y2 ) { mPieceRestoreTimes[i] = pieceRestoreTime; if( mFracturedPieces[i] ) continue; pcs.push_back( i ); fractureOutPiece( i ); } } }
void FactorialFactorization(TLLI n, const TIntVector& primes, TLLIVector* result) { result->resize(primes.size()); for (size_t i = 0; i < primes.size(); ++i) { TLLI power = 0; TLLI nn = n; while (nn) { nn /= primes[i]; power += nn; } (*result)[i] = power; } }
void begin( int totalVerts ) { polygonCount = 0; vertices.clear(); borderVertices.clear(); vertexNexts.clear(); vertexPrevs.clear(); vertexUseCount.resize( 0 ); vertexUseCount.resize( totalVerts, 0 ); vertexTraceID.resize( totalVerts, -1 ); vertexTypes.resize( 0 ); vertexTypes.resize( totalVerts, VTYPE_NONE ); }
bool isVertexInterior( int idx ) { assert( idx >= 0 && idx < vertexUseCount.size() ); // vertex is interior if it's use count is >1, AND // it's all neighbors' use counts are >1, AND it has exactly "usecount" // different neighbors. int useCount = vertexUseCount[idx]; assert( useCount >= 1 ); if( useCount < 2 ) return false; TIntIntsMap::const_iterator it; int i, n; it = vertexNexts.find( idx ); assert( it != vertexNexts.end() ); const TIntVector& vnext = it->second; n = vnext.size(); assert( n == useCount ); for( i = 0; i < n; ++i ) { if( vertexUseCount[vnext[i]] < 2 ) return false; } it = vertexPrevs.find( idx ); assert( it != vertexPrevs.end() ); const TIntVector& vprev = it->second; n = vprev.size(); assert( n == useCount ); for( i = 0; i < n; ++i ) { int nidx = vprev[i]; if( vertexUseCount[nidx] < 2 ) return false; if( std::find( vnext.begin(), vnext.end(), nidx ) == vnext.end() ) return false; } return true; // fall through: must be interior }
void addPolygon( const TIntVector& ib ) { ++polygonCount; TIntVector::const_iterator vit, vitEnd = ib.end(); for( vit = ib.begin(); vit != vitEnd; ++vit ) { int idx = *vit; assert( idx >= 0 && idx < vertexUseCount.size() ); vertices.insert( idx ); ++vertexUseCount[idx]; int idxNext = (vit==vitEnd-1) ? ib.front() : *(vit+1); int idxPrev = (vit==ib.begin()) ? ib.back() : *(vit-1); vertexNexts[idx].push_back( idxNext ); vertexPrevs[idx].push_back( idxPrev ); } }
void Output(const TIntVector& vct) { char buffer[100]; for (size_t i = 0; i < vct.size(); ++i) { int num = vct[i] + 1; char* pBuffer = buffer; while (num) { *pBuffer = (num % 10) + '0'; num /= 10; ++pBuffer; } *pBuffer = 0; std::reverse(buffer, pBuffer); *pBuffer = ' '; ++pBuffer; *pBuffer = 0; fputs(buffer, stdout); } fputs("\n", stdout); }
void CWallPieceCombined::initEnd( TWallQuadNode* quadtree ) { assert( mInitPiece == this ); assert( mInitWall ); // if we're root, just construct the full-wall quad if( mInitRoot ) { assert( mQuadNode == quadtree ); mVB.resize( 4 ); mIB.resize( 6 ); const SVector2& bmin = mBounds.getMin(); const SVector2& bmax = mBounds.getMax(); // VB const SMatrix4x4& mat = mInitWall->getMatrix(); { DWORD nrmCol = gVectorToColor( mat.getAxisZ() ); SVertexXyzDiffuse vtx; vtx.p.set( bmin.x, bmin.y, 0 ); D3DXVec3TransformCoord( &vtx.p, &vtx.p, &mat ); vtx.diffuse = nrmCol; mVB[0] = vtx; vtx.p.set( bmin.x, bmax.y, 0 ); D3DXVec3TransformCoord( &vtx.p, &vtx.p, &mat ); vtx.diffuse = nrmCol; mVB[1] = vtx; vtx.p.set( bmax.x, bmin.y, 0 ); D3DXVec3TransformCoord( &vtx.p, &vtx.p, &mat ); vtx.diffuse = nrmCol; mVB[2] = vtx; vtx.p.set( bmax.x, bmax.y, 0 ); D3DXVec3TransformCoord( &vtx.p, &vtx.p, &mat ); vtx.diffuse = nrmCol; mVB[3] = vtx; } // IB { mIB[0] = 0; mIB[1] = 1; mIB[2] = 2; mIB[3] = 1; mIB[4] = 3; mIB[5] = 2; } mVBSizeNoCaps = mVB.size(); mIBSizeNoCaps = mIB.size(); } else { // for non-roots, construct proper polygon const TWallVertexVector& wallVerts = mInitWall->getWall2D().getVerts(); // merge the polygons TIntVector polygon; TIntVector ibFront; polygon_merger::end( wallVerts, polygon, ibFront ); static TIntVector vertRemap; vertRemap.resize(0); vertRemap.resize( wallVerts.size(), -1 ); int i; int nidx = ibFront.size(); mIB.reserve( nidx + polygon.size()*6 ); mVB.reserve( polygon.size()*3 ); // construct the front side for( i = 0; i < nidx; ++i ) { int oldIdx = ibFront[i]; int newIdx = vertRemap[oldIdx]; if( newIdx < 0 ) { newIdx = mVB.size(); vertRemap[oldIdx] = newIdx; SVector2 pos = wallVerts[oldIdx]; SVector3 pos3( pos.x, pos.y, 0.0f ); D3DXVec3TransformCoord( &pos3, &pos3, &mInitWall->getMatrix() ); SVertexXyzDiffuse vtx; vtx.p = pos3; vtx.diffuse = gVectorToColor( mInitWall->getMatrix().getAxisZ() ); mVB.push_back( vtx ); } mIB.push_back( newIdx ); } // reverse the ordering of triangles for( i = 0; i < nidx/3; ++i ) { int iii = mIB[i*3+1]; mIB[i*3+1] = mIB[i*3+2]; mIB[i*3+2] = iii; } mVBSizeNoCaps = mVB.size(); mIBSizeNoCaps = mIB.size(); // Don't construct the side caps for non-leaf pieces. // I think they never can be seen (not sure) if( !mQuadNode ) { int nverts = mVB.size(); int npolygon = polygon.size(); // Construct side caps. To conserve the geometry amount, // treat them as a single smoothing group. for( i = 0; i < nverts; ++i ) { int oldIdx0 = polygon[i]; int oldIdx1 = polygon[(i+1)%npolygon]; int oldIdx2 = polygon[(i+nverts-1)%npolygon]; int idx0 = vertRemap[oldIdx0]; int idx1 = vertRemap[oldIdx1]; int idx2 = vertRemap[oldIdx2]; assert( idx0 >= 0 && idx0 < nverts ); assert( idx1 >= 0 && idx1 < nverts ); assert( idx2 >= 0 && idx2 < nverts ); SVertexXyzDiffuse v0 = mVB[idx0]; SVertexXyzDiffuse v1 = v0; v1.p -= mInitWall->getMatrix().getAxisZ() * (HALF_THICK*2); const SVertexXyzDiffuse& vnear1 = mVB[idx1]; const SVertexXyzDiffuse& vnear2 = mVB[idx2]; SVector3 edge1 = vnear2.p - vnear1.p; SVector3 edge2 = v1.p - v0.p; SVector3 normal = edge1.cross( edge2 ).getNormalized(); v0.diffuse = v1.diffuse = gVectorToColor( normal ); mVB.push_back( v0 ); mVB.push_back( v1 ); int ibidx0 = i*2 + 0; int ibidx1 = i*2 + 1; int ibidx2 = ((i+1)%nverts)*2 + 0; int ibidx3 = ((i+1)%nverts)*2 + 1; mIB.push_back( ibidx0 ); mIB.push_back( ibidx2 ); mIB.push_back( ibidx1 ); mIB.push_back( ibidx1 ); mIB.push_back( ibidx2 ); mIB.push_back( ibidx3 ); } } } if( !mQuadNode ) { assert( mCombinedPieces.size()==1 ); TWallQuadNode* node = quadtree->getNode( mBounds ); assert( node ); while( node ) { node->getData().leafs.push_back( this ); node = node->getParent(); } } else { // record ourselves in the quadtree assert( !mQuadNode->getData().combined ); mQuadNode->getData().combined = this; } mInitPiece = NULL; mInitWall = NULL; }
int main() { #ifndef ONLINE_JUDGE ifstream fIn("input.txt"); cin.rdbuf( fIn.rdbuf() ); #endif int n; int m; cin >> n >> m; TBoolVector dummy(2*n, false); TMatrix g(2*n, dummy); for (int i = 0; i < m; ++i) { int a; int b; cin >> a >> b; --a; --b; g[a][b] = true; g[b][a] = true; } for (int i = 0; i < 2 * n; ++i) { g[i][i] = true; } TIntVector s; s.push_back(0); int next = 1; do { int i = next; for (; i < 2 * n; ++i) { int j = 0; while (j < s.size() && !g[s[j]][i]) { ++j; } if (j == s.size()) { break; } } if (i == 2 * n) { next = s.back() + 1; s.pop_back(); } else { next = 1; s.push_back(i); } } while (!s.empty() && s.size() != n); if (s.size() == n) { for (int i = 0; i < 2 * n; ++i) { if (find(s.begin(), s.end(), i) != s.end()) { cout << i + 1 << " "; } } cout << endl; for (int i = 0; i < 2 * n; ++i) { if (find(s.begin(), s.end(), i) == s.end()) { cout << i + 1 << " "; } } cout << endl; } else { cout << "IMPOSSIBLE\n"; } return 0; }
int main() { string strProblemName = "stamps"; string strInFile = strProblemName + ".in"; string strOutFile = strProblemName + ".out"; ofstream fout ( strOutFile.c_str() ); ifstream fin ( strInFile.c_str() ); if( !fin ) { cout << "open input file fail!" << endl; return 0; } int nMaxStampNum, nStampValueNum; fin >> nMaxStampNum >> nStampValueNum; for ( int i=0; i<nStampValueNum; ++i ) { fin >> arStampValue[ i ]; } int *arValueSumFlag = new int[MAX_VALUE_SUM+1]; memset( arValueSumFlag, 0, sizeof( arValueSumFlag[0] ) * MAX_VALUE_SUM+1 ); typedef std::vector<int> TIntVector; TIntVector tCurSumValue; tCurSumValue.push_back( 0 ); for ( int i=0; i<nMaxStampNum; ++i ) { TIntVector tNewSumValue; for ( int k=0; k<tCurSumValue.size(); ++k ) { for ( int j = 0; j<nStampValueNum; ++j ) { int nSum = tCurSumValue[k] + arStampValue[ j ]; if ( !arValueSumFlag[nSum] ) { tNewSumValue.push_back( nSum ); arValueSumFlag[nSum] = true; // tAllSumValue.insert( nSum ); } } } tCurSumValue = tNewSumValue; } // 找出连续最多的. int nMaxContinueNum = 0; int nMaxContinueTail = 0; int nLastNum = -1; int nCurContinueNum = 1; // int nCurContinueHead = 0; for ( int i=0; i<MAX_VALUE_SUM; ++i ) { if ( !arValueSumFlag[i] ) { continue; } int nCurNum = i; if ( nLastNum+1 == nCurNum ) { // 连续. nCurContinueNum ++; } else { // 不连续了. nCurContinueNum = 1; } nLastNum = nCurNum; if ( nCurContinueNum > nMaxContinueNum ) { nMaxContinueNum = nCurContinueNum; nMaxContinueTail = nLastNum; } } delete[] arValueSumFlag; fout << nMaxContinueTail << endl; fin.close(); fout.close(); #ifdef THINKINGL cout << "use clock: " << clock() << " / " << CLOCKS_PER_SEC << endl; cout << "-----------begin--dump--output--file----------------" << endl << endl; system( ( string( "type " ) + strOutFile ).c_str() ); cout << endl; system( "pause" ); #endif return 0; }
void traceBorder( const TWallVertexVector& vb, TIntVector& polygon, TIntVector& ib ) { static int traceID = 0; ++traceID; int idx0 = getBorderIndex(); assert( idx0 >= 0 && idx0 < vertexTypes.size() ); ib.resize( 0 ); polygon.resize( 0 ); polygon.reserve( vertices.size()/2 ); TIntVector localPolygon; localPolygon.reserve( 128 ); TIntVector localIB; localIB.reserve( 128 ); int idxPrev = idx0; int idx = idx0; int debugCounter = 0; int debugLoopCounter = 0; do { localIB.resize( 0 ); bool willFormLoop; do{ localPolygon.push_back( idx ); borderVertices.erase( idx ); vertexTraceID[idx] = traceID; assert( ++debugCounter <= vertices.size()*2 ); // Next vertex is the neighbor of current, that is not interior // and that is not the previous one. // When there are many possible ones, trace based on angle. int idxNext = -1; SVector2 prevToCurr = vb[idx] - vb[idxPrev]; if( prevToCurr.lengthSq() < 1.0e-6f ) prevToCurr.set( -0.01f, -0.01f ); TIntIntsMap::const_iterator it; it = vertexNexts.find( idx ); assert( it != vertexNexts.end() ); const TIntVector& vnext = it->second; int n = vnext.size(); float bestAngle = 100.0f; for( int i = 0; i < n; ++i ) { int idx1 = vnext[i]; if( idx1 != idxPrev && vertexTypes[idx1] != VTYPE_INTERIOR ) { //if( idx1 != idxPrev ) { SVector2 currToNext = vb[idx1] - vb[idx]; float ang = signedAngle2D( prevToCurr, currToNext ); if( ang < bestAngle ) { bestAngle = ang; idxNext = idx1; } } } assert( bestAngle > -4.0f && bestAngle < 4.0f ); assert( idxNext >= 0 ); willFormLoop = (vertexTraceID[idxNext] == traceID); // Optimization: if best angle is zero, then we're walking // in a straight line. Optimize out the current vertex. if( bestAngle == 0.0f && idx != idx0 && !willFormLoop ) { localPolygon.pop_back(); } idxPrev = idx; idx = idxNext; } while( !willFormLoop ); assert( localPolygon.size() >= 3 ); //if( localPolygon.size() < 3 ) { // return; //} assert( ++debugLoopCounter < vertices.size() ); if( idx == idx0 ) { // The polygon is simple or we found the last loop. // Triangulate local and append to results. triangulator::process( vb, localPolygon, localIB ); polygon.insert( polygon.end(), localPolygon.begin(), localPolygon.end() ); ib.insert( ib.end(), localIB.begin(), localIB.end() ); // We can have separated other loops. Try fetching them as well. idx0 = getBorderIndex(); if( idx0 == -1 ) { return; } else { localPolygon.resize( 0 ); idxPrev = idx0; idx = idx0; } } else { // The polygon must be complex, and we just found a closed loop. // Take only the loop, triangulate it, append to results, continue. TIntVector::const_iterator itLoopStart = std::find( localPolygon.begin(), localPolygon.end(), idx ); assert( itLoopStart != localPolygon.end() ); // append to results TIntVector loopPolygon( itLoopStart, localPolygon.end() ); triangulator::process( vb, loopPolygon, localIB ); polygon.insert( polygon.end(), loopPolygon.begin(), loopPolygon.end() ); ib.insert( ib.end(), localIB.begin(), localIB.end() ); // continue - remove the looped polygon from local localPolygon.resize( itLoopStart - localPolygon.begin() ); } } while( true ); }
int main() { TIntVector primes; { TBoolVector erato(N + 1, true); for (size_t i = 2; i < N; ++i) { if (erato[i]) { if (i > 1000) { primes.push_back(static_cast<int>(i)); } for (size_t j = i + i; j < erato.size(); j += i) { erato[j] = false; } } } } printf("Primes: %d\n", static_cast<int>(primes.size())); /* TLLIVector powerLB1; FactorialFactorization(LB, primes, &powerLB1); TLLIVector powerLB2; FactorialFactorization(UB - LB, primes, &powerLB2); TLLIVector powerUB; FactorialFactorization(UB, primes, &powerUB); TLLIVector primePowers(primes.size()); size_t zeroes = 0; for (size_t i = 0; i < primes.size(); ++i) { TLLI primePower = powerUB[i] - powerLB1[i] - powerLB2[i]; if (0 == primePower) { ++zeroes; } primePowers[i] = primePower; printf("%d %d\n", static_cast<int>(primes[i]), static_cast<int>(primePower)); } printf("Zeroes: %d\n", static_cast<int>(zeroes)); for (size_t i = 0; i < primes.size(); ++i) { if (!primePowers[i]) { printf("...%d\n", static_cast<int>(i)); int modi = BinomialModPrime(UB, LB, primes[i]); for (size_t j = 0; j < primes.size(); ++j) { if (!primePowers[j]) { int modj = BinomialModPrime(UB, LB, primes[j]); for (size_t k = 0; k < primes.size(); ++k) { if (!primePowers[k]) { int modk = BinomialModPrime(UB, LB, primes[k]); } } } } } } */ for (size_t i = 0; i < primes.size(); ++i) { printf("...%d\n", static_cast<int>(i)); int modi = BinomialModPrime(UB, LB, primes[i]); for (size_t j = 0; j < primes.size(); ++j) { int modj = BinomialModPrime(UB, LB, primes[j]); { for (size_t k = 0; k < primes.size(); ++k) { int modk = BinomialModPrime(UB, LB, primes[k]); printf("%d %d %d\n", modi, modj, modk); } } } } return 0; }
void Out(const TIntVector& v) { for (TIntVector::const_iterator i = v.begin(); i != v.end(); ++i) printf("%c", 'A' + *i); }
int Len(TIntVector v, bool print) { int result = 0; if (print) { Out(v); printf("\n"); } for (size_t i = 0; i < v.size(); ++i) { size_t j = 0; while ( v[j] != i ) ++j; if (j != i) { TIntVector nw; for (size_t k = 0; k < i; ++k) nw.push_back(v[k]); if (j + 1 != v.size()) { for (size_t k = j; k < v.size(); ++k) nw.push_back(v[k]); for (size_t k = i; k < j; ++k) nw.push_back(v[i + (j - k) - 1]); result += 2; } else { for (size_t k = i; k < v.size(); ++k) nw.push_back(v[v.size() - k + i - 1]); ++result; } v.swap(nw); if (print) { Out(v); printf(" %d\n", result); } } } return result; }
void CWall3D::fracturePiecesInSphere( float t, const SVector3& pos, float radius, TIntVector& pcs, float restoreAfter, float restoreDuration, bool noRestore ) { if( !mPiecesInited ) initPieces(); pcs.resize( 0 ); // to local space SVector3 locPos; D3DXVec3TransformCoord( &locPos, &pos, &mInvMatrix ); if( locPos.z < -radius || locPos.z > radius ) return; // remember restore times if( mResTimeGrid && !noRestore ) { float rad = radius*2.0f; float lx1 = (locPos.x - rad) / mWall2D.getSize().x * RESGRID_X; float lx2 = (locPos.x + rad) / mWall2D.getSize().x * RESGRID_X; float ly1 = (locPos.y - rad) / mWall2D.getSize().y * RESGRID_Y; float ly2 = (locPos.y + rad) / mWall2D.getSize().y * RESGRID_Y; int ix1 = (int)clamp( lx1, 0, RESGRID_X-1 ); int ix2 = (int)clamp( lx2, 0, RESGRID_X-1 ); int iy1 = (int)clamp( ly1, 0, RESGRID_Y-1 ); int iy2 = (int)clamp( ly2, 0, RESGRID_Y-1 ); float dx = mWall2D.getSize().x / RESGRID_X; float dy = mWall2D.getSize().y / RESGRID_Y; for( int iy = iy1; iy <= iy2; ++iy ) { float* resval = mResTimeGrid + RESGRID_X*iy + ix1; float fy = iy * dy; for( int ix = ix1; ix <= ix2; ++ix, ++resval ) { float fx = ix * dx; // don't touch restore grid outside the circle float diffX = fx-locPos.x; float diffY = fy-locPos.y; float diffR2 = diffX*diffX + diffY*diffY; if( diffR2 > rad*rad ) continue; // restore time for this grid point - start at // t+restoreAfter at circle boundaries, later at circle // center float resTime = t + restoreAfter + (1.0f-diffR2/(rad*rad)) * restoreDuration; if( *resval < 0.0f ) *resval = resTime; else *resval = max( (*resval), resTime ); } } } // fetch the pieces float pieceRestoreTime; if( noRestore ) { pieceRestoreTime = t + 1.0e9f; } else { pieceRestoreTime = t + restoreAfter + restoreDuration; } // TODO: optimize, right now linear search! int n = mWall2D.getPieceCount(); for( int i = 0; i < n; ++i ) { const CWallPiece2D& p = mWall2D.getPiece( i ); SVector2 c = p.getAABB().getCenter(); SVector3 tocenter = locPos - SVector3(c.x,c.y,0); if( tocenter.lengthSq() < radius*radius ) { mPieceRestoreTimes[i] = pieceRestoreTime; if( mFracturedPieces[i] ) continue; pcs.push_back( i ); fractureOutPiece( i ); } } }
namespace polygon_merger { int polygonCount; typedef std::set<int> TIntSet; TIntSet vertices; TIntSet borderVertices; typedef std::map< int, TIntVector > TIntIntsMap; TIntIntsMap vertexNexts; TIntIntsMap vertexPrevs; TIntVector vertexUseCount; TIntVector vertexTraceID; enum eVertexType { VTYPE_NONE, ///< Not computed yet VTYPE_INTERIOR, ///< Completely interior VTYPE_SINGLE, ///< On the border, belongs to single polygon VTYPE_MULTI, ///< On the border, belongs to multiple polygons VTYPE_DONE, ///< Already fully processed (traced into result polygon) }; TIntVector vertexTypes; bool isVertexInterior( int idx ) { assert( idx >= 0 && idx < vertexUseCount.size() ); // vertex is interior if it's use count is >1, AND // it's all neighbors' use counts are >1, AND it has exactly "usecount" // different neighbors. int useCount = vertexUseCount[idx]; assert( useCount >= 1 ); if( useCount < 2 ) return false; TIntIntsMap::const_iterator it; int i, n; it = vertexNexts.find( idx ); assert( it != vertexNexts.end() ); const TIntVector& vnext = it->second; n = vnext.size(); assert( n == useCount ); for( i = 0; i < n; ++i ) { if( vertexUseCount[vnext[i]] < 2 ) return false; } it = vertexPrevs.find( idx ); assert( it != vertexPrevs.end() ); const TIntVector& vprev = it->second; n = vprev.size(); assert( n == useCount ); for( i = 0; i < n; ++i ) { int nidx = vprev[i]; if( vertexUseCount[nidx] < 2 ) return false; if( std::find( vnext.begin(), vnext.end(), nidx ) == vnext.end() ) return false; } return true; // fall through: must be interior } void markVertexTypes() { TIntSet::const_iterator vit, vitEnd = vertices.end(); // first pass: mark all interior and single-border vertices for( vit = vertices.begin(); vit != vitEnd; ++vit ) { int idx = *vit; if( vertexUseCount[idx] == 1 ) { vertexTypes[idx] = VTYPE_SINGLE; borderVertices.insert( idx ); } else if( isVertexInterior(idx) ) vertexTypes[idx] = VTYPE_INTERIOR; } // now, the unmarked vertices are all shared and on border for( vit = vertices.begin(); vit != vitEnd; ++vit ) { int idx = *vit; if( vertexTypes[idx] == VTYPE_NONE ) { vertexTypes[idx] = VTYPE_MULTI; borderVertices.insert( idx ); } } } int getBorderIndex() { if( borderVertices.empty() ) return -1; return *borderVertices.begin(); } void traceBorder( const TWallVertexVector& vb, TIntVector& polygon, TIntVector& ib ) { static int traceID = 0; ++traceID; int idx0 = getBorderIndex(); assert( idx0 >= 0 && idx0 < vertexTypes.size() ); ib.resize( 0 ); polygon.resize( 0 ); polygon.reserve( vertices.size()/2 ); TIntVector localPolygon; localPolygon.reserve( 128 ); TIntVector localIB; localIB.reserve( 128 ); int idxPrev = idx0; int idx = idx0; int debugCounter = 0; int debugLoopCounter = 0; do { localIB.resize( 0 ); bool willFormLoop; do{ localPolygon.push_back( idx ); borderVertices.erase( idx ); vertexTraceID[idx] = traceID; assert( ++debugCounter <= vertices.size()*2 ); // Next vertex is the neighbor of current, that is not interior // and that is not the previous one. // When there are many possible ones, trace based on angle. int idxNext = -1; SVector2 prevToCurr = vb[idx] - vb[idxPrev]; if( prevToCurr.lengthSq() < 1.0e-6f ) prevToCurr.set( -0.01f, -0.01f ); TIntIntsMap::const_iterator it; it = vertexNexts.find( idx ); assert( it != vertexNexts.end() ); const TIntVector& vnext = it->second; int n = vnext.size(); float bestAngle = 100.0f; for( int i = 0; i < n; ++i ) { int idx1 = vnext[i]; if( idx1 != idxPrev && vertexTypes[idx1] != VTYPE_INTERIOR ) { //if( idx1 != idxPrev ) { SVector2 currToNext = vb[idx1] - vb[idx]; float ang = signedAngle2D( prevToCurr, currToNext ); if( ang < bestAngle ) { bestAngle = ang; idxNext = idx1; } } } assert( bestAngle > -4.0f && bestAngle < 4.0f ); assert( idxNext >= 0 ); willFormLoop = (vertexTraceID[idxNext] == traceID); // Optimization: if best angle is zero, then we're walking // in a straight line. Optimize out the current vertex. if( bestAngle == 0.0f && idx != idx0 && !willFormLoop ) { localPolygon.pop_back(); } idxPrev = idx; idx = idxNext; } while( !willFormLoop ); assert( localPolygon.size() >= 3 ); //if( localPolygon.size() < 3 ) { // return; //} assert( ++debugLoopCounter < vertices.size() ); if( idx == idx0 ) { // The polygon is simple or we found the last loop. // Triangulate local and append to results. triangulator::process( vb, localPolygon, localIB ); polygon.insert( polygon.end(), localPolygon.begin(), localPolygon.end() ); ib.insert( ib.end(), localIB.begin(), localIB.end() ); // We can have separated other loops. Try fetching them as well. idx0 = getBorderIndex(); if( idx0 == -1 ) { return; } else { localPolygon.resize( 0 ); idxPrev = idx0; idx = idx0; } } else { // The polygon must be complex, and we just found a closed loop. // Take only the loop, triangulate it, append to results, continue. TIntVector::const_iterator itLoopStart = std::find( localPolygon.begin(), localPolygon.end(), idx ); assert( itLoopStart != localPolygon.end() ); // append to results TIntVector loopPolygon( itLoopStart, localPolygon.end() ); triangulator::process( vb, loopPolygon, localIB ); polygon.insert( polygon.end(), loopPolygon.begin(), loopPolygon.end() ); ib.insert( ib.end(), localIB.begin(), localIB.end() ); // continue - remove the looped polygon from local localPolygon.resize( itLoopStart - localPolygon.begin() ); } } while( true ); } void begin( int totalVerts ) { polygonCount = 0; vertices.clear(); borderVertices.clear(); vertexNexts.clear(); vertexPrevs.clear(); vertexUseCount.resize( 0 ); vertexUseCount.resize( totalVerts, 0 ); vertexTraceID.resize( totalVerts, -1 ); vertexTypes.resize( 0 ); vertexTypes.resize( totalVerts, VTYPE_NONE ); } void addPolygon( const TIntVector& ib ) { ++polygonCount; TIntVector::const_iterator vit, vitEnd = ib.end(); for( vit = ib.begin(); vit != vitEnd; ++vit ) { int idx = *vit; assert( idx >= 0 && idx < vertexUseCount.size() ); vertices.insert( idx ); ++vertexUseCount[idx]; int idxNext = (vit==vitEnd-1) ? ib.front() : *(vit+1); int idxPrev = (vit==ib.begin()) ? ib.back() : *(vit-1); vertexNexts[idx].push_back( idxNext ); vertexPrevs[idx].push_back( idxPrev ); } } void end( const TWallVertexVector& vb, TIntVector& polygon, TIntVector& ib ) { assert( polygonCount ); if( polygonCount == 1 ) { // trivial case, just output input polygon polygon.resize( 0 ); polygon.reserve( vertices.size() ); int idx0 = *vertices.begin(); int idx = idx0; do { polygon.push_back( idx ); const TIntVector& vnext = vertexNexts[idx]; assert( vnext.size() == 1 ); idx = vnext[0]; } while( idx != idx0 ); triangulator::process( vb, polygon, ib ); } else { // mark vertex types markVertexTypes(); // trace and triangulate the polygon(s) traceBorder( vb, polygon, ib ); } } }; // namespace polygon_merger
void CWallPiece3D::init( const CWall3D& w, int idx ) { const CWallPiece2D& piece = w.getWall2D().getPiece(idx); // construct VB/IB for this piece, with positions centered SVector2 pcenter = piece.getAABB().getCenter(); static TIntVector vertRemap; vertRemap.resize(0); vertRemap.resize( w.getWall2D().getVerts().size(), -1 ); int i; int nidx = piece.getTriCount()*3; mIB.reserve( nidx * 2 + piece.getVertexCount()*6 ); mVB.reserve( piece.getVertexCount()*4 ); // construct one side for( i = 0; i < nidx; ++i ) { int oldIdx = piece.getIB()[i]; int newIdx = vertRemap[oldIdx]; if( newIdx < 0 ) { newIdx = mVB.size(); vertRemap[oldIdx] = newIdx; SVector2 pos = w.getWall2D().getVerts()[oldIdx]; pos -= pcenter; SVertexXyzNormal vtx; vtx.p.set( pos.x, pos.y, HALF_THICK ); vtx.n.set( 0, 0, 1 ); mVB.push_back( vtx ); } mIB.push_back( newIdx ); } for( i = 0; i < nidx/3; ++i ) { int iii = mIB[i*3+1]; mIB[i*3+1] = mIB[i*3+2]; mIB[i*3+2] = iii; } // construct another side int nverts = mVB.size(); //int npolygon = piece.getPolygon().size(); for( i = 0; i < nverts; ++i ) { SVertexXyzNormal vtx = mVB[i]; vtx.p.z = -vtx.p.z; vtx.n.set( 0,0, -1 ); mVB.push_back( vtx ); } for( i = 0; i < nidx/3; ++i ) { int idx0 = mIB[i*3+0]; int idx1 = mIB[i*3+1]; int idx2 = mIB[i*3+2]; mIB.push_back( idx0 + nverts ); mIB.push_back( idx2 + nverts ); mIB.push_back( idx1 + nverts ); } // construct side caps. To conserve the geometry amount, // treat them as a single smoothing group. assert( nverts == piece.getVertexCount() ); for( i = 0; i < nverts; ++i ) { int oldIdx0 = piece.getPolygon()[i]; int oldIdx1 = piece.getPolygon()[(i+1)%nverts]; int oldIdx2 = piece.getPolygon()[(i+nverts-1)%nverts]; int idx0 = vertRemap[oldIdx0]; int idx1 = vertRemap[oldIdx1]; int idx2 = vertRemap[oldIdx2]; assert( idx0 >= 0 && idx0 < nverts ); assert( idx1 >= 0 && idx1 < nverts ); assert( idx2 >= 0 && idx2 < nverts ); SVertexXyzNormal v0 = mVB[idx0]; SVertexXyzNormal v1 = v0; v1.p.z = -v1.p.z; const SVertexXyzNormal& vnear1 = mVB[idx1]; const SVertexXyzNormal& vnear2 = mVB[idx2]; SVector3 edge1 = vnear2.p - vnear1.p; SVector3 edge2 = v1.p - v0.p; SVector3 normal = edge1.cross( edge2 ).getNormalized(); v0.n = v1.n = normal; mVB.push_back( v0 ); mVB.push_back( v1 ); int ibidx0 = nverts*2 + i*2 + 0; int ibidx1 = nverts*2 + i*2 + 1; int ibidx2 = nverts*2 + ((i+1)%nverts)*2 + 0; int ibidx3 = nverts*2 + ((i+1)%nverts)*2 + 1; mIB.push_back( ibidx0 ); mIB.push_back( ibidx2 ); mIB.push_back( ibidx1 ); mIB.push_back( ibidx1 ); mIB.push_back( ibidx2 ); mIB.push_back( ibidx3 ); } // construct initial mMatrix mMatrix.identify(); mMatrix = w.getMatrix(); mMatrix.getOrigin() += mMatrix.getAxisX() * pcenter.x; mMatrix.getOrigin() += mMatrix.getAxisY() * pcenter.y; mSize.set( piece.getAABB().getSize().x, piece.getAABB().getSize().y, HALF_THICK*2 ); }