Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sp-shape.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Base class for shapes, including <path> element
4 *
5 * Author:
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 * Copyright (C) 2004 John Cliff
12 * Copyright (C) 2007-2008 Johan Engelen
13 * Copyright (C) 2010 Jon A. Cruz <jon@joncruz.org>
14 *
15 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
16 */
17
18#include <2geom/rect.h>
19#include <2geom/transforms.h>
20#include <2geom/pathvector.h>
22#include "helper/geom.h"
24
25#include <sigc++/functors/ptr_fun.h>
26#include <sigc++/adaptors/bind.h>
27
29#include "display/curve.h"
30#include "print.h"
31#include "document.h"
32#include "style.h"
33#include "sp-marker.h"
34#include "sp-root.h"
35#include "sp-path.h"
36#include "preferences.h"
37#include "attributes.h"
38#include "path/path-outline.h" // For bound box calculation
39
40#include "svg/svg.h"
41#include "svg/path-string.h"
42#include "snap-candidate.h"
43#include "snap-preferences.h"
45
46#define noSHAPE_VERBOSE
47
49
51 for (auto & i : this->_marker) {
52 i = nullptr;
53 }
54}
55
57 for ( int i = 0 ; i < SP_MARKER_LOC_QTY ; i++ ) {
58 this->_release_connect[i].disconnect();
59 this->_modified_connect[i].disconnect();
60 }
61}
62
64{
66
67 for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
69 }
71 if (is<SPPath>(this)) {
72 if (auto originald = getAttribute("inkscape:original-d")) {
73 if (isOnClipboard()) {
74 setAttribute("d", originald);
75 }
76 setAttribute("inkscape:original-d", nullptr);
77 }
78 }
79 }
80}
81
93{
94 for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
95 if (_marker[i]) {
96
97 for (auto &v : views) {
98 sp_marker_hide(_marker[i], v.drawingitem->key() + ITEM_KEY_MARKERS + i);
99 }
100
101 _release_connect[i].disconnect();
102 _modified_connect[i].disconnect();
103 _marker[i]->unhrefObject(this);
104 _marker[i] = nullptr;
105 }
106 }
107
108 _curve.reset();
109
110 _curve_before_lpe.reset();
111
113}
114
115void SPShape::set(SPAttr key, const gchar* value) {
116 SPLPEItem::set(key, value);
117}
118
119
121 SPLPEItem::write(xml_doc, repr, flags);
122 return repr;
123}
124
125void SPShape::update(SPCtx* ctx, guint flags) {
126 // Any update can change the bounding box,
127 // so the cached version can no longer be used.
128 // But the idle checker usually is just moving the objects around.
131
132 // std::cout << "SPShape::update(): " << (getId()?getId():"null") << std::endl;
133 SPLPEItem::update(ctx, flags);
134
135 /* This stanza checks that an object's marker style agrees with
136 * the marker objects it has allocated. sp_shape_set_marker ensures
137 * that the appropriate marker objects are present (or absent) to
138 * match the style.
139 */
140 for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
142 }
143
144 if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
145 if (this->style->stroke_width.unit == SP_CSS_UNIT_PERCENT) {
146 SPItemCtx *ictx = (SPItemCtx *) ctx;
147 double const aw = 1.0 / ictx->i2vp.descrim();
148 this->style->stroke_width.computed = this->style->stroke_width.value * aw;
149
150 for (auto &v : views) {
151 auto sh = cast<Inkscape::DrawingShape>(v.drawingitem.get());
152 if (hasMarkers()) {
154 sh->setStyle(style, context_style);
155 // Done at end:
156 // sh->setChildrenStyle(this->context_style); //Resolve 'context-xxx' in children.
157 } else if (parent) {
159 sh->setStyle(style, context_style);
160 }
161 }
162 }
163 }
164
165 if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) {
166 /* This is suboptimal, because changing parent style schedules recalculation */
167 /* But on the other hand - how can we know that parent does not tie style and transform */
168 for (auto &v : views) {
169 if (flags & SP_OBJECT_MODIFIED_FLAG) {
170 auto sh = static_cast<Inkscape::DrawingShape*>(v.drawingitem.get());
171 sh->setPath(_curve);
172 }
173 }
174 }
175
176 if (this->hasMarkers ()) {
177
178 /* Dimension marker views */
179 for (auto &v : views) {
180 SPItem::ensure_key(v.drawingitem.get());
181 for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
182 if (_marker[i]) {
183 sp_marker_show_dimension(_marker[i], v.drawingitem->key() + ITEM_KEY_MARKERS + i, numberOfMarkers(i));
184 }
185 }
186 }
187
188 /* Update marker views */
189 for (auto &v : views) {
190 sp_shape_update_marker_view (this, v.drawingitem.get());
191 }
192
193 // Marker selector needs this here or marker previews are not rendered.
194 for (auto &v : views) {
195 auto sh = static_cast<Inkscape::DrawingShape*>(v.drawingitem.get());
196 sh->setChildrenStyle(this->context_style); // Resolve 'context-xxx' in children.
197 }
198 }
199
200 /* Update stroke/dashes for relative units. */
201 if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
202
203 SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx);
204
205 double const w = ictx->viewport.width();
206 double const h = ictx->viewport.height();
207 double const d = sqrt(w*w + h*h) * M_SQRT1_2; // diagonal per SVG spec
208 double const em = style->font_size.computed;
209 double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype.
210
211 if (style->stroke_width.unit == SP_CSS_UNIT_EM) {
212 style->stroke_width.computed = style->stroke_width.value * em;
213 }
214 else if (style->stroke_width.unit == SP_CSS_UNIT_EX) {
215 style->stroke_width.computed = style->stroke_width.value * ex;
216 }
217 else if (style->stroke_width.unit == SP_CSS_UNIT_PERCENT) {
218 style->stroke_width.computed = style->stroke_width.value * d;
219 }
220
221 if (style->stroke_dasharray.values.size() != 0) {
222 for (auto&& i: style->stroke_dasharray.values) {
223 if (i.unit == SP_CSS_UNIT_EM) i.computed = i.value * em;
224 else if (i.unit == SP_CSS_UNIT_EX) i.computed = i.value * ex;
225 else if (i.unit == SP_CSS_UNIT_PERCENT) i.computed = i.value * d;
226 }
227 }
228
230 style->stroke_dashoffset.computed = style->stroke_dashoffset.value * em;
231 }
232 else if (style->stroke_dashoffset.unit == SP_CSS_UNIT_EX) {
233 style->stroke_dashoffset.computed = style->stroke_dashoffset.value * ex;
234 }
235 else if (style->stroke_dashoffset.unit == SP_CSS_UNIT_PERCENT) {
236 style->stroke_dashoffset.computed = style->stroke_dashoffset.value * d;
237 }
238 }
239}
240
247std::vector<std::tuple<SPMarkerLoc, SPMarker *, Geom::Affine>> SPShape::get_markers() const
248{
249 std::vector<std::tuple<SPMarkerLoc, SPMarker *, Geom::Affine>> markers;
250
251 Geom::PathVector const &pathv = curve()->get_pathvector();
252 if (pathv.empty())
253 return markers; // empty list
254
255 auto width = style->stroke_width.computed;
256 auto add_marker = [this, &markers, width](SPMarkerLoc marker_type, Geom::Affine const &m, bool start) {
257 if (SPMarker *marker = _marker[marker_type]) {
258 // TODO: We shouldn't need to return the marker type
259 markers.emplace_back(marker_type, marker, marker->get_marker_transform(m, width, start));
260 }
261 };
262
263 // START marker
264 {
266 for (auto marker_type : {SP_MARKER_LOC, SP_MARKER_LOC_START}) {
267 add_marker(marker_type, m, true);
268 }
269 }
270
271 // MID marker
272 for (Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
273 // START position
274 // if this is the last path and it is a moveto-only, don't draw mid marker there
275 if (path_it != pathv.begin() && !((path_it == (pathv.end() - 1)) && (path_it->size_default() == 0))) {
276 Geom::Affine const m(sp_shape_marker_get_transform_at_start(path_it->front()));
277 for (auto marker_type : {SP_MARKER_LOC, SP_MARKER_LOC_MID}) {
278 add_marker(marker_type, m, false);
279 }
280 }
281 // MID position
282 if (path_it->size_default() > 1) {
283 Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve
284 Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve
285 while (curve_it2 != path_it->end_default()) {
286 /* Put marker between curve_it1 and curve_it2.
287 * Loop to end_default (so including closing segment), because when a path is closed,
288 * there should be a midpoint marker between last segment and closing straight line segment
289 */
290 Geom::Affine const m(sp_shape_marker_get_transform(*curve_it1, *curve_it2));
291 for (auto marker_type : {SP_MARKER_LOC, SP_MARKER_LOC_MID}) {
292 add_marker(marker_type, m, false);
293 }
294 ++curve_it1;
295 ++curve_it2;
296 }
297 }
298 // END position
299 if (path_it != (pathv.end() - 1) && !path_it->empty()) {
300 Geom::Curve const &lastcurve = path_it->back_default();
302 for (auto marker_type : {SP_MARKER_LOC, SP_MARKER_LOC_MID}) {
303 add_marker(marker_type, m, false);
304 }
305 }
306 }
307
308 // END marker
309 {
310 /* Get reference to last curve in the path.
311 * For moveto-only path, this returns the "closing line segment". */
312 Geom::Path const &path_last = pathv.back();
313 auto index = path_last.size_default();
314 Geom::Curve const &lastcurve = path_last[index > 0 ? index - 1 : index];
316
317 for (auto marker_type : {SP_MARKER_LOC, SP_MARKER_LOC_END}) {
318 add_marker(marker_type, m, false);
319 }
320 }
321 return markers;
322}
323
341{
342 Geom::Point p = c1.pointAt(1);
343 Geom::Curve * c1_reverse = c1.reverse();
344 Geom::Point tang1 = - c1_reverse->unitTangentAt(0);
345 delete c1_reverse;
346 Geom::Point tang2 = c2.unitTangentAt(0);
347
348 double const angle1 = Geom::atan2(tang1);
349 double const angle2 = Geom::atan2(tang2);
350
351 double ret_angle = .5 * (angle1 + angle2);
352
353 if ( fabs( angle2 - angle1 ) > M_PI ) {
354 /* ret_angle is in the middle of the larger of the two sectors between angle1 and
355 * angle2, so flip it by 180degrees to force it to the middle of the smaller sector.
356 *
357 * (Imagine a circle with rays drawn at angle1 and angle2 from the centre of the
358 * circle. Those two rays divide the circle into two sectors.)
359 */
360 ret_angle += M_PI;
361 }
362
363 return Geom::Rotate(ret_angle) * Geom::Translate(p);
364}
365
367{
368 Geom::Point p = c.pointAt(0);
370
371 if ( !c.isDegenerate() ) {
372 Geom::Point tang = c.unitTangentAt(0);
373 double const angle = Geom::atan2(tang);
374 ret = Geom::Rotate(angle) * Geom::Translate(p);
375 } else {
376 /* FIXME: the svg spec says to search for a better alternative than zero angle directionality:
377 * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes */
378 }
379
380 return ret;
381}
382
384{
385 Geom::Point p = c.pointAt(1);
387
388 if ( !c.isDegenerate() ) {
389 Geom::Curve * c_reverse = c.reverse();
390 Geom::Point tang = - c_reverse->unitTangentAt(0);
391 delete c_reverse;
392 double const angle = Geom::atan2(tang);
393 ret = Geom::Rotate(angle) * Geom::Translate(p);
394 } else {
395 /* FIXME: the svg spec says to search for a better alternative than zero angle directionality:
396 * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes */
397 }
398
399 return ret;
400}
401
410{
411 if (!shape->curve())
412 return;
413
414 // the first vertex should get a start marker, the last an end marker, and all the others a mid marker
415 // see bug 456148
416
417 // Record the number of instances of each marker type and their absolute position
418 unsigned int counter[SPMarkerLoc::SP_MARKER_LOC_QTY] = {0};
419 unsigned int z_order = 0;
420
421 // C++23: Use std::ranges::enumerate for z_order
422 for (auto const &[type, marker, tr] : shape->get_markers()) {
423 sp_marker_show_instance(marker, ai, type, counter[type]++, z_order++, tr, shape->style->stroke_width.computed);
424 }
425}
426
427void SPShape::modified(unsigned int flags) {
428 // std::cout << "SPShape::modified(): " << (getId()?getId():"null") << std::endl;
429 SPLPEItem::modified(flags);
430
431 if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
432 for (auto &v : views) {
433 auto sh = cast<Inkscape::DrawingShape>(v.drawingitem.get());
434 if (hasMarkers()) {
435 this->context_style = this->style;
436 sh->setStyle(this->style, this->context_style);
437 // Note: marker selector preview does not trigger SP_OBJECT_STYLE_MODIFIED_FLAG so
438 // this is not called when marker previews are generated, however there is code in
439 // SPShape::update() that calls this routine so we don't worry about it here.
440 sh->setChildrenStyle(this->context_style); // Resolve 'context-xxx' in children.
441 } else if (this->parent) {
442 this->context_style = this->parent->context_style;
443 sh->setStyle(this->style, this->context_style);
444 }
445 }
446 }
447
448 if (flags & SP_OBJECT_MODIFIED_FLAG && style->filter.set) {
449 if (auto filter = style->getFilter()) {
450 filter->update_filter_all_regions();
451 }
452 }
453
454 if (!_curve) {
455 sp_lpe_item_update_patheffect(this, true, false);
456 }
457}
458
460{
461 if (hasBrokenPathEffect()) {
462 g_warning("The shape has unknown LPE on it. Convert to path to make it editable preserving the appearance; "
463 "editing it will remove the bad LPE");
464
465 if (this->getRepr()->attribute("d")) {
466 // unconditionally read the curve from d, if any, to preserve appearance
469 }
470
471 return true;
472 }
473 return false;
474}
475
476/* Reset the shape's curve to the "original_curve"
477 * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
478
480{
481 auto const before = curveBeforeLPE();
482 if (before && before->get_pathvector() != c->get_pathvector()) {
484 sp_lpe_item_update_patheffect(this, true, false);
485 return true;
486 }
487
489 if (!before && this->getRepr()->attribute("d")) {
491 }
493 return true;
494 }
496 return false;
497}
498
499Geom::OptRect SPShape::bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype) const {
500 // If the object is clipped, the update function that invalidates
501 // the cache doesn't get called if the object is moved, so we need
502 // to compare the transformations as well.
503
504 if (bboxtype == SPItem::VISUAL_BBOX) {
507 if (bbox_vis_cache) {
510 }
511 return bbox_vis_cache;
512 } else {
515 if (bbox_geom_cache) {
518 }
519 return bbox_geom_cache;
520 }
521}
522
523Geom::OptRect SPShape::either_bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype, bool cache_is_valid,
524 Geom::OptRect bbox_cache, Geom::Affine const &transform_cache) const
525{
526
528
529 // Return the cache if possible.
530 auto delta = transform_cache.inverse() * transform;
531 if (cache_is_valid && bbox_cache && delta.isTranslation()) {
532
533 // Don't re-adjust the cache if we haven't moved
534 if (!delta.isNonzeroTranslation()) {
535 return bbox_cache;
536 }
537 // delta is pure translation so it's safe to use it as is
538 return *bbox_cache * delta;
539 }
540
541 if (!this->_curve || this->_curve->get_pathvector().empty()) {
542 return bbox;
543 }
544
545 bbox = bounds_exact_transformed(this->_curve->get_pathvector(), transform);
546
547 if (!bbox) {
548 return bbox;
549 }
550
551 if (bboxtype == SPItem::VISUAL_BBOX) {
552 // convert the stroke to a path and calculate that path's geometric bbox
553
554 if (!this->style->stroke.isNone() && !this->style->stroke_extensions.hairline) {
555 Geom::PathVector *pathv = item_to_outline(this, true); // calculate bbox_only
556
557 if (pathv) {
559 delete pathv;
560 }
561 }
562
563 if (this->hasMarkers()) {
564 for (auto const &[_, marker, tr] : this->get_markers()) {
565 if (auto const marker_item = sp_item_first_item_child(marker)) {
566 bbox |= marker_item->visualBounds(marker_item->transform * marker->c2p * tr * transform);
567 }
568 }
569 }
570 }
571
572 return bbox;
573}
574
576 if (!this->_curve) {
577 return;
578 }
579
580 Geom::PathVector const & pathv = this->_curve->get_pathvector();
581
582 if (pathv.empty()) {
583 return;
584 }
585
586 /* fixme: Think (Lauris) */
587 Geom::OptRect pbox, dbox, bbox;
588 pbox = this->geometricBounds();
589 bbox = this->desktopVisualBounds();
591
592 Geom::Affine const i2dt(this->i2dt_affine());
593
594 // Copy the style for this printable item
595 SPStyle *style = this->style;
596 SPStyle *new_style = nullptr;
597
598 if (ctx->context_item) {
599 new_style = new SPStyle(document, this);
600 new_style->merge(style);
601 // Set style contexts for print here
603 new_style->fill.overwrite(ctx->context_item->style->stroke.upcast());
604 if (style->fill.paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_FILL)
605 new_style->fill.overwrite(ctx->context_item->style->fill.upcast());
607 new_style->stroke.overwrite(ctx->context_item->style->stroke.upcast());
609 new_style->stroke.overwrite(ctx->context_item->style->fill.upcast());
610 style = new_style;
611 }
612
613 if (!style->fill.isNone()) {
614 ctx->fill (pathv, i2dt, style, pbox, dbox, bbox);
615 }
616
617 if (!style->stroke.isNone()) {
618 ctx->stroke (pathv, i2dt, style, pbox, dbox, bbox);
619 }
620
621 auto linewidth = this->style->stroke_width.computed;
622
623 if (new_style) {
624 // Clean up temporary context style copy
625 delete new_style;
626 }
627
628 for (auto const &[_, marker, tr] : this->get_markers()) {
629 if (auto marker_item = sp_item_first_item_child(marker)) {
630 auto const old_tr = marker_item->transform;
631 marker_item->transform = old_tr * marker->c2p * tr;
632 marker_item->invoke_print(ctx);
633 marker_item->transform = old_tr;
634 }
635 }
636
637 // Clear any context item used in the above markers.
638 ctx->context_item = nullptr;
639}
640
641std::optional<Geom::PathVector> SPShape::documentExactBounds() const
642{
643 std::optional<Geom::PathVector> result;
644 if (auto const *c = curve()) {
645 result = c->get_pathvector() * i2doc_affine();
646 }
647 return result;
648}
649
651{
652 if (!curveForEdit()) {
653 set_shape();
654 }
655 if (curveForEdit()) {
656 auto c_lpe = *curveForEdit();
657 /* if a path has an lpeitem applied, then reset the curve to the _curve_before_lpe.
658 * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
659 setCurveInsync(&c_lpe);
660
661
662 bool success = false;
663 // avoid update lpe in each selection
664 // must be set also to non effect items (satellites or parents)
665 lpe_initialized = true;
667 success = this->performPathEffect(&c_lpe, this);
668 if (success) {
669 if (!document->getRoot()->inkscape.getVersion().isInsideRangeInclusive({0, 1}, {0, 92})) {
671 }
672 setCurveInsync(&c_lpe);
673 applyToClipPath(this);
674 applyToMask(this);
675 }
676 }
677 if (write && success) {
678 if (auto repr = getRepr()) {
679 repr->setAttribute("d", sp_svg_write_path(c_lpe.get_pathvector()));
680 }
681 }
682 if (success) {
683 requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
684 }
685 }
686}
687
688Inkscape::DrawingItem* SPShape::show(Inkscape::Drawing &drawing, unsigned int /*key*/, unsigned int /*flags*/) {
689 // std::cout << "SPShape::show(): " << (getId()?getId():"null") << std::endl;
691
692 bool has_markers = this->hasMarkers();
693
694 s->setPath(_curve);
695
696 /* This stanza checks that an object's marker style agrees with
697 * the marker objects it has allocated. sp_shape_set_marker ensures
698 * that the appropriate marker objects are present (or absent) to
699 * match the style.
700 */
701 for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
703 }
704
705 if (has_markers) {
706 /* provide key and dimension the marker views */
708 for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
709 if (_marker[i]) {
711 }
712 }
713
714 /* Update marker views */
716
717 this->context_style = this->style;
718 s->setStyle(this->style, this->context_style);
719 s->setChildrenStyle(this->context_style); // Resolve 'context-xxx' in children.
720 } else if (this->parent) {
721 this->context_style = this->parent->context_style;
722 s->setStyle(this->style, this->context_style);
723 }
724
725 // apply 'shape-rendering' presentation attribute
727
728 return s;
729}
730
734void SPShape::hide(unsigned key)
735{
736 for (int i = 0; i < SP_MARKER_LOC_QTY; ++i) {
737 if (_marker[i]) {
738 for (auto &v : views) {
739 if (key == v.key) {
740 sp_marker_hide(_marker[i], v.drawingitem->key() + ITEM_KEY_MARKERS + i);
741 }
742 }
743 }
744 }
745
746 //SPLPEItem::onHide(key);
747}
748
754{
755 /* Note, we're ignoring 'marker' settings, which technically should apply for
756 all three settings. This should be fixed later such that if 'marker' is
757 specified, then all three should appear. */
758
759 // Ignore markers for objects which are inside markers themselves.
760 for (SPObject *parent = this->parent; parent != nullptr; parent = parent->parent) {
761 if (is<SPMarker>(parent)) {
762 return 0;
763 }
764 }
765
766 return (
767 this->_curve &&
768 (this->_marker[SP_MARKER_LOC] ||
770 this->_marker[SP_MARKER_LOC_MID] ||
772 );
773}
774
775
781int SPShape::numberOfMarkers(int type) const {
782 Geom::PathVector const & pathv = this->_curve->get_pathvector();
783
784 if (pathv.size() == 0) {
785 return 0;
786 }
787 switch(type) {
788
789 case SP_MARKER_LOC:
790 {
791 if ( this->_marker[SP_MARKER_LOC] ) {
792 guint n = 0;
793 for(const auto & path_it : pathv) {
794 n += path_it.size_default() + 1;
795 }
796 return n;
797 } else {
798 return 0;
799 }
800 }
802 // there is only a start marker on the first path of a pathvector
803 return this->_marker[SP_MARKER_LOC_START] ? 1 : 0;
804
806 {
807 if ( this->_marker[SP_MARKER_LOC_MID] ) {
808 guint n = 0;
809 for(const auto & path_it : pathv) {
810 n += path_it.size_default() + 1;
811 }
812 n = (n > 1) ? (n - 2) : 0; // Minus the start and end marker, but never negative.
813 // A path or polyline may have only one point.
814 return n;
815 } else {
816 return 0;
817 }
818 }
819
821 {
822 // there is only an end marker on the last path of a pathvector
823 return this->_marker[SP_MARKER_LOC_END] ? 1 : 0;
824 }
825
826 default:
827 return 0;
828 }
829}
830
836static void
838{
839 auto item = shape;
840 g_return_if_fail(item != nullptr);
841
842 for (int i = 0; i < SP_MARKER_LOC_QTY; i++) {
843 if (marker == shape->_marker[i]) {
844 /* Hide marker */
845 for (auto &v : item->views) {
846 sp_marker_hide(shape->_marker[i], v.drawingitem->key() + ITEM_KEY_MARKERS + i);
847 }
848 /* Detach marker */
849 shape->_release_connect[i].disconnect();
850 shape->_modified_connect[i].disconnect();
851 shape->_marker[i]->unhrefObject(item);
852 shape->_marker[i] = nullptr;
853 }
854 }
855}
856
860static void sp_shape_marker_modified (SPObject* marker, guint flags, SPItem* item) {
861 if ((flags & SP_OBJECT_MODIFIED_FLAG) && item && marker) {
862 // changing marker can impact object's visual bounding box, so request update on this object itself
863 item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
864 }
865}
866
874void SPShape::set_marker(unsigned key, char const *value)
875{
876 if (key > SP_MARKER_LOC_END) {
877 return;
878 }
879
880 auto mrk = sp_css_uri_reference_resolve(document, value);
881 auto marker = cast<SPMarker>(mrk);
882
883 if (marker != _marker[key]) {
884 if (_marker[key]) {
885 /* Detach marker */
886 _release_connect[key].disconnect();
887 _modified_connect[key].disconnect();
888
889 /* Hide marker */
890 for (auto &v : views) {
891 sp_marker_hide(_marker[key], v.drawingitem->key() + ITEM_KEY_MARKERS + key);
892 }
893
894 /* Unref marker */
895 _marker[key]->unhrefObject(this);
896 _marker[key] = nullptr;
897 }
898 if (marker) {
899 _marker[key] = marker;
900 _marker[key]->hrefObject(this);
901 _release_connect[key] = marker->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_shape_marker_release), this));
902 _modified_connect[key] = marker->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_shape_marker_modified), this));
903 }
904 }
905}
906
907// CPPIFY: make pure virtual
909 //throw;
910}
911
912/* Shape section */
913
920{
921 _curve = std::make_shared<SPCurve>(std::move(new_curve));
922 if (document) {
923 requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
924 }
925}
927{
928 if (new_curve) {
930 } else {
931 _curve.reset();
932 }
933}
934
943{
944 if (new_curve) {
946 } else {
947 _curve_before_lpe.reset();
948 }
949}
950
955{
956 _curve = std::make_shared<SPCurve>(std::move(new_curve));
957}
959{
960 if (new_curve) {
962 } else {
963 _curve.reset();
964 }
965}
966
971{
972 return _curve.get();
973}
974
979{
980 return _curve_before_lpe ? &*_curve_before_lpe : nullptr;
981}
982
987{
989}
990
991void SPShape::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const {
992 if (this->_curve == nullptr) {
993 return;
994 }
995
996 Geom::PathVector const &pathv = this->_curve->get_pathvector();
997
998 if (pathv.empty()) {
999 return;
1000 }
1001
1002 Geom::Affine const i2dt (this->i2dt_affine ());
1003
1006
1007 if (bbox) {
1009 }
1010 }
1011
1012 for(const auto & path_it : pathv) {
1014 // Add the first point of the path
1015 p.emplace_back(path_it.initialPoint() * i2dt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP);
1016 }
1017
1018 Geom::Path::const_iterator curve_it1 = path_it.begin(); // incoming curve
1019 Geom::Path::const_iterator curve_it2 = ++(path_it.begin()); // outgoing curve
1020
1021 while (curve_it1 != path_it.end_default())
1022 {
1023 // For each path: consider midpoints of line segments for snapping
1025 if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
1027 }
1028 }
1029
1030 if (curve_it2 == path_it.end_default()) { // Test will only pass for the last iteration of the while loop
1031 if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && !path_it.closed()) {
1032 // Add the last point of the path, but only for open paths
1033 // (for closed paths the first and last point will coincide)
1034 p.emplace_back((*curve_it1).finalPoint() * i2dt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP);
1035 }
1036 } else {
1037 /* Test whether to add the node between curve_it1 and curve_it2.
1038 * Loop to end_default (so only iterating through the stroked part); */
1039
1040 Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
1041
1042 bool c1 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
1043 bool c2 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_SMOOTH) && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
1044
1045 if (c1 || c2) {
1048
1049 switch (nodetype) {
1050 case Geom::NODE_CUSP:
1053 break;
1054 case Geom::NODE_SMOOTH:
1055 case Geom::NODE_SYMM:
1058 break;
1059 default:
1062 break;
1063 }
1064
1065 p.emplace_back(curve_it1->finalPoint() * i2dt, sst, stt);
1066 }
1067 }
1068
1069 ++curve_it1;
1070 ++curve_it2;
1071 }
1072
1073 // Find the internal intersections of each path and consider these for snapping
1074 // (using "Method 1" as described in Inkscape::ObjectSnapper::_collectNodes())
1076 Geom::Crossings cs;
1077
1078 try {
1079 cs = self_crossings(path_it); // This can be slow!
1080
1081 if (!cs.empty()) { // There might be multiple intersections...
1082 for (const auto & c : cs) {
1083 Geom::Point p_ix = path_it.pointAt(c.ta);
1085 }
1086 }
1087 } catch (Geom::RangeError &e) {
1088 // do nothing
1089 // The exception could be Geom::InfiniteSolutions: then no snappoints should be added
1090 }
1091
1092 }
1093 }
1094}
1095
1096/*
1097 Local Variables:
1098 mode:c++
1099 c-file-style:"stroustrup"
1100 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1101 indent-tabs-mode:nil
1102 fill-column:99
1103 End:
1104*/
1105// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
curve_type new_curve(void)
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
3x3 matrix representing an affine transformation.
Definition affine.h:70
Coord descrim() const
Calculate the descriminant.
Definition affine.cpp:434
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
virtual Curve * reverse() const
Create a reversed version of this curve.
Definition curve.h:234
virtual Point unitTangentAt(Coord t, unsigned n=3) const
Compute a vector tangent to the curve.
Definition curve.cpp:201
virtual Point pointAt(Coord t) const
Evaluate the curve at a specified time value.
Definition curve.h:110
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Sequence of subpaths.
Definition pathvector.h:122
size_type size() const
Get the number of paths in the vector.
Definition pathvector.h:147
Sequence::const_iterator const_iterator
Definition pathvector.h:127
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
iterator begin()
Definition pathvector.h:151
iterator end()
Definition pathvector.h:152
Sequence of contiguous curves, aka spline.
Definition path.h:353
size_type size_default() const
Natural size of the path.
Definition path.h:486
Curve const & front() const
Access the first curve in the path.
Definition path.h:443
Two-dimensional point that doubles as a vector.
Definition point.h:66
Rotation around the origin.
Definition transforms.h:187
Translation by a vector.
Definition transforms.h:115
SVG drawing item for display.
unsigned key() const
void setPath(std::shared_ptr< SPCurve const > curve)
void setChildrenStyle(SPStyle const *context_style) override
Recursively update children style.
void setStyle(SPStyle const *style, SPStyle const *context_style=nullptr) override
Process information related to the new style.
unsigned int fill(Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox)
Definition print.cpp:66
unsigned int stroke(Geom::PathVector const &pathv, Geom::Affine const &transform, SPStyle const *style, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox)
Definition print.cpp:73
Storing of snapping preferences.
bool isSourceSnappable(Inkscape::SnapSourceType const source) const
bool isTargetSnappable(Inkscape::SnapTargetType const target) 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
Wrapper around a Geom::PathVector object.
Definition curve.h:26
Geom::PathVector const & get_pathvector() const
Definition curve.cpp:52
Typed SVG document implementation.
Definition document.h:103
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:202
Geom::Point getDimensions() const
Definition document.cpp:973
char const * value() const
Get value if set, or inherited value, or default value (may be NULL)
Base class for visual SVG elements.
Definition sp-item.h:109
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
Definition sp-item.cpp:1821
Geom::Affine transform
Definition sp-item.h:138
Geom::OptRect desktopVisualBounds() const
Get item's visual bbox in desktop coordinate system.
Definition sp-item.cpp:1049
@ VISUAL_BBOX
Definition sp-item.h:118
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
Definition sp-item.cpp:920
static unsigned ensure_key(Inkscape::DrawingItem *di)
Ensures that a drawing item's key is the first of a block of ITEM_KEY_SIZE keys, assigning it such a ...
Definition sp-item.cpp:1255
Geom::Affine i2doc_affine() const
Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
Definition sp-item.cpp:1816
std::vector< SPItemView > views
Definition sp-item.h:163
bool isOnClipboard()
The lpeitem is on clipboard.
void release() override
void resetClipPathAndMaskLPE(bool fromrecurse=false)
void applyToMask(SPItem *to, Inkscape::LivePathEffect::Effect *lpe=nullptr)
bool hasBrokenPathEffect() const
used for shapes so they can see if they should also disable shape calculation and read from d=
bool hasPathEffect() const
void applyToClipPath(SPItem *to, Inkscape::LivePathEffect::Effect *lpe=nullptr)
bool hasPathEffectOnClipOrMaskRecursive(SPLPEItem *shape) const
returns true when any LPE apply to clip or mask.
bool lpe_initialized
bool pathEffectsEnabled() const
void update(SPCtx *ctx, unsigned int flags) override
void build(SPDocument *doc, Inkscape::XML::Node *repr) override
bool performPathEffect(SPCurve *curve, SPShape *current, bool is_clip_or_mask=false)
returns true when LPE was successful.
void modified(unsigned int flags) override
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
void set(SPAttr key, char const *value) override
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
Inkscape::XML::Node * repr
Definition sp-object.h:193
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
SPDocument * document
Definition sp-object.h:188
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
SPObject * parent
Definition sp-object.h:189
SPStyle * context_style
Represents the style that should be used to resolve 'context-fill' and 'context-stroke'.
Definition sp-object.h:253
void unhrefObject(SPObject *owner=nullptr)
Decrease weak refcount.
void hrefObject(SPObject *owner=nullptr)
Increase weak refcount.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
char const * getAttribute(char const *name) const
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
struct SPRoot::@40 inkscape
Base class for shapes, including <path> element.
Definition sp-shape.h:38
SPCurve const * curve() const
Return a borrowed pointer to the curve (if any exists) or NULL if there is no curve.
Definition sp-shape.cpp:970
void update(SPCtx *ctx, unsigned int flags) override
Definition sp-shape.cpp:125
int hasMarkers() const
Definition sp-shape.cpp:753
void setCurveInsync(SPCurve const *)
Definition sp-shape.cpp:958
Geom::OptRect bbox_geom_cache
Definition sp-shape.h:65
void snappoints(std::vector< Inkscape::SnapCandidatePoint > &p, Inkscape::SnapPreferences const *snapprefs) const override
Definition sp-shape.cpp:991
virtual void set_shape()
Definition sp-shape.cpp:908
std::optional< SPCurve > _curve_before_lpe
Definition sp-shape.h:69
bool prepareShapeForLPE(SPCurve const *c)
Definition sp-shape.cpp:479
void modified(unsigned int flags) override
Definition sp-shape.cpp:427
Geom::Affine bbox_vis_cache_transform
Definition sp-shape.h:64
Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype) const override
Definition sp-shape.cpp:499
void release() override
Removes, releases and unrefs all children of object.
Definition sp-shape.cpp:92
void set(SPAttr key, char const *value) override
Definition sp-shape.cpp:115
void setCurveBeforeLPE(SPCurve const *)
Definition sp-shape.cpp:942
Geom::Affine bbox_geom_cache_transform
Definition sp-shape.h:63
sigc::connection _release_connect[SP_MARKER_LOC_QTY]
Definition sp-shape.h:74
Geom::OptRect bbox_vis_cache
Definition sp-shape.h:66
~SPShape() override
Definition sp-shape.cpp:56
void build(SPDocument *document, Inkscape::XML::Node *repr) override
Definition sp-shape.cpp:63
bool bbox_geom_cache_is_valid
Definition sp-shape.h:61
void set_marker(unsigned key, char const *value)
Adds a new marker to shape object at the location indicated by key.
Definition sp-shape.cpp:874
void update_patheffect(bool write) override
Definition sp-shape.cpp:650
std::shared_ptr< SPCurve const > _curve
Definition sp-shape.h:70
SPMarker * _marker[SP_MARKER_LOC_QTY]
Definition sp-shape.h:73
bool bbox_vis_cache_is_valid
Definition sp-shape.h:62
int numberOfMarkers(int type) const
Definition sp-shape.cpp:781
void print(SPPrintContext *ctx) override
Definition sp-shape.cpp:575
sigc::connection _modified_connect[SP_MARKER_LOC_QTY]
Definition sp-shape.h:75
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Definition sp-shape.cpp:120
SPCurve const * curveBeforeLPE() const
Return a borrowed pointer of the curve before LPE (if any exists) or NULL if there is no curve.
Definition sp-shape.cpp:978
SPCurve const * curveForEdit() const
Return a borrowed pointer of the curve for edit.
Definition sp-shape.cpp:986
std::optional< Geom::PathVector > documentExactBounds() const override
Get an exact geometric shape representing the visual bounds of the item in the document coordinates.
Definition sp-shape.cpp:641
std::vector< std::tuple< SPMarkerLoc, SPMarker *, Geom::Affine > > get_markers() const
Lists every marker on this shape along with its transform and marker type.
Definition sp-shape.cpp:247
bool checkBrokenPathEffect()
Definition sp-shape.cpp:459
void setCurve(SPCurve const *)
Definition sp-shape.cpp:926
Inkscape::DrawingItem * show(Inkscape::Drawing &drawing, unsigned int key, unsigned int flags) override
Definition sp-shape.cpp:688
Geom::OptRect either_bbox(Geom::Affine const &transform, SPItem::BBoxType bboxtype, bool cache_is_valid, Geom::OptRect bbox_cache, Geom::Affine const &transform_cache) const
Definition sp-shape.cpp:523
void hide(unsigned int key) override
Sets style, path, and paintbox.
Definition sp-shape.cpp:734
An SVG style object.
Definition style.h:45
void merge(SPStyle const *parent)
Combine style and parent style specifications into a single style specification that preserves (as mu...
Definition style.cpp:843
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::STROKE_DASHARRAY, SPIDashArray > stroke_dasharray
stroke-dasharray
Definition style.h:257
T< SPAttr::STROKE, SPIPaint > stroke
stroke
Definition style.h:247
SPFilter * getFilter()
Definition style.h:335
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Definition style.h:249
T< SPAttr::FILTER, SPIFilter > filter
Filter effect.
Definition style.h:275
SPIString * marker_ptrs[SP_MARKER_LOC_QTY]
Definition style.h:270
T< SPAttr::STROKE_DASHOFFSET, SPILength > stroke_dashoffset
stroke-dashoffset
Definition style.h:259
T< SPAttr::SHAPE_RENDERING, SPIEnum< SPShapeRendering > > shape_rendering
Definition style.h:293
T< SPAttr::FONT_SIZE, SPIFontSize > font_size
Size of the font.
Definition style.h:116
const double w
Definition conic-4.cpp:19
Css & result
double c[8][4]
Group belonging to an SVG drawing element.
Specific nodetype geometry functions for Inkscape, not provided my lib2geom.
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.
SPItem * item
Geom::Point start
double atan2(Point const &p)
NodeType
What kind of node is this? This is the value for the node->type field.
@ NODE_NONE
Discontinuous node, usually either start or endpoint of a path.
@ NODE_CUSP
This node continuously joins two segments, but the unit tangent is discontinuous.
@ NODE_SYMM
This node is symmetric.
@ NODE_SMOOTH
This node continuously joins two segments, with continuous unit tangent.
NodeType get_nodetype(Curve const &c_incoming, Curve const &c_outgoing)
std::vector< Crossing > Crossings
Definition crossing.h:126
Point middle_point(LineSegment const &_segment)
SnapSourceType
enumerations of snap source types and snap target types.
Definition snap-enums.h:18
@ SNAPSOURCE_NODE_CUSP
Definition snap-enums.h:37
@ SNAPSOURCE_PATH_INTERSECTION
Definition snap-enums.h:39
@ SNAPSOURCE_UNDEFINED
Definition snap-enums.h:19
@ SNAPSOURCE_NODE_SMOOTH
Definition snap-enums.h:36
@ SNAPSOURCE_OBJECT_MIDPOINT
Definition snap-enums.h:53
@ SNAPSOURCE_LINE_MIDPOINT
Definition snap-enums.h:38
void propagate_antialias(SPShapeRendering shape_rendering, DrawingItem &item)
Propagate element's shape rendering attribute into internal anti-aliasing setting of DrawingItem.
@ SNAPTARGET_UNDEFINED
Definition snap-enums.h:71
@ SNAPTARGET_NODE_CUSP
Definition snap-enums.h:83
@ SNAPTARGET_LINE_MIDPOINT
Definition snap-enums.h:84
@ SNAPTARGET_NODE_SMOOTH
Definition snap-enums.h:82
@ SNAPTARGET_OBJECT_MIDPOINT
Definition snap-enums.h:115
@ SNAPTARGET_PATH_INTERSECTION
Definition snap-enums.h:88
static cairo_user_data_key_t key
static gint counter
Definition box3d.cpp:39
Path intersection.
Geom::PathVector * item_to_outline(SPItem const *item, bool exclude_markers)
Returns a pathvector that is the outline of the stroked item, with markers.
Two related object to path operations:
Inkscape::SVG::PathString - builder for SVG path strings.
PathVector - a sequence of subpaths.
Singleton class to access the preferences file in a convenient way.
Axis-aligned rectangle.
Some utility classes to store various kinds of snap candidates.
SPItem const * sp_item_first_item_child(SPObject const *obj)
Definition sp-item.cpp:1862
@ ITEM_KEY_MARKERS
Definition sp-item.h:72
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
SPMarkerLoc
These enums are to allow us to have 4-element arrays that represent a set of marker locations (all,...
@ SP_MARKER_LOC_START
@ SP_MARKER_LOC_QTY
@ SP_MARKER_LOC_END
@ SP_MARKER_LOC_MID
@ SP_MARKER_LOC
void sp_marker_hide(SPMarker *marker, unsigned int key)
Hides/removes all views of the given marker that have key 'key'.
Inkscape::DrawingItem * sp_marker_show_instance(SPMarker *marker, Inkscape::DrawingItem *parent, unsigned int loc, unsigned int pos, unsigned int z_order, Geom::Affine const &marker_transform, float linewidth)
Shows an instance of a marker.
void sp_marker_show_dimension(SPMarker *marker, unsigned int key, unsigned int size)
Removes any SPMarkerViews that a marker has with a specific key.
SPRoot: SVG <svg> implementation.
static void sp_shape_marker_modified(SPObject *marker, guint flags, SPItem *item)
No-op.
Definition sp-shape.cpp:860
Geom::Affine sp_shape_marker_get_transform_at_end(Geom::Curve const &c)
Definition sp-shape.cpp:383
Geom::Affine sp_shape_marker_get_transform(Geom::Curve const &c1, Geom::Curve const &c2)
Calculate the transform required to get a marker's path object in the right place for particular path...
Definition sp-shape.cpp:340
Geom::Affine sp_shape_marker_get_transform_at_start(Geom::Curve const &c)
Definition sp-shape.cpp:366
static void sp_shape_marker_release(SPObject *marker, SPShape *shape)
Checks if the given marker is used in the shape, and if so, it releases it by calling sp_marker_hide.
Definition sp-shape.cpp:837
static void sp_shape_update_marker_view(SPShape *shape, Inkscape::DrawingItem *ai)
Updates the instances (views) of a given marker in a shape.
Definition sp-shape.cpp:409
Geom::Affine sp_shape_marker_get_transform_at_end(Geom::Curve const &c)
Definition sp-shape.cpp:383
Geom::Affine sp_shape_marker_get_transform(Geom::Curve const &c1, Geom::Curve const &c2)
Calculate the transform required to get a marker's path object in the right place for particular path...
Definition sp-shape.cpp:340
Geom::Affine sp_shape_marker_get_transform_at_start(Geom::Curve const &c)
Definition sp-shape.cpp:366
Interface for XML documents.
Definition document.h:43
Unused.
Definition sp-object.h:94
Contains transformations to document/viewport and the viewport size.
Definition sp-item.h:92
Geom::Affine i2vp
Item to viewport transformation.
Definition sp-item.h:100
Geom::Rect viewport
Viewport size.
Definition sp-item.h:97
unsigned int fill(Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox)
Definition print.cpp:51
unsigned int stroke(Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox)
Definition print.cpp:58
Inkscape::Extension::Print *SPItem * context_item
Definition print.h:43
@ SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE
@ SP_CSS_PAINT_ORIGIN_CONTEXT_FILL
@ SP_CSS_UNIT_PERCENT
@ SP_CSS_UNIT_EM
@ SP_CSS_UNIT_EX
SPStyle - a style object for SPItem objects.
Geom::PathVector sp_svg_read_pathv(char const *str)
Definition svg-path.cpp:37
static void sp_svg_write_path(Inkscape::SVG::PathString &str, Geom::Path const &p, bool normalize=false)
Definition svg-path.cpp:109
int delta
int index
double width
Affine transformation classes.
SPObject * sp_css_uri_reference_resolve(SPDocument *document, const gchar *uri)