Exemple #1
0
Geom::OptRect CGroup::bounds(SPItem::BBoxType type, Geom::Affine const &transform)
{
    Geom::OptRect bbox;

    GSList *l = _group->childList(false, SPObject::ActionBBox);
    while (l) {
        SPObject *o = SP_OBJECT (l->data);
        if (SP_IS_ITEM(o) && !SP_ITEM(o)->isHidden()) {
            SPItem *child = SP_ITEM(o);
            Geom::Affine const ct(child->transform * transform);
            bbox |= child->bounds(type, ct);
        }
        l = g_slist_remove (l, o);
    }
    return bbox;
}
Exemple #2
0
void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent,
                                              std::vector<SPItem const *> const *it,
                                              bool const &first_point,
                                              Geom::Rect const &bbox_to_snap,
                                              bool const clip_or_mask,
                                              Geom::Affine const additional_affine) const // transformation of the item being clipped / masked
{
    SPDesktop const *dt = _snapmanager->getDesktop();
    if (dt == NULL) {
        g_warning("desktop == NULL, so we cannot snap; please inform the developers of this bug");
        // Apparently the setup() method from the SnapManager class hasn't been called before trying to snap.
    }

    if (first_point) {
        _candidates->clear();
    }

    Geom::Rect bbox_to_snap_incl = bbox_to_snap; // _incl means: will include the snapper tolerance
    bbox_to_snap_incl.expandBy(getSnapperTolerance()); // see?

    for ( SPObject *o = parent->firstChild(); o; o = o->getNext() ) {
        g_assert(dt != NULL);
        if (SP_IS_ITEM(o) && !(dt->itemIsHidden(SP_ITEM(o)) && !clip_or_mask)) {
            // Snapping to items in a locked layer is allowed
            // Don't snap to hidden objects, unless they're a clipped path or a mask
            /* See if this item is on the ignore list */
            std::vector<SPItem const *>::const_iterator i;
            if (it != NULL) {
                i = it->begin();
                while (i != it->end() && *i != o) {
                    ++i;
                }
            }

            if (it == NULL || i == it->end()) {
                SPItem *item = SP_ITEM(o);
                if (item) {
                    if (!clip_or_mask) { // cannot clip or mask more than once
                        // The current item is not a clipping path or a mask, but might
                        // still be the subject of clipping or masking itself ; if so, then
                        // we should also consider that path or mask for snapping to
                        SPObject *obj = SP_OBJECT(item->clip_ref ? item->clip_ref->getObject() : NULL);
                        if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_CLIP)) {
                            _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine());
                        }
                        obj = SP_OBJECT(item->mask_ref ? item->mask_ref->getObject() : NULL);
                        if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_MASK)) {
                            _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine());
                        }
                    }
                }

                if (SP_IS_GROUP(o)) {
                    _findCandidates(o, it, false, bbox_to_snap, clip_or_mask, additional_affine);
                } else {
                    Geom::OptRect bbox_of_item;
                    Preferences *prefs = Preferences::get();
                    int prefs_bbox = prefs->getBool("/tools/bounding_box", 0);
                    // We'll only need to obtain the visual bounding box if the user preferences tell
                    // us to, AND if we are snapping to the bounding box itself. If we're snapping to
                    // paths only, then we can just as well use the geometric bounding box (which is faster)
                    SPItem::BBoxType bbox_type = (!prefs_bbox && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) ?
                        SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX;
                    if (clip_or_mask) {
                        // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to
                        // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine)
                        bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt());
                    } else {
                        bbox_of_item = item->desktopBounds(bbox_type);
                    }
                    if (bbox_of_item) {
                        // See if the item is within range
                        if (bbox_to_snap_incl.intersects(*bbox_of_item)
                                || (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box
                            // This item is within snapping range, so record it as a candidate
                            _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine));
                            // For debugging: print the id of the candidate to the console
                            // SPObject *obj = (SPObject*)item;
                            // std::cout << "Snap candidate added: " << obj->getId() << std::endl;
                        }
                    }
                }
            }
        }
    }
}