X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-conn-end-pair.cpp;h=0a5a6d7bdde9e9fb72ae144ba76ab29c7e0355c5;hb=9dc68827cbd515262ecb8d5ae8547d9e82c72e00;hp=c5cc752514bd0899cd4e4ef39ee404a38164f939;hpb=031a094cece1123331bae8b916d3f79e805372d2;p=inkscape.git diff --git a/src/sp-conn-end-pair.cpp b/src/sp-conn-end-pair.cpp index c5cc75251..0a5a6d7bd 100644 --- a/src/sp-conn-end-pair.cpp +++ b/src/sp-conn-end-pair.cpp @@ -4,12 +4,18 @@ * Authors: * Peter Moulder * Michael Wybrow + * Abhishek Sharma * * * Copyright (C) 2004-2005 Monash University * * Released under GNU GPL, read the file 'COPYING' for more information */ +#include +#include +#include +#include + #include "attributes.h" #include "sp-conn-end.h" #include "uri.h" @@ -23,10 +29,10 @@ SPConnEndPair::SPConnEndPair(SPPath *const owner) - : _invalid_path_connection() - , _path(owner) + : _path(owner) , _connRef(NULL) , _connType(SP_CONNECTOR_NOAVOID) + , _connCurvature(0.0) , _transformed_connection() { for (unsigned handle_ix = 0; handle_ix <= 1; ++handle_ix) { @@ -44,14 +50,6 @@ SPConnEndPair::~SPConnEndPair() delete this->_connEnd[handle_ix]; this->_connEnd[handle_ix] = NULL; } - if (_connRef) { - _connRef->removeFromGraph(); - delete _connRef; - _connRef = NULL; - } - - _invalid_path_connection.disconnect(); - _transformed_connection.disconnect(); } void @@ -65,74 +63,132 @@ SPConnEndPair::release() this->_connEnd[handle_ix]->href = NULL; this->_connEnd[handle_ix]->ref.detach(); } + + // If the document is being destroyed then the router instance + // and the ConnRefs will have been destroyed with it. + const bool routerInstanceExists = (_path->document->router != NULL); + + if (_connRef && routerInstanceExists) { + _connRef->removeFromGraph(); + delete _connRef; + } + _connRef = NULL; + + _transformed_connection.disconnect(); } void sp_conn_end_pair_build(SPObject *object) { - sp_object_read_attr(object, "inkscape:connector-type"); - sp_object_read_attr(object, "inkscape:connection-start"); - sp_object_read_attr(object, "inkscape:connection-end"); + object->readAttr( "inkscape:connector-type" ); + object->readAttr( "inkscape:connection-start" ); + object->readAttr( "inkscape:connection-start-point" ); + object->readAttr( "inkscape:connection-end" ); + object->readAttr( "inkscape:connection-end-point" ); + object->readAttr( "inkscape:connector-curvature" ); } static void -avoid_conn_move(NR::Matrix const *mp, SPItem *moved_item) +avoid_conn_transformed(Geom::Matrix const */*mp*/, SPItem *moved_item) { - // Reroute connector SPPath *path = SP_PATH(moved_item); - path->connEndPair.makePathInvalid(); - sp_conn_adjust_invalid_path(path); + if (path->connEndPair.isAutoRoutingConn()) { + path->connEndPair.tellLibavoidNewEndpoints(); + } } void SPConnEndPair::setAttr(unsigned const key, gchar const *const value) { - if (key == SP_ATTR_CONNECTOR_TYPE) { - if (value && (strcmp(value, "polyline") == 0)) { - _connType = SP_CONNECTOR_POLYLINE; - - Avoid::Router *router = _path->document->router; - GQuark itemID = g_quark_from_string(SP_OBJECT(_path)->id); - _connRef = new Avoid::ConnRef(router, itemID); - _invalid_path_connection = connectInvalidPath( - sigc::ptr_fun(&sp_conn_adjust_invalid_path)); - _transformed_connection = _path->connectTransformed( - sigc::ptr_fun(&avoid_conn_move)); - } - else { - _connType = SP_CONNECTOR_NOAVOID; - - if (_connRef) { - _connRef->removeFromGraph(); - delete _connRef; - _connRef = NULL; - _invalid_path_connection.disconnect(); - _transformed_connection.disconnect(); + switch (key) + { + case SP_ATTR_CONNECTOR_TYPE: + if (value && (strcmp(value, "polyline") == 0 || strcmp(value, "orthogonal") == 0)) { + int newconnType = strcmp(value, "polyline") ? SP_CONNECTOR_ORTHOGONAL : SP_CONNECTOR_POLYLINE; + + if (!_connRef) + { + _connType = newconnType; + Avoid::Router *router = _path->document->router; + GQuark itemID = g_quark_from_string(_path->getId()); + _connRef = new Avoid::ConnRef(router, itemID); + switch (newconnType) + { + case SP_CONNECTOR_POLYLINE: + _connRef->setRoutingType(Avoid::ConnType_PolyLine); + break; + case SP_CONNECTOR_ORTHOGONAL: + _connRef->setRoutingType(Avoid::ConnType_Orthogonal); + } + _transformed_connection = _path->connectTransformed( + sigc::ptr_fun(&avoid_conn_transformed)); + } + else + if (newconnType != _connType) + { + _connType = newconnType; + switch (newconnType) + { + case SP_CONNECTOR_POLYLINE: + _connRef->setRoutingType(Avoid::ConnType_PolyLine); + break; + case SP_CONNECTOR_ORTHOGONAL: + _connRef->setRoutingType(Avoid::ConnType_Orthogonal); + } + sp_conn_reroute_path(_path); + } } - } - return; - + else { + _connType = SP_CONNECTOR_NOAVOID; + + if (_connRef) { + _connRef->removeFromGraph(); + delete _connRef; + _connRef = NULL; + _transformed_connection.disconnect(); + } + } + break; + case SP_ATTR_CONNECTOR_CURVATURE: + if (value) { + _connCurvature = g_strtod(value, NULL); + if (_connRef && _connRef->isInitialised()) { + // Redraw the connector, but only if it has been initialised. + sp_conn_reroute_path(_path); + } + } + break; + case SP_ATTR_CONNECTION_START: + case SP_ATTR_CONNECTION_END: + this->_connEnd[(key == SP_ATTR_CONNECTION_START ? 0 : 1)]->setAttacherHref(value, _path); + break; + case SP_ATTR_CONNECTION_START_POINT: + case SP_ATTR_CONNECTION_END_POINT: + this->_connEnd[(key == SP_ATTR_CONNECTION_START_POINT ? 0 : 1)]->setAttacherEndpoint(value, _path); + break; } - unsigned const handle_ix = key - SP_ATTR_CONNECTION_START; - g_assert( handle_ix <= 1 ); - this->_connEnd[handle_ix]->setAttacherHref(value); } void SPConnEndPair::writeRepr(Inkscape::XML::Node *const repr) const { + char const * const attr_strs[] = {"inkscape:connection-start", "inkscape:connection-start-point", + "inkscape:connection-end", "inkscape:connection-end-point"}; for (unsigned handle_ix = 0; handle_ix < 2; ++handle_ix) { if (this->_connEnd[handle_ix]->ref.getURI()) { - char const * const attr_strs[] = {"inkscape:connection-start", - "inkscape:connection-end"}; - gchar *uri_string = this->_connEnd[handle_ix]->ref.getURI()->toString(); - repr->setAttribute(attr_strs[handle_ix], uri_string); - g_free(uri_string); + repr->setAttribute(attr_strs[2*handle_ix], this->_connEnd[handle_ix]->ref.getURI()->toString()); + std::ostringstream ostr; + ostr<<(this->_connEnd[handle_ix]->type == ConnPointDefault ? "d":"u") << + this->_connEnd[handle_ix]->id; + repr->setAttribute(attr_strs[2*handle_ix+1], ostr.str().c_str()); } } + repr->setAttribute("inkscape:connector-curvature", Glib::Ascii::dtostr(_connCurvature).c_str()); + if (_connType == SP_CONNECTOR_POLYLINE || _connType == SP_CONNECTOR_ORTHOGONAL) + repr->setAttribute("inkscape:connector-type", _connType == SP_CONNECTOR_POLYLINE ? "polyline" : "orthogonal" ); } void @@ -141,7 +197,7 @@ SPConnEndPair::getAttachedItems(SPItem *h2attItem[2]) const { h2attItem[h] = this->_connEnd[h]->ref.getObject(); // Deal with the case of the attached object being an empty group. - // A group containing no items does not have a valid bbox, so + // A group containing no items does not have a valid bbox, so // causes problems for the auto-routing code. Also, since such a // group no longer has an onscreen representation and can only be // selected through the XML editor, it makes sense just to detach @@ -157,59 +213,62 @@ SPConnEndPair::getAttachedItems(SPItem *h2attItem[2]) const { } void -SPConnEndPair::getEndpoints(NR::Point endPts[]) const { - SPCurve *curve = _path->curve; +SPConnEndPair::getEndpoints(Geom::Point endPts[]) const { + SPCurve *curve = _path->original_curve ? _path->original_curve : _path->curve; SPItem *h2attItem[2]; getAttachedItems(h2attItem); for (unsigned h = 0; h < 2; ++h) { if ( h2attItem[h] ) { - NR::Rect const bbox = h2attItem[h]->invokeBbox(sp_item_i2doc_affine(h2attItem[h])); - endPts[h] = bbox.midpoint(); + g_assert(h2attItem[h]->avoidRef); + endPts[h] = h2attItem[h]->avoidRef->getConnectionPointPos(_connEnd[h]->type, _connEnd[h]->id); } else { if (h == 0) { - endPts[h] = sp_curve_first_point(curve); + endPts[h] = *(curve->first_point()); } else { - endPts[h] = sp_curve_last_point(curve); + endPts[h] = *(curve->last_point()); } } } } -sigc::connection -SPConnEndPair::connectInvalidPath(sigc::slot slot) -{ - return _invalid_path_signal.connect(slot); +gdouble +SPConnEndPair::getCurvature(void) const { + return _connCurvature; } -static void emitPathInvalidationNotification(void *ptr) +SPConnEnd** +SPConnEndPair::getConnEnds(void) { - // We emit a signal here rather than just calling the reroute function - // since this allows all the movement action computation to happen, - // then all connectors (that require it) will be rerouted. Otherwise, - // one connector could get rerouted several times as a result of - // dragging a couple of shapes. + return _connEnd; +} - SPPath *path = SP_PATH(ptr); - path->connEndPair._invalid_path_signal.emit(path); +bool +SPConnEndPair::isOrthogonal(void) const { + return _connType == SP_CONNECTOR_ORTHOGONAL; } -void -SPConnEndPair::rerouteFromManipulation(void) + +static void redrawConnectorCallback(void *ptr) { - _connRef->makePathInvalid(); - sp_conn_adjust_path(_path); + SPPath *path = SP_PATH(ptr); + if (path->document == NULL) { + // This can happen when the document is being destroyed. + return; + } + sp_conn_redraw_path(path); } void -SPConnEndPair::reroute(void) +SPConnEndPair::rerouteFromManipulation(void) { - sp_conn_adjust_path(_path); + sp_conn_reroute_path_immediate(_path); } + // Called from sp_path_update to initialise the endpoints. void SPConnEndPair::update(void) @@ -217,14 +276,14 @@ SPConnEndPair::update(void) if (_connType != SP_CONNECTOR_NOAVOID) { g_assert(_connRef != NULL); if (!(_connRef->isInitialised())) { - NR::Point endPt[2]; + Geom::Point endPt[2]; getEndpoints(endPt); - Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] }; - Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] }; + Avoid::Point src(endPt[0][Geom::X], endPt[0][Geom::Y]); + Avoid::Point dst(endPt[1][Geom::X], endPt[1][Geom::Y]); - _connRef->lateSetup(src, dst); - _connRef->setCallback(&emitPathInvalidationNotification, _path); + _connRef->setEndpoints(src, dst); + _connRef->setCallback(&redrawConnectorCallback, _path); } // Store the ID of the objects attached to the connector. storeIds(); @@ -270,39 +329,90 @@ SPConnEndPair::makePathInvalid(void) _connRef->makePathInvalid(); } + +// Redraws the curve along the recalculated route +// Straight or curved +void recreateCurve(SPCurve *curve, Avoid::ConnRef *connRef, const gdouble curvature) +{ + bool straight = curvature<1e-3; + + Avoid::PolyLine route = connRef->displayRoute(); + if (!straight) + route = route.curvedPolyline(curvature); + connRef->calcRouteDist(); + + curve->reset(); + + curve->moveto( Geom::Point(route.ps[0].x, route.ps[0].y) ); + int pn = route.size(); + for (int i = 1; i < pn; ++i) { + Geom::Point p(route.ps[i].x, route.ps[i].y); + if (straight) { + curve->lineto( p ); + } + else { + switch (route.ts[i]) { + case 'M': + curve->moveto( p ); + break; + case 'L': + curve->lineto( p ); + break; + case 'C': + g_assert( i+2curveto( p, Geom::Point(route.ps[i+1].x, route.ps[i+1].y), + Geom::Point(route.ps[i+2].x, route.ps[i+2].y) ); + i+=2; + break; + } + } + } +} + + void -SPConnEndPair::reroutePath(void) +SPConnEndPair::tellLibavoidNewEndpoints(const bool processTransaction) { if (!isAutoRoutingConn()) { // Do nothing return; } + makePathInvalid(); - SPCurve *curve = _path->curve; - - NR::Point endPt[2]; + Geom::Point endPt[2]; getEndpoints(endPt); - Avoid::Point src = { endPt[0][NR::X], endPt[0][NR::Y] }; - Avoid::Point dst = { endPt[1][NR::X], endPt[1][NR::Y] }; + Avoid::Point src(endPt[0][Geom::X], endPt[0][Geom::Y]); + Avoid::Point dst(endPt[1][Geom::X], endPt[1][Geom::Y]); - _connRef->updateEndPoint(Avoid::VertID::src, src); - _connRef->updateEndPoint(Avoid::VertID::tar, dst); + _connRef->setEndpoints(src, dst); + if (processTransaction) + { + _connRef->router()->processTransaction(); + } + return; +} - _connRef->generatePath(src, dst); - Avoid::PolyLine route = _connRef->route(); - _connRef->calcRouteDist(); +bool +SPConnEndPair::reroutePathFromLibavoid(void) +{ + if (!isAutoRoutingConn()) { + // Do nothing + return false; + } - sp_curve_reset(curve); - sp_curve_moveto(curve, endPt[0]); + SPCurve *curve = _path->original_curve ?_path->original_curve : _path->curve; - for (int i = 1; i < route.pn; ++i) { - NR::Point p(route.ps[i].x, route.ps[i].y); - sp_curve_lineto(curve, p); - } + recreateCurve( curve, _connRef, _connCurvature ); + + Geom::Matrix doc2item = SP_ITEM(_path)->i2doc_affine().inverse(); + curve->transform(doc2item); + + return true; } + /* Local Variables: mode:c++