Code

5c94f1e1b4cc255cc9f331bcba4eb89f14015b69
[inkscape.git] / src / svg / gnome-canvas-bpath-util.cpp
1 /* GnomeCanvas Bezier polyline paths & segments
2  *
3  * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget.  Tk is
4  * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
5  *
6  * Copyright (C) 1998,1999 The Free Software Foundation
7  *
8  * Authors: Federico Mena <federico@nuclecu.unam.mx>
9  *          Lauris Kaplinski <lauris@ariman.ee>
10  *          Raph Levien <raph@acm.org>
11  *          Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
12  */
14 #include <cstring>
15 #include <string>
16 #include <cstdlib>
17 #include <cstdio>
18 #include <glib/gmem.h>
19 #include <glib/gmessages.h>
20 #include <algorithm>
22 #include "libnr/n-art-bpath.h"
23 #include "libnr/nr-point-ops.h"
24 #include "gnome-canvas-bpath-util.h"
25 #include "prefs-utils.h"
27 static inline NR::Point distTo(GnomeCanvasBpathDef *bpd, size_t idx1, size_t idx2, unsigned int coord1=3, unsigned int coord2=3) {
28     NR::Point diff(bpd->bpath[idx1].c(coord1) - bpd->bpath[idx2].c(coord2));
29     return NR::Point(std::abs(diff[NR::X]), std::abs(diff[NR::Y]));
30 }
32 static bool isApproximatelyClosed(GnomeCanvasBpathDef *bpd) {
33     int const np = prefs_get_int_attribute("options.svgoutput", "numericprecision", 8);
34     double const precision = pow(10.0, -(np+1)); // This roughly corresponds to a difference below the last significant digit
35         int const initial = bpd->moveto_idx;
36         int const current = bpd->n_bpath - 1;
37     NR::Point distToInit(distTo(bpd, current, initial));
38     return
39         distToInit[NR::X] <= abs(bpd->bpath[current].c(3)[NR::X])*precision &&
40         distToInit[NR::Y] <= abs(bpd->bpath[current].c(3)[NR::Y])*precision;
41 }
43 GnomeCanvasBpathDef *
44 gnome_canvas_bpath_def_new (void)
45 {
46         GnomeCanvasBpathDef *bpd;
48         bpd = g_new (GnomeCanvasBpathDef, 1);
49         bpd->n_bpath = 0;
50         bpd->n_bpath_max = 16;
51         bpd->moveto_idx = -1;
52         bpd->bpath = g_new (NArtBpath, bpd->n_bpath_max);
53         bpd->ref_count = 1;
55         return bpd;
56 }
58 GnomeCanvasBpathDef *
59 gnome_canvas_bpath_def_new_from (NArtBpath *path)
60 {
61         GnomeCanvasBpathDef *bpd;
62         int i;
64         g_return_val_if_fail (path != NULL, NULL);
66         bpd = g_new (GnomeCanvasBpathDef, 1);
67         
68         for (i = 0; path [i].code != NR_END; i++)
69                 ;
70         bpd->n_bpath = i;
71         bpd->n_bpath_max = i;
72         bpd->moveto_idx = -1;
73         bpd->ref_count = 1;
74         bpd->bpath = g_new (NArtBpath, i);
76         memcpy (bpd->bpath, path, i * sizeof (NArtBpath));
77         return bpd;
78 }
80 GnomeCanvasBpathDef *
81 gnome_canvas_bpath_def_ref (GnomeCanvasBpathDef *bpd)
82 {
83         g_return_val_if_fail (bpd != NULL, NULL);
85         bpd->ref_count += 1;
86         return bpd;
87 }
89 void
90 gnome_canvas_bpath_def_free (GnomeCanvasBpathDef *bpd)
91 {
92         g_return_if_fail (bpd != NULL);
94         bpd->ref_count -= 1;
95         if (bpd->ref_count == 0) {
96                 g_free (bpd->bpath);
97                 g_free (bpd);
98         }
99 }
101 void
102 gnome_canvas_bpath_def_moveto (GnomeCanvasBpathDef *bpd, double x, double y)
104         NArtBpath *bpath;
105         int n_bpath;
107         g_return_if_fail (bpd != NULL);
109         n_bpath = bpd->n_bpath++;
111         if (n_bpath == bpd->n_bpath_max)
112                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
113                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
114         bpath = bpd->bpath;
115         bpath[n_bpath].code = NR_MOVETO_OPEN;
116         bpath[n_bpath].x3 = x;
117         bpath[n_bpath].y3 = y;
118         bpd->moveto_idx = n_bpath;
121 void
122 gnome_canvas_bpath_def_lineto (GnomeCanvasBpathDef *bpd, double x, double y)
124         NArtBpath *bpath;
125         int n_bpath;
127         g_return_if_fail (bpd != NULL);
128         g_return_if_fail (bpd->moveto_idx >= 0);
130         n_bpath = bpd->n_bpath++;
132         if (n_bpath == bpd->n_bpath_max)
133                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
134                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
135         bpath = bpd->bpath;
136         bpath[n_bpath].code = NR_LINETO;
137         bpath[n_bpath].x3 = x;
138         bpath[n_bpath].y3 = y;
141 void
142 gnome_canvas_bpath_def_curveto (GnomeCanvasBpathDef *bpd, double x1, double y1, double x2, double y2, double x3, double y3)
144         NArtBpath *bpath;
145         int n_bpath;
147         g_return_if_fail (bpd != NULL);
148         g_return_if_fail (bpd->moveto_idx >= 0);
150         n_bpath = bpd->n_bpath++;
152         if (n_bpath == bpd->n_bpath_max)
153                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
154                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
155         bpath = bpd->bpath;
156         bpath[n_bpath].code = NR_CURVETO;
157         bpath[n_bpath].x1 = x1;
158         bpath[n_bpath].y1 = y1;
159         bpath[n_bpath].x2 = x2;
160         bpath[n_bpath].y2 = y2;
161         bpath[n_bpath].x3 = x3;
162         bpath[n_bpath].y3 = y3;
165 void
166 gnome_canvas_bpath_def_closepath (GnomeCanvasBpathDef *bpd)
168         NArtBpath *bpath;
169         int n_bpath;
171         g_return_if_fail (bpd != NULL);
172         g_return_if_fail (bpd->moveto_idx >= 0);
173         g_return_if_fail (bpd->n_bpath > 0);
174         
175         bpath = bpd->bpath;
176         n_bpath = bpd->n_bpath;
178         /* Add closing vector if we need it. */
179     if (!isApproximatelyClosed(bpd)) {
180                 gnome_canvas_bpath_def_lineto (bpd, bpath[bpd->moveto_idx].x3,
181                                                bpath[bpd->moveto_idx].y3);
182                 bpath = bpd->bpath;
183     } else {
184         // If it is approximately closed we close it here to prevent internal logic to fail.
185         // In addition it is probably better to continue working with this end point, as it
186         // is probably more precise than the original.
187         bpath[n_bpath-1].x3 = bpath[bpd->moveto_idx].x3;
188         bpath[n_bpath-1].y3 = bpath[bpd->moveto_idx].y3;
189     }
190         bpath[bpd->moveto_idx].code = NR_MOVETO;
191         bpd->moveto_idx = -1;
194 void
195 gnome_canvas_bpath_def_art_finish (GnomeCanvasBpathDef *bpd)
197         int n_bpath;
199         g_return_if_fail (bpd != NULL);
200         
201         n_bpath = bpd->n_bpath++;
203         if (n_bpath == bpd->n_bpath_max)
204                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
205                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
206         bpd->bpath [n_bpath].code = NR_END;