Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sp-polygon.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * SVG <polygon> implementation
4 *
5 * Authors:
6 * Lauris Kaplinski <lauris@kaplinski.com>
7 * Abhishek Sharma
8 *
9 * Copyright (C) 1999-2002 Lauris Kaplinski
10 * Copyright (C) 2000-2001 Ximian, Inc.
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "sp-polygon.h"
16
17#include <glibmm/i18n.h>
18
19#include "attributes.h" // for SPAttr
20#include <2geom/curve.h> // for Curve
21#include "helper/geom-curves.h" // for is_straight_curve
22#include "object/sp-object.h" // for SP_OBJECT_WRITE_BUILD
23#include "object/sp-shape.h" // for SPShape
24#include <2geom/path.h> // for Path, BaseIterator
25#include <2geom/pathvector.h> // for PathVector
26#include <2geom/point.h> // for Point
27#include "svg/stringstream.h" // for SVGOStringStream
28#include "xml/document.h" // for Document
29#include "xml/node.h" // for Node
30class SPDocument;
31
34
35SPPolygon::~SPPolygon() = default;
36
38 SPPolygon* object = this;
39
41
42 object->readAttr(SPAttr::POINTS);
43}
44
45/*
46 * sp_svg_write_polygon: Write points attribute for polygon tag.
47 * pathv may only contain paths with only straight line segments
48 * Return value: points attribute string.
49 */
50static char *sp_svg_write_polygon(Geom::PathVector const &pathv)
51{
53
54 for (const auto & pit : pathv) {
55 for (Geom::Path::const_iterator cit = pit.begin(); cit != pit.end_default(); ++cit) {
56 if ( is_straight_curve(*cit) )
57 {
58 os << cit->finalPoint()[0] << "," << cit->finalPoint()[1] << " ";
59 } else {
60 g_error("sp_svg_write_polygon: polygon path contains non-straight line segments");
61 }
62 }
63 }
64
65 return g_strdup(os.str().c_str());
66}
67
69 // Tolerable workaround: we need to update the object's curve before we set points=
70 // because it's out of sync when e.g. some extension attrs of the polygon or star are changed in XML editor
71 this->set_shape();
72
73 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
74 repr = xml_doc->createElement("svg:polygon");
75 }
76
77 /* We can safely write points here, because all subclasses require it too (Lauris) */
78 /* While saving polygon element without points attribute _curve is NULL (see bug 1202753) */
79 if (_curve) {
80 char *str = sp_svg_write_polygon(*_curve);
81 repr->setAttribute("points", str);
82 g_free(str);
83 }
84
85 SPShape::write(xml_doc, repr, flags);
86
87 return repr;
88}
89
97SPPolyParseError sp_poly_get_value(char const **p, double *v)
98{
99 while (**p != '\0' && (**p == ',' || **p == '\x20' || **p == '\x9' || **p == '\xD' || **p == '\xA')) {
100 (*p)++;
101 }
102
103 if (**p == '\0') {
104 return POLY_END_OF_STRING;
105 }
106
107 gchar *e = nullptr;
108 double value = g_ascii_strtod(*p, &e);
109 if (e == *p) {
110 return POLY_INVALID_NUMBER;
111 }
112 if (std::isnan(value)) {
113 return POLY_NOT_A_NUMBER;
114 }
115 if (std::isinf(value)) {
116 return POLY_INFINITE_VALUE;
117 }
118
119 *p = e;
120 *v = value;
121 return POLY_OK;
122}
123
127static void sp_poly_print_warning(char const *points, char const *error_location, SPPolyParseError error)
128{
129 switch (error) {
130 case POLY_END_OF_STRING: // Unexpected end of string!
131 {
132 size_t constexpr MAX_DISPLAY_SIZE = 64;
133 Glib::ustring s{points};
134 if (s.size() > MAX_DISPLAY_SIZE) {
135 s = "... " + s.substr(s.size() - MAX_DISPLAY_SIZE);
136 }
137 g_warning("Error parsing a 'points' attribute: string ended unexpectedly!\n\t\"%s\"", s.c_str());
138 break;
139 }
141 g_warning("Invalid number in the 'points' attribute:\n\t\"(...) %s\"", error_location);
142 break;
143
145 g_warning("Infinity is not allowed in the 'points' attribute:\n\t\"(...) %s\"", error_location);
146 break;
147
149 g_warning("NaN-value is not allowed in the 'points' attribute:\n\t\"(...) %s\"", error_location);
150 break;
151
152 case POLY_OK:
153 default:
154 break;
155 }
156}
157
164std::optional<Geom::Path> sp_poly_parse_curve(char const *points)
165{
166 std::optional<Geom::Path> result;
167 char const *cptr = points;
168
169 while (true) {
170 double x, y;
171
172 if (auto error = sp_poly_get_value(&cptr, &x)) {
173 // If the error is something other than end of input, we must report it.
174 // End of input is allowed when scanning for the next x coordinate: it
175 // simply means that we have reached the end of the coordinate list.
176 if (error != POLY_END_OF_STRING) {
177 sp_poly_print_warning(points, cptr, error);
178 }
179 break;
180 }
181 if (auto error = sp_poly_get_value(&cptr, &y)) {
182 // End of input is not allowed when scanning for y.
183 sp_poly_print_warning(points, cptr, error);
184 break;
185 }
186
187 if (result) {
188 result->appendNew<Geom::LineSegment>(Geom::Point{x, y});
189 } else {
190 result.emplace(Geom::Point{x, y});
191 }
192 }
193
194 return result;
195}
196
197void SPPolygon::set(SPAttr key, const gchar* value) {
198 switch (key) {
199 case SPAttr::POINTS: {
200 if (!value) {
201 /* fixme: The points attribute is required. We should handle its absence as per
202 * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */
203 break;
204 }
205
206 auto curve = sp_poly_parse_curve(value).value_or(Geom::Path{});
207 curve.close();
208 setCurve(std::move(curve));
209 break;
210 }
211 default:
212 SPShape::set(key, value);
213 break;
214 }
215}
216
217const char* SPPolygon::typeName() const {
218 return "path";
219}
220
222 return g_strdup(_("<b>Polygon</b>"));
223}
224
225/*
226 Local Variables:
227 mode:c++
228 c-file-style:"stroustrup"
229 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
230 indent-tabs-mode:nil
231 fill-column:99
232 End:
233*/
234// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Abstract curve type.
Path - a sequence of contiguous curves.
Cartesian point / 2D vector and related operations.
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
Sequence of subpaths.
Definition pathvector.h:122
Sequence of contiguous curves, aka spline.
Definition path.h:353
Two-dimensional point that doubles as a vector.
Definition point.h:66
std::string str() const
Interface for refcounted XML nodes.
Definition node.h:80
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
Typed SVG document implementation.
Definition document.h:101
Inkscape::XML::Node * repr
Definition sp-object.h:193
SPDocument * document
Definition sp-object.h:188
char * description() const override
~SPPolygon() override
char const * typeName() const override
The item's type name, not node tag name.
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
void build(SPDocument *document, Inkscape::XML::Node *repr) override
void set(SPAttr key, char const *value) override
Base class for shapes, including <path> element.
Definition sp-shape.h:38
virtual void set_shape()
Definition sp-shape.cpp:905
std::shared_ptr< Geom::PathVector const > _curve
Definition sp-shape.h:70
void setCurve(Geom::PathVector const *)
Definition sp-shape.cpp:923
void set(SPAttr key, char const *value) override
Definition sp-shape.cpp:114
void build(SPDocument *document, Inkscape::XML::Node *repr) override
Definition sp-shape.cpp:62
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Definition sp-shape.cpp:119
Css & result
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Definition geom-curves.h:22
static cairo_user_data_key_t key
PathVector - a sequence of subpaths.
static void sp_poly_print_warning(char const *points, char const *error_location, SPPolyParseError error)
Print a warning message related to the parsing of a 'points' attribute.
static char * sp_svg_write_polygon(Geom::PathVector const &pathv)
SPPolyParseError sp_poly_get_value(char const **p, double *v)
Parse a double from the string passed by pointer and advance the string start.
std::optional< Geom::Path > sp_poly_parse_curve(char const *points)
Parse a 'points' attribute, printing a warning when an error occurs.
SPPolyParseError
Definition sp-polygon.h:35
@ POLY_INVALID_NUMBER
Definition sp-polygon.h:38
@ POLY_END_OF_STRING
Definition sp-polygon.h:37
@ POLY_NOT_A_NUMBER
Definition sp-polygon.h:40
@ POLY_INFINITE_VALUE
Definition sp-polygon.h:39
@ POLY_OK
Definition sp-polygon.h:36
std::optional< Geom::Path > sp_poly_parse_curve(char const *points)
Parse a 'points' attribute, printing a warning when an error occurs.
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
Definition curve.h:24
TODO: insert short description here.
Interface for XML documents.
Interface for XML nodes.