void SPLPEItem::apply_to_clippath(SPItem *item) { SPClipPath *clipPath = item->clip_ref->getObject(); if(clipPath) { SPObject * clip_data = clipPath->firstChild(); SPCurve * clip_curve = NULL; if (SP_IS_PATH(clip_data)) { clip_curve = SP_PATH(clip_data)->get_original_curve(); } else if(SP_IS_SHAPE(clip_data)) { clip_curve = SP_SHAPE(clip_data)->getCurve(); } else if(SP_IS_GROUP(clip_data)) { apply_to_clip_or_mask_group(SP_ITEM(clip_data), item); return; } if(clip_curve) { bool success = false; if(SP_IS_GROUP(this)){ clip_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this))); success = this->performPathEffect(clip_curve); clip_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse()); } else { success = this->performPathEffect(clip_curve); } Inkscape::XML::Node *reprClip = clip_data->getRepr(); if (success) { gchar *str = sp_svg_write_path(clip_curve->get_pathvector()); reprClip->setAttribute("d", str); g_free(str); } else { // LPE was unsuccesfull. Read the old 'd'-attribute. if (gchar const * value = reprClip->attribute("d")) { Geom::PathVector pv = sp_svg_read_pathv(value); SPCurve *oldcurve = new SPCurve(pv); if (oldcurve) { SP_SHAPE(clip_data)->setCurve(oldcurve, TRUE); oldcurve->unref(); } } } clip_curve->unref(); } } if(SP_IS_GROUP(item)){ GSList const *item_list = sp_item_group_item_list(SP_GROUP(item)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast<SPObject *>(iter->data); apply_to_clippath(SP_ITEM(subitem)); } } }
static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { SPShape *shape = SP_SHAPE(object); // Tolerable workaround: we need to update the object's curve before we set points= // because it's out of sync when e.g. some extension attrs of the polygon or star are changed in XML editor sp_shape_set_shape(shape); if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:polygon"); } /* We can safely write points here, because all subclasses require it too (Lauris) */ /* While saving polygon element without points attribute _curve is NULL (see bug 1202753) */ if (shape->curve != NULL) { gchar *str = sp_svg_write_polygon(shape->curve->get_pathvector()); repr->setAttribute("points", str); g_free(str); } if (((SPObjectClass *) (parent_class))->write) { ((SPObjectClass *) (parent_class))->write(object, xml_doc, repr, flags); } return repr; }
Inkscape::XML::Node* SPUse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:use"); } SPItem::write(xml_doc, repr, flags); sp_repr_set_svg_double(repr, "x", this->x.computed); sp_repr_set_svg_double(repr, "y", this->y.computed); repr->setAttribute("width", sp_svg_length_write_with_units(this->width).c_str()); repr->setAttribute("height", sp_svg_length_write_with_units(this->height).c_str()); if (this->ref->getURI()) { gchar *uri_string = this->ref->getURI()->toString(); repr->setAttribute("xlink:href", uri_string); g_free(uri_string); } if (SP_IS_SHAPE(this->child)) { SP_SHAPE(this->child)->set_shape(); // evaluate SPCurve of child } else if (SP_IS_TEXT(this->child)) { SP_TEXT(this->child)->rebuildLayout(); // refresh Layout, LP Bug 1339305 } else if (SP_IS_FLOWTEXT(this->child)) { if (SP_IS_FLOWREGION(SP_FLOWTEXT(this->child)->firstChild())) SP_FLOWREGION(SP_FLOWTEXT(this->child)->firstChild())->UpdateComputed(); SP_FLOWTEXT(this->child)->rebuildLayout(); } return repr; }
void SPUsePath::refresh_source() { sourceDirty = false; delete originalPath; originalPath = NULL; // le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour // [tr: The bad case: no d attribute. Must check that it's a SPShape and then take the outline.] SPObject *refobj = sourceObject; if ( refobj == NULL ) return; SPItem *item = SP_ITEM(refobj); SPCurve *curve = NULL; if (SP_IS_SHAPE(item)) { curve = SP_SHAPE(item)->getCurve(); } else if (SP_IS_TEXT(item)) { curve = SP_TEXT(item)->getNormalizedBpath(); } else { return; } if (curve == NULL) return; originalPath = new Path; originalPath->LoadPathVector(curve->get_pathvector(), item->transform, true); curve->unref(); }
void SPPolyLine::set(SPObject *object, unsigned int key, const gchar *value) { SPPolyLine *polyline = SP_POLYLINE(object); switch (key) { case SP_ATTR_POINTS: { SPCurve * curve; const gchar * cptr; char * eptr; gboolean hascpt; if (!value) break; curve = new SPCurve (); hascpt = FALSE; cptr = value; eptr = NULL; while (TRUE) { gdouble x, y; while (*cptr != '\0' && (*cptr == ',' || *cptr == '\x20' || *cptr == '\x9' || *cptr == '\xD' || *cptr == '\xA')) { cptr++; } if (!*cptr) break; x = g_ascii_strtod (cptr, &eptr); if (eptr == cptr) break; cptr = eptr; while (*cptr != '\0' && (*cptr == ',' || *cptr == '\x20' || *cptr == '\x9' || *cptr == '\xD' || *cptr == '\xA')) { cptr++; } if (!*cptr) break; y = g_ascii_strtod (cptr, &eptr); if (eptr == cptr) break; cptr = eptr; if (hascpt) { curve->lineto(x, y); } else { curve->moveto(x, y); hascpt = TRUE; } } (SP_SHAPE (polyline))->setCurve (curve, TRUE); curve->unref(); break; } default: if (((SPObjectClass *) SPPolyLineClass::static_parent_class)->set) { ((SPObjectClass *) SPPolyLineClass::static_parent_class)->set (object, key, value); } break; } }
static void knot_moved_handler (SPKnot *knot, NRPointF *p, guint state, gpointer data) { SPKnotHolder *knot_holder; SPItem *item; SPObject *object; NRMatrixF i2d; GSList *el; knot_holder = (SPKnotHolder *) data; item = SP_ITEM (knot_holder->item); object = SP_OBJECT (item); for (el = knot_holder->entity; el; el = el->next) { SPKnotHolderEntity *e = (SPKnotHolderEntity *)el->data; if (e->knot == knot) { NRMatrixF d2i; NRPointF q; sp_item_i2d_affine(item, &i2d); nr_matrix_f_invert (&d2i, &i2d); q.x = NR_MATRIX_DF_TRANSFORM_X (&d2i, p->x, p->y); q.y = NR_MATRIX_DF_TRANSFORM_Y (&d2i, p->x, p->y); e->knot_set (item, &q, state); break; } } sp_shape_set_shape (SP_SHAPE (item)); sp_item_i2d_affine(item, &i2d); for (el = knot_holder->entity; el; el = el->next) { SPKnotHolderEntity *e = (SPKnotHolderEntity *)el->data; NRPointF sp, dp; GObject *kob; kob = G_OBJECT (e->knot); e->knot_get (item, &sp); dp.x = NR_MATRIX_DF_TRANSFORM_X (&i2d, sp.x, sp.y); dp.y = NR_MATRIX_DF_TRANSFORM_Y (&i2d, sp.x, sp.y); g_signal_handler_block (kob, e->handler_id); sp_knot_set_position (e->knot, &dp, SP_KNOT_STATE_NORMAL); g_signal_handler_unblock (kob, e->handler_id); } }
static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_pv, SPItem* item, const Geom::Affine& item_transform, double& intersect_pos) { double initial_pos = intersect_pos; // if this is a group... if (SP_IS_GROUP(item)) { SPGroup* group = SP_GROUP(item); // consider all first-order children double child_pos = 0.0; std::vector<SPItem*> g = sp_item_group_item_list(group); for (std::vector<SPItem*>::const_iterator i = g.begin();i!=g.end();i++) { SPItem* child_item = *i; try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); if (intersect_pos < child_pos) intersect_pos = child_pos; } return intersect_pos != initial_pos; } // if this is not a shape, nothing to be done if (!SP_IS_SHAPE(item)) return false; // make sure it has an associated curve SPCurve* item_curve = SP_SHAPE(item)->getCurve(); if (!item_curve) return false; // apply transformations (up to common ancestor) item_curve->transform(item_transform); const Geom::PathVector& curve_pv = item_curve->get_pathvector(); Geom::CrossingSet cross = crossings(conn_pv, curve_pv); // iterate over all Crossings //TODO: check correctness of the following code: inner loop uses loop variable // with a name identical to the loop variable of the outer loop. Then rename. for (Geom::CrossingSet::const_iterator i = cross.begin(); i != cross.end(); ++i) { const Geom::Crossings& cr = *i; for (Geom::Crossings::const_iterator i = cr.begin(); i != cr.end(); ++i) { const Geom::Crossing& cr_pt = *i; if ( intersect_pos < cr_pt.ta) intersect_pos = cr_pt.ta; } } item_curve->unref(); return intersect_pos != initial_pos; }
static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_pv, SPItem* item, const Geom::Matrix& item_transform, double& intersect_pos) { double initial_pos = intersect_pos; // if this is a group... if (SP_IS_GROUP(item)) { SPGroup* group = SP_GROUP(item); // consider all first-order children double child_pos = 0.0; for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) { SPItem* child_item = SP_ITEM(i->data); try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); if (intersect_pos < child_pos) intersect_pos = child_pos; } return intersect_pos != initial_pos; } // if this is not a shape, nothing to be done if (!SP_IS_SHAPE(item)) return false; // make sure it has an associated curve SPCurve* item_curve = sp_shape_get_curve(SP_SHAPE(item)); if (!item_curve) return false; // apply transformations (up to common ancestor) item_curve->transform(item_transform); const Geom::PathVector& curve_pv = item_curve->get_pathvector(); Geom::CrossingSet cross = crossings(conn_pv, curve_pv); // iterate over all Crossings for (Geom::CrossingSet::const_iterator i = cross.begin(); i != cross.end(); i++) { const Geom::Crossings& cr = *i; for (Geom::Crossings::const_iterator i = cr.begin(); i != cr.end(); i++) { const Geom::Crossing& cr_pt = *i; if ( intersect_pos < cr_pt.ta) intersect_pos = cr_pt.ta; } } item_curve->unref(); return intersect_pos != initial_pos; }
static void spdc_attach_selection (SPDrawContext *dc, SPSelection *sel) { SPItem *item; /* We reset white and forget white/start/end anchors */ spdc_reset_white (dc); dc->sa = NULL; dc->ea = NULL; item = sp_selection_item (dc->selection); if (item && SP_IS_PATH (item)) { SPCurve *norm; NRMatrixD i2dt; GSList *l; /* Create new white data */ /* Item */ dc->white_item = item; /* Curve list */ /* We keep it in desktop coordinates to eliminate calculation errors */ norm = sp_shape_get_curve (SP_SHAPE (item)); sp_item_i2d_affine_d (dc->white_item, &i2dt); norm = sp_curve_transform (norm, NR_MATRIX_D_TO_DOUBLE (&i2dt)); g_return_if_fail (norm != NULL); dc->white_curves = sp_curve_split (norm); sp_curve_unref (norm); /* Anchor list */ for (l = dc->white_curves; l != NULL; l = l->next) { SPCurve *c; c = (SPCurve*)l->data; g_return_if_fail (c->end > 1); if (c->bpath->code == ART_MOVETO_OPEN) { ArtBpath *s, *e; SPDrawAnchor *a; s = sp_curve_first_bpath (c); e = sp_curve_last_bpath (c); a = sp_draw_anchor_new (dc, c, TRUE, s->x3, s->y3); dc->white_anchors = g_slist_prepend (dc->white_anchors, a); a = sp_draw_anchor_new (dc, c, FALSE, e->x3, e->y3); dc->white_anchors = g_slist_prepend (dc->white_anchors, a); } } /* fixme: recalculate active anchor? */ } }
static void GetDest(SPObject* child,Shape **computed) { if ( child == NULL ) return; SPCurve *curve=NULL; Geom::Matrix tr_mat; SPObject* u_child=child; if ( SP_IS_USE(u_child) ) { u_child=SP_USE(u_child)->child; tr_mat = SP_ITEM(u_child)->getRelativeTransform(SP_OBJECT_PARENT(child)); } else { tr_mat = SP_ITEM(u_child)->transform; } if ( SP_IS_SHAPE (u_child) ) { curve = sp_shape_get_curve (SP_SHAPE (u_child)); } else if ( SP_IS_TEXT (u_child) ) { curve = SP_TEXT (u_child)->getNormalizedBpath (); } if ( curve ) { Path* temp=new Path; temp->LoadPathVector(curve->get_pathvector(), tr_mat, true); Shape* n_shp=new Shape; temp->Convert(0.25); temp->Fill(n_shp,0); Shape* uncross=new Shape; SPStyle* style=SP_OBJECT_STYLE(u_child); if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) { uncross->ConvertToShape(n_shp,fill_oddEven); } else { uncross->ConvertToShape(n_shp,fill_nonZero); } UnionShape(computed, uncross); delete uncross; delete n_shp; delete temp; curve->unref(); } else { // printf("no curve\n"); } }
static void sp_star_finish (SPStarContext * sc) { if (sc->item != NULL) { SPDesktop *desktop; SPObject *object; desktop = SP_EVENT_CONTEXT (sc)->desktop; object = SP_OBJECT(sc->item); sp_shape_set_shape (SP_SHAPE (sc->item)); sp_object_invoke_write (object, NULL, SP_OBJECT_WRITE_EXT); sp_selection_set_item (SP_DT_SELECTION (desktop), sc->item); sp_document_done (SP_DT_DOCUMENT (desktop)); sc->item = NULL; } }
static void sp_spiral_finish(SPSpiralContext *sc) { sc->_message_context->clear(); if (sc->item != NULL) { SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; SPSpiral *spiral = SP_SPIRAL(sc->item); sp_shape_set_shape(SP_SHAPE(spiral)); SP_OBJECT(spiral)->updateRepr(SP_OBJECT_WRITE_EXT); sp_canvas_end_forced_full_redraws(desktop->canvas); sp_desktop_selection(desktop)->set(sc->item); sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, _("Create spiral")); sc->item = NULL; } }
void OriginalPathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/) { SPCurve *curve = NULL; if (SP_IS_SHAPE(linked_obj)) { curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE(); } if (SP_IS_TEXT(linked_obj)) { curve = SP_TEXT(linked_obj)->getNormalizedBpath(); } if (curve == NULL) { // curve invalid, set empty pathvector _pathvector = Geom::PathVector(); } else { _pathvector = curve->get_pathvector(); curve->unref(); } must_recalculate_pwd2 = true; emit_changed(); SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); }
static void sp_spiral_set (SPObject *object, unsigned int key, const gchar *value) { SPSpiral *spiral; SPShape *shape; gulong unit; spiral = SP_SPIRAL (object); shape = SP_SHAPE (object); /* fixme: we should really collect updates */ switch (key) { case SP_ATTR_SODIPODI_CX: if (!sp_svg_length_read_lff (value, &unit, NULL, &spiral->cx) || (unit == SP_SVG_UNIT_EM) || (unit == SP_SVG_UNIT_EX) || (unit == SP_SVG_UNIT_PERCENT)) { spiral->cx = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_CY: if (!sp_svg_length_read_lff (value, &unit, NULL, &spiral->cy) || (unit == SP_SVG_UNIT_EM) || (unit == SP_SVG_UNIT_EX) || (unit == SP_SVG_UNIT_PERCENT)) { spiral->cy = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_EXPANSION: if (value) { spiral->exp = atof (value); spiral->exp = CLAMP (spiral->exp, 0.0, 1000.0); } else { spiral->exp = 1.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_REVOLUTION: if (value) { spiral->revo = atof (value); spiral->revo = CLAMP (spiral->revo, 0.05, 20.0); } else { spiral->revo = 3.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_RADIUS: if (!sp_svg_length_read_lff (value, &unit, NULL, &spiral->rad) || (unit != SP_SVG_UNIT_EM) || (unit != SP_SVG_UNIT_EX) || (unit != SP_SVG_UNIT_PERCENT)) { spiral->rad = MAX (spiral->rad, 0.001); } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_ARGUMENT: if (value) { spiral->arg = atof (value); } else { spiral->arg = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_T0: if (value) { spiral->t0 = atof (value); spiral->t0 = CLAMP (spiral->t0, -1.0, 0.999); } else { spiral->t0 = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; default: if (((SPObjectClass *) parent_class)->set) ((SPObjectClass *) parent_class)->set (object, key, value); break; } }
Inkscape::XML::Node * sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) { if (!item) return NULL; Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(item)->document(); if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { // Special treatment for text: convert each glyph to separate path, then group the paths Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); g_repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); /* Mask */ gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); if ( mask_str ) g_repr->setAttribute("mask", mask_str); /* Clip path */ gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); if ( clip_path_str ) g_repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ g_repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); g_repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); /* Whole text's style */ gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); g_repr->setAttribute("style", style_str); g_free(style_str); Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); do { Inkscape::Text::Layout::iterator iter_next = iter; iter_next.nextGlyph(); // iter_next is one glyph ahead from iter if (iter == iter_next) break; /* This glyph's style */ SPObject const *pos_obj = 0; void *rawptr = 0; te_get_layout(item)->getSourceOfCharacter(iter, &rawptr); if (!rawptr || !SP_IS_OBJECT(rawptr)) // no source for glyph, abort break; pos_obj = SP_OBJECT(rawptr); while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) { pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style } gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(pos_obj), SP_OBJECT_STYLE(SP_OBJECT_PARENT(pos_obj))); // get path from iter to iter_next: SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); iter = iter_next; // shift to next glyph if (!curve) { // error converting this glyph g_free (style_str); continue; } if (curve->is_empty()) { // whitespace glyph? curve->unref(); g_free (style_str); continue; } Inkscape::XML::Node *p_repr = xml_doc->createElement("svg:path"); gchar *def_str = sp_svg_write_path(curve->get_pathvector()); p_repr->setAttribute("d", def_str); g_free(def_str); curve->unref(); p_repr->setAttribute("style", style_str); g_free(style_str); g_repr->appendChild(p_repr); Inkscape::GC::release(p_repr); if (iter == te_get_layout(item)->end()) break; } while (true); return g_repr; } SPCurve *curve = NULL; if (SP_IS_SHAPE(item)) { curve = sp_shape_get_curve(SP_SHAPE(item)); } if (!curve) return NULL; // Prevent empty paths from being added to the document // otherwise we end up with zomby markup in the SVG file if(curve->is_empty()) { curve->unref(); return NULL; } Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); /* Transformation */ repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); /* Style */ gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); repr->setAttribute("style", style_str); g_free(style_str); /* Mask */ gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); if ( mask_str ) repr->setAttribute("mask", mask_str); /* Clip path */ gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); if ( clip_path_str ) repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); /* Definition */ gchar *def_str = sp_svg_write_path(curve->get_pathvector()); repr->setAttribute("d", def_str); g_free(def_str); curve->unref(); return repr; }
/// @todo investigate why Geom::Point p is passed in but ignored. void Inkscape::ObjectSnapper::_collectPaths(Geom::Point /*p*/, SnapSourceType const source_type, bool const &first_point) const { // Now, let's first collect all paths to snap to. If we have a whole bunch of points to snap, // e.g. when translating an item using the selector tool, then we will only do this for the // first point and store the collection for later use. This significantly improves the performance if (first_point) { _clear_paths(); // Determine the type of bounding box we should snap to SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; bool p_is_a_node = source_type & SNAPSOURCE_NODE_CATEGORY; bool p_is_a_bbox = source_type & SNAPSOURCE_BBOX_CATEGORY; bool p_is_other = (source_type & SNAPSOURCE_OTHERS_CATEGORY) || (source_type & SNAPSOURCE_DATUMS_CATEGORY); if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE)) { Preferences *prefs = Preferences::get(); int prefs_bbox = prefs->getBool("/tools/bounding_box", 0); bbox_type = !prefs_bbox ? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; } // Consider the page border for snapping if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_BORDER) && _snapmanager->snapprefs.isAnyCategorySnappable()) { Geom::PathVector *border_path = _getBorderPathv(); if (border_path != NULL) { _paths_to_snap_to->push_back(SnapCandidatePath(border_path, SNAPTARGET_PAGE_BORDER, Geom::OptRect())); } } for (std::vector<SnapCandidateItem>::const_iterator i = _candidates->begin(); i != _candidates->end(); ++i) { /* Transform the requested snap point to this item's coordinates */ Geom::Affine i2doc(Geom::identity()); SPItem *root_item = NULL; /* We might have a clone at hand, so make sure we get the root item */ if (SP_IS_USE((*i).item)) { i2doc = SP_USE((*i).item)->get_root_transform(); root_item = SP_USE((*i).item)->root(); g_return_if_fail(root_item); } else { i2doc = (*i).item->i2doc_affine(); root_item = (*i).item; } //Build a list of all paths considered for snapping to //Add the item's path to snap to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION, SNAPTARGET_TEXT_BASELINE)) { if (p_is_other || p_is_a_node || (!_snapmanager->snapprefs.getStrictSnapping() && p_is_a_bbox)) { if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_TEXT_BASELINE)) { // Snap to the text baseline Text::Layout const *layout = te_get_layout(static_cast<SPItem *>(root_item)); if (layout != NULL && layout->outputExists()) { Geom::PathVector *pv = new Geom::PathVector(); pv->push_back(layout->baseline() * root_item->i2dt_affine() * (*i).additional_affine * _snapmanager->getDesktop()->doc2dt()); _paths_to_snap_to->push_back(SnapCandidatePath(pv, SNAPTARGET_TEXT_BASELINE, Geom::OptRect())); } } } else { // Snapping for example to a traced bitmap is very stressing for // the CPU, so we'll only snap to paths having no more than 500 nodes // This also leads to a lag of approx. 500 msec (in my lousy test set-up). bool very_complex_path = false; if (SP_IS_PATH(root_item)) { very_complex_path = SP_PATH(root_item)->nodesInPath() > 500; } if (!very_complex_path && root_item && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION)) { SPCurve *curve = NULL; if (SP_IS_SHAPE(root_item)) { curve = SP_SHAPE(root_item)->getCurve(); }/* else if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { curve = te_get_layout(root_item)->convertToCurves(); }*/ if (curve) { // We will get our own copy of the pathvector, which must be freed at some point // Geom::PathVector *pv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine); Geom::PathVector *pv = new Geom::PathVector(curve->get_pathvector()); (*pv) *= root_item->i2dt_affine() * (*i).additional_affine * _snapmanager->getDesktop()->doc2dt(); // (_edit_transform * _i2d_transform); _paths_to_snap_to->push_back(SnapCandidatePath(pv, SNAPTARGET_PATH, Geom::OptRect())); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it. curve->unref(); } } } } } //Add the item's bounding box to snap to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE)) { if (p_is_other || p_is_a_bbox || (!_snapmanager->snapprefs.getStrictSnapping() && p_is_a_node)) { // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox // of the item AND the bbox of the clipping path at the same time if (!(*i).clip_or_mask) { Geom::OptRect rect = root_item->bounds(bbox_type, i2doc); if (rect) { Geom::PathVector *path = _getPathvFromRect(*rect); rect = root_item->desktopBounds(bbox_type); _paths_to_snap_to->push_back(SnapCandidatePath(path, SNAPTARGET_BBOX_EDGE, rect)); } } } } } } }
void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) { SPPolygon *polygon = SP_POLYGON(object); switch (key) { case SP_ATTR_POINTS: { if (!value) { /* fixme: The points attribute is required. We should handle its absence as per * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */ break; } SPCurve *curve = new SPCurve(); gboolean hascpt = FALSE; gchar const *cptr = value; bool has_error = false; while (TRUE) { gdouble x; if (!polygon_get_value(&cptr, &x)) { break; } gdouble y; if (!polygon_get_value(&cptr, &y)) { /* fixme: It is an error for an odd number of points to be specified. We * should display the points up to now (as we currently do, though perhaps * without the closepath: the spec isn't quite clear on whether to do a * closepath or not, though I'd guess it's best not to do a closepath), but * then flag the document as in error, as per * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. * * (Ref: http://www.w3.org/TR/SVG11/shapes.html#PolygonElement.) */ has_error = true; break; } if (hascpt) { curve->lineto(x, y); } else { curve->moveto(x, y); hascpt = TRUE; } } if (has_error || *cptr != '\0') { /* TODO: Flag the document as in error, as per * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */ } else if (hascpt) { /* We might have done a moveto but no lineto. I'm not sure how we're supposed to represent * a single-point polygon in SPCurve. TODO: add a testcase with only one coordinate pair */ curve->closepath(); } sp_shape_set_curve(SP_SHAPE(polygon), curve, TRUE); curve->unref(); break; } default: if (((SPObjectClass *) parent_class)->set) { ((SPObjectClass *) parent_class)->set(object, key, value); } break; } }
/** * Get the selected image. Also check for any SPItems over it, in * case the user wants SIOX pre-processing. */ SPImage * Tracer::getSelectedSPImage() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) { g_warning("Trace: No active desktop"); return NULL; } Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop); Inkscape::Selection *sel = sp_desktop_selection(desktop); if (!sel) { char *msg = _("Select an <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } if (sioxEnabled) { SPImage *img = NULL; GSList const *list = sel->itemList(); std::vector<SPItem *> items; sioxShapes.clear(); /* First, things are selected top-to-bottom, so we need to invert them as bottom-to-top so that we can discover the image and any SPItems above it */ for ( ; list ; list=list->next) { if (!SP_IS_ITEM(list->data)) { continue; } SPItem *item = SP_ITEM(list->data); items.insert(items.begin(), item); } std::vector<SPItem *>::iterator iter; for (iter = items.begin() ; iter!= items.end() ; iter++) { SPItem *item = *iter; if (SP_IS_IMAGE(item)) { if (img) //we want only one { char *msg = _("Select only one <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } img = SP_IMAGE(item); } else // if (img) //# items -after- the image in tree (above it in Z) { if (SP_IS_SHAPE(item)) { SPShape *shape = SP_SHAPE(item); sioxShapes.push_back(shape); } } } if (!img || sioxShapes.size() < 1) { char *msg = _("Select one image and one or more shapes above it"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } return img; } else //### SIOX not enabled. We want exactly one image selected { SPItem *item = sel->singleItem(); if (!item) { char *msg = _("Select an <b>image</b> to trace"); //same as above msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } if (!SP_IS_IMAGE(item)) { char *msg = _("Select an <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } SPImage *img = SP_IMAGE(item); return img; } }