Ejemplo n.º 1
0
void
lpetool_get_limiting_bbox_corners(SPDocument *document, Geom::Point &A, Geom::Point &B) {
    Geom::Coord w = document->getWidth().value("px");
    Geom::Coord h = document->getHeight().value("px");
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    double ulx = prefs->getDouble("/tools/lpetool/bbox_upperleftx", 0);
    double uly = prefs->getDouble("/tools/lpetool/bbox_upperlefty", 0);
    double lrx = prefs->getDouble("/tools/lpetool/bbox_lowerrightx", w);
    double lry = prefs->getDouble("/tools/lpetool/bbox_lowerrighty", h);

    A = Geom::Point(ulx, uly);
    B = Geom::Point(lrx, lry);
}
/**
Returns the topmost non-layer group from the descendants of group which is at point
p, or NULL if none. Recurses into layers but not into groups.
 */
SPItem*
find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Point const p)
{
    SPItem *seen = NULL;
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);

    for (SPObject *o = sp_object_first_child(SP_OBJECT(group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {
        if (!SP_IS_ITEM(o)) continue;
        if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER) {
            SPItem *newseen = find_group_at_point(dkey, SP_GROUP(o), p);
            if (newseen) {
                seen = newseen;
            }
        }
        if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) {
            SPItem *child = SP_ITEM(o);
            NRArenaItem *arenaitem = sp_item_get_arenaitem(child, dkey);

            // seen remembers the last (topmost) of groups pickable at this point
            if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL) {
                seen = child;
            }
        }
    }
    return seen;
}
/**
Returns the bottommost item from the list which is at the point, or NULL if none.
*/
SPItem*
sp_document_item_from_list_at_point_bottom(unsigned int dkey, SPGroup *group, GSList const *list,
                                           Geom::Point const p, bool take_insensitive)
{
    g_return_val_if_fail(group, NULL);
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);

    for (SPObject *o = sp_object_first_child(SP_OBJECT(group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {

        if (!SP_IS_ITEM(o)) continue;

        SPItem *item = SP_ITEM(o);
        NRArenaItem *arenaitem = sp_item_get_arenaitem(item, dkey);
        if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL
            && (take_insensitive || item->isVisibleAndUnlocked(dkey))) {
            if (g_slist_find((GSList *) list, item) != NULL)
                return item;
        }

        if (SP_IS_GROUP(o)) {
            SPItem *found = sp_document_item_from_list_at_point_bottom(dkey, SP_GROUP(o), list, p, take_insensitive);
            if (found)
                return found;
        }

    }
    return NULL;
}
Ejemplo n.º 4
0
void spdc_create_single_dot(ToolBase *ec, Geom::Point const &pt, char const *tool, guint event_state) {
    g_return_if_fail(!strcmp(tool, "/tools/freehand/pen") || !strcmp(tool, "/tools/freehand/pencil"));
    Glib::ustring tool_path = tool;

    SPDesktop *desktop = ec->desktop;
    Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
    Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
    repr->setAttribute("sodipodi:type", "arc");
    SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
    Inkscape::GC::release(repr);

    // apply the tool's current style
    sp_desktop_apply_style_tool(desktop, repr, tool, false);

    // find out stroke width (TODO: is there an easier way??)
    double stroke_width = 3.0;
    gchar const *style_str = repr->attribute("style");
    if (style_str) {
        SPStyle style(SP_ACTIVE_DOCUMENT);
        style.mergeString(style_str);
        stroke_width = style.stroke_width.computed;
    }

    // unset stroke and set fill color to former stroke color
    gchar * str;
    str = g_strdup_printf("fill:#%06x;stroke:none;", sp_desktop_get_color_tool(desktop, tool, false) >> 8);
    repr->setAttribute("style", str);
    g_free(str);

    // put the circle where the mouse click occurred and set the diameter to the
    // current stroke width, multiplied by the amount specified in the preferences
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    Geom::Affine const i2d (item->i2dt_affine ());
    Geom::Point pp = pt * i2d.inverse();
    double rad = 0.5 * prefs->getDouble(tool_path + "/dot-size", 3.0);
    if (event_state & GDK_MOD1_MASK) {
        // TODO: We vary the dot size between 0.5*rad and 1.5*rad, where rad is the dot size
        // as specified in prefs. Very simple, but it might be sufficient in practice. If not,
        // we need to devise something more sophisticated.
        double s = g_random_double_range(-0.5, 0.5);
        rad *= (1 + s);
    }
    if (event_state & GDK_SHIFT_MASK) {
        // double the point size
        rad *= 2;
    }

    sp_repr_set_svg_double (repr, "sodipodi:cx", pp[Geom::X]);
    sp_repr_set_svg_double (repr, "sodipodi:cy", pp[Geom::Y]);
    sp_repr_set_svg_double (repr, "sodipodi:rx", rad * stroke_width);
    sp_repr_set_svg_double (repr, "sodipodi:ry", rad * stroke_width);
    item->updateRepr();

    desktop->getSelection()->set(item);

    desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Creating single dot"));
    DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Create single dot"));
}
Ejemplo n.º 5
0
void SPGenericEllipse::position_set(gdouble x, gdouble y, gdouble rx, gdouble ry)
{
    this->cx.computed = x;
    this->cy.computed = y;
    this->rx.computed = rx;
    this->ry.computed = ry;

    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    // those pref values are in degrees, while we want radians
    if (prefs->getDouble("/tools/shapes/arc/start", 0.0) != 0) {
        this->start = Geom::Angle::from_degrees(prefs->getDouble("/tools/shapes/arc/start", 0.0)).radians0();
    }

    if (prefs->getDouble("/tools/shapes/arc/end", 0.0) != 0) {
        this->end = Geom::Angle::from_degrees(prefs->getDouble("/tools/shapes/arc/end", 0.0)).radians0();
    }

    this->_closed = !prefs->getBool("/tools/shapes/arc/open");

    this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
Ejemplo n.º 6
0
/** \brief  Use the superclass' allocator and set the \c _value */
ParamFloat::ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
        Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(0.0), _min(0.0), _max(10.0)
{
    const gchar * defaultval = NULL;
    if (sp_repr_children(xml) != NULL)
        defaultval = sp_repr_children(xml)->content();
    if (defaultval != NULL) {
        _value = g_ascii_strtod (defaultval,NULL);
    }

    const char * maxval = xml->attribute("max");
    if (maxval != NULL)
        _max = g_ascii_strtod (maxval,NULL);

    const char * minval = xml->attribute("min");
    if (minval != NULL)
        _min = g_ascii_strtod (minval,NULL);

    _precision = 1;
    const char * precision = xml->attribute("precision");
    if (precision != NULL)
        _precision = atoi(precision);

    /* We're handling this by just killing both values */
    if (_max < _min) {
        _max = 10.0;
        _min = 0.0;
    }

    gchar * pref_name = this->pref_name();
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    _value = prefs->getDouble(extension_pref_root + pref_name, _value);
    g_free(pref_name);

    // std::cout << "New Float::  value: " << _value << "  max: " << _max << "  min: " << _min << std::endl;

    if (_value > _max) _value = _max;
    if (_value < _min) _value = _min;

    return;
}
/**
Returns the topmost (in z-order) item from the descendants of group (recursively) which
is at the point p, or NULL if none. Honors into_groups on whether to recurse into
non-layer groups or not. Honors take_insensitive on whether to return insensitive
items. If upto != NULL, then if item upto is encountered (at any level), stops searching
upwards in z-order and returns what it has found so far (i.e. the found item is
guaranteed to be lower than upto).
 */
SPItem*
find_item_at_point(unsigned int dkey, SPGroup *group, Geom::Point const p, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL)
{
    SPItem *seen = NULL, *newseen = NULL;
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);

    for (SPObject *o = sp_object_first_child(SP_OBJECT(group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {
        if (!SP_IS_ITEM(o)) continue;

        if (upto && SP_ITEM(o) == upto)
            break;

        if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) {
            // if nothing found yet, recurse into the group
            newseen = find_item_at_point(dkey, SP_GROUP(o), p, into_groups, take_insensitive, upto);
            if (newseen) {
                seen = newseen;
                newseen = NULL;
            }

            if (item_is_in_group(upto, SP_GROUP(o)))
                break;

        } else {
            SPItem *child = SP_ITEM(o);
            NRArenaItem *arenaitem = sp_item_get_arenaitem(child, dkey);

            // seen remembers the last (topmost) of items pickable at this point
            if (arenaitem && nr_arena_item_invoke_pick(arenaitem, p, delta, 1) != NULL
                && (take_insensitive || child->isVisibleAndUnlocked(dkey))) {
                seen = child;
            }
        }
    }
    return seen;
}
GSList *
sp_document_items_at_points(SPDocument *document, unsigned const key, std::vector<Geom::Point> points)
{
    GSList *items = NULL;
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    // When picking along the path, we don't want small objects close together
    // (such as hatching strokes) to obscure each other by their deltas,
    // so we temporarily set delta to a small value
    gdouble saved_delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
    prefs->setDouble("/options/cursortolerance/value", 0.25);

    for(unsigned int i = 0; i < points.size(); i++) {
        SPItem *item = sp_document_item_at_point(document, key, points[i],
                                                 false, NULL);
        if (item && !g_slist_find(items, item))
            items = g_slist_prepend (items, item);
    }

    // and now we restore it back
    prefs->setDouble("/options/cursortolerance/value", saved_delta);

    return items;
}
Ejemplo n.º 9
0
SPDocument *
GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
{
    // Determine whether the image should be embedded
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    bool ask = prefs->getBool("/dialogs/import/ask");
    Glib::ustring link  = prefs->getString("/dialogs/import/link");
    bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi");
    Glib::ustring scale = prefs->getString("/dialogs/import/scale");
    // std::cout << "GkdpixbufInput::open: "
    //           << " ask: " << ask
    //           << ", link: " << link
    //           << ", forcexdpi: " << forcexdpi
    //           << ", scale: " << scale << std::endl;
    // std::cout << "     in  preferences: "
    //           << " ask: " << !mod->get_param_bool("do_not_ask")
    //           << ", link: " << mod->get_param_optiongroup("link")
    //           << ", mod_dpi: " << mod->get_param_optiongroup("dpi")
    //           << ", scale: " << mod->get_param_optiongroup("scale") << std::endl;
    if( ask ) {
        Glib::ustring mod_link = mod->get_param_optiongroup("link");
        Glib::ustring mod_dpi = mod->get_param_optiongroup("dpi");
        bool mod_forcexdpi = ( mod_dpi.compare( "from_default" ) == 0 );
        Glib::ustring mod_scale = mod->get_param_optiongroup("scale");
        if( link.compare( mod_link ) != 0 ) {
            link = mod_link;
        }
        prefs->setString("/dialogs/import/link", link );
        if( forcexdpi != mod_forcexdpi ) {
            forcexdpi = mod_forcexdpi;
        }
        prefs->setBool("/dialogs/import/forcexdpi", forcexdpi );
        if( scale.compare( mod_scale ) != 0 ) {
            scale = mod_scale;
        }
        prefs->setString("/dialogs/import/scale", scale );
        prefs->setBool("/dialogs/import/ask", !mod->get_param_bool("do_not_ask") );
    }
    bool embed = ( link.compare( "embed" ) == 0 );

    SPDocument *doc = NULL;
    boost::scoped_ptr<Inkscape::Pixbuf> pb(Inkscape::Pixbuf::create_from_file(uri));

    // TODO: the pixbuf is created again from the base64-encoded attribute in SPImage.
    // Find a way to create the pixbuf only once.

    if (pb) {
        doc = SPDocument::createNewDoc(NULL, TRUE, TRUE);
        bool saved = DocumentUndo::getUndoSensitive(doc);
        DocumentUndo::setUndoSensitive(doc, false); // no need to undo in this temporary document

        double width = pb->width();
        double height = pb->height();
        double defaultxdpi = prefs->getDouble("/dialogs/import/defaultxdpi/value", Inkscape::Util::Quantity::convert(1, "in", "px"));
        //bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi");
        ImageResolution *ir = 0;
        double xscale = 1;
        double yscale = 1;


        if (!ir && !forcexdpi) {
            ir = new ImageResolution(uri);
        }
        if (ir && ir->ok()) {
            xscale = 900.0 / floor(10.*ir->x() + .5);  // round-off to 0.1 dpi
            yscale = 900.0 / floor(10.*ir->y() + .5);
        } else {
            xscale = 90.0 / defaultxdpi;
            yscale = 90.0 / defaultxdpi;
        }

        width *= xscale;
        height *= yscale;

        delete ir; // deleting NULL is safe

        // Create image node
        Inkscape::XML::Document *xml_doc = doc->getReprDoc();
        Inkscape::XML::Node *image_node = xml_doc->createElement("svg:image");
        sp_repr_set_svg_double(image_node, "width", width);
        sp_repr_set_svg_double(image_node, "height", height);

        // Added 11 Feb 2014 as we now honor "preserveAspectRatio" and this is
        // what Inkscaper's expect.
        image_node->setAttribute("preserveAspectRatio", "none");

        if( scale.compare( "auto" ) != 0 ) {
            SPCSSAttr *css = sp_repr_css_attr_new();
            sp_repr_css_set_property(css, "image-rendering", scale.c_str());
            sp_repr_css_set(image_node, css, "style");
            sp_repr_css_attr_unref( css );
        }

        if (embed) {
            sp_embed_image(image_node, pb.get());
        } else {
            // convert filename to uri
            gchar* _uri = g_filename_to_uri(uri, NULL, NULL);
            if(_uri) {
                image_node->setAttribute("xlink:href", _uri);
                g_free(_uri);
            } else {
                image_node->setAttribute("xlink:href", uri);
            }
        }

        // Add it to the current layer
        doc->getRoot()->appendChildRepr(image_node);
        Inkscape::GC::release(image_node);
        fit_canvas_to_drawing(doc);

        // Set viewBox if it doesn't exist
        if (!doc->getRoot()->viewBox_set) {
            //std::cout << "Viewbox not set, setting" << std::endl;
            doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit())));
        }

        // restore undo, as now this document may be shown to the user if a bitmap was opened
        DocumentUndo::setUndoSensitive(doc, saved);
    } else {
        printf("GdkPixbuf loader failed\n");
    }

    return doc;
}
SPDocument *
sp_document_create(Inkscape::XML::Document *rdoc,
                   gchar const *uri,
                   gchar const *base,
                   gchar const *name,
                   unsigned int keepalive)
{
    SPDocument *document;
    Inkscape::XML::Node *rroot;
    Inkscape::Version sodipodi_version;
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    rroot = rdoc->root();

    document = new SPDocument();

    document->keepalive = keepalive;

    document->rdoc = rdoc;
    document->rroot = rroot;

#ifndef WIN32
    prepend_current_dir_if_relative(&(document->uri), uri);
#else
    // FIXME: it may be that prepend_current_dir_if_relative works OK on windows too, test!
    document->uri = uri? g_strdup(uri) : NULL;
#endif

    // base is simply the part of the path before filename; e.g. when running "inkscape ../file.svg" the base is "../"
    // which is why we use g_get_current_dir() in calculating the abs path above
    //This is NULL for a new document
    if (base)
        document->base = g_strdup(base);
    else
        document->base = NULL;
    document->name = g_strdup(name);

    document->root = sp_object_repr_build_tree(document, rroot);

    sodipodi_version = SP_ROOT(document->root)->version.sodipodi;

    /* fixme: Not sure about this, but lets assume ::build updates */
    rroot->setAttribute("sodipodi:version", SODIPODI_VERSION);
    rroot->setAttribute("inkscape:version", Inkscape::version_string);
    /* fixme: Again, I moved these here to allow version determining in ::build (Lauris) */

    /* Quick hack 2 - get default image size into document */
    if (!rroot->attribute("width")) rroot->setAttribute("width", "100%");
    if (!rroot->attribute("height")) rroot->setAttribute("height", "100%");
    /* End of quick hack 2 */

    /* Quick hack 3 - Set uri attributes */
    if (uri) {
        rroot->setAttribute("sodipodi:docname", uri);
    }
    /* End of quick hack 3 */

    /* Eliminate obsolete sodipodi:docbase, for privacy reasons */
    rroot->setAttribute("sodipodi:docbase", NULL);
    
    /* Eliminate any claim to adhere to a profile, as we don't try to */
    rroot->setAttribute("baseProfile", NULL);

    // creating namedview
    if (!sp_item_group_get_child_by_name((SPGroup *) document->root, NULL, "sodipodi:namedview")) {
        // if there's none in the document already,
        Inkscape::XML::Node *rnew = NULL;
        
        rnew = rdoc->createElement("sodipodi:namedview");
        //rnew->setAttribute("id", "base");

        // Add namedview data from the preferences
        // we can't use getAllEntries because this could produce non-SVG doubles
        Glib::ustring pagecolor = prefs->getString("/template/base/pagecolor");
        if (!pagecolor.empty()) {
            rnew->setAttribute("pagecolor", pagecolor.data());
        }
        Glib::ustring bordercolor = prefs->getString("/template/base/bordercolor");
        if (!bordercolor.empty()) {
            rnew->setAttribute("bordercolor", bordercolor.data());
        }
        sp_repr_set_svg_double(rnew, "borderopacity",
            prefs->getDouble("/template/base/borderopacity", 1.0));
        sp_repr_set_svg_double(rnew, "objecttolerance",
            prefs->getDouble("/template/base/objecttolerance", 10.0));
        sp_repr_set_svg_double(rnew, "gridtolerance",
            prefs->getDouble("/template/base/gridtolerance", 10.0));
        sp_repr_set_svg_double(rnew, "guidetolerance",
            prefs->getDouble("/template/base/guidetolerance", 10.0));
        sp_repr_set_svg_double(rnew, "inkscape:pageopacity",
            prefs->getDouble("/template/base/inkscape:pageopacity", 0.0));
        sp_repr_set_int(rnew, "inkscape:pageshadow",
            prefs->getInt("/template/base/inkscape:pageshadow", 2));
        sp_repr_set_int(rnew, "inkscape:window-width",
            prefs->getInt("/template/base/inkscape:window-width", 640));
        sp_repr_set_int(rnew, "inkscape:window-height",
            prefs->getInt("/template/base/inkscape:window-height", 480));
        
        // insert into the document
        rroot->addChild(rnew, NULL);
        // clean up
        Inkscape::GC::release(rnew);
    }

    /* Defs */
    if (!SP_ROOT(document->root)->defs) {
        Inkscape::XML::Node *r;
        r = rdoc->createElement("svg:defs");
        rroot->addChild(r, NULL);
        Inkscape::GC::release(r);
        g_assert(SP_ROOT(document->root)->defs);
    }

    /* Default RDF */
    rdf_set_defaults( document );

    if (keepalive) {
        inkscape_ref();
    }

    // Remark: Here, we used to create a "currentpersp3d" element in the document defs.
    // But this is probably a bad idea since we need to adapt it for every change of selection, which will
    // completely clutter the undo history. Maybe rather save it to prefs on exit and re-read it on startup?

    document->current_persp3d = persp3d_document_first_persp(document);
    if (!document->current_persp3d) {
        document->current_persp3d = persp3d_create_xml_element (document);
    }

    sp_document_set_undo_sensitive(document, true);

    // reset undo key when selection changes, so that same-key actions on different objects are not coalesced
    if (!Inkscape::NSApplication::Application::getNewGui()) {
        g_signal_connect(G_OBJECT(INKSCAPE), "change_selection",
                         G_CALLBACK(sp_document_reset_key), document);
        g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop",
                         G_CALLBACK(sp_document_reset_key), document);
    } else {
        document->_selection_changed_connection = Inkscape::NSApplication::Editor::connectSelectionChanged (sigc::mem_fun (*document, &SPDocument::reset_key));
        document->_desktop_activated_connection = Inkscape::NSApplication::Editor::connectDesktopActivated (sigc::mem_fun (*document, &SPDocument::reset_key));
    }

    return document;
}
Ejemplo n.º 11
0
/**
* Takes a list of inkscape items, extracts the graph defined by
* connectors between them, and uses graph layout techniques to find
* a nice layout
*/
void graphlayout(std::vector<SPItem*> const &items) {
    if(items.empty()) {
        return;
    }

    list<SPItem *> selected;
    filterConnectors(items,selected);
    if (selected.empty()) return;

    const unsigned n=selected.size();
    //Check 2 or more selected objects
    if (n < 2) return;

    // add the connector spacing to the size of node bounding boxes
    // so that connectors can always be routed between shapes
    SPDesktop* desktop = SP_ACTIVE_DESKTOP;
    double spacing = 0;
    if(desktop) spacing = desktop->namedview->connector_spacing+0.1;

    map<string,unsigned> nodelookup;
    vector<Rectangle*> rs;
    vector<Edge> es;
    for (list<SPItem *>::iterator i(selected.begin());
         i != selected.end();
         ++i)
    {
        SPItem *u=*i;
        Geom::OptRect const item_box = u->desktopVisualBounds();
        if(item_box) {
            Geom::Point ll(item_box->min());
            Geom::Point ur(item_box->max());
            nodelookup[u->getId()]=rs.size();
            rs.push_back(new Rectangle(ll[0]-spacing,ur[0]+spacing,
                        ll[1]-spacing,ur[1]+spacing));
        } else {
            // I'm not actually sure if it's possible for something with a
            // NULL item-box to be attached to a connector in which case we
            // should never get to here... but if such a null box can occur it's
            // probably pretty safe to simply ignore
            //fprintf(stderr,"NULL item_box found in graphlayout, ignoring!\n");
        }
    }

    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
    SimpleConstraints scx,scy;
    double ideal_connector_length = prefs->getDouble("/tools/connector/length", 100.0);
    double directed_edge_height_modifier = 1.0;

    bool directed =       prefs->getBool("/tools/connector/directedlayout");
    bool avoid_overlaps = prefs->getBool("/tools/connector/avoidoverlaplayout");

    for (list<SPItem *>::iterator i(selected.begin());
         i != selected.end();
         ++i)
    {
        SPItem *iu=*i;
        map<string,unsigned>::iterator i_iter=nodelookup.find(iu->getId());
        map<string,unsigned>::iterator i_iter_end=nodelookup.end();
        if(i_iter==i_iter_end) {
            continue;
        }
        unsigned u=i_iter->second;
        std::vector<SPItem *> nlist=iu->avoidRef->getAttachedConnectors(Avoid::runningFrom);
        list<SPItem *> connectors;

        connectors.insert(connectors.end(), nlist.begin(), nlist.end());

        for (list<SPItem *>::iterator j(connectors.begin());
                j != connectors.end();
                ++j) {
            SPItem *conn=*j;
            SPItem *iv;
            SPItem *items[2];
            assert(isConnector(conn));
            SP_PATH(conn)->connEndPair.getAttachedItems(items);
            if(items[0]==iu) {
                iv=items[1];
            } else {
                iv=items[0];
            }

            if (iv == NULL) {
                // The connector is not attached to anything at the
                // other end so we should just ignore it.
                continue;
            }

            // If iv not in nodelookup we again treat the connector
            // as disconnected and continue
            map<string,unsigned>::iterator v_pair=nodelookup.find(iv->getId());
            if(v_pair!=nodelookup.end()) {
                unsigned v=v_pair->second;
                //cout << "Edge: (" << u <<","<<v<<")"<<endl;
                es.push_back(make_pair(u,v));
                if(conn->style->marker_end.set) {
                    if(directed && strcmp(conn->style->marker_end.value,"none")) {
                        scy.push_back(new SimpleConstraint(v, u,
                                    (ideal_connector_length * directed_edge_height_modifier)));
                    }
                }
            }
        }
    }
    const unsigned E = es.size();
    double eweights[E];
    fill(eweights,eweights+E,1);
    vector<Component*> cs;
    connectedComponents(rs,es,scx,scy,cs);
    for(unsigned i=0;i<cs.size();i++) {
        Component* c=cs[i];
        if(c->edges.size()<2) continue;
        CheckProgress test(0.0001,100,selected,rs,nodelookup);
        ConstrainedMajorizationLayout alg(c->rects,c->edges,eweights,ideal_connector_length,test);
        alg.setupConstraints(NULL,NULL,avoid_overlaps,
                NULL,NULL,&c->scx,&c->scy,NULL,NULL);
        alg.run();
    }
    separateComponents(cs);

    for (list<SPItem *>::iterator it(selected.begin());
         it != selected.end();
         ++it)
    {
        SPItem *u=*it;
        if(!isConnector(u)) {
            map<string,unsigned>::iterator i=nodelookup.find(u->getId());
            if(i!=nodelookup.end()) {
                Rectangle* r=rs[i->second];
                Geom::OptRect item_box = u->desktopVisualBounds();
                if (item_box) {
                    Geom::Point const curr(item_box->midpoint());
                    Geom::Point const dest(r->getCentreX(),r->getCentreY());
                    sp_item_move_rel(u, Geom::Translate(dest - curr));
                }
            }
        }
    }
    for(unsigned i=0;i<scx.size();i++) {
        delete scx[i];
    }
    for(unsigned i=0;i<scy.size();i++) {
        delete scy[i];
    }
    for(unsigned i=0;i<rs.size();i++) {
        delete rs[i];
    }
}