X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fconn-avoid-ref.cpp;h=21ef2deab53c14bd87502c68c47648ea9c14d249;hb=8a2e76b7021b9b960d7c30801a1a14461d9b5939;hp=b9dc218b4fcc84bfaa48e06df9b81ad0c11cf701;hpb=cc618cb0faf84b6f5ab2cc9802b29d03f6a22f97;p=inkscape.git diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index b9dc218b4..21ef2deab 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -3,6 +3,7 @@ * * Authors: * Michael Wybrow + * Abhishek Sharma * * Copyright (C) 2005 Michael Wybrow * @@ -19,6 +20,7 @@ #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" @@ -27,15 +29,17 @@ #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 "sp-item-group.h" #include "inkscape.h" #include - +using Inkscape::DocumentUndo; using Avoid::Router; @@ -61,8 +65,8 @@ SPAvoidRef::~SPAvoidRef() 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; @@ -192,10 +196,10 @@ void SPAvoidRef::setConnectionPointsAttrUndoable(const gchar* value, const gchar { 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(); - 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) @@ -232,7 +236,7 @@ void SPAvoidRef::addConnectionPoint(ConnectionPoint &cp) else ostr<<'|'<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) @@ -257,7 +261,7 @@ void SPAvoidRef::updateConnectionPoint(ConnectionPoint &cp) else ostr<<'|'<<*to_write; } - this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Moved a connection point") ); + this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Move a connection point") ); } } @@ -277,7 +281,7 @@ void SPAvoidRef::deleteConnectionPoint(ConnectionPoint &cp) } } } - this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Removed a connection point") ); + this->setConnectionPointsAttrUndoable( ostr.str().c_str(), _("Remove a connection point") ); } } @@ -292,7 +296,7 @@ void SPAvoidRef::handleSettingChange(void) // 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; } @@ -312,7 +316,7 @@ void SPAvoidRef::handleSettingChange(void) _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); // Get a unique ID for the item. @@ -327,7 +331,8 @@ void SPAvoidRef::handleSettingChange(void) { g_assert(shapeRef); - router->removeShape(shapeRef); + // Deleting the shapeRef will remove it completely from + // an existing Router instance. delete shapeRef; shapeRef = NULL; } @@ -339,7 +344,7 @@ GSList *SPAvoidRef::getAttachedShapes(const unsigned int type) 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); Avoid::IntList::iterator finish = shapes.end(); @@ -363,7 +368,7 @@ GSList *SPAvoidRef::getAttachedConnectors(const unsigned int type) 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); Avoid::IntList::iterator finish = conns.end(); @@ -385,14 +390,12 @@ Geom::Point SPAvoidRef::getConnectionPointPos(const int type, const int id) { g_assert(item); Geom::Point pos; - const Geom::Matrix& transform = sp_item_i2doc_affine(item); - // TODO investigate why this was asking for the active desktop: - 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 - 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 @@ -424,134 +427,130 @@ bool SPAvoidRef::isValidConnPointId( const int type, const int id ) return true; } -static Avoid::Polygon avoid_item_poly(SPItem const *item) +static std::vector 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 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 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(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(&*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::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; +} +static std::vector approxItemWithPoints(SPItem const *item, const Geom::Matrix& item_transform) +{ + // The structure to hold the output + std::vector poly_points; - return poly; - }// else printf("[sommer] is no curve\n"); - }// else printf("[sommer] is no shape\n"); + 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 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 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; - 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]; - } + Geom::Matrix itd_mat = item->i2doc_affine(); + std::vector hull_points; + hull_points = approxItemWithPoints(item, itd_mat); + // 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."<firstChild() ; child != NULL; child = child->next ) { if (SP_IS_ITEM(child) && !desktop->isLayer(SP_ITEM(child)) && !SP_ITEM(child)->isLocked() && @@ -598,8 +596,8 @@ void init_avoided_shape_geometry(SPDesktop *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, @@ -613,7 +611,7 @@ void init_avoided_shape_geometry(SPDesktop *desktop) if (items) { g_slist_free(items); } - sp_document_set_undo_sensitive(document, saved); + DocumentUndo::setUndoSensitive(document, saved); }