diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp
index c04ad9e49a4cb2d3a0c122653faf16a986bf721e..21ef2deab53c14bd87502c68c47648ea9c14d249 100644 (file)
--- a/src/conn-avoid-ref.cpp
+++ b/src/conn-avoid-ref.cpp
*
* Authors:
* Michael Wybrow <mjwybrow@users.sourceforge.net>
*
* Authors:
* Michael Wybrow <mjwybrow@users.sourceforge.net>
+ * Abhishek Sharma
*
* Copyright (C) 2005 Michael Wybrow
*
*
* Copyright (C) 2005 Michael Wybrow
*
#include "2geom/line.h"
#include "2geom/crossing.h"
#include "2geom/convex-cover.h"
#include "2geom/line.h"
#include "2geom/crossing.h"
#include "2geom/convex-cover.h"
+#include "helper/geom-curves.h"
#include "svg/stringstream.h"
#include "conn-avoid-ref.h"
#include "connection-points.h"
#include "svg/stringstream.h"
#include "conn-avoid-ref.h"
#include "connection-points.h"
#include "libavoid/router.h"
#include "libavoid/connector.h"
#include "libavoid/geomtypes.h"
#include "libavoid/router.h"
#include "libavoid/connector.h"
#include "libavoid/geomtypes.h"
+#include "libavoid/shape.h"
#include "xml/node.h"
#include "document.h"
#include "desktop.h"
#include "desktop-handles.h"
#include "sp-namedview.h"
#include "xml/node.h"
#include "document.h"
#include "desktop.h"
#include "desktop-handles.h"
#include "sp-namedview.h"
+#include "sp-item-group.h"
#include "inkscape.h"
#include <glibmm/i18n.h>
#include "inkscape.h"
#include <glibmm/i18n.h>
-
+using Inkscape::DocumentUndo;
using Avoid::Router;
using Avoid::Router;
{
_transformed_connection.disconnect();
{
_transformed_connection.disconnect();
- // If the document is being destroyed then the router instance
+ // If the document is being destroyed then the router instance
// and the ShapeRefs will have been destroyed with it.
const bool routerInstanceExists = (item->document->router != NULL);
if (shapeRef && routerInstanceExists) {
// and the ShapeRefs will have been destroyed with it.
const bool routerInstanceExists = (item->document->router != NULL);
if (shapeRef && routerInstanceExists) {
- Router *router = shapeRef->router();
- router->removeShape(shapeRef);
+ // Deleting the shapeRef will remove it completely from
+ // an existing Router instance.
delete shapeRef;
}
shapeRef = NULL;
delete shapeRef;
}
shapeRef = NULL;
Update the connectors for which
the endpoint has changed.
*/
Update the connectors for which
the endpoint has changed.
*/
-
+
gchar ** strarray = g_strsplit(value, "|", 0);
gchar ** iter = strarray;
gchar ** strarray = g_strsplit(value, "|", 0);
gchar ** iter = strarray;
-
+
while (*iter != NULL) {
ConnectionPoint cp;
Inkscape::SVGIStringStream is(*iter);
while (*iter != NULL) {
ConnectionPoint cp;
Inkscape::SVGIStringStream is(*iter);
{
SPPath* path = SP_PATH(i->data);
SPConnEnd** connEnds = path->connEndPair.getConnEnds();
{
SPPath* path = SP_PATH(i->data);
SPConnEnd** connEnds = path->connEndPair.getConnEnds();
- for (int ix=0; ix<2; ++ix)
- if (connEnds[ix]->type == ConnPointUserDefined)
- if (updates.find(connEnds[ix]->id) != updates.end())
- if (path->connEndPair.isAutoRoutingConn())
+ for (int ix=0; ix<2; ++ix) {
+ if (connEnds[ix]->type == ConnPointUserDefined) {
+ if (updates.find(connEnds[ix]->id) != updates.end()) {
+ if (path->connEndPair.isAutoRoutingConn()) {
path->connEndPair.tellLibavoidNewEndpoints();
path->connEndPair.tellLibavoidNewEndpoints();
- else
- {
+ } else {
}
}
- else
- if (deletes.find(connEnds[ix]->id) != deletes.end())
- sp_conn_end_detach(path, ix);
+ }
+ else if (deletes.find(connEnds[ix]->id) != deletes.end()) {
+ sp_conn_end_detach(path, ix);
+ }
+ }
+ }
}
g_slist_free(conns);
// Remove all deleted connection points
}
g_slist_free(conns);
// Remove all deleted connection points
void SPAvoidRef::setConnectionPointsAttrUndoable(const gchar* value, const gchar* action)
{
SPDocument* doc = SP_OBJECT_DOCUMENT(item);
void SPAvoidRef::setConnectionPointsAttrUndoable(const gchar* value, const gchar* action)
{
SPDocument* doc = SP_OBJECT_DOCUMENT(item);
-
- sp_object_setAttribute( SP_OBJECT(item), "inkscape:connection-points", value, 0 );
+
+ item->setAttribute( "inkscape:connection-points", value, 0 );
item->updateRepr();
item->updateRepr();
- sp_document_ensure_up_to_date(doc);
- sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, action);
+ doc->ensureUpToDate();
+ DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, action);
}
void SPAvoidRef::addConnectionPoint(ConnectionPoint &cp)
}
void SPAvoidRef::addConnectionPoint(ConnectionPoint &cp)
}
else
ostr<<'|'<<cp;
}
else
ostr<<'|'<<cp;
-
- this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Added a new connection point") );
+
+ this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Add a new connection point") );
}
void SPAvoidRef::updateConnectionPoint(ConnectionPoint &cp)
}
void SPAvoidRef::updateConnectionPoint(ConnectionPoint &cp)
else
ostr<<'|'<<*to_write;
}
else
ostr<<'|'<<*to_write;
}
- this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Moved a connection point") );
+ this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Move a connection point") );
}
}
}
}
{
Inkscape::SVGOStringStream ostr;
IdConnectionPointMap::iterator cp_pos = connection_points.find( cp.id );
{
Inkscape::SVGOStringStream ostr;
IdConnectionPointMap::iterator cp_pos = connection_points.find( cp.id );
- if ( cp_pos != connection_points.end() )
- {
+ if ( cp_pos != connection_points.end() ) {
bool first = true;
bool first = true;
- for (IdConnectionPointMap::iterator it = connection_points.begin(); it != connection_points.end(); ++it)
- {
- if ( it != cp_pos )
- if ( first )
- {
+ for (IdConnectionPointMap::iterator it = connection_points.begin(); it != connection_points.end(); ++it) {
+ if ( it != cp_pos ) {
+ if ( first ) {
first = false;
ostr<<it->second;
first = false;
ostr<<it->second;
- }
- else
+ } else {
ostr<<'|'<<it->second;
ostr<<'|'<<it->second;
+ }
+ }
}
}
- this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Removed a connection point") );
+ this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Remove a connection point") );
}
}
}
}
// isn't the same as the document that this item is part of. This
// case can happen if a new document is loaded from the file chooser
// or via the recent file menu. In this case, we can end up here
// isn't the same as the document that this item is part of. This
// case can happen if a new document is loaded from the file chooser
// or via the recent file menu. In this case, we can end up here
- // as a rersult of a sp_document_ensure_up_to_date performed on a
+ // as a rersult of a ensureUpToDate performed on a
// document not yet attached to the active desktop.
return;
}
// document not yet attached to the active desktop.
return;
}
setting = new_setting;
Router *router = item->document->router;
setting = new_setting;
Router *router = item->document->router;
-
+
_transformed_connection.disconnect();
if (new_setting) {
Avoid::Polygon poly = avoid_item_poly(item);
_transformed_connection.disconnect();
if (new_setting) {
Avoid::Polygon poly = avoid_item_poly(item);
_transformed_connection = item->connectTransformed(
sigc::ptr_fun(&avoid_item_move));
_transformed_connection = item->connectTransformed(
sigc::ptr_fun(&avoid_item_move));
- const char *id = SP_OBJECT_REPR(item)->attribute("id");
+ char const *id = item->getAttribute("id");
g_assert(id != NULL);
g_assert(id != NULL);
-
+
// Get a unique ID for the item.
GQuark itemID = g_quark_from_string(id);
shapeRef = new Avoid::ShapeRef(router, poly, itemID);
// Get a unique ID for the item.
GQuark itemID = g_quark_from_string(id);
shapeRef = new Avoid::ShapeRef(router, poly, itemID);
-
+
router->addShape(shapeRef);
}
}
else
{
g_assert(shapeRef);
router->addShape(shapeRef);
}
}
else
{
g_assert(shapeRef);
-
- router->removeShape(shapeRef);
+
+ // Deleting the shapeRef will remove it completely from
+ // an existing Router instance.
delete shapeRef;
shapeRef = NULL;
}
delete shapeRef;
shapeRef = NULL;
}
GSList *list = NULL;
Avoid::IntList shapes;
GSList *list = NULL;
Avoid::IntList shapes;
- GQuark shapeId = g_quark_from_string(item->id);
+ GQuark shapeId = g_quark_from_string(item->getId());
item->document->router->attachedShapes(shapes, shapeId, type);
item->document->router->attachedShapes(shapes, shapeId, type);
-
+
Avoid::IntList::iterator finish = shapes.end();
for (Avoid::IntList::iterator i = shapes.begin(); i != finish; ++i) {
const gchar *connId = g_quark_to_string(*i);
Avoid::IntList::iterator finish = shapes.end();
for (Avoid::IntList::iterator i = shapes.begin(); i != finish; ++i) {
const gchar *connId = g_quark_to_string(*i);
GSList *list = NULL;
Avoid::IntList conns;
GSList *list = NULL;
Avoid::IntList conns;
- GQuark shapeId = g_quark_from_string(item->id);
+ GQuark shapeId = g_quark_from_string(item->getId());
item->document->router->attachedConns(conns, shapeId, type);
item->document->router->attachedConns(conns, shapeId, type);
-
+
Avoid::IntList::iterator finish = conns.end();
for (Avoid::IntList::iterator i = conns.begin(); i != finish; ++i) {
const gchar *connId = g_quark_to_string(*i);
Avoid::IntList::iterator finish = conns.end();
for (Avoid::IntList::iterator i = conns.begin(); i != finish; ++i) {
const gchar *connId = g_quark_to_string(*i);
{
g_assert(item);
Geom::Point pos;
{
g_assert(item);
Geom::Point pos;
- const Geom::Matrix& transform = sp_item_i2doc_affine(item);
- SPDesktop *desktop = inkscape_active_desktop();
+ const Geom::Matrix& transform = item->i2doc_affine();
if ( type == ConnPointDefault )
{
// For now, just default to the centre of the item
if ( type == ConnPointDefault )
{
// For now, just default to the centre of the item
- Geom::OptRect bbox = item->getBounds(sp_item_i2doc_affine(item));
+ Geom::OptRect bbox = item->getBounds(item->i2doc_affine());
pos = (bbox) ? bbox->midpoint() : Geom::Point(0, 0);
}
else
pos = (bbox) ? bbox->midpoint() : Geom::Point(0, 0);
}
else
else
return connection_points.find( id ) != connection_points.end();
}
else
return connection_points.find( id ) != connection_points.end();
}
-
+
return true;
}
return true;
}
-static Avoid::Polygon avoid_item_poly(SPItem const *item)
+static std::vector<Geom::Point> approxCurveWithPoints(SPCurve *curve)
{
{
- SPDesktop *desktop = inkscape_active_desktop();
- g_assert(desktop != NULL);
-
- // TODO: The right way to do this is to return the convex hull of
- // the object, or an approximation in the case of a rounded
- // object. Specific SPItems will need to have a new
- // function that returns points for the convex hull.
- // For some objects it is enough to feed the snappoints to
- // some convex hull code, though not NR::ConvexHull as this
- // only keeps the bounding box of the convex hull currently.
-
- double spacing = desktop->namedview->connector_spacing;
-
- // [sommer] If item is a shape, use an approximation of its convex hull
+ // The number of segments to use for not straight curves approximation
+ const unsigned NUM_SEGS = 4;
+
+ const Geom::PathVector& curve_pv = curve->get_pathvector();
+
+ // The structure to hold the output
+ std::vector<Geom::Point> poly_points;
+
+ // Iterate over all curves, adding the endpoints for linear curves and
+ // sampling the other curves
+ double seg_size = 1.0 / NUM_SEGS;
+ double at;
+ at = 0;
+ Geom::PathVector::const_iterator pit = curve_pv.begin();
+ while (pit != curve_pv.end())
{
{
- // MJW: Disable this for the moment. It still has some issues.
- const bool convex_hull_approximation_enabled = false;
-
- if ( convex_hull_approximation_enabled && SP_IS_SHAPE (item) ) {
- // The number of points to use for approximation
- const unsigned NUM_POINTS = 64;
-
-// printf("[sommer] is a shape\n");
- SPCurve* curve = sp_shape_get_curve (SP_SHAPE (item));
- if (curve) {
-// printf("[sommer] is a curve\n");
-
- // apply all transformations
- Geom::Matrix itd_mat = sp_item_i2doc_affine(item);
- curve->transform(itd_mat);
-
- // iterate over all paths
- const Geom::PathVector& curve_pv = curve->get_pathvector();
- std::vector<Geom::Point> hull_points;
- for (Geom::PathVector::const_iterator i = curve_pv.begin(); i != curve_pv.end(); i++) {
- const Geom::Path& curve_pv_path = *i;
-// printf("[sommer] tracing sub-path\n");
-
- // FIXME: enlarge path by "desktop->namedview->connector_spacing" (using sp_selected_path_do_offset)?
-
- // use appropriate fraction of points for this path (first one gets any remainder)
- unsigned num_points = NUM_POINTS / curve_pv.size();
- if (i == curve_pv.begin()) num_points += NUM_POINTS - (num_points * curve_pv.size());
- printf("[sommer] using %d points for this path\n", num_points);
-
- // sample points along the path for approximation of convex hull
- for (unsigned n = 0; n < num_points; n++) {
- double at = curve_pv_path.size() / static_cast<double>(num_points) * n;
- Geom::Point pt = curve_pv_path.pointAt(at);
- hull_points.push_back(pt);
- }
- }
-
- curve->unref();
-
- // create convex hull from all sampled points
- Geom::ConvexHull hull(hull_points);
-
- // store expanded convex hull in Avoid::Polygn
- unsigned n = 0;
- Avoid::Polygon poly;
- const Geom::Point& old_pt = *hull.boundary.begin();
-
- Geom::Line hull_edge(*hull.boundary.begin(), *(hull.boundary.begin()+1));
- Geom::Line parallel_hull_edge;
- parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
- parallel_hull_edge.versor(hull_edge.versor());
- Geom::Line bisector = Geom::make_angle_bisector_line( *(hull.boundary.end()), *hull.boundary.begin(),
- *(hull.boundary.begin()+1));
- Geom::OptCrossing int_pt = Geom::intersection(parallel_hull_edge, bisector);
+ Geom::Path::const_iterator cit = pit->begin();
+ while (cit != pit->end())
+ {
+ if (cit == pit->begin())
+ {
+ poly_points.push_back(cit->initialPoint());
+ }
- if (int_pt)
+ if (dynamic_cast<Geom::CubicBezier const*>(&*cit))
+ {
+ at += seg_size;
+ if (at <= 1.0 )
+ poly_points.push_back(cit->pointAt(at));
+ else
{
{
- Avoid::Point avoid_pt((parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
- (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);
-// printf("[sommer] %f, %f\n", old_pt[Geom::X], old_pt[Geom::Y]);
-/* printf("[sommer] %f, %f\n", (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
- (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);*/
- poly.ps.push_back(avoid_pt);
- }
- for (std::vector<Geom::Point>::const_iterator i = hull.boundary.begin() + 1; i != hull.boundary.end(); i++, n++) {
- const Geom::Point& old_pt = *i;
- Geom::Line hull_edge(*i, *(i+1));
- Geom::Line parallel_hull_edge;
- parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
- parallel_hull_edge.versor(hull_edge.versor());
- Geom::Line bisector = Geom::make_angle_bisector_line( *(i-1), *i, *(i+1));
- Geom::OptCrossing intersect_pt = Geom::intersection(parallel_hull_edge, bisector);
-
- if (int_pt)
- {
- Avoid::Point avoid_pt((parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
- (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);
-/* printf("[sommer] %f, %f\n", old_pt[Geom::X], old_pt[Geom::Y]);
- printf("[sommer] %f, %f\n", (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
- (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);*/
- poly.ps.push_back(avoid_pt);
- }
+ at = 0.0;
+ ++cit;
}
}
-
+ }
+ else
+ {
+ poly_points.push_back(cit->finalPoint());
+ ++cit;
+ }
+ }
+ ++pit;
+ }
+ return poly_points;
+}
- return poly;
- }// else printf("[sommer] is no curve\n");
- }// else printf("[sommer] is no shape\n");
+static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const Geom::Matrix& item_transform)
+{
+ // The structure to hold the output
+ std::vector<Geom::Point> poly_points;
+
+ if (SP_IS_GROUP(item))
+ {
+ SPGroup* group = SP_GROUP(item);
+ // consider all first-order children
+ for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) {
+ SPItem* child_item = SP_ITEM(i->data);
+ std::vector<Geom::Point> child_points = approxItemWithPoints(child_item, item_transform * child_item->transform);
+ poly_points.insert(poly_points.end(), child_points.begin(), child_points.end());
+ }
}
}
-
- Geom::OptRect rHull = item->getBounds(sp_item_i2doc_affine(item));
- if (!rHull) {
- return Avoid::Polygon();
+ else if (SP_IS_SHAPE(item))
+ {
+ SPCurve* item_curve = SP_SHAPE(item)->getCurve();
+ // make sure it has an associated curve
+ if (item_curve)
+ {
+ // apply transformations (up to common ancestor)
+ item_curve->transform(item_transform);
+ std::vector<Geom::Point> curve_points = approxCurveWithPoints(item_curve);
+ poly_points.insert(poly_points.end(), curve_points.begin(), curve_points.end());
+ item_curve->unref();
+ }
}
}
- // Add a little buffer around the edge of each object.
- Geom::Rect rExpandedHull = *rHull;
- rExpandedHull.expandBy(spacing);
- Avoid::Polygon poly(4);
+ return poly_points;
+}
+static Avoid::Polygon avoid_item_poly(SPItem const *item)
+{
+ SPDesktop *desktop = inkscape_active_desktop();
+ g_assert(desktop != NULL);
+ double spacing = desktop->namedview->connector_spacing;
+
+ Geom::Matrix itd_mat = item->i2doc_affine();
+ std::vector<Geom::Point> hull_points;
+ hull_points = approxItemWithPoints(item, itd_mat);
- for (size_t n = 0; n < 4; ++n) {
- Geom::Point hullPoint = rExpandedHull.corner(n);
- poly.ps[n].x = hullPoint[Geom::X];
- poly.ps[n].y = hullPoint[Geom::Y];
- }
+ // create convex hull from all sampled points
+ Geom::ConvexHull hull(hull_points);
+
+ // enlarge path by "desktop->namedview->connector_spacing"
+ // store expanded convex hull in Avoid::Polygn
+ Avoid::Polygon poly;
+ Geom::Line hull_edge(hull[-1], hull[0]);
+ Geom::Line prev_parallel_hull_edge;
+ prev_parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
+ prev_parallel_hull_edge.versor(hull_edge.versor());
+ int hull_size = hull.boundary.size();
+ for (int i = 0; i < hull_size; ++i)
+ {
+ hull_edge.setBy2Points(hull[i], hull[i+1]);
+ Geom::Line parallel_hull_edge;
+ parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
+ parallel_hull_edge.versor(hull_edge.versor());
+
+ // determine the intersection point
+
+ Geom::OptCrossing int_pt = Geom::intersection(parallel_hull_edge, prev_parallel_hull_edge);
+ if (int_pt)
+ {
+ Avoid::Point avoid_pt((parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::X],
+ (parallel_hull_edge.origin()+parallel_hull_edge.versor()*int_pt->ta)[Geom::Y]);
+ poly.ps.push_back(avoid_pt);
+ }
+ else
+ {
+ // something went wrong...
+ std::cout<<"conn-avoid-ref.cpp: avoid_item_poly: Geom:intersection failed."<<std::endl;
+ }
+ prev_parallel_hull_edge = parallel_hull_edge;
+ }
return poly;
}
return poly;
}
-GSList *get_avoided_items(GSList *list, SPObject *from, SPDesktop *desktop,
+GSList *get_avoided_items(GSList *list, SPObject *from, SPDesktop *desktop,
bool initialised)
{
bool initialised)
{
- for (SPObject *child = sp_object_first_child(SP_OBJECT(from)) ;
- child != NULL; child = SP_OBJECT_NEXT(child) ) {
+ for (SPObject *child = from->firstChild() ; child != NULL; child = child->next ) {
if (SP_IS_ITEM(child) &&
!desktop->isLayer(SP_ITEM(child)) &&
if (SP_IS_ITEM(child) &&
!desktop->isLayer(SP_ITEM(child)) &&
- !SP_ITEM(child)->isLocked() &&
+ !SP_ITEM(child)->isLocked() &&
!desktop->itemIsHidden(SP_ITEM(child)) &&
(!initialised || SP_ITEM(child)->avoidRef->shapeRef)
)
!desktop->itemIsHidden(SP_ITEM(child)) &&
(!initialised || SP_ITEM(child)->avoidRef->shapeRef)
)
// Don't count this as changes to the document,
// it is basically just late initialisation.
SPDocument *document = sp_desktop_document(desktop);
// Don't count this as changes to the document,
// it is basically just late initialisation.
SPDocument *document = sp_desktop_document(desktop);
- bool saved = sp_document_get_undo_sensitive(document);
- sp_document_set_undo_sensitive(document, false);
-
+ bool saved = DocumentUndo::getUndoSensitive(document);
+ DocumentUndo::setUndoSensitive(document, false);
+
bool initialised = false;
GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop,
initialised);
bool initialised = false;
GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop,
initialised);
if (items) {
g_slist_free(items);
}
if (items) {
g_slist_free(items);
}
- sp_document_set_undo_sensitive(document, saved);
+ DocumentUndo::setUndoSensitive(document, saved);
}
}