From 179fa413b047bede6e32109e2ce82437c5fb8d34 Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Mon, 16 Jan 2006 02:36:01 +0000 Subject: moving trunk for module inkscape (bzr r1) --- src/conn-avoid-ref.cpp | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 src/conn-avoid-ref.cpp (limited to 'src/conn-avoid-ref.cpp') diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp new file mode 100644 index 000000000..0dbd8c730 --- /dev/null +++ b/src/conn-avoid-ref.cpp @@ -0,0 +1,176 @@ +/* + * A class for handling shape interaction with libavoid. + * + * Authors: + * Michael Wybrow + * + * Copyright (C) 2005 Michael Wybrow + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + + + +#include "sp-item.h" +#include "conn-avoid-ref.h" +#include "libnr/nr-rect-ops.h" +#include "libavoid/polyutil.h" +#include "libavoid/incremental.h" +#include "xml/simple-node.cpp" +#include "document.h" + + +static Avoid::Polygn avoid_item_poly(SPItem const *item); +static void avoid_item_move(NR::Matrix const *mp, SPItem *moved_item); + + +SPAvoidRef::SPAvoidRef(SPItem *spitem) + : shapeRef(NULL) + , item(spitem) + , setting(false) + , new_setting(false) + , _transformed_connection() +{ +} + + +SPAvoidRef::~SPAvoidRef() +{ + _transformed_connection.disconnect(); + if (shapeRef) { + // shapeRef is finalised by delShape, + // so no memory is lost here. + Avoid::delShape(shapeRef); + shapeRef = NULL; + } +} + + +void SPAvoidRef::setAvoid(char const *value) +{ + if (SP_OBJECT_IS_CLONED(item)) { + // Don't keep avoidance information for cloned objects. + return; + } + new_setting = false; + if (value && (strcmp(value, "true") == 0)) { + new_setting = true; + } +} + + +void SPAvoidRef::handleSettingChange(void) +{ + if (new_setting == setting) { + // Don't need to make any changes + return; + } + + _transformed_connection.disconnect(); + if (new_setting) { + _transformed_connection = item->connectTransformed( + sigc::ptr_fun(&avoid_item_move)); + + Avoid::Polygn poly = avoid_item_poly(item); + if (poly.pn > 0) { + const char *id = SP_OBJECT_REPR(item)->attribute("id"); + g_assert(id != NULL); + + // Get a unique ID for the item. + GQuark itemID = g_quark_from_string(id); + + shapeRef = new Avoid::ShapeRef(itemID, poly); + Avoid::freePoly(poly); + + Avoid::addShape(shapeRef); + } + } + else + { + g_assert(shapeRef); + + // shapeRef is finalised by delShape, + // so no memory is lost here. + Avoid::delShape(shapeRef); + shapeRef = NULL; + } + setting = new_setting; +} + + +static Avoid::Polygn avoid_item_poly(SPItem const *item) +{ + Avoid::Polygn poly; + + // 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. + + // TODO: SPItem::invokeBbox gives the wrong result for some objects + // that have internal representations that are updated later + // by the sp_*_update functions, e.g., text. + sp_document_ensure_up_to_date(item->document); + + NR::Rect rHull = item->invokeBbox(sp_item_i2doc_affine(item)); + + // Add a little buffer around the edge of each object. + NR::Rect rExpandedHull = NR::expand(rHull, -10.0); + poly = Avoid::newPoly(4); + + for (unsigned n = 0; n < 4; ++n) { + // TODO: I think the winding order in libavoid or inkscape might + // be backwards, probably due to the inverse y co-ordinates + // used for the screen. The '3 - n' reverses the order. + /* On "correct" winding order: Winding order of NR::Rect::corner is in a positive + * direction, like libart. "Positive direction" means the same as in most of Inkscape and + * SVG: if you visualize y as increasing upwards, as is the convention in mathematics, then + * positive angle is visualized as anticlockwise, as in mathematics; so if you visualize y + * as increasing downwards, as is common outside of mathematics, then positive angle + * direction is visualized as clockwise, as is common outside of mathematics. This + * convention makes it easier mix pure mathematics code with graphics code: the important + * thing when mixing code is that the number values stored in variables (representing y + * coordinate, angle) match up; variables store numbers, not visualized positions, and the + * programmer is free to switch between visualizations when thinking about a given piece of + * code. + * + * MathWorld, libart and NR::Rect::corner all seem to take positive winding (i.e. winding + * that yields +1 winding number inside a simple closed shape) to mean winding in a + * positive angle. This, together with the observation that variables store numbers rather + * than positions, suggests that NR::Rect::corner uses the right direction. + */ + NR::Point hullPoint = rExpandedHull.corner(3 - n); + poly.ps[n].x = hullPoint[NR::X]; + poly.ps[n].y = hullPoint[NR::Y]; + } + + return poly; +} + + +static void avoid_item_move(NR::Matrix const *mp, SPItem *moved_item) +{ + Avoid::ShapeRef *shapeRef = moved_item->avoidRef->shapeRef; + g_assert(shapeRef); + + Avoid::Polygn poly = avoid_item_poly(moved_item); + if (poly.pn > 0) { + // moveShape actually destroys the old shapeRef and returns a new one. + moved_item->avoidRef->shapeRef = Avoid::moveShape(shapeRef, &poly); + Avoid::freePoly(poly); + } +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : -- cgit v1.2.3