Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
canvas-item-bpath.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
6/*
7 * Author:
8 * Tavmjong Bah
9 *
10 * Copyright (C) 2020 Tavmjong Bah
11 *
12 * Rewrite of SPCanvasBPath
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include "canvas-item-bpath.h"
18#include <cairomm/matrix.h>
19#include <cstdint>
20
21#include "display/curve.h"
22#include "display/cairo-utils.h"
23#include "helper/geom.h" // bounds_exact_transformed()
24
25namespace Inkscape {
26
31 : CanvasItem(group)
32{
33 _name = "CanvasItemBpath:Null";
34 _pickable = true; // For now, everyone gets events from this class!
35}
36
41 : CanvasItem(group)
42 , _path(std::move(path))
43 , _phantom_line(phantom_line)
44{
45 _name = "CanvasItemBpath";
46 _pickable = true; // For now, everyone gets events from this class!
47 request_update(); // Render immediately or temporary bpaths won't show.
48}
49
53void CanvasItemBpath::set_bpath(SPCurve const *curve, bool phantom_line)
54{
55 set_bpath(curve ? curve->get_pathvector() : Geom::PathVector(), phantom_line);
56}
57
61void CanvasItemBpath::set_bpath(Geom::PathVector path, bool phantom_line)
62{
63 defer([=, this, path = std::move(path)] () mutable {
64 _path = std::move(path);
65 _phantom_line = phantom_line;
67 });
68}
69
73void CanvasItemBpath::set_fill(uint32_t fill, SPWindRule fill_rule)
74{
75 defer([=, this] {
76 if (_fill == fill && _fill_rule == fill_rule) return;
77 _fill = fill;
78 _fill_rule = fill_rule;
80 });
81}
82
83void CanvasItemBpath::set_dashes(std::vector<double> &&dashes)
84{
85 defer([this, dashes = std::move(dashes)] () mutable {
86 _dashes = std::move(dashes);
87 });
88}
89
94{
95 double d = Geom::infinity();
96
97 // Convert p to document coordinates (quicker than converting path to canvas units).
98 Geom::Point p_doc = p * affine().inverse();
99 _path.nearestTime(p_doc, &d);
100 d *= affine().descrim(); // Uniform scaling and rotation only.
101
102 return d;
103}
104
108bool CanvasItemBpath::contains(Geom::Point const &p, double tolerance)
109{
110 if (tolerance == 0) {
111 tolerance = 1; // Need a minimum tolerance value or always returns false.
112 }
113
114 // Check for 'inside' a filled bpath if a fill is being used.
115 if ((_fill & 0xff) != 0) {
116 Geom::Point p_doc = p * affine().inverse();
117 if (_path.winding(p_doc) % 2 != 0) {
118 return true;
119 }
120 }
121
122 // Otherwise see how close we are to the outside line.
123 return closest_distance_to(p) < tolerance;
124}
125
130{
131 // Queue redraw of old area (erase previous content).
133
134 if (_path.empty()) {
135 _bounds = {};
136 return;
137 }
138
139 // Room for stroke and outline.
140 // CanvasItemBpath doesn't seem to require the extra adjustment of 2 units to avoid artifacts,
141 // but it is done for consistency with CanvasItemRect.
143
144 // Queue redraw of new area
146}
147
152{
153 bool do_fill = (_fill & 0xff) != 0; // Not invisible.
154 bool do_stroke = (_stroke & 0xff) != 0; // Not invisible.
155
156 if (!do_fill && !do_stroke) {
157 // Both fill and stroke invisible.
158 return;
159 }
160
161 buf.cr->save();
162
163 // Setup path
164 buf.cr->set_tolerance(0.5);
165 buf.cr->begin_new_path();
166
167 feed_pathvector_to_cairo(buf.cr->cobj(), _path, affine(), buf.rect,
168 /* optimize_stroke */ !(do_fill || _fill_pattern), get_effective_outline());
169
170 // Do fill
171 if (do_fill) {
173 buf.cr->set_fill_rule(_fill_rule == SP_WIND_RULE_EVENODD ?
174 Cairo::Context::FillRule::EVEN_ODD : Cairo::Context::FillRule::WINDING);
175 buf.cr->fill_preserve();
176 }
177
178 // Do fill pattern
179 if (_fill_pattern) {
180 buf.cr->save();
181 buf.cr->translate(-buf.rect.min().x(), -buf.rect.min().y());
182 buf.cr->set_source(_fill_pattern);
183 buf.cr->fill_preserve();
184 buf.cr->restore();
185 }
186
187 // Do outline
188 if (SP_RGBA32_A_U(_outline) > 0 && _outline_width > 0) {
190 buf.cr->set_line_width(get_effective_outline());
191 buf.cr->stroke_preserve();
192 }
193
194 // Do stroke
195 if (do_stroke && _stroke_width > 0) {
196
197 if (!_dashes.empty()) {
198 buf.cr->set_dash(_dashes, 0.0); // 0.0 is offset
199 }
200
201 if (_phantom_line) {
202 buf.cr->set_source_rgba(1.0, 1.0, 1.0, 0.25);
203 buf.cr->set_line_width(2.0);
204 buf.cr->stroke_preserve();
205 }
206
208 buf.cr->set_line_width(_stroke_width);
209 buf.cr->stroke();
210
211 } else {
212 buf.cr->begin_new_path(); // Clears path
213 }
214
215 buf.cr->restore();
216}
217
218} // namespace Inkscape
219
220/*
221 Local Variables:
222 mode:c++
223 c-file-style:"stroustrup"
224 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
225 indent-tabs-mode:nil
226 fill-column:99
227 End:
228*/
229// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
void feed_pathvector_to_cairo(cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width)
Feeds path-creating calls to the cairo context translating them from the PathVector,...
void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba)
Cairo integration helpers.
Coord descrim() const
Calculate the descriminant.
Definition affine.cpp:434
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Sequence of subpaths.
Definition pathvector.h:122
int winding(Point const &p) const
Determine the winding number at the specified point.
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
std::optional< PathVectorTime > nearestTime(Point const &p, Coord *dist=NULL) const
Two-dimensional point that doubles as a vector.
Definition point.h:66
CanvasItemBpath(CanvasItemGroup *group)
Create a null control bpath.
std::vector< double > _dashes
bool contains(Geom::Point const &p, double tolerance=0) override
Returns true if point p (in canvas units) is within tolerance (canvas units) distance of bpath.
double closest_distance_to(Geom::Point const &p) const
Returns distance between point in canvas units and nearest point on bpath.
void set_bpath(SPCurve const *curve, bool phantom_line=false)
Set a control bpath.
void set_dashes(std::vector< double > &&dashes)
void set_fill(uint32_t rgba, SPWindRule fill_rule)
Set the fill color and fill rule.
void _update(bool propagate) override
Update and redraw control bpath.
void _render(Inkscape::CanvasItemBuffer &buf) const override
Render bpath to screen via Cairo.
double get_effective_outline() const
Get the effective outline.
Cairo::RefPtr< Cairo::Pattern > _fill_pattern
Geom::OptRect _bounds
Geom::Affine const & affine() const
Wrapper around a Geom::PathVector object.
Definition curve.h:26
constexpr uint32_t SP_RGBA32_A_U(uint32_t v)
Definition utils.h:39
constexpr Coord infinity()
Get a value representing infinity.
Definition coord.h:88
Geom::OptRect bounds_exact_transformed(Geom::PathVector const &pv, Geom::Affine const &t)
Definition geom.cpp:153
Specific geometry functions for Inkscape, not provided my lib2geom.
auto expandedBy(Geom::IntRect rect, int amount)
Definition geom.h:66
Helper class to stream background task notifications as a series of messages.
STL namespace.
int buf
Class used when rendering canvas items.
Definition curve.h:24
SPWindRule
Definition style-enums.h:23
@ SP_WIND_RULE_EVENODD
Definition style-enums.h:26