René Nyffenegger
René Nyffenegger

Reputation: 40553

How does inkscape calculate the coordinates for control points for "smooth edges"?

I am wondering what algorithm (or formula) Inkscape uses to calculate the control points if the nodes on a path are made "smooth".

That is, if I have a path with five nodes whose d attribute is

M 115.85065,503.57451
  49.653441,399.52543 
  604.56143,683.48319 
  339.41126,615.97628 
  264.65997,729.11336

And I change the nodes to smooth, the d attribute is changed to

M 115.85065,503.57451 
C                     115.85065,503.57451 24.747417,422.50451
  49.653441,399.52543 192.62243,267.61777 640.56491,558.55577
  604.56143,683.48319 580.13686,768.23328 421.64047,584.07809
  339.41126,615.97628 297.27039,632.32348 264.65997,729.11336
  264.65997,729.11336

Obviously, Inkscape calculates the control point coordinates (second last and last coordinate pair on lines on or after C). I am interested in the algorithm Inkscape uses for it.

Upvotes: 3

Views: 1714

Answers (2)

René Nyffenegger
René Nyffenegger

Reputation: 40553

I have found the corresponding piece of code in Inkscape's source tree under src/ui/tool/node.cpp, method Node::_updateAutoHandles:

void Node::_updateAutoHandles()
{

    // Recompute the position of automatic handles.
    // For endnodes, retract both handles. (It's only possible to create an end auto node
    // through the XML editor.)
    if (isEndNode()) {
        _front.retract();
        _back.retract();
        return;
    }

    // Auto nodes automaticaly adjust their handles to give an appearance of smoothness,
    // no matter what their surroundings are.
    Geom::Point vec_next = _next()->position() - position();
    Geom::Point vec_prev = _prev()->position() - position();
    double len_next = vec_next.length(), len_prev = vec_prev.length();
    if (len_next > 0 && len_prev > 0) {
        // "dir" is an unit vector perpendicular to the bisector of the angle created
        // by the previous node, this auto node and the next node.
        Geom::Point dir = Geom::unit_vector((len_prev / len_next) * vec_next - vec_prev);
        // Handle lengths are equal to 1/3 of the distance from the adjacent node.
        _back.setRelativePos(-dir * (len_prev / 3));
        _front.setRelativePos(dir * (len_next / 3));
    } else {
        // If any of the adjacent nodes coincides, retract both handles.
        _front.retract();
        _back.retract();
    }
}

Upvotes: 5

Joehannes
Joehannes

Reputation: 301

I'm not 100% sure of the quality of this information. But at least at some point in time for calculating some curves inkscape seems to have used >>spiro<<.

http://www.levien.com/spiro/

Take a quick look at the page, he's providing a link to his PhD-thesis: http://www.levien.com/phd/thesis.pdf in which he's introducing the theory/algorithms ...

Cheers

EDIT:

I'm currently investigating a bit into the matter for a similar purpose, so I stumbled across ... http://www.w3.org/TR/SVG11/paths.html#PathDataCurveCommands ... the specification of curves for SVG. So curves, like not circles or arcs, are cubic or quadratic beziers then ... Have a look at wikipedia for bezier formulas as well: http://en.wikipedia.org/wiki/B-spline#Uniform_quadratic_B-spline

Upvotes: 1

Related Questions