5c94f1e1b4cc255cc9f331bcba4eb89f14015b69
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);
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)
103 {
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;
119 }
121 void
122 gnome_canvas_bpath_def_lineto (GnomeCanvasBpathDef *bpd, double x, double y)
123 {
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;
139 }
141 void
142 gnome_canvas_bpath_def_curveto (GnomeCanvasBpathDef *bpd, double x1, double y1, double x2, double y2, double x3, double y3)
143 {
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;
163 }
165 void
166 gnome_canvas_bpath_def_closepath (GnomeCanvasBpathDef *bpd)
167 {
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);
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;
192 }
194 void
195 gnome_canvas_bpath_def_art_finish (GnomeCanvasBpathDef *bpd)
196 {
197 int n_bpath;
199 g_return_if_fail (bpd != NULL);
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;
207 }