Code

bd55bfb10d9f37d1296f7c33526464f94d73bfc2
[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     // TODO check the double to int conversion in the abs() call:
39     return
40         distToInit[NR::X] <= abs(bpd->bpath[current].c(3)[NR::X])*precision &&
41         distToInit[NR::Y] <= abs(bpd->bpath[current].c(3)[NR::Y])*precision;
42 }
44 GnomeCanvasBpathDef *
45 gnome_canvas_bpath_def_new (void)
46 {
47         GnomeCanvasBpathDef *bpd;
49         bpd = g_new (GnomeCanvasBpathDef, 1);
50         bpd->n_bpath = 0;
51         bpd->n_bpath_max = 16;
52         bpd->moveto_idx = -1;
53         bpd->bpath = g_new (NArtBpath, bpd->n_bpath_max);
54         bpd->ref_count = 1;
56         return bpd;
57 }
59 GnomeCanvasBpathDef *
60 gnome_canvas_bpath_def_new_from (NArtBpath *path)
61 {
62         GnomeCanvasBpathDef *bpd;
63         int i;
65         g_return_val_if_fail (path != NULL, NULL);
67         bpd = g_new (GnomeCanvasBpathDef, 1);
68         
69         for (i = 0; path [i].code != NR_END; i++)
70                 ;
71         bpd->n_bpath = i;
72         bpd->n_bpath_max = i;
73         bpd->moveto_idx = -1;
74         bpd->ref_count = 1;
75         bpd->bpath = g_new (NArtBpath, i);
77         memcpy (bpd->bpath, path, i * sizeof (NArtBpath));
78         return bpd;
79 }
81 GnomeCanvasBpathDef *
82 gnome_canvas_bpath_def_ref (GnomeCanvasBpathDef *bpd)
83 {
84         g_return_val_if_fail (bpd != NULL, NULL);
86         bpd->ref_count += 1;
87         return bpd;
88 }
90 void
91 gnome_canvas_bpath_def_free (GnomeCanvasBpathDef *bpd)
92 {
93         g_return_if_fail (bpd != NULL);
95         bpd->ref_count -= 1;
96         if (bpd->ref_count == 0) {
97                 g_free (bpd->bpath);
98                 g_free (bpd);
99         }
102 void
103 gnome_canvas_bpath_def_moveto (GnomeCanvasBpathDef *bpd, double x, double y)
105         NArtBpath *bpath;
106         int n_bpath;
108         g_return_if_fail (bpd != NULL);
110         n_bpath = bpd->n_bpath++;
112         if (n_bpath == bpd->n_bpath_max)
113                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
114                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
115         bpath = bpd->bpath;
116         bpath[n_bpath].code = NR_MOVETO_OPEN;
117         bpath[n_bpath].x3 = x;
118         bpath[n_bpath].y3 = y;
119         bpd->moveto_idx = n_bpath;
122 void
123 gnome_canvas_bpath_def_lineto (GnomeCanvasBpathDef *bpd, double x, double y)
125         NArtBpath *bpath;
126         int n_bpath;
128         g_return_if_fail (bpd != NULL);
129         g_return_if_fail (bpd->moveto_idx >= 0);
131         n_bpath = bpd->n_bpath++;
133         if (n_bpath == bpd->n_bpath_max)
134                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
135                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
136         bpath = bpd->bpath;
137         bpath[n_bpath].code = NR_LINETO;
138         bpath[n_bpath].x3 = x;
139         bpath[n_bpath].y3 = y;
142 void
143 gnome_canvas_bpath_def_curveto (GnomeCanvasBpathDef *bpd, double x1, double y1, double x2, double y2, double x3, double y3)
145         NArtBpath *bpath;
146         int n_bpath;
148         g_return_if_fail (bpd != NULL);
149         g_return_if_fail (bpd->moveto_idx >= 0);
151         n_bpath = bpd->n_bpath++;
153         if (n_bpath == bpd->n_bpath_max)
154                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
155                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
156         bpath = bpd->bpath;
157         bpath[n_bpath].code = NR_CURVETO;
158         bpath[n_bpath].x1 = x1;
159         bpath[n_bpath].y1 = y1;
160         bpath[n_bpath].x2 = x2;
161         bpath[n_bpath].y2 = y2;
162         bpath[n_bpath].x3 = x3;
163         bpath[n_bpath].y3 = y3;
166 void
167 gnome_canvas_bpath_def_closepath (GnomeCanvasBpathDef *bpd)
169         NArtBpath *bpath;
170         int n_bpath;
172         g_return_if_fail (bpd != NULL);
173         g_return_if_fail (bpd->moveto_idx >= 0);
174         g_return_if_fail (bpd->n_bpath > 0);
175         
176         bpath = bpd->bpath;
177         n_bpath = bpd->n_bpath;
179         /* Add closing vector if we need it. */
180     if (!isApproximatelyClosed(bpd)) {
181                 gnome_canvas_bpath_def_lineto (bpd, bpath[bpd->moveto_idx].x3,
182                                                bpath[bpd->moveto_idx].y3);
183                 bpath = bpd->bpath;
184     } else {
185         // If it is approximately closed we close it here to prevent internal logic to fail.
186         // In addition it is probably better to continue working with this end point, as it
187         // is probably more precise than the original.
188         bpath[n_bpath-1].x3 = bpath[bpd->moveto_idx].x3;
189         bpath[n_bpath-1].y3 = bpath[bpd->moveto_idx].y3;
190     }
191         bpath[bpd->moveto_idx].code = NR_MOVETO;
192         bpd->moveto_idx = -1;
195 void
196 gnome_canvas_bpath_def_art_finish (GnomeCanvasBpathDef *bpd)
198         int n_bpath;
200         g_return_if_fail (bpd != NULL);
201         
202         n_bpath = bpd->n_bpath++;
204         if (n_bpath == bpd->n_bpath_max)
205                 bpd->bpath = (NArtBpath*)g_realloc (bpd->bpath,
206                                         (bpd->n_bpath_max <<= 1) * sizeof (NArtBpath));
207         bpd->bpath [n_bpath].code = NR_END;