// 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>(); } }
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; } } } } } } }
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; }