コード例 #1
0
ファイル: Wm5ContMinBox2.cpp プロジェクト: kanbang/myexercise
    MinBox2<Real>::MinBox2 ( int numPoints, const Vector2<Real>* points,
                             Real epsilon, Query::Type queryType, bool isConvexPolygon )
    {
        // Get the convex hull of the points.
        Vector2<Real>* hullPoints = 0;
        if ( isConvexPolygon )
        {
            hullPoints = ( Vector2<Real>* )points;
        }
        else
        {
            ConvexHull2<Real> hull( numPoints, ( Vector2<Real>* )points, epsilon,
                                    false, queryType );
            int hullDim = hull.GetDimension();
            int hullNumSimplices = hull.GetNumSimplices();
            const int* hullIndices = hull.GetIndices();

            if ( hullDim == 0 )
            {
                mMinBox.Center = points[0];
                mMinBox.Axis[0] = Vector2<Real>::UNIT_X;
                mMinBox.Axis[1] = Vector2<Real>::UNIT_Y;
                mMinBox.Extent[0] = ( Real )0;
                mMinBox.Extent[1] = ( Real )0;
                return;
            }

            if ( hullDim == 1 )
            {
                ConvexHull1<Real>* hull1 = hull.GetConvexHull1();
                hullIndices = hull1->GetIndices();

                mMinBox.Center = ( ( Real )0.5 ) * ( points[hullIndices[0]] +
                                                     points[hullIndices[1]] );
                Vector2<Real> diff =
                    points[hullIndices[1]] - points[hullIndices[0]];
                mMinBox.Extent[0] = ( ( Real )0.5 ) * diff.Normalize();
                mMinBox.Extent[1] = ( Real )0.0;
                mMinBox.Axis[0] = diff;
                mMinBox.Axis[1] = -mMinBox.Axis[0].Perp();

                delete0( hull1 );
                return;
            }

            numPoints = hullNumSimplices;
            hullPoints = new1<Vector2<Real> >( numPoints );
            for ( int i = 0; i < numPoints; ++i )
            {
                hullPoints[i] = points[hullIndices[i]];
            }
        }

        // The input points are V[0] through V[N-1] and are assumed to be the
        // vertices of a convex polygon that are counterclockwise ordered.  The
        // input points must not contain three consecutive collinear points.

        // Unit-length edge directions of convex polygon.  These could be
        // precomputed and passed to this routine if the application requires it.
        int numPointsM1 = numPoints - 1;
        Vector2<Real>* edges = new1<Vector2<Real> >( numPoints );
        bool* visited = new1<bool>( numPoints );
        int i;
        for ( i = 0; i < numPointsM1; ++i )
        {
            edges[i] = hullPoints[i + 1] - hullPoints[i];
            edges[i].Normalize();
            visited[i] = false;
        }
        edges[numPointsM1] = hullPoints[0] - hullPoints[numPointsM1];
        edges[numPointsM1].Normalize();
        visited[numPointsM1] = false;

        // Find the smallest axis-aligned box containing the points.  Keep track
        // of the extremum indices, L (left), R (right), B (bottom), and T (top)
        // so that the following constraints are met:
        //   V[L].X() <= V[i].X() for all i and V[(L+1)%N].X() > V[L].X()
        //   V[R].X() >= V[i].X() for all i and V[(R+1)%N].X() < V[R].X()
        //   V[B].Y() <= V[i].Y() for all i and V[(B+1)%N].Y() > V[B].Y()
        //   V[T].Y() >= V[i].Y() for all i and V[(T+1)%N].Y() < V[T].Y()
        Real xmin = hullPoints[0].X(), xmax = xmin;
        Real ymin = hullPoints[0].Y(), ymax = ymin;
        int LIndex = 0, RIndex = 0, BIndex = 0, TIndex = 0;
        for ( i = 1; i < numPoints; ++i )
        {
            if ( hullPoints[i].X() <= xmin )
            {
                xmin = hullPoints[i].X();
                LIndex = i;
            }
            if ( hullPoints[i].X() >= xmax )
            {
                xmax = hullPoints[i].X();
                RIndex = i;
            }

            if ( hullPoints[i].Y() <= ymin )
            {
                ymin = hullPoints[i].Y();
                BIndex = i;
            }
            if ( hullPoints[i].Y() >= ymax )
            {
                ymax = hullPoints[i].Y();
                TIndex = i;
            }
        }

        // Apply wrap-around tests to ensure the constraints mentioned above are
        // satisfied.
        if ( LIndex == numPointsM1 )
        {
            if ( hullPoints[0].X() <= xmin )
            {
                xmin = hullPoints[0].X();
                LIndex = 0;
            }
        }

        if ( RIndex == numPointsM1 )
        {
            if ( hullPoints[0].X() >= xmax )
            {
                xmax = hullPoints[0].X();
                RIndex = 0;
            }
        }

        if ( BIndex == numPointsM1 )
        {
            if ( hullPoints[0].Y() <= ymin )
            {
                ymin = hullPoints[0].Y();
                BIndex = 0;
            }
        }

        if ( TIndex == numPointsM1 )
        {
            if ( hullPoints[0].Y() >= ymax )
            {
                ymax = hullPoints[0].Y();
                TIndex = 0;
            }
        }

        // The dimensions of the axis-aligned box.  The extents store width and
        // height for now.
        mMinBox.Center.X() = ( ( Real )0.5 ) * ( xmin + xmax );
        mMinBox.Center.Y() = ( ( Real )0.5 ) * ( ymin + ymax );
        mMinBox.Axis[0] = Vector2<Real>::UNIT_X;
        mMinBox.Axis[1] = Vector2<Real>::UNIT_Y;
        mMinBox.Extent[0] = ( ( Real )0.5 ) * ( xmax - xmin );
        mMinBox.Extent[1] = ( ( Real )0.5 ) * ( ymax - ymin );
        Real minAreaDiv4 = mMinBox.Extent[0] * mMinBox.Extent[1];

        // The rotating calipers algorithm.
        Vector2<Real> U = Vector2<Real>::UNIT_X;
        Vector2<Real> V = Vector2<Real>::UNIT_Y;

        bool done = false;
        while ( !done )
        {
            // Determine the edge that forms the smallest angle with the current
            // box edges.
            int flag = F_NONE;
            Real maxDot = ( Real )0;

            Real dot = U.Dot( edges[BIndex] );
            if ( dot > maxDot )
            {
                maxDot = dot;
                flag = F_BOTTOM;
            }

            dot = V.Dot( edges[RIndex] );
            if ( dot > maxDot )
            {
                maxDot = dot;
                flag = F_RIGHT;
            }

            dot = -U.Dot( edges[TIndex] );
            if ( dot > maxDot )
            {
                maxDot = dot;
                flag = F_TOP;
            }

            dot = -V.Dot( edges[LIndex] );
            if ( dot > maxDot )
            {
                maxDot = dot;
                flag = F_LEFT;
            }

            switch ( flag )
            {
            case F_BOTTOM:
                if ( visited[BIndex] )
                {
                    done = true;
                }
                else
                {
                    // Compute box axes with E[B] as an edge.
                    U = edges[BIndex];
                    V = -U.Perp();
                    UpdateBox( hullPoints[LIndex], hullPoints[RIndex],
                               hullPoints[BIndex], hullPoints[TIndex], U, V,
                               minAreaDiv4 );

                    // Mark edge visited and rotate the calipers.
                    visited[BIndex] = true;
                    if ( ++BIndex == numPoints )
                    {
                        BIndex = 0;
                    }
                }
                break;
            case F_RIGHT:
                if ( visited[RIndex] )
                {
                    done = true;
                }
                else
                {
                    // Compute box axes with E[R] as an edge.
                    V = edges[RIndex];
                    U = V.Perp();
                    UpdateBox( hullPoints[LIndex], hullPoints[RIndex],
                               hullPoints[BIndex], hullPoints[TIndex], U, V,
                               minAreaDiv4 );

                    // Mark edge visited and rotate the calipers.
                    visited[RIndex] = true;
                    if ( ++RIndex == numPoints )
                    {
                        RIndex = 0;
                    }
                }
                break;
            case F_TOP:
                if ( visited[TIndex] )
                {
                    done = true;
                }
                else
                {
                    // Compute box axes with E[T] as an edge.
                    U = -edges[TIndex];
                    V = -U.Perp();
                    UpdateBox( hullPoints[LIndex], hullPoints[RIndex],
                               hullPoints[BIndex], hullPoints[TIndex], U, V,
                               minAreaDiv4 );

                    // Mark edge visited and rotate the calipers.
                    visited[TIndex] = true;
                    if ( ++TIndex == numPoints )
                    {
                        TIndex = 0;
                    }
                }
                break;
            case F_LEFT:
                if ( visited[LIndex] )
                {
                    done = true;
                }
                else
                {
                    // Compute box axes with E[L] as an edge.
                    V = -edges[LIndex];
                    U = V.Perp();
                    UpdateBox( hullPoints[LIndex], hullPoints[RIndex],
                               hullPoints[BIndex], hullPoints[TIndex], U, V,
                               minAreaDiv4 );

                    // Mark edge visited and rotate the calipers.
                    visited[LIndex] = true;
                    if ( ++LIndex == numPoints )
                    {
                        LIndex = 0;
                    }
                }
                break;
            case F_NONE:
                // The polygon is a rectangle.
                done = true;
                break;
            }
        }

        delete1( visited );
        delete1( edges );
        if ( !isConvexPolygon )
        {
            delete1( hullPoints );
        }
    }