Exemplo n.º 1
0
bool
pointTest(const std::vector<Path>& paths,
        const std::vector<LineStyle>& lineStyles, boost::int32_t x,
        boost::int32_t y, const SWFMatrix& wm)
{

    /*
    Principle:
    For the fill of the shape, we project a ray from the test point to the left
    side of the shape counting all crossings. When a line or curve segment is
    crossed we add 1 if the left fill style is set. Regardless of the left fill
    style we subtract 1 from the counter then the right fill style is set.
    This is true when the line goes in downward direction. If it goes upward,
    the fill styles are reversed.

    The final counter value reveals if the point is inside the shape (and
    depends on filling rule, see below).
    This method should not depend on subshapes and work for some malformed
    shapes situations:
    - wrong fill side (eg. left side set for a clockwise drawen rectangle)
    - intersecting paths
    */
    point pt(x, y);

    // later we will need non-zero for glyphs... (TODO)
    bool even_odd = true;  

    unsigned npaths = paths.size();
    int counter = 0;

    // browse all paths
    for (unsigned pno=0; pno<npaths; pno++)
    {
        const Path& pth = paths[pno];
        unsigned nedges = pth.m_edges.size();

        float next_pen_x = pth.ap.x;
        float next_pen_y = pth.ap.y;
        float pen_x, pen_y;

        if (pth.empty()) continue;

        // If the path has a line style, check for strokes there
        if (pth.m_line != 0 )
        {
            assert(lineStyles.size() >= pth.m_line);
            const LineStyle& ls = lineStyles[pth.m_line-1];
            double thickness = ls.getThickness();
            if (! thickness )
            {
                thickness = 20; // at least ONE PIXEL thick.
            }
            else if ((!ls.scaleThicknessVertically()) &&
                    (!ls.scaleThicknessHorizontally()) )
            {
                // TODO: pass the SWFMatrix to withinSquareDistance instead ?
                double xScale = wm.get_x_scale();
                double yScale = wm.get_y_scale();
                thickness *= std::max(xScale, yScale);
            }
            else if (ls.scaleThicknessVertically() != 
                    ls.scaleThicknessHorizontally())
            {
                LOG_ONCE(log_unimpl(_("Collision detection for "
                                      "unidirectionally scaled strokes")));
            }

            double dist = thickness / 2.0;
            double sqdist = dist * dist;
            if (pth.withinSquareDistance(pt, sqdist))
                return true;
        }

        // browse all edges of the path
        for (unsigned eno=0; eno<nedges; eno++)
        {
            const Edge& edg = pth.m_edges[eno];
            pen_x = next_pen_x;
            pen_y = next_pen_y;
            next_pen_x = edg.ap.x;
            next_pen_y = edg.ap.y;

            float cross1 = 0.0, cross2 = 0.0;
            int dir1 = 0, dir2 = 0; // +1 = downward, -1 = upward
            int crosscount = 0;

            if (edg.straight())
            {
                // ignore horizontal lines
                // TODO: better check for small difference?
                if (edg.ap.y == pen_y)  
                {
                    continue;
                }
                // does this line cross the Y coordinate?
                if ( ((pen_y <= y) && (edg.ap.y >= y))
                    || ((pen_y >= y) && (edg.ap.y <= y)) )
                {

                    // calculate X crossing
                    cross1 = pen_x + (edg.ap.x - pen_x) *
                        (y - pen_y) / (edg.ap.y - pen_y);

                    if (pen_y > edg.ap.y)
                        dir1 = -1;  // upward
                    else
                        dir1 = +1;  // downward

                    crosscount = 1;
                }
                else
                {
                    // no crossing found
                    crosscount = 0;
                }
            }
            else {
                // ==> curve case
                crosscount = 
                    curve_x_crossings<float>(pen_x, pen_y, edg.ap.x, edg.ap.y,
                        edg.cp.x, edg.cp.y, y, cross1, cross2);
                dir1 = pen_y > y ? -1 : +1;
                dir2 = dir1 * (-1); // second crossing always in opposite dir.
            } // curve

            // ==> we have now:
            //  - one (cross1) or two (cross1, cross2) ray crossings (X
            //    coordinate)
            //  - dir1/dir2 tells the direction of the crossing
            //    (+1 = downward, -1 = upward)
            //  - crosscount tells the number of crossings

            // need at least one crossing
            if (crosscount == 0)
            {
                continue;
            }

            // check first crossing
            if (cross1 <= x)
            {
                if (pth.m_fill0 > 0) counter += dir1;
                if (pth.m_fill1 > 0) counter -= dir1;
            }

            // check optional second crossing (only possible with curves)
            if ( (crosscount > 1) && (cross2 <= x) )
            {
                if (pth.m_fill0 > 0) counter += dir2;
                if (pth.m_fill1 > 0) counter -= dir2;
            }

        }// for edge
    } // for path

    return ( (even_odd && (counter % 2) != 0) ||
             (!even_odd && (counter != 0)) );
}
Exemplo n.º 2
0
int
main(int /*argc*/, char** /*argv*/)
{
    // 
    // Test boost types, SWFMatrix design is rely on this.
    // 
    // Note: If any of the following tests fails, your boost library
    // is bogus or hasn't been installed properly.
    // 
    check_equals(sizeof(boost::int8_t),   1);
    check_equals(sizeof(boost::uint8_t),  1);
    check_equals(sizeof(boost::int16_t),  2);
    check_equals(sizeof(boost::uint16_t), 2);
    check_equals(sizeof(boost::int32_t),  4);
    check_equals(sizeof(boost::uint32_t), 4);
    check_equals(sizeof(boost::int64_t),  8);
    check_equals(sizeof(boost::uint64_t), 8);

    // 
    //  Test identity SWFMatrix.
    // 
    SWFMatrix identity; 
    check(identity.is_valid());
    check_equals(identity.get_x_scale(), 1);
    check_equals(identity.get_y_scale(), 1);
    check_equals(identity.get_rotation(), 0);
    check_equals(identity.get_x_translation(), 0);
    check_equals(identity.get_y_translation(), 0);

    check_equals(identity.invert(), identity);

    //
    // Test parameter setting and getting, interfaces for AS.
    //
    SWFMatrix m1;
    m1.set_scale_rotation(1, 3, 0);
    check_equals(m1.get_x_scale(), 1);
    check_equals(m1.get_y_scale(), 3);
    check_equals(m1.get_rotation(), 0);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_scale(1.5, 2.5);
    check_equals(D(m1.get_x_scale()), 1.5);
    check_equals(D(m1.get_y_scale()), 2.5);
    check_equals(D(m1.get_rotation()), 0);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_scale(34, 4);
    check_equals(D(m1.get_x_scale()), 34);
    check_equals(D(m1.get_y_scale()), 4);
    check_equals(D(m1.get_rotation()), 0);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_scale_rotation(1, 1, 2);
    check_equals(D(m1.get_x_scale()), 1);
    check_equals(D(m1.get_y_scale()), 1);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_x_scale(2);
    check_equals(D(m1.get_x_scale()), 2);
    check_equals(D(m1.get_y_scale()), 1);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_scale(1, 2);
    check_equals(D(m1.get_x_scale()), 1);
    check_equals(D(m1.get_y_scale()), 2);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_rotation(0);
    check_equals(D(m1.get_x_scale()), 1);
    check_equals(D(m1.get_y_scale()), 2);
    check_equals(D(m1.get_rotation()), 0);
    check_equals(m1.get_x_translation(), 0);
    check_equals(m1.get_y_translation(), 0);

    m1.set_translation(5, 6);
    check_equals(D(m1.get_x_scale()), 1);
    check_equals(D(m1.get_y_scale()), 2);
    check_equals(D(m1.get_rotation()), 0);
    check_equals(m1.get_x_translation(), 5);
    check_equals(m1.get_y_translation(), 6);

    m1.set_rotation(2);
    check_equals(D(m1.get_x_scale()), 1);
    check_equals(D(m1.get_y_scale()), 2);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 5);
    check_equals(m1.get_y_translation(), 6);

    SWFMatrix m2;
    check_equals(D(m2.get_rotation()), 0);
    m2.set_x_scale(16);
    check_equals(D(m2.get_x_scale()), 16);
    check_equals(D(m2.get_y_scale()), 1);
    check_equals(D(m2.get_rotation()), 0);
    m2.set_x_scale(-16);
    check_equals(D(m2.get_x_scale()), 16);
    check_equals(D(m2.get_y_scale()), 1);
    check_equals(D(m2.get_rotation()), 3.14159);
    m2.set_x_scale(16);
    check_equals(D(m2.get_x_scale()), 16);
    check_equals(D(m2.get_y_scale()), 1);
    check_equals(D(m2.get_rotation()), 3.14159);
    m2.set_x_scale(16);
    m2.set_y_scale(-64);
    check_equals(D(m2.get_x_scale()), 16);
    check_equals(D(m2.get_y_scale()), 64);
    check_equals(D(m2.get_rotation()), 3.14159);
    m2.set_x_scale(16);
    m2.set_x_scale(-128);
    check_equals(D(m2.get_x_scale()), 128);
    check_equals(D(m2.get_y_scale()), 64);
    check_equals(D(m2.get_rotation()), 0);

    //
    // Test SWFMatrix concatenation
    //
    m1.concatenate_scale(2, 2);
    check_equals(D(m1.get_x_scale()), 2);
    check_equals(D(m1.get_y_scale()), 4);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 5);
    check_equals(m1.get_y_translation(), 6);

    m1.concatenate_scale(3, 3);
    check_equals(D(m1.get_x_scale()), 6);
    check_equals(D(m1.get_y_scale()), 12);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 5);
    check_equals(m1.get_y_translation(), 6);

    m1.concatenate_scale(2, 1);
    check_equals(D(m1.get_x_scale()), 12);
    check_equals(D(m1.get_y_scale()), 12);
    check_equals(D(m1.get_rotation()), 2);
    check_equals(m1.get_x_translation(), 5);
    check_equals(m1.get_y_translation(), 6);

    //
    // Test SWFMatrix transformations
    //
    point p1(0, 0);
    point p2(64, 64);
    point r;

    m1.set_identity();
    // Make a distance of 64 become a distance of 20 .. 
    m1.set_scale(20.0/64, 20.0/64);

    m1.transform(&r, p1);
    check_equals(r.x, 0);
    check_equals(r.y, 0);
   
    m1.transform(&r, p2);
    check_equals(r.x, 20);
    check_equals(r.y, 20);

    // Translate points to have the origin at 32,32
    // (coordinates expressed in prior-to-scaling SWFMatrix)
    m1.concatenate_translation(-32, -32);

    m1.transform(&r, p1);
    check_equals(r.x, -10);
    check_equals(r.y, -10);

    m1.transform(&r, p2);
    check_equals(r.x, 10);
    check_equals(r.y, 10);

    //  Apply a final scaling by 10 keeping the current origin 
    // (reached after translation)
    SWFMatrix final;
    final.set_scale(10, 10);