~centralelyon2010/inkscape/imagelinks2

1 by mental
moving trunk for module inkscape
1
#include <cstring>
4629 by bryce
Applying fixes for gcc 4.3 build issues (closes LP: #169115)
2
#include <string>
3
#include <limits>
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
4
4629 by bryce
Applying fixes for gcc 4.3 build issues (closes LP: #169115)
5
#include "display/curve.h"
1 by mental
moving trunk for module inkscape
6
#include "xml/repr.h"
7
#include "sp-conn-end.h"
8
#include "sp-path.h"
9
#include "uri.h"
10
#include "document.h"
11
#include "sp-item-group.h"
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
12
#include "2geom/path.h"
13
#include "2geom/pathvector.h"
14
#include "2geom/path-intersection.h"
15
1 by mental
moving trunk for module inkscape
16
17
static void change_endpts(SPCurve *const curve, double const endPos[2]);
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
18
1 by mental
moving trunk for module inkscape
19
SPConnEnd::SPConnEnd(SPObject *const owner) :
20
    ref(owner),
21
    href(NULL),
22
    // Default to center connection endpoint
9012.3.1 by Arcadie M. Cracan
Disabled unfinished connection point edit mode. Added inkscape:connection-start-point, inkscape:connection-end-point attributes for connector endpoints. This corrects the previous approach making drawings created in 0.48 version compatible with earlier versions (new attributes are silently ignored).
23
    type(ConnPointDefault),
24
    id(4),
25
    _changed_connection(),
1 by mental
moving trunk for module inkscape
26
    _delete_connection(),
27
    _transformed_connection()
28
{
29
}
30
31
static SPObject const *
32
get_nearest_common_ancestor(SPObject const *const obj, SPItem const *const objs[2]) {
33
    SPObject const *anc_sofar = obj;
34
    for (unsigned i = 0; i < 2; ++i) {
35
        if ( objs[i] != NULL ) {
36
            anc_sofar = anc_sofar->nearestCommonAncestor(objs[i]);
37
        }
38
    }
39
    return anc_sofar;
40
}
41
42
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
43
static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_pv, SPItem* item,
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
44
        const Geom::Affine& item_transform, double& intersect_pos) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
45
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
46
    double initial_pos = intersect_pos;
47
    // if this is a group...
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
48
    if (SP_IS_GROUP(item)) {
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
49
        SPGroup* group = SP_GROUP(item);
50
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
51
        // consider all first-order children
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
52
        double child_pos = 0.0;
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
53
        for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) {
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
54
            SPItem* child_item = SP_ITEM(i->data);
55
            try_get_intersect_point_with_item_recursive(conn_pv, child_item,
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
56
                    item_transform * child_item->transform, child_pos);
57
            if (intersect_pos < child_pos)
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
58
                intersect_pos = child_pos;
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
59
        }
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
60
        return intersect_pos != initial_pos;
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
61
    }
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
62
63
    // if this is not a shape, nothing to be done
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
64
    if (!SP_IS_SHAPE(item)) return false;
65
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
66
    // make sure it has an associated curve
67
    SPCurve* item_curve = SP_SHAPE(item)->getCurve();
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
68
    if (!item_curve) return false;
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
69
70
    // apply transformations (up to common ancestor)
71
    item_curve->transform(item_transform);
72
73
    const Geom::PathVector& curve_pv = item_curve->get_pathvector();
74
    Geom::CrossingSet cross = crossings(conn_pv, curve_pv);
75
    // iterate over all Crossings
76
    for (Geom::CrossingSet::const_iterator i = cross.begin(); i != cross.end(); i++) {
77
        const Geom::Crossings& cr = *i;
78
79
        for (Geom::Crossings::const_iterator i = cr.begin(); i != cr.end(); i++) {
80
            const Geom::Crossing& cr_pt = *i;
81
            if ( intersect_pos < cr_pt.ta)
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
82
                intersect_pos = cr_pt.ta;
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
83
        }
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
84
    }
85
86
    item_curve->unref();
87
88
    return intersect_pos != initial_pos;
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
89
}
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
90
91
92
// This function returns the outermost intersection point between the path (a connector)
93
// and the item given.  If the item is a group, then the component items are considered.
94
// The transforms given should be to a common ancestor of both the path and item.
95
//
96
static bool try_get_intersect_point_with_item(SPPath* conn, SPItem* item,
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
97
        const Geom::Affine& item_transform, const Geom::Affine& conn_transform,
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
98
        const bool at_start, double& intersect_pos) {
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
99
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
100
    // Copy the curve and apply transformations up to common ancestor.
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
101
    SPCurve* conn_curve = conn->curve->copy();
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
102
    conn_curve->transform(conn_transform);
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
103
104
    Geom::PathVector conn_pv = conn_curve->get_pathvector();
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
105
106
    // If this is not the starting point, use Geom::Path::reverse() to reverse the path
107
    if (!at_start)
108
    {
109
        // connectors are actually a single path, so consider the first element from a Geom::PathVector
110
        conn_pv[0] = conn_pv[0].reverse();
111
    }
112
113
    // We start with the intersection point at the beginning of the path
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
114
    intersect_pos = 0.0;
115
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
116
    // Find the intersection.
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
117
    bool result = try_get_intersect_point_with_item_recursive(conn_pv, item, item_transform, intersect_pos);
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
118
119
    if (!result)
120
        // No intersection point has been found (why?)
121
        // just default to connector end
122
        intersect_pos = 0;
123
    // If not at the starting point, recompute position with respect to original path
124
    if (!at_start)
125
        intersect_pos = conn_pv[0].size() - intersect_pos;
126
    // Free the curve copy.
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
127
    conn_curve->unref();
128
129
    return result;
130
}
131
132
133
static void
1 by mental
moving trunk for module inkscape
134
sp_conn_get_route_and_redraw(SPPath *const path,
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
135
        const bool updatePathRepr = true)
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
136
{
1 by mental
moving trunk for module inkscape
137
    // Get the new route around obstacles.
138
    bool rerouted = path->connEndPair.reroutePathFromLibavoid();
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
139
    if (!rerouted) {
140
        return;
141
    }
142
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
143
    SPItem *h2attItem[2] = {0};
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
144
    path->connEndPair.getAttachedItems(h2attItem);
1 by mental
moving trunk for module inkscape
145
146
    SPObject const *const ancestor = get_nearest_common_ancestor(path, h2attItem);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
147
    Geom::Affine const path2anc(i2anc_affine(path, ancestor));
148
1 by mental
moving trunk for module inkscape
149
    // Set sensible values incase there the connector ends are not
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
150
    // attached to any shapes.
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
151
    Geom::PathVector conn_pv = path->curve->get_pathvector();
152
    double endPos[2] = { 0, conn_pv[0].size() };
153
154
    SPConnEnd** _connEnd = path->connEndPair.getConnEnds();
155
    for (unsigned h = 0; h < 2; ++h) {
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
156
        if (h2attItem[h] && _connEnd[h]->type == ConnPointDefault && _connEnd[h]->id == ConnPointPosCC) {
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
157
            Geom::Affine h2i2anc = i2anc_affine(h2attItem[h], ancestor);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
158
            try_get_intersect_point_with_item(path, h2attItem[h], h2i2anc, path2anc,
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
159
                        (h == 0), endPos[h]);
160
        }
8284 by mjwybrow
- Fix bug #171150: Connectors should always touch the shape boundary
161
    }
1 by mental
moving trunk for module inkscape
162
    change_endpts(path->curve, endPos);
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
163
    if (updatePathRepr) {
1 by mental
moving trunk for module inkscape
164
        path->updateRepr();
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
165
        path->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
1 by mental
moving trunk for module inkscape
166
    }
167
}
168
169
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
170
static void
1 by mental
moving trunk for module inkscape
171
sp_conn_end_shape_move(Geom::Affine const */*mp*/, SPItem */*moved_item*/,
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
172
                            SPPath *const path)
1 by mental
moving trunk for module inkscape
173
{
174
    if (path->connEndPair.isAutoRoutingConn()) {
175
        path->connEndPair.tellLibavoidNewEndpoints();
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
176
    }
177
}
178
179
180
void
181
sp_conn_reroute_path(SPPath *const path)
182
{
183
    if (path->connEndPair.isAutoRoutingConn()) {
184
        path->connEndPair.tellLibavoidNewEndpoints();
185
    }
186
}
187
188
189
void
190
sp_conn_reroute_path_immediate(SPPath *const path)
191
{
192
    if (path->connEndPair.isAutoRoutingConn()) {
193
        bool processTransaction = true;
194
        path->connEndPair.tellLibavoidNewEndpoints(processTransaction);
195
    }
1 by mental
moving trunk for module inkscape
196
    // Don't update the path repr or else connector dragging is slowed by
197
    // constant update of values to the xml editor, and each step is also
198
    // needlessly remembered by undo/redo.
199
    bool const updatePathRepr = false;
200
    sp_conn_get_route_and_redraw(path, updatePathRepr);
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
201
}
202
203
void sp_conn_redraw_path(SPPath *const path)
204
{
205
    sp_conn_get_route_and_redraw(path);
206
}
1 by mental
moving trunk for module inkscape
207
208
209
static void
210
change_endpts(SPCurve *const curve, double const endPos[2])
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
211
{
1 by mental
moving trunk for module inkscape
212
    // Use Geom::Path::portion to cut the curve at the end positions
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
213
    if (endPos[0] > endPos[1])
214
    {
215
        // Path is "negative", reset the curve and return
216
        curve->reset();
217
        return;
218
    }
219
    const Geom::Path& old_path = curve->get_pathvector()[0];
220
    Geom::PathVector new_path_vector;
221
    new_path_vector.push_back(old_path.portion(endPos[0], endPos[1]));
222
    curve->set_pathvector(new_path_vector);
223
}
1 by mental
moving trunk for module inkscape
224
225
static void
226
sp_conn_end_deleted(SPObject *, SPObject *const owner, unsigned const handle_ix)
227
{
228
    // todo: The first argument is the deleted object, or just NULL if
229
    //       called by sp_conn_end_detach.
230
    g_return_if_fail(handle_ix < 2);
231
    char const * const attr_strs[] = {"inkscape:connection-start", "inkscape:connection-start-point",
9012.3.1 by Arcadie M. Cracan
Disabled unfinished connection point edit mode. Added inkscape:connection-start-point, inkscape:connection-end-point attributes for connector endpoints. This corrects the previous approach making drawings created in 0.48 version compatible with earlier versions (new attributes are silently ignored).
232
                                      "inkscape:connection-end", "inkscape:connection-end-point"};
233
    owner->getRepr()->setAttribute(attr_strs[2*handle_ix], NULL);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
234
    owner->getRepr()->setAttribute(attr_strs[2*handle_ix+1], NULL);
235
    /* I believe this will trigger sp_conn_end_href_changed. */
1 by mental
moving trunk for module inkscape
236
}
237
238
void
239
sp_conn_end_detach(SPObject *const owner, unsigned const handle_ix)
240
{
241
    sp_conn_end_deleted(NULL, owner, handle_ix);
242
}
243
244
void
245
SPConnEnd::setAttacherHref(gchar const *value, SPPath* /*path*/)
8857.1.1 by Arcadie M. Cracan
Connector tool: make connectors avoid the convex hull of shapes.
246
{
149 by rwst
bulk trailing spaces removal. consistency through MD5 of binary
247
    if ( value && href && ( strcmp(value, href) == 0 ) ) {
1 by mental
moving trunk for module inkscape
248
        /* No change, do nothing. */
249
    } 
9012.3.1 by Arcadie M. Cracan
Disabled unfinished connection point edit mode. Added inkscape:connection-start-point, inkscape:connection-end-point attributes for connector endpoints. This corrects the previous approach making drawings created in 0.48 version compatible with earlier versions (new attributes are silently ignored).
250
    else 
251
    {
252
        if (!value)
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
253
        {
254
            ref.detach();
255
            g_free(href);
256
            href = NULL;
257
        }
258
        else
259
        {
260
            bool validRef = true;
261
            href = g_strdup(value);
9012.3.1 by Arcadie M. Cracan
Disabled unfinished connection point edit mode. Added inkscape:connection-start-point, inkscape:connection-end-point attributes for connector endpoints. This corrects the previous approach making drawings created in 0.48 version compatible with earlier versions (new attributes are silently ignored).
262
            // Now do the attaching, which emits the changed signal.
263
            try {
264
                ref.attach(Inkscape::URI(value));
265
            } catch (Inkscape::BadURIException &e) {
266
                /* TODO: Proper error handling as per
267
                * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.  (Also needed for
268
                * sp-use.) */
269
                g_warning("%s", e.what());
270
                validRef = false;
271
            }
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
272
273
            if ( !validRef )
274
            {
275
                ref.detach();
1 by mental
moving trunk for module inkscape
276
                g_free(href);
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
277
                href = NULL;
278
            }
1 by mental
moving trunk for module inkscape
279
        }
9012.3.1 by Arcadie M. Cracan
Disabled unfinished connection point edit mode. Added inkscape:connection-start-point, inkscape:connection-end-point attributes for connector endpoints. This corrects the previous approach making drawings created in 0.48 version compatible with earlier versions (new attributes are silently ignored).
280
    }
281
}
282
283
void
284
SPConnEnd::setAttacherEndpoint(gchar const *value, SPPath* /*path*/)
285
{
286
    
287
    /* References to the connection points have the following format
288
        <t><id>, where t is the type of the point, which
289
        can be either "d" for default or "u" for user-defined, and
290
        id is the local (inside the item) id of the connection point.
291
        In the case of default points id represents the position on the
292
        item (i.e. Top-Left, Center-Center, etc.).
293
    */
294
    
295
    bool changed = false;
296
    ConnPointType newtype = type;
297
    
298
    if (!value)
299
    {
300
        // Default to center endpoint
301
        type = ConnPointDefault;
302
        id = 4;
303
    }
304
    else
305
    {
306
        switch (value[0])
307
        {
308
            case 'd':
309
                if ( newtype != ConnPointDefault )
310
                {
311
                    newtype = ConnPointDefault;
312
                    changed = true;
313
                }
314
                break;
315
            case 'u':
316
                if ( newtype != ConnPointUserDefined)
317
                {
318
                    newtype = ConnPointUserDefined;
319
                    changed = true;
320
                }
321
                break;
322
            default:
323
                g_warning("Bad reference to a connection point.");
324
        }
325
        
326
        int newid = (int) g_ascii_strtod( value+1, 0 );
327
        if ( id != newid )
328
        {
329
            id = newid;
330
            changed = true;
331
        }
332
333
        // We have to verify that the reference to the
334
        // connection point is a valid one.
335
        
336
        if ( changed )
337
        {
338
339
            // Get the item the connector is attached to
340
            SPItem* item = ref.getObject();
341
            if ( item )
342
            {
343
                if (!item->avoidRef->isValidConnPointId( newtype, newid ) )
344
                {
345
                    g_warning("Bad reference to a connection point.");
346
                }
347
                else
348
                {
349
                    type = newtype;
350
                    id = newid;
351
                }
352
    /*          // Update the connector
353
                if (path->connEndPair.isAutoRoutingConn()) {
354
                    path->connEndPair.tellLibavoidNewEndpoints();
355
                }
356
    */
357
            }
358
        }
1 by mental
moving trunk for module inkscape
359
    }
360
}
361
362
void
363
sp_conn_end_href_changed(SPObject */*old_ref*/, SPObject */*ref*/,
4025 by joncruz
Warning cleanup
364
                         SPConnEnd *connEndPtr, SPPath *const path, unsigned const handle_ix)
1 by mental
moving trunk for module inkscape
365
{
366
    g_return_if_fail(connEndPtr != NULL);
367
    SPConnEnd &connEnd = *connEndPtr;
368
    connEnd._delete_connection.disconnect();
369
    connEnd._transformed_connection.disconnect();
370
371
    if (connEnd.href) {
372
        SPObject *refobj = connEnd.ref.getObject();
373
        if (refobj) {
374
            connEnd._delete_connection
375
                = refobj->connectDelete(sigc::bind(sigc::ptr_fun(&sp_conn_end_deleted),
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
376
                                                   path, handle_ix));
377
            connEnd._transformed_connection
1 by mental
moving trunk for module inkscape
378
                = SP_ITEM(refobj)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_conn_end_shape_move),
8855 by Arcadie M. Cracan
Merge GSoC2009 Connectors into trunk
379
                                                                 path));
1 by mental
moving trunk for module inkscape
380
        }
381
    }
382
}
383
384
385
386
/*
387
  Local Variables:
388
  mode:c++
389
  c-file-style:"stroustrup"
390
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
391
  indent-tabs-mode:nil
392
  fill-column:99
393
  End:
394
*/
395
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
396