13#include <gdk/gdkkeysyms.h>
14#include <glib/gi18n.h>
63 static double error_of(
double value) {
return value * instance().rel_error; }
68 set_numeric_precision(digits);
72 SvgOutputPrecisionWatcher()
73 : Observer(
"/options/svgoutput/numericprecision")
78 set_numeric_precision(digits);
83 void set_numeric_precision(
int digits)
85 double relative_error = 0.5;
90 rel_error = relative_error;
93 static SvgOutputPrecisionWatcher &instance()
95 static SvgOutputPrecisionWatcher
_instance;
99 std::atomic<double> rel_error;
103double serializing_error_of(
const Geom::Point &point)
105 return SvgOutputPrecisionWatcher::error_of(point.
length());
119 const double tolerance_factor = 10;
120 const double tolerance_A = serializing_error_of(A) * tolerance_factor;
121 const double tolerance_B = serializing_error_of(B) * tolerance_factor;
122 const double tolerance_C = serializing_error_of(C) * tolerance_factor;
123 const double CB_length = (B - C).
length();
124 const double AB_length = (B - A).
length();
125 Geom::Point C_reflect_scaled = B + (B - C) / CB_length * AB_length;
126 double tolerance_C_reflect_scaled = tolerance_B + (tolerance_B + tolerance_C) *
127 (1 + (tolerance_A + tolerance_B) / AB_length) *
128 (1 + (tolerance_C + tolerance_B) / CB_length);
129 return Geom::are_near(C_reflect_scaled, A, tolerance_C_reflect_scaled + tolerance_A);
141std::ostream &operator<<(std::ostream &out,
NodeType type)
198 if (
_pm()._isBSpline()) {
255 if (direction_length == 0) {
341 return _(
"Corner node handle");
343 return _(
"Smooth node handle");
345 return _(
"Symmetric node handle");
347 return _(
"Auto-smooth node handle");
359 switch (event.keyval) {
366 if (mod_shift_only(event) && _parent->_type == NODE_CUSP) {
369 if (other()->isDegenerate())
370 other()->setRelativePos(-relativePos());
372 other()->setDirection(-relativePos());
373 _parent->setType(NODE_SMOOTH, false);
376 _parent->_pm().update();
379 _parent->_pm()._commit(_(
"Change node type"));
413 if (event.num_press != 2) {
419 handle_2button_press();
422 [&](CanvasEvent
const &event) {});
428void Handle::handle_2button_press()
430 if (_pm()._isBSpline()) {
432 this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),
DEFAULT_START_POWER));
439 _saved_other_pos = other()->position();
440 _saved_length = _drag_out ? 0 : length();
442 _pm()._handleGrabbed();
452 std::optional<Inkscape::Snapper::SnapConstraint> ctrl_constraint;
461 _saved_length = _drag_out ? 0 : length();
467 other()->setRelativePos(-relativePos());
474 int snaps = 2 * prefs->
getIntLimited(
"/options/rotationsnapsperpi/value", 12, 1, 1000);
498 if (_pm()._isBSpline()) {
499 setPosition(new_pos);
500 int steps = _pm()._bsplineGetSteps();
502 _pm()._bsplineHandleReposition(
this, ceilf(_pm()._bsplineHandlePosition(
this,
false) * steps) / steps);
506 std::vector<Inkscape::SnapCandidatePoint> unselected;
508 if (snap && !_pm()._isBSpline()) {
512 for (
auto node : nodes) {
515 unselected.push_back(n->snapCandidatePoint());
521 if (_parent->type() == NODE_SMOOTH && Node::_is_line_segment(_parent, node_away)) {
526 }
else if (ctrl_constraint) {
540 if (_parent->type() == NODE_CUSP && !_drag_out) {
542 Geom::Point other_relpos = _saved_other_pos - parent_pos;
544 other()->setRelativePos(other_relpos);
547 other()->setPosition(_saved_other_pos);
552 new_pos = _last_drag_origin();
564 int drag_tolerance = prefs->getIntLimited(
"/options/dragtolerance/value", 0, 0, 100);
566 auto const dist = _desktop->d2w(_parent->position()) - _desktop->d2w(position());
567 if (dist.length() <= drag_tolerance) {
568 move(_parent->position());
575 _parent->ungrabbed(event);
578 Tools::sp_update_helperpath(_desktop);
579 _pm()._handleUngrabbed();
586 if (_parent->type() == NODE_SMOOTH) {
591 if (_pm()._nodeClicked(this->
parent(), event)) {
594 _pm()._handleClicked(
this, event);
600 return const_cast<Handle *
>(
this)->other();
605 if (
this == &_parent->_front) {
606 return &_parent->_back;
608 return &_parent->_front;
615 int snaps = prefs->
getIntLimited(
"/options/rotationsnapsperpi/value", 12, 1, 1000);
616 return 180.0 / snaps;
619Glib::ustring Handle::_getTip(
unsigned state)
const
625 bool isBSpline = _pm()._isBSpline();
626 bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate();
627 Glib::ustring s = C_(
"Status line hint",
628 "node control handle");
630 if (
mod_alt(state) && !isBSpline) {
632 if (
mod_shift(state) && can_shift_rotate) {
633 s = format_tip(C_(
"Status line hint",
"<b>Shift+Ctrl+Alt</b>: "
634 "preserve length and snap rotation angle to %g° increments, "
635 "and rotate both handles"),
638 s = format_tip(C_(
"Status line hint",
"<b>Ctrl+Alt</b>: "
639 "preserve length and snap rotation angle to %g° increments"),
643 if (
mod_shift(state) && can_shift_rotate) {
644 s = C_(
"Path handle tip",
"<b>Shift+Alt</b>: preserve handle length and rotate both handles");
646 s = C_(
"Path handle tip",
"<b>Alt</b>: preserve handle length while dragging");
651 if (
mod_shift(state) && can_shift_rotate && !isBSpline) {
652 s = format_tip(C_(
"Path handle tip",
"<b>Shift+Ctrl</b>: "
653 "snap rotation angle to %g° increments, and rotate both handles"),
655 }
else if (isBSpline) {
656 s = C_(
"Path handle tip",
"<b>Ctrl</b>: "
657 "Snap handle to steps defined in BSpline Live Path Effect");
659 s = format_tip(C_(
"Path handle tip",
"<b>Ctrl</b>: "
660 "snap rotation angle to %g° increments, click to retract"),
663 }
else if (
mod_shift(state) && can_shift_rotate && !isBSpline) {
664 s = C_(
"Path handle tip",
"<b>Shift</b>: rotate both handles by the same angle");
665 }
else if (
mod_shift(state) && isBSpline) {
666 s = C_(
"Path handle tip",
"<b>Shift</b>: move handle");
668 char const *handletype = handle_type_to_localized_string(_parent->_type);
671 if (can_shift_rotate && !isBSpline) {
672 more = C_(
"Status line hint",
"Shift, Ctrl, Alt");
673 }
else if (isBSpline) {
674 more = C_(
"Status line hint",
"Shift, Ctrl");
676 more = C_(
"Status line hint",
"Ctrl, Alt");
679 double power = _pm()._bsplineHandlePosition(h);
680 s = format_tip(C_(
"Status line hint",
"<b>BSpline node handle</b> (%.3g power): "
681 "Shift-drag to move, "
682 "double-click to reset. "
685 }
else if (_parent->type() == NODE_CUSP) {
686 s = format_tip(C_(
"Status line hint",
"<b>%s</b>: "
687 "drag to shape the path"
691 "Shift+S to make smooth"
693 "Shift+Y to make symmetric"
697 }
else if (_parent->type() == NODE_SMOOTH) {
698 s = format_tip(C_(
"Status line hint",
"<b>%s</b>: "
699 "drag to shape the path"
703 "Shift+Y to make symmetric"
707 }
else if (_parent->type() ==
NODE_AUTO) {
708 s = format_tip(C_(
"Status line hint",
"<b>%s</b>: "
709 "drag to make smooth, "
712 "Shift+Y to make symmetric"
717 s = format_tip(C_(
"Status line hint",
"<b>%s</b>: "
718 "drag to shape the path"
723 s = C_(
"Status line hint",
724 "<b>unknown node handle</b>");
734 Geom::Point dist = position() - _last_drag_origin();
738 angle *= 360.0 / (2 * M_PI);
743 Glib::ustring x = x_q.
string(_desktop->getNamedView()->display_units);
744 Glib::ustring y = y_q.
string(_desktop->getNamedView()->display_units);
745 Glib::ustring
len = len_q.
string(_desktop->getNamedView()->display_units);
746 Glib::ustring ret = format_tip(C_(
"Status line hint",
"Move handle by %s, %s; angle %.2f°, length %s"), x.c_str(),
747 y.c_str(), angle,
len.c_str());
754 , _front(
data, initial_pos, this)
755 , _back(
data, initial_pos, this)
757 , _handles_shown(false)
765 return const_cast<Node *
>(
this)->
_next();
781 return const_cast<Node *
>(
this)->
_prev();
804 Node *nextNode = n->nodeToward(n->front());
805 Node *prevNode = n->nodeToward(n->back());
806 nodeWeight = fmax(
_pm()._bsplineHandlePosition(n->front(),
false),
_pm()._bsplineHandlePosition(n->back(),
false));
822 if (
_pm()._isBSpline()) {
842 Node *nextNode = n->nodeToward(n->front());
843 Node *prevNode = n->nodeToward(n->back());
860 if (
_pm()._isBSpline()) {
910 Handle *handle, *other_handle;
948 double len_next = vec_next.
length(), len_prev = vec_prev.
length();
949 if (len_next > 0 && len_prev > 0) {
992 if (update_handles) {
1029 }
else if (
_prev()) {
1036 }
else if (
_next()) {
1057 if (vec_next.
length() == 0 || vec_prev.
length() == 0) {
1066 double len_next = vec_next.
length(), len_prev = vec_prev.
length();
1067 double len = (len_next + len_prev) / 6;
1089 if (
_pm()._isBSpline()) {
1108 bool both_degen = front_degen && back_degen;
1109 bool neither_degen = !front_degen && !back_degen;
1115 if (neither_degen) {
1183 state =
event.modifiers;
1184 switch (event.keyval) {
1185 case GDK_KEY_Page_Up:
1188 case GDK_KEY_Page_Down:
1201 if (dir && (linear_grow || spatial_grow)) {
1204 }
else if (spatial_grow) {
1224 double distance_back = 0, distance_front = 0;
1235 while (fwd && fwd->selected()) {
1238 Geom::bezier_length(fwd->position(), fwd->_front.position(), n->_back.position(), n->position());
1240 if (fwd == this_iter)
1247 while (rev && rev->selected()) {
1250 Geom::bezier_length(rev->position(), rev->_back.position(), p->_front.position(), p->position());
1256 if (distance_front <= distance_back)
1277 double last_distance_back = 0, last_distance_front = 0;
1279 while (rev || fwd) {
1280 if (fwd && (!rev || distance_front <= distance_back)) {
1281 if (fwd->selected()) {
1283 last_distance_front = distance_front;
1287 distance_front +=
Geom::bezier_length(fwd->position(), fwd->_front.position(), n->_back.position(),
1290 }
else if (rev && (!fwd || distance_front > distance_back)) {
1291 if (rev->selected()) {
1293 last_distance_back = distance_back;
1297 distance_back +=
Geom::bezier_length(rev->position(), rev->_back.position(), p->_front.position(),
1305 if (fwd && fwd == rev) {
1306 if (!fwd->selected())
1309 double df = distance_front +
Geom::bezier_length(fwdp->position(), fwdp->_front.position(),
1310 fwd->_back.position(), fwd->position());
1312 rev->_front.position(), rev->position());
1315 last_distance_front = df;
1318 last_distance_back = db;
1325 if (last_fwd && last_rev) {
1326 if (last_distance_front >= last_distance_back)
1376 double angle_next = HUGE_VAL;
1377 double angle_prev = HUGE_VAL;
1378 bool has_degenerate =
false;
1383 has_degenerate =
true;
1388 has_degenerate =
true;
1390 if (!has_degenerate) {
1413 bool snap = !
mod_shift(event) && sm.someSnapperMightSnap();
1416 std::vector<Inkscape::SnapCandidatePoint> unselected;
1427 if (!
node->selected()) {
1428 auto n =
static_cast<Node *
>(
node);
1429 unselected.emplace_back(n->position(), n->_snapSourceType(), n->_snapTargetType());
1433 sm.setupIgnoreSelection(
_desktop,
true, &unselected);
1440 std::optional<Geom::Point> front_direction, back_direction;
1481 std::vector<Inkscape::Snapper::SnapConstraint> constraints;
1484 int snaps = prefs->
getIntLimited(
"/options/rotationsnapsperpi/value", 12, 1, 1000);
1485 double min_angle = M_PI / snaps;
1487 if (front_direction) {
1489 constraints.emplace_back(
origin, *front_direction);
1492 if (back_direction) {
1493 constraints.emplace_back(
origin, *back_direction);
1500 std::optional<Geom::Point> front_normal =
Geom::rot90(*front_direction);
1501 if (front_normal && (!back_direction ||
1504 constraints.emplace_back(
origin, *front_normal);
1507 std::optional<Geom::Point> back_normal =
Geom::rot90(*back_direction);
1508 if (back_normal && (!front_direction ||
1511 constraints.emplace_back(
origin, *back_normal);
1537 if (
_pm()._nodeClicked(
this, event)) {
1564 if (
_next() == to) {
1567 if (
_prev() == to) {
1570 g_error(
"Node::handleToward(): second node is not adjacent!");
1576 if (
front() == dir) {
1579 if (
back() == dir) {
1582 g_error(
"Node::nodeToward(): handle is not a child of this node!");
1588 if (
_next() == to) {
1591 if (
_prev() == to) {
1594 g_error(
"Node::handleAwayFrom(): second node is not adjacent!");
1606 g_error(
"Node::nodeAwayFrom(): handle is not a child of this node!");
1614 Glib::ustring s = C_(
"Path node tip",
1626 s = C_(
"Path node tip",
"<b>Shift</b>: drag out a handle, click to toggle selection");
1628 s = C_(
"Path node tip",
"<b>Shift</b>: click to toggle selection");
1634 s = C_(
"Path node tip",
"<b>Ctrl+Alt</b>: move along handle lines or line segment, click to delete node");
1636 s = C_(
"Path node tip",
"<b>Ctrl</b>: move along axes, click to change node type");
1641 s = C_(
"Path node tip",
"<b>Alt</b>: sculpt nodes");
1651 s =
format_tip(C_(
"Path node tip",
"<b>%s</b>: "
1652 "drag to shape the path"
1654 "(more: Shift, Ctrl, Alt)"),
1657 s =
format_tip(C_(
"Path node tip",
"<b>BSpline node</b> (%.3g power): "
1658 "drag to shape the path"
1660 "(more: Shift, Ctrl, Alt)"),
1664 s =
format_tip(C_(
"Path node tip",
"<b>%s</b>: "
1665 "drag to shape the path"
1667 "click to toggle scale/rotation handles"
1669 "(more: Shift, Ctrl, Alt)"),
1672 }
else if (!isBSpline) {
1673 s =
format_tip(C_(
"Path node tip",
"<b>%s</b>: "
1674 "drag to shape the path"
1676 "click to select only this node"
1678 "(more: Shift, Ctrl, Alt)"),
1681 s =
format_tip(C_(
"Path node tip",
"<b>BSpline node</b> (%.3g power): "
1682 "drag to shape the path"
1684 "click to select only this node"
1686 "(more: Shift, Ctrl, Alt)"),
1702 Glib::ustring ret =
format_tip(C_(
"Path node tip",
"Move node by %s, %s"), x.c_str(), y.c_str());
1713 return _(
"Corner node");
1715 return _(
"Smooth node");
1717 return _(
"Symmetric node");
1719 return _(
"Auto-smooth node");
1727 if (!first || !second)
1729 if (first->
_next() == second)
1731 if (second->
_next() == first)
1770 *fracpart = std::modf(t, &intpart);
1771 int index = intpart;
1774 std::advance(ret,
index);
1833 new_begin = new_begin->
ln_next;
1836 new_begin = new_begin->
ln_prev;
1848 std::swap(ln->ln_next, ln->ln_prev);
1860 std::vector<ControlPointSelection *> to_clear;
1861 std::vector<std::pair<SelectableControlPoint *, long>> nodes;
1865 if (std::find(to_clear.begin(), to_clear.end(), &rm->
_selection) == to_clear.end()) {
1869 nodes.emplace_back(rm, in);
1871 for (
auto const &
node : nodes) {
1872 to_clear[
node.second]->erase(
node.first,
false);
1874 std::vector<std::vector<SelectableControlPoint *>> emission;
1875 for (
long i = 0, e = to_clear.size(); i != e; ++i) {
1876 emission.emplace_back();
1877 for (
auto const &
node : nodes) {
1878 if (
node.second != i)
1880 emission[i].push_back(
node.first);
1884 for (
size_t i = 0, e = emission.size(); i != e; ++i) {
1885 to_clear[i]->signal_selection_changed.emit(emission[i],
false);
1909 for (SubpathList::iterator i =
_list.begin(); i !=
_list.end(); ++i) {
1910 if (i->get() ==
this) {
1919 return n->nodeList();
auto make_canvasitem(Args &&... args)
Convienence function to create a CanvasItemPtr, like std::make_unique.
3x3 matrix representing an affine transformation.
void expandTo(CPoint const &p)
Enlarge the rectangle to contain the given point.
Infinite line on a plane.
Coord nearestTime(Point const &p) const
Find a point on the line closest to the query point.
Point pointAt(Coord t) const
Two-dimensional point that doubles as a vector.
Coord length() const
Compute the distance from origin.
Axis aligned, non-empty rectangle.
Rotation around the origin.
Data type representing a typeless value of a preference.
int getIntLimited(int def=0, int min=INT_MIN, int max=INT_MAX) const
Interpret the preference as a limited integer.
Base class for preference observers.
virtual void notify(Preferences::Entry const &new_val)=0
Notification about a preference change.
Preference storage class.
static Preferences * get()
Access the singleton Preferences object.
static Preferences * _instance
void removeObserver(Observer &)
Remove an observer an prevent further notifications to it.
void addObserver(Observer &)
Register a preference observer.
int getIntLimited(Glib::ustring const &pref_path, int def=0, int min=INT_MIN, int max=INT_MAX)
Retrieve a limited integer.
Class to store data for points which are snap candidates, either as a source or as a target.
void addOrigin(Geom::Point pt)
void addVector(Geom::Point v)
Class describing the result of an attempt to snap.
Geom::Point getPoint() const
std::pair< iterator, bool > insert(const value_type &x, bool notify=true, bool to_update=true)
Add a control point to the selection.
bool transformHandlesEnabled()
set_type const & allPoints() const
void erase(iterator pos, bool to_update=true)
Remove a point from the selection.
void spatialGrow(SelectableControlPoint *origin, int dir)
Draggable point, the workhorse of on-canvas editing.
static Geom::Point const & _last_click_event_point()
void transferGrab(ControlPoint *from, MotionEvent const &event)
Transfer the grab to another point.
void _setControlType(Inkscape::CanvasItemCtrlType type)
Geom::Point const & position() const
Current position of the control point.
static Glib::ustring format_tip(char const *format,...) G_GNUC_PRINTF(1
virtual void setVisible(bool v)
Set the visibility of the control point.
virtual void setPosition(Geom::Point const &pos)
Relocate the control point without side effects.
void _handleControlStyling()
State
Enumeration representing the possible states of the control point, used to determine its appearance.
@ STATE_CLICKED
First mouse button pressed over the control point.
@ STATE_MOUSEOVER
Mouse is hovering over the control point.
@ STATE_NORMAL
Normal state.
SPDesktop *const _desktop
The desktop this control point resides on.
static Glib::ustring virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event)
static Geom::Point const & _last_drag_origin()
void set_selected_appearance(bool selected)
CanvasItemPtr< Inkscape::CanvasItemCtrl > _canvas_item_ctrl
Visual representation of the control point.
Geom::Point relativePos() const
bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event) override
void _update_bspline_handles()
void setDirection(Geom::Point const &from, Geom::Point const &to)
void setRelativePos(Geom::Point const &p)
static double _saved_length
static Geom::Point _saved_dir
static Geom::Point _saved_other_pos
Control point of a cubic Bezier curve in a path.
bool isDegenerate() const
void setVisible(bool) override
Set the visibility of the control point.
void setLength(double len)
void setPosition(Geom::Point const &p) override
Relocate the control point without side effects.
static char const * handle_type_to_localized_string(NodeType type)
See also: Node::node_type_to_localized_string(NodeType type)
void move(Geom::Point const &p) override
Move the control point to new position with side effects.
CanvasItemPtr< CanvasItemCurve > _handle_line
NodeIterator< value_type > iterator
static NodeList & get(Node *n)
NodeList(SubpathList &_list)
An editable list of nodes representing a subpath.
iterator insert(iterator pos, Node *x)
insert a node before pos.
static iterator get_iterator(Node *n)
bool degenerate() const
A subpath is degenerate if it has no segments - either one node in an open path or no nodes in a clos...
void splice(iterator pos, NodeList &list)
iterator before(double t, double *fracpart=nullptr)
iterator erase(iterator pos)
Node * nodeAwayFrom(Handle *h)
Gets the node in the direction opposite to the given handle.
static NodeType parse_nodetype(char x)
Node * nodeToward(Handle *h)
Gets the node in the direction of the given handle.
Handle * handleAwayFrom(Node *to)
Gets the handle that goes in the direction opposite to the given adjacent node.
Glib::ustring _getTip(unsigned state) const override
void fixNeighbors() override
Affine transforms keep handle invariants for smooth and symmetric nodes, but smooth nodes at ends of ...
Glib::ustring _getDragTip(MotionEvent const &event) const override
void _linearGrow(int dir)
Select or deselect a node in this node's subpath based on its path distance from this node.
void move(Geom::Point const &p) override
Move the control point to new position with side effects.
Geom::Rect bounds() const override
bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event) override
Customized event handler to catch scroll events needed for selection grow/shrink.
bool clicked(ButtonReleaseEvent const &event) override
Called when the control point is clicked, at mouse button release.
void setType(NodeType type, bool update_handles=true)
Sets the node type and optionally restores the invariants associated with the given type.
static bool _is_line_segment(Node *first, Node *second)
Determine whether two nodes are joined by a linear segment.
bool isDegenerate() const
std::optional< Geom::Point > _unfixed_pos
bool grabbed(MotionEvent const &event) override
Called when the user moves the point beyond the drag tolerance with the first button held down.
void dragged(Geom::Point &new_pos, MotionEvent const &event) override
Called while dragging, but before moving the knot to new position.
Handle _front
Node handle in the backward direction of the path.
void sink()
Move the node to the bottom of its canvas group.
static char const * node_type_to_localized_string(NodeType type)
See also: Handle::handle_type_to_localized_string(NodeType type)
Handle _back
Node handle in the forward direction of the path.
void pickBestType()
Pick the best type for this node, based on the position of its handles.
NodeType _type
Type of node - cusp, smooth...
void _updateAutoHandles()
Inkscape::SnapTargetType _snapTargetType() const
void transform(Geom::Affine const &m) override
Apply an arbitrary affine transformation to a control point.
Handle * handleToward(Node *to)
Gets the handle that faces the given adjacent node.
void _setState(State state) override
Change the state of the knot.
Inkscape::SnapCandidatePoint snapCandidatePoint()
Inkscape::SnapSourceType _snapSourceType() const
void update(bool alert_LPE=false)
Update the display and the outline of the path.
void _commit(Glib::ustring const &annotation)
Update the XML representation and put the specified annotation on the undo stack.
double _bsplineHandlePosition(Handle *h, bool check_other=true)
Desktop-bound selectable control object.
bool grabbed(MotionEvent const &event) override
Called when the user moves the point beyond the drag tolerance with the first button held down.
void dragged(Geom::Point &new_pos, MotionEvent const &event) override
Called while dragging, but before moving the knot to new position.
bool clicked(ButtonReleaseEvent const &event) override
Called when the control point is clicked, at mouse button release.
ControlPointSelection & _selection
void _setState(State state) override
Change the state of the knot.
Glib::ustring string(Unit const *u) const
Return a printable string of the value in the specified unit.
virtual void setPosition(int pos)=0
Set the position of this node in parent's child order.
virtual unsigned position() const =0
Get the index of this node in parent's child order.
Geom::Affine const & d2w() const
Transformation from desktop to window coordinates.
SPNamedView * getNamedView() const
Geom::Affine const & w2d() const
Transformation from window to desktop coordinates (zoom/rotate).
Inkscape::Util::Unit const * display_units
Class to coordinate snapping operations.
void setup(SPDesktop const *desktop, bool snapindicator=true, SPObject const *item_to_ignore=nullptr, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Convenience shortcut when there is only one item to ignore.
void setupIgnoreSelection(SPDesktop const *desktop, bool snapindicator=true, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Setup, taking the list of items to ignore from the desktop's selection.
void freeSnapReturnByRef(Geom::Point &p, Inkscape::SnapSourceType const source_type, Geom::OptRect const &bbox_to_snap=Geom::OptRect()) const
Try to snap a point to grids, guides or objects.
SPNamedView const * getNamedView() const
Inkscape::SnappedPoint constrainedSnap(Inkscape::SnapCandidatePoint const &p, Inkscape::Snapper::SnapConstraint const &constraint, Geom::OptRect const &bbox_to_snap=Geom::OptRect()) const
Try to snap a point along a constraint line to grids, guides or objects.
bool someSnapperMightSnap(bool immediately=true) const
Return true if any snapping might occur, whether its to grids, guides or objects.
Control point selection - stores a set of control points and applies transformations to them.
Editable view implementation.
static char const *const parent
double Coord
Floating point type used to store coordinates.
Inkscape::XML::Node * node
static InkscapeApplication * _instance
Coord length(LineSegment const &seg)
int sgn(const T &x)
Sign function - indicates the sign of a numeric type.
Angle distance(Angle const &a, Angle const &b)
Coord bezier_length(std::vector< Point > const &points, Coord tolerance=0.01)
Compute the length of a bezier curve given by a vector of its control points.
Point constrain_angle(Point const &A, Point const &B, unsigned n=4, Point const &dir={1, 0})
double angle_between(Line const &l1, Line const &l2)
T dot(D2< T > const &a, D2< T > const &b)
Point unit_vector(Point const &a)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
D2< T > rot90(D2< T > const &a)
static double snap_increment_degrees()
static Geom::Point direction(Geom::Point const &first, Geom::Point const &second)
Computes an unit vector of the direction from first to second control point.
NodeType
Types of nodes supported in the node tool.
@ NODE_CUSP
Cusp node - no handle constraints.
@ NODE_PICK_BEST
Select type based on handle positions.
@ NODE_SYMMETRIC
Symmetric node - handles must be colinear and of equal length.
@ NODE_AUTO
Auto node - handles adjusted automatically based on neighboring nodes.
@ NODE_SMOOTH
Smooth node - handles must be colinear.
const double DEFAULT_START_POWER
Helper class to stream background task notifications as a series of messages.
bool mod_alt(unsigned modifiers)
void inspect_event(E &&event, Fs... funcs)
Perform pattern-matching on a CanvasEvent.
SnapSourceType
enumerations of snap source types and snap target types.
bool mod_ctrl(unsigned modifiers)
bool mod_shift_only(unsigned modifiers)
@ CANVAS_ITEM_CTRL_TYPE_NODE_AUTO
@ CANVAS_ITEM_CTRL_TYPE_NODE_CUSP
@ CANVAS_ITEM_CTRL_TYPE_NODE_SMOOTH
@ CANVAS_ITEM_CTRL_TYPE_NODE_SYMMETRICAL
@ CANVAS_ITEM_CTRL_TYPE_ROTATE
bool mod_shift(unsigned modifiers)
Path manipulator - a component that edits a single path on-canvas.
Generalized time value in the path.
size_type curve_index
Index of the curve in the path.
Abstract base class for events.
unsigned modifiers
The modifiers mask immediately before the event.
Movement of the mouse pointer.