// If we have a selection of multiple items, then the center of the first item
// will be returned; this is also the case in SelTrans::centerRequest()
boost::optional<Geom::Point> Selection::center() const {
    std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
    if (!items.empty()) {
        SPItem *first = items.back(); // from the first item in selection
        if (first->isCenterSet()) { // only if set explicitly
            return first->getCenter();
        }
    }
    Geom::OptRect bbox = preferredBounds();
    if (bbox) {
        return bbox->midpoint();
    } else {
        return boost::optional<Geom::Point>();
    }
}
Ejemplo n.º 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;
                        }
                    }
                }
            }
        }
    }
}
Ejemplo n.º 3
0
static bool sp_spray_recursive(SPDesktop *desktop,
                               Inkscape::Selection *selection,
                               SPItem *item,
                               Geom::Point p,
                               Geom::Point /*vector*/,
                               gint mode,
                               double radius,
                               double /*force*/,
                               double population,
                               double &scale,
                               double scale_variation,
                               bool /*reverse*/,
                               double mean,
                               double standard_deviation,
                               double ratio,
                               double tilt,
                               double rotation_variation,
                               gint _distrib)
{
    bool did = false;
    
    if (SP_IS_BOX3D(item) ) {
        // convert 3D boxes to ordinary groups before spraying their shapes
        item = box3d_convert_to_group(SP_BOX3D(item));
        selection->add(item);
    }

    double _fid = g_random_double_range(0, 1);
    double angle = g_random_double_range( - rotation_variation / 100.0 * M_PI , rotation_variation / 100.0 * M_PI );
    double _scale = g_random_double_range( 1.0 - scale_variation / 100.0, 1.0 + scale_variation / 100.0 );
    double dr; double dp;
    random_position( dr, dp, mean, standard_deviation, _distrib );
    dr=dr*radius;

    if (mode == SPRAY_MODE_COPY) {
        Geom::OptRect a = item->documentVisualBounds();
        if (a) {
            SPItem *item_copied;
            if(_fid <= population)
            {
                // duplicate
                SPDocument *doc = item->document;
                Inkscape::XML::Document* xml_doc = doc->getReprDoc();
                Inkscape::XML::Node *old_repr = item->getRepr();
                Inkscape::XML::Node *parent = old_repr->parent();
                Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
                parent->appendChild(copy);

                SPObject *new_obj = doc->getObjectByRepr(copy);
                item_copied = (SPItem *) new_obj;   //convertion object->item
                Geom::Point center=item->getCenter();
                sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale));
                sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale));

                sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
                //Move the cursor p
                Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
                sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
                did = true;
            }
        }
    } else if (mode == SPRAY_MODE_SINGLE_PATH) {

        SPItem *father = NULL;         //initial Object
        SPItem *item_copied = NULL;    //Projected Object
        SPItem *unionResult = NULL;    //previous union
        SPItem *son = NULL;            //father copy

        int i=1;
        for (GSList *items = g_slist_copy((GSList *) selection->itemList());
                items != NULL;
                items = items->next) {

            SPItem *item1 = (SPItem *) items->data;
            if (i == 1) {
                father = item1;
            }
            if (i == 2) {
                unionResult = item1;
            }
            i++;
        }
        SPDocument *doc = father->document;
        Inkscape::XML::Document* xml_doc = doc->getReprDoc();
        Inkscape::XML::Node *old_repr = father->getRepr();
        Inkscape::XML::Node *parent = old_repr->parent();

        Geom::OptRect a = father->documentVisualBounds();
        if (a) {
            if (i == 2) {
                Inkscape::XML::Node *copy1 = old_repr->duplicate(xml_doc);
                parent->appendChild(copy1);
                SPObject *new_obj1 = doc->getObjectByRepr(copy1);
                son = (SPItem *) new_obj1;   // conversion object->item
                unionResult = son;
                Inkscape::GC::release(copy1);
            }

            if (_fid <= population) { // Rules the population of objects sprayed
                // duplicates the father
                Inkscape::XML::Node *copy2 = old_repr->duplicate(xml_doc);
                parent->appendChild(copy2);
                SPObject *new_obj2 = doc->getObjectByRepr(copy2);
                item_copied = (SPItem *) new_obj2;

                // Move around the cursor
                Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); 

                Geom::Point center=father->getCenter();
                sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale));
                sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale));
                sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle));
                sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));

                // union and duplication
                selection->clear();
                selection->add(item_copied);
                selection->add(unionResult);
                sp_selected_path_union_skip_undo(selection->desktop());
                selection->add(father);
                Inkscape::GC::release(copy2);
                did = true;
            }
        }
    } else if (mode == SPRAY_MODE_CLONE) {
        Geom::OptRect a = item->documentVisualBounds();
        if (a) {
            if(_fid <= population) {
                SPItem *item_copied;
                SPDocument *doc = item->document;
                Inkscape::XML::Document* xml_doc = doc->getReprDoc();
                Inkscape::XML::Node *old_repr = item->getRepr();
                Inkscape::XML::Node *parent = old_repr->parent();

                // Creation of the clone
                Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
                // Ad the clone to the list of the father's sons
                parent->appendChild(clone);
                // Generates the link between father and son attributes
                clone->setAttribute("xlink:href", g_strdup_printf("#%s", old_repr->attribute("id")), false); 

                SPObject *clone_object = doc->getObjectByRepr(clone);
                // conversion object->item
                item_copied = (SPItem *) clone_object;
                Geom::Point center = item->getCenter();
                sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale));
                sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale));
                sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle));
                Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
                sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));

                Inkscape::GC::release(clone);

                did = true;
            }
        }
    }

    return did;
}