//----------------------------------------------------------------------- void ConvexBody::mergePolygons( void ) { // Merge all polygons that lay in the same plane as one big polygon. // A convex body does not have two separate regions (separated by polygons // with different normals) where the same normal occurs, so we can simply // search all similar normals of a polygon. Two different options are // possible when the normals fit: // - the two polygons are neighbors // - the two polygons aren't neighbors (but a third, fourth,.. polygon lays // in between) // Signals if the body holds polygons which aren't neighbors but have the same // normal. That means another step has to be processed. bool bDirty = false; for ( size_t iPolyA = 0; iPolyA < getPolygonCount(); ++iPolyA ) { // ?? OgreAssert( iPolyA >= 0, "strange..." ); for ( size_t iPolyB = iPolyA+1; iPolyB < getPolygonCount(); ++iPolyB ) { const Vector3& n1 = getNormal( iPolyA ); const Vector3& n2 = getNormal( iPolyB ); // if the normals point into the same direction if ( n1.directionEquals( n2, Radian( Degree( 0.00001 ) ) ) ) { // indicates if a neighbor has been found and joined bool bFound = false; // search the two fitting vertices (if there are any) for the common edge const size_t numVerticesA = getVertexCount( iPolyA ); for ( size_t iVertexA = 0; iVertexA < numVerticesA; ++iVertexA ) { const size_t numVerticesB = getVertexCount( iPolyB ); for ( size_t iVertexB = 0; iVertexB < numVerticesB; ++iVertexB ) { const Vector3& aCurrent = getVertex( iPolyA, iVertexA ); const Vector3& aNext = getVertex( iPolyA, (iVertexA + 1) % getVertexCount( iPolyA ) ); const Vector3& bCurrent = getVertex( iPolyB, iVertexB ); const Vector3& bNext = getVertex( iPolyB, (iVertexB + 1) % getVertexCount( iPolyB ) ); // if the edge is the same the current vertex of A has to be equal to the next of B and the other // way round if ( aCurrent.positionEquals(bNext) && bCurrent.positionEquals(aNext)) { // polygons are neighbors, assemble new one Polygon *pNew = allocatePolygon(); // insert all vertices of A up to the join (including the common vertex, ignoring // whether the first vertex of A may be a shared vertex) for ( size_t i = 0; i <= iVertexA; ++i ) { pNew->insertVertex( getVertex( iPolyA, i%numVerticesA ) ); } // insert all vertices of B _after_ the join to the end for ( size_t i = iVertexB + 2; i < numVerticesB; ++i ) { pNew->insertVertex( getVertex( iPolyB, i ) ); } // insert all vertices of B from the beginning up to the join (including the common vertex // and excluding the first vertex if the first is part of the shared edge) for ( size_t i = 0; i <= iVertexB; ++i ) { pNew->insertVertex( getVertex( iPolyB, i%numVerticesB ) ); } // insert all vertices of A _after_ the join to the end for ( size_t i = iVertexA + 2; i < numVerticesA; ++i ) { pNew->insertVertex( getVertex( iPolyA, i ) ); } // in case there are double vertices (in special cases), remove them for ( size_t i = 0; i < pNew->getVertexCount(); ++i ) { const Vector3& a = pNew->getVertex( i ); const Vector3& b = pNew->getVertex( (i + 1) % pNew->getVertexCount() ); // if the two vertices are the same... if (a.positionEquals(b)) { // remove a pNew->deleteVertex( i ); // decrement counter --i; } } // delete the two old ones OgreAssert( iPolyA != iPolyB, "PolyA and polyB are the same!" ); // polyB is always higher than polyA, so delete polyB first deletePolygon( iPolyB ); deletePolygon( iPolyA ); // continue with next (current is deleted, so don't jump to the next after the next) --iPolyA; --iPolyB; // insert new polygon insertPolygon( pNew ); bFound = true; break; } } if ( bFound ) { break; } } if ( bFound == false ) { // there are two polygons available with the same normal direction, but they // could not be merged into one single because of no shared edge bDirty = true; break; } } } } // recursion to merge the previous non-neighbors if ( bDirty ) { mergePolygons(); } }
//----------------------------------------------------------------------- void ConvexBody::define(const AxisAlignedBox& aab) { // ordering of the AAB points: // 1-----2 // /| /| // / | / | // 5-----4 | // | 0--|--3 // | / | / // |/ |/ // 6-----7 const Vector3& min = aab.getMinimum(); const Vector3& max = aab.getMaximum(); Vector3 currentVertex = min; Polygon *poly; // reset body reset(); // far poly = allocatePolygon(); poly->insertVertex( currentVertex ); // 0 currentVertex.y = max.y; poly->insertVertex( currentVertex ); // 1 currentVertex.x = max.x; poly->insertVertex( currentVertex ); // 2 currentVertex.y = min.y; poly->insertVertex( currentVertex ); // 3 insertPolygon( poly ); // right poly = allocatePolygon(); poly->insertVertex( currentVertex ); // 3 currentVertex.y = max.y; poly->insertVertex( currentVertex ); // 2 currentVertex.z = max.z; poly->insertVertex( currentVertex ); // 4 currentVertex.y = min.y; poly->insertVertex( currentVertex ); // 7 insertPolygon( poly ); // near poly = allocatePolygon(); poly->insertVertex( currentVertex ); // 7 currentVertex.y = max.y; poly->insertVertex( currentVertex ); // 4 currentVertex.x = min.x; poly->insertVertex( currentVertex ); // 5 currentVertex.y = min.y; poly->insertVertex( currentVertex ); // 6 insertPolygon( poly ); // left poly = allocatePolygon(); poly->insertVertex( currentVertex ); // 6 currentVertex.y = max.y; poly->insertVertex( currentVertex ); // 5 currentVertex.z = min.z; poly->insertVertex( currentVertex ); // 1 currentVertex.y = min.y; poly->insertVertex( currentVertex ); // 0 insertPolygon( poly ); // bottom poly = allocatePolygon(); poly->insertVertex( currentVertex ); // 0 currentVertex.x = max.x; poly->insertVertex( currentVertex ); // 3 currentVertex.z = max.z; poly->insertVertex( currentVertex ); // 7 currentVertex.x = min.x; poly->insertVertex( currentVertex ); // 6 insertPolygon( poly ); // top poly = allocatePolygon(); currentVertex = max; poly->insertVertex( currentVertex ); // 4 currentVertex.z = min.z; poly->insertVertex( currentVertex ); // 2 currentVertex.x = min.x; poly->insertVertex( currentVertex ); // 1 currentVertex.z = max.z; poly->insertVertex( currentVertex ); // 5 insertPolygon( poly ); }
//----------------------------------------------------------------------- void ConvexBody::extend(const Vector3& pt) { // Erase all polygons facing towards the point. For all edges that // are not removed twice (once in AB and once BA direction) build a // convex polygon (triangle) with the point. Polygon::EdgeMap edgeMap; for ( size_t i = 0; i < getPolygonCount(); ++i ) { const Vector3& normal = getNormal( i ); // direction of the point in regard to the polygon // the polygon is planar so we can take an arbitrary vertex Vector3 ptDir = pt - getVertex( i, 0 ); ptDir.normalise(); // remove polygon if dot product is greater or equals null. if ( normal.dotProduct( ptDir ) >= 0 ) { // store edges (copy them because if the polygon is deleted // its vertices are also deleted) storeEdgesOfPolygon( i, &edgeMap ); // remove polygon deletePolygon( i ); // decrement iterator because of deleted polygon --i; } } // point is already a part of the hull (point lies inside) if ( edgeMap.empty() ) return; // remove the edges that are twice in the list (once from each side: AB,BA) Polygon::EdgeMap::iterator it; // iterate from first to the element before the last one for (Polygon::EdgeMap::iterator itStart = edgeMap.begin(); itStart != edgeMap.end(); ) { // compare with iterator + 1 to end // don't need to skip last entry in itStart since omitted in inner loop it = itStart; ++it; bool erased = false; // iterate from itStart+1 to the element before the last one for ( ; it != edgeMap.end(); ++it ) { if (itStart->first.positionEquals(it->second) && itStart->second.positionEquals(it->first)) { edgeMap.erase(it); // increment itStart before deletion (iterator invalidation) Polygon::EdgeMap::iterator delistart = itStart++; edgeMap.erase(delistart); erased = true; break; // found and erased } } // increment itStart if we didn't do it when erasing if (!erased) ++itStart; } // use the remaining edges to build triangles with the point // the vertices of the edges are in ccw order (edgePtA-edgePtB-point // to form a ccw polygon) while ( !edgeMap.empty() ) { Polygon::EdgeMap::iterator mapIt = edgeMap.begin(); // build polygon it.first, it.second, point Polygon *p = allocatePolygon(); p->insertVertex(mapIt->first); p->insertVertex(mapIt->second); p->insertVertex( pt ); // attach polygon to body insertPolygon( p ); // erase the vertices from the list // pointers are now held by the polygon edgeMap.erase( mapIt ); } }
//----------------------------------------------------------------------- void ConvexBody::define( const Vector3 corners[8] ) { // ordering of the AAB points: // 1-----2 // /| /| // / | / | // 5-----4 | // | 0--|--3 // | / | / // |/ |/ // 6-----7 Polygon *poly; // reset body reset(); // far poly = allocatePolygon(); poly->insertVertex( corners[0] ); // 0 poly->insertVertex( corners[1] ); // 1 poly->insertVertex( corners[2] ); // 2 poly->insertVertex( corners[3] ); // 3 insertPolygon( poly ); // right poly = allocatePolygon(); poly->insertVertex( corners[3] ); // 3 poly->insertVertex( corners[2] ); // 2 poly->insertVertex( corners[4] ); // 4 poly->insertVertex( corners[7] ); // 7 insertPolygon( poly ); // near poly = allocatePolygon(); poly->insertVertex( corners[7] ); // 7 poly->insertVertex( corners[4] ); // 4 poly->insertVertex( corners[5] ); // 5 poly->insertVertex( corners[6] ); // 6 insertPolygon( poly ); // left poly = allocatePolygon(); poly->insertVertex( corners[6] ); // 6 poly->insertVertex( corners[5] ); // 5 poly->insertVertex( corners[1] ); // 1 poly->insertVertex( corners[0] ); // 0 insertPolygon( poly ); // bottom poly = allocatePolygon(); poly->insertVertex( corners[0] ); // 0 poly->insertVertex( corners[3] ); // 3 poly->insertVertex( corners[7] ); // 7 poly->insertVertex( corners[6] ); // 6 insertPolygon( poly ); // top poly = allocatePolygon(); poly->insertVertex( corners[4] ); // 4 poly->insertVertex( corners[2] ); // 2 poly->insertVertex( corners[1] ); // 1 poly->insertVertex( corners[5] ); // 5 insertPolygon( poly ); }