Code

moving trunk for module inkscape
[inkscape.git] / src / conn-avoid-ref.cpp
1 /*
2  * A class for handling shape interaction with libavoid.
3  *
4  * Authors:
5  *   Michael Wybrow <mjwybrow@users.sourceforge.net>
6  *
7  * Copyright (C) 2005 Michael Wybrow
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
14 #include "sp-item.h"
15 #include "conn-avoid-ref.h"
16 #include "libnr/nr-rect-ops.h"
17 #include "libavoid/polyutil.h"
18 #include "libavoid/incremental.h"
19 #include "xml/simple-node.cpp"
20 #include "document.h"
23 static Avoid::Polygn avoid_item_poly(SPItem const *item);
24 static void avoid_item_move(NR::Matrix const *mp, SPItem *moved_item);
27 SPAvoidRef::SPAvoidRef(SPItem *spitem)
28     : shapeRef(NULL)
29     , item(spitem)
30     , setting(false)
31     , new_setting(false)
32     , _transformed_connection()
33 {
34 }
37 SPAvoidRef::~SPAvoidRef()
38 {
39     _transformed_connection.disconnect();
40     if (shapeRef) {
41         // shapeRef is finalised by delShape,
42         // so no memory is lost here.
43         Avoid::delShape(shapeRef);
44         shapeRef = NULL;
45     }
46 }
49 void SPAvoidRef::setAvoid(char const *value)
50 {
51     if (SP_OBJECT_IS_CLONED(item)) {
52         // Don't keep avoidance information for cloned objects.
53         return;
54     }
55     new_setting = false;
56     if (value && (strcmp(value, "true") == 0)) {
57         new_setting = true;
58     }
59 }
62 void SPAvoidRef::handleSettingChange(void)
63 {
64     if (new_setting == setting) {
65         // Don't need to make any changes
66         return;
67     }
69     _transformed_connection.disconnect();
70     if (new_setting) {
71         _transformed_connection = item->connectTransformed(
72                 sigc::ptr_fun(&avoid_item_move));
74         Avoid::Polygn poly = avoid_item_poly(item);
75         if (poly.pn > 0) {
76             const char *id = SP_OBJECT_REPR(item)->attribute("id");
77             g_assert(id != NULL);
78             
79             // Get a unique ID for the item.
80             GQuark itemID = g_quark_from_string(id);
82             shapeRef = new Avoid::ShapeRef(itemID, poly);
83             Avoid::freePoly(poly);
84         
85             Avoid::addShape(shapeRef);
86         }
87     }
88     else
89     {
90         g_assert(shapeRef);
91         
92         // shapeRef is finalised by delShape,
93         // so no memory is lost here.
94         Avoid::delShape(shapeRef);
95         shapeRef = NULL;
96     }
97     setting = new_setting;
98 }
101 static Avoid::Polygn avoid_item_poly(SPItem const *item)
103     Avoid::Polygn poly;
105     // TODO: The right way to do this is to return the convex hull of
106     //       the object, or an approximation in the case of a rounded
107     //       object.  Specific SPItems will need to have a new
108     //       function that returns points for the convex hull.
109     //       For some objects it is enough to feed the snappoints to
110     //       some convex hull code, though not NR::ConvexHull as this
111     //       only keeps the bounding box of the convex hull currently.
113     // TODO: SPItem::invokeBbox gives the wrong result for some objects
114     //       that have internal representations that are updated later
115     //       by the sp_*_update functions, e.g., text.
116     sp_document_ensure_up_to_date(item->document);
117     
118     NR::Rect rHull = item->invokeBbox(sp_item_i2doc_affine(item));
119     
120     // Add a little buffer around the edge of each object.
121     NR::Rect rExpandedHull = NR::expand(rHull, -10.0); 
122     poly = Avoid::newPoly(4);
124     for (unsigned n = 0; n < 4; ++n) {
125         // TODO: I think the winding order in libavoid or inkscape might
126         //       be backwards, probably due to the inverse y co-ordinates
127         //       used for the screen.  The '3 - n' reverses the order.
128         /* On "correct" winding order: Winding order of NR::Rect::corner is in a positive
129          * direction, like libart.  "Positive direction" means the same as in most of Inkscape and
130          * SVG: if you visualize y as increasing upwards, as is the convention in mathematics, then
131          * positive angle is visualized as anticlockwise, as in mathematics; so if you visualize y
132          * as increasing downwards, as is common outside of mathematics, then positive angle
133          * direction is visualized as clockwise, as is common outside of mathematics.  This
134          * convention makes it easier mix pure mathematics code with graphics code: the important
135          * thing when mixing code is that the number values stored in variables (representing y
136          * coordinate, angle) match up; variables store numbers, not visualized positions, and the
137          * programmer is free to switch between visualizations when thinking about a given piece of
138          * code.
139          *
140          * MathWorld, libart and NR::Rect::corner all seem to take positive winding (i.e. winding
141          * that yields +1 winding number inside a simple closed shape) to mean winding in a
142          * positive angle.  This, together with the observation that variables store numbers rather
143          * than positions, suggests that NR::Rect::corner uses the right direction.
144          */
145         NR::Point hullPoint = rExpandedHull.corner(3 - n);
146         poly.ps[n].x = hullPoint[NR::X];
147         poly.ps[n].y = hullPoint[NR::Y];
148     }
150     return poly;
154 static void avoid_item_move(NR::Matrix const *mp, SPItem *moved_item)
156     Avoid::ShapeRef *shapeRef = moved_item->avoidRef->shapeRef;
157     g_assert(shapeRef);
159     Avoid::Polygn poly = avoid_item_poly(moved_item);
160     if (poly.pn > 0) {
161         // moveShape actually destroys the old shapeRef and returns a new one.
162         moved_item->avoidRef->shapeRef = Avoid::moveShape(shapeRef, &poly);
163         Avoid::freePoly(poly);
164     }
166  
167 /*
168   Local Variables:
169   mode:c++
170   c-file-style:"stroustrup"
171   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
172   indent-tabs-mode:nil
173   fill-column:99
174   End:
175 */
176 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :