CrossingSet crossings_among(std::vector<Path> const &p) {
    CrossingSet results(p.size(), Crossings());
    if(p.empty()) return results;
    
    SimpleCrosser cc;
    
    std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(p));
    for(unsigned i = 0; i < cull.size(); i++) {
        Crossings res = self_crossings(p[i]);
        for(unsigned k = 0; k < res.size(); k++) { res[k].a = res[k].b = i; }
        merge_crossings(results[i], res, i);
        flip_crossings(res);
        merge_crossings(results[i], res, i);
        for(unsigned jx = 0; jx < cull[i].size(); jx++) {
            unsigned j = cull[i][jx];
            
            Crossings res = cc.crossings(p[i], p[j]);
            for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = j; }
            merge_crossings(results[i], res, i);
            merge_crossings(results[j], res, j);
        }
    }
    return results;
}
Beispiel #2
0
void SPShape::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const {
    if (this->_curve == NULL) {
        return;
    }

    Geom::PathVector const &pathv = this->_curve->get_pathvector();

    if (pathv.empty()) {
        return;
    }

    Geom::Affine const i2dt (this->i2dt_affine ());

    if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT)) {
        Geom::OptRect bbox = this->desktopVisualBounds();

        if (bbox) {
            p.push_back(Inkscape::SnapCandidatePoint(bbox->midpoint(), Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
        }
    }

    for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
        if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP)) {
            // Add the first point of the path
            p.push_back(Inkscape::SnapCandidatePoint(path_it->initialPoint() * i2dt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
        }

        Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
        Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve

        while (curve_it1 != path_it->end_default())
        {
            // For each path: consider midpoints of line segments for snapping
            if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_LINE_MIDPOINT)) {
                if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
                    p.push_back(Inkscape::SnapCandidatePoint(Geom::middle_point(*line_segment) * i2dt, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
                }
            }

            if (curve_it2 == path_it->end_default()) { // Test will only pass for the last iteration of the while loop
                if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && !path_it->closed()) {
                    // Add the last point of the path, but only for open paths
                    // (for closed paths the first and last point will coincide)
                    p.push_back(Inkscape::SnapCandidatePoint((*curve_it1).finalPoint() * i2dt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
                }
            } else {
                /* Test whether to add the node between curve_it1 and curve_it2.
                 * Loop to end_default (so only iterating through the stroked part); */

                Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);

                bool c1 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
                bool c2 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_SMOOTH) && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);

                if (c1 || c2) {
                    Inkscape::SnapSourceType sst;
                    Inkscape::SnapTargetType stt;

                    switch (nodetype) {
                    case Geom::NODE_CUSP:
                        sst = Inkscape::SNAPSOURCE_NODE_CUSP;
                        stt = Inkscape::SNAPTARGET_NODE_CUSP;
                        break;
                    case Geom::NODE_SMOOTH:
                    case Geom::NODE_SYMM:
                        sst = Inkscape::SNAPSOURCE_NODE_SMOOTH;
                        stt = Inkscape::SNAPTARGET_NODE_SMOOTH;
                        break;
                    default:
                        sst = Inkscape::SNAPSOURCE_UNDEFINED;
                        stt = Inkscape::SNAPTARGET_UNDEFINED;
                        break;
                    }

                    p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2dt, sst, stt));
                }
            }

            ++curve_it1;
            ++curve_it2;
        }

        // Find the internal intersections of each path and consider these for snapping
        // (using "Method 1" as described in Inkscape::ObjectSnapper::_collectNodes())
        if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_PATH_INTERSECTION) || snapprefs->isSourceSnappable(Inkscape::SNAPSOURCE_PATH_INTERSECTION)) {
            Geom::Crossings cs;

            try {
                cs = self_crossings(*path_it); // This can be slow!

                if (!cs.empty()) { // There might be multiple intersections...
                    for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); ++i) {
                        Geom::Point p_ix = (*path_it).pointAt((*i).ta);
                        p.push_back(Inkscape::SnapCandidatePoint(p_ix * i2dt, Inkscape::SNAPSOURCE_PATH_INTERSECTION, Inkscape::SNAPTARGET_PATH_INTERSECTION));
                    }
                }
            } catch (Geom::RangeError &e) {
                // do nothing
                // The exception could be Geom::InfiniteSolutions: then no snappoints should be added
            }

        }
    }
}