1 #define __SP_POLYGON_C__
3 /*
4 * SVG <polygon> implementation
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * Copyright (C) 1999-2002 Lauris Kaplinski
10 * Copyright (C) 2000-2001 Ximian, Inc.
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #include "config.h"
17 #include "attributes.h"
18 #include "sp-polygon.h"
19 #include "display/curve.h"
20 #include <glibmm/i18n.h>
21 #include <2geom/pathvector.h>
22 #include <2geom/bezier-curve.h>
23 #include <2geom/hvlinesegment.h>
24 #include "helper/geom-curves.h"
25 #include "svg/stringstream.h"
26 #include "xml/repr.h"
27 #include "document.h"
29 static void sp_polygon_class_init(SPPolygonClass *pc);
30 static void sp_polygon_init(SPPolygon *polygon);
32 static void sp_polygon_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
33 static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
35 static gchar *sp_polygon_description(SPItem *item);
37 static SPShapeClass *parent_class;
39 GType sp_polygon_get_type(void)
40 {
41 static GType type = 0;
43 if (!type) {
44 GTypeInfo info = {
45 sizeof(SPPolygonClass),
46 0, // base_init
47 0, // base_finalize
48 (GClassInitFunc)sp_polygon_class_init,
49 0, // class_finalize
50 0, // class_data
51 sizeof(SPPolygon),
52 0, // n_preallocs
53 (GInstanceInitFunc)sp_polygon_init,
54 0 // value_table
55 };
56 type = g_type_register_static(SP_TYPE_SHAPE, "SPPolygon", &info, static_cast<GTypeFlags>(0));
57 }
59 return type;
60 }
62 static void sp_polygon_class_init(SPPolygonClass *pc)
63 {
64 SPObjectClass *sp_object_class = (SPObjectClass *) pc;
65 SPItemClass *item_class = (SPItemClass *) pc;
67 parent_class = (SPShapeClass *) g_type_class_ref(SP_TYPE_SHAPE);
69 sp_object_class->build = sp_polygon_build;
70 sp_object_class->write = sp_polygon_write;
71 sp_object_class->set = sp_polygon_set;
73 item_class->description = sp_polygon_description;
74 }
76 static void sp_polygon_init(SPPolygon */*polygon*/)
77 {
78 /* Nothing here */
79 }
81 static void sp_polygon_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
82 {
83 if (((SPObjectClass *) parent_class)->build) {
84 ((SPObjectClass *) parent_class)->build(object, document, repr);
85 }
87 sp_object_read_attr(object, "points");
88 }
91 /*
92 * sp_svg_write_polygon: Write points attribute for polygon tag.
93 * pathv may only contain paths with only straight line segments
94 * Return value: points attribute string.
95 */
96 static gchar *sp_svg_write_polygon(Geom::PathVector const & pathv)
97 {
98 Inkscape::SVGOStringStream os;
100 for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) {
101 for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit) {
102 if ( is_straight_curve(*cit) )
103 {
104 os << cit->finalPoint()[0] << "," << cit->finalPoint()[1] << " ";
105 } else {
106 g_error("sp_svg_write_polygon: polygon path contains non-straight line segments");
107 }
108 }
109 }
111 return g_strdup(os.str().c_str());
112 }
114 static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
115 {
116 SPShape *shape = SP_SHAPE(object);
117 // Tolerable workaround: we need to update the object's curve before we set points=
118 // because it's out of sync when e.g. some extension attrs of the polygon or star are changed in XML editor
119 sp_shape_set_shape(shape);
121 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
122 repr = xml_doc->createElement("svg:polygon");
123 }
125 /* We can safely write points here, because all subclasses require it too (Lauris) */
126 gchar *str = sp_svg_write_polygon(shape->curve->get_pathvector());
127 repr->setAttribute("points", str);
128 g_free(str);
130 if (((SPObjectClass *) (parent_class))->write) {
131 ((SPObjectClass *) (parent_class))->write(object, xml_doc, repr, flags);
132 }
134 return repr;
135 }
138 static gboolean polygon_get_value(gchar const **p, gdouble *v)
139 {
140 while (**p != '\0' && (**p == ',' || **p == '\x20' || **p == '\x9' || **p == '\xD' || **p == '\xA')) {
141 (*p)++;
142 }
144 if (*p == '\0') {
145 return false;
146 }
148 gchar *e = NULL;
149 *v = g_ascii_strtod(*p, &e);
150 if (e == *p) {
151 return false;
152 }
154 *p = e;
155 return true;
156 }
159 void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value)
160 {
161 SPPolygon *polygon = SP_POLYGON(object);
163 switch (key) {
164 case SP_ATTR_POINTS: {
165 if (!value) {
166 /* fixme: The points attribute is required. We should handle its absence as per
167 * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */
168 break;
169 }
170 SPCurve *curve = new SPCurve();
171 gboolean hascpt = FALSE;
173 gchar const *cptr = value;
174 bool has_error = false;
176 while (TRUE) {
177 gdouble x;
178 if (!polygon_get_value(&cptr, &x)) {
179 break;
180 }
182 gdouble y;
183 if (!polygon_get_value(&cptr, &y)) {
184 /* fixme: It is an error for an odd number of points to be specified. We
185 * should display the points up to now (as we currently do, though perhaps
186 * without the closepath: the spec isn't quite clear on whether to do a
187 * closepath or not, though I'd guess it's best not to do a closepath), but
188 * then flag the document as in error, as per
189 * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.
190 *
191 * (Ref: http://www.w3.org/TR/SVG11/shapes.html#PolygonElement.) */
192 has_error = true;
193 break;
194 }
196 if (hascpt) {
197 curve->lineto(x, y);
198 } else {
199 curve->moveto(x, y);
200 hascpt = TRUE;
201 }
202 }
204 if (has_error || *cptr != '\0') {
205 /* TODO: Flag the document as in error, as per
206 * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */
207 } else if (hascpt) {
208 /* We might have done a moveto but no lineto. I'm not sure how we're supposed to represent
209 * a single-point polygon in SPCurve. TODO: add a testcase with only one coordinate pair */
210 curve->closepath();
211 }
212 sp_shape_set_curve(SP_SHAPE(polygon), curve, TRUE);
213 curve->unref();
214 break;
215 }
216 default:
217 if (((SPObjectClass *) parent_class)->set) {
218 ((SPObjectClass *) parent_class)->set(object, key, value);
219 }
220 break;
221 }
222 }
224 static gchar *sp_polygon_description(SPItem */*item*/)
225 {
226 return g_strdup(_("<b>Polygon</b>"));
227 }
229 /*
230 Local Variables:
231 mode:c++
232 c-file-style:"stroustrup"
233 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
234 indent-tabs-mode:nil
235 fill-column:99
236 End:
237 */
238 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :