node.cpp revision 1209feccaf55ecb15851234806a37631407e6376
188N/A * Krzysztof KosiĆski <tweenk.pl@gmail.com> 188N/A * Jon A. Cruz <jon@joncruz.org> 188N/A * Copyright (C) 2009 Authors 188N/A * Released under GNU GPL, read the file 'COPYING' for more information {
0xbfbfbf00,
0x000000ff},
// normal fill, stroke {
0xff000000,
0x000000ff},
// mouseover fill, stroke {
0xff000000,
0x000000ff},
// clicked fill, stroke {
0x0000ffff,
0x000000ff},
// normal fill, stroke when selected {
0xff000000,
0x000000ff},
// mouseover fill, stroke when selected {
0xff000000,
0x000000ff}
// clicked fill, stroke when selected {
0xffffffff,
0x000000ff},
// normal fill, stroke {
0xff000000,
0x000000ff},
// mouseover fill, stroke {
0xff000000,
0x000000ff},
// clicked fill, stroke {
0xffffffff,
0x000000ff},
// normal fill, stroke {
0xff000000,
0x000000ff},
// mouseover fill, stroke {
0xff000000,
0x000000ff}
// clicked fill, stroke default:
out <<
'b';
break;
/** Computes an unit vector of the direction from first to second control point */ //sp_canvas_item_hide(_handle_line); // The handle becomes degenerate. // Adjust node type as necessary. // If both handles become degenerate, convert to parent cusp node // Only 1 handle becomes degenerate // do nothing for other node types // If the segment between the handle and the node // in its direction becomes linear and there are smooth nodes // at its ends, make their handles colinear with the segment //spanish: mueve el tirador y su opuesto la misma proporciĂłn // restrict movement to the line joining the nodes // project the relative position on the direction line //spanish: mueve el tirador y su opuesto la misma proporciĂłn // fall through - auto nodes degrade into smooth nodes /* for smooth nodes, we need to rotate the other handle so that it's colinear * with the dragged one while conserving length. */ // for symmetric nodes, place the other handle on the opposite side //spanish: mueve el tirador y su opuesto la misma proporciĂłn // update degeneration info and visibility case NODE_CUSP:
return _(
"Cusp node handle");
case NODE_AUTO:
return _(
"Auto-smooth node handle");
// when Shift+S is pressed when hovering over a handle belonging to a cusp node, // hold this handle in place; otherwise process normally // this handle is guaranteed not to be degenerate //spanish: nuevo evento de doble click para resetear a la proporciĂłn por defecto, 0.3334%, los tiradores de un nodo //spanish: funciĂłn que mueve el tirador y su opuesto a la proporciĂłn por defecto de 0.3334 // with Alt, preserve length // and the original position. // note: if snapping to the original position is only desired in the original // direction of the handle, change to Ray instead of Line //spanish: mueve el tirador y su opuesto en X posiciones fijas depenfiendo de la configuraciĂłn de el //parametro "steps whith control" del efecto en vivo BSpline //spanish: si estĂĄ activado el ajuste (snap) y no es bspline // NOTE: this is subtly wrong. // We should get all possible constraints and snap along them using // multipleConstrainedSnaps, instead of first snapping to angle and then to objects // with Shift, if the node is cusp, rotate the other handle as well //spanish: si es bspline pero no estĂĄ presionado SHIFT o CONTROL //lo fija en la posiciĂłn original move(
new_pos);
// needed for correct update, even though it's redundant // hide the handle if it's less than dragtolerance away from the node // however, never do this for cancelled drag / broken grab // TODO is this actually a good idea? //spanish: marca la fuerza del bspline como 0.0000 // HACK: If the handle was dragged out, call parent's ungrabbed handler, // so that transform handles reappear //spanish: un truco par, si el nodo tiene fuerza, nos marca que es //del tipo bspline, lo utilizaremos despues para mostras los mensajes apropiados //no lo podemos hacer de otra forma al ser constante la funcion more =
C_(
"Path handle tip",
"more: Shift, Ctrl, Alt");
more =
C_(
"Path handle tip",
"more: Ctrl");
more =
C_(
"Path handle tip",
"more: Ctrl, Alt");
"<b>Shift+Ctrl+Alt</b>: preserve length and snap rotation angle to %g° " "increments while rotating both handles"),
"<b>Ctrl+Alt</b>: preserve length and snap rotation angle to %g° increments"),
return C_(
"Path handle tip",
"<b>Shift+Alt</b>: preserve handle length and rotate both handles");
return C_(
"Path handle tip",
"<b>Alt</b>: preserve handle length while dragging");
"<b>Shift+Ctrl</b>: snap rotation angle to %g° increments and rotate both handles"),
"<b>Ctrl</b>: Move handle by his actual steps in BSpline Live Effect"));
"<b>Ctrl</b>: snap rotation angle to %g° increments, click to retract"),
return C_(
"Path hande tip",
"<b>Shift</b>: rotate both handles by the same angle");
return C_(
"Path hande tip",
"<b>Shift</b>: move handle");
"<b>Auto node handle</b>: drag to convert to smooth node (%s)"),
more);
"<b>Auto node handle</b>: drag to convert to smooth node (%s)"),
more);
"<b>BSpline node handle</b>: Shift to drag, double click to reset (%s)"),
more);
// report angle in mathematical convention angle +=
M_PI;
// angle is (-M_PI...M_PI] - offset by +pi and scale to 0...360 // NOTE we do not set type here, because the handles are still degenerate // NOTE: not using iterators won't make this much quicker because iterators can be 100% inlined. // move handles when the node moves. //spanish: guardamos la fuerza anterior del nodo para reaplicarsela //de nuevo una vez sea movido el nodo // if the node has a smooth handle after a line segment, it should be kept colinear //spanish: movemos los tiradores involucrados, primero los del nodo en cuestiĂłn //y despues los de los nodos colindantes //spanish: guardamos la fuerza anterior del nodo para reaplicarsela //de nuevo una vez sea movido el nodo /* Affine transforms keep handle invariants for smooth and symmetric nodes, * but smooth nodes at ends of linear segments and auto nodes need special treatment */ //spanish: movemos los tiradores involucrados, primero los del nodo en cuestiĂłn //y despues los de los nodos colindantes /* This method restores handle invariants for neighboring nodes, * and invariants that are based on positions of those nodes for this one. */ /* Fix smooth handles at the ends of linear segments. * Rotate the appropriate handle to be colinear with the segment. * If there is a smooth node at the other end of the segment, rotate it too. */ // also update the handle on the other end of the segment // 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.) // Auto nodes automaticaly adjust their handles to give an appearance of smoothness, // no matter what their surroundings are. // "dir" is an unit vector perpendicular to the bisector of the angle created // by the previous node, this auto node and the next node. // Handle lengths are equal to 1/3 of the distance from the adjacent node. // If any of the adjacent nodes coincides, retract both handles. //spanish: definimos la fuerza de los nodos,segĂșn sea o no trazado bspline. //Cada vez que actuemos sobre dichos tiradores en un trazado //bspline esta fuerza se tiene que actualizar updateState();
// The size of the control might have changed // if update_handles is true, adjust handle positions to match the node type // handle degenerate handles appropriately // auto handles make no sense for endnodes // ignore attempts to make smooth endnodes. // rotate handles to be colinear // for degenerate nodes set positions like auto handles // For a node that is already smooth and has a degenerate handle, // drag out the second handle without changing the direction of the first one. // if the front handle is degenerate and this...next is a line segment, // make back colinear; otherwise pull out the other handle // to 1/3 of distance to prev // both handles are extended. make colinear while keeping length // first make back colinear with the vector front ---> back, // then make front colinear with back ---> node // (not back ---> front because back's position was changed in the first call) if (
isEndNode())
return;
// symmetric handles make no sense for endnodes // similar to auto handles but set the same length for both // Both handles are extended. Compute average length, use direction from // back handle to front handle. This also works correctly for degenerates //spanish: en los cambios de tipo de nodo, sobre trazados bspline, //o bien los mantenemos con potencia 0.0000 en modo esquina //o les damos la potencia por defecto en modo de curva // if both handles are degenerate, do nothing // if neither are degenerate, check their respective positions // for now do not automatically make nodes symmetric, it can be annoying /*if (Geom::are_near(front_delta, -back_delta)) { // check whether the handle aligns with the previous line segment. // we know that if front is degenerate, back isn't, because // Interestingly, we do not need any help from PathManipulator when doing linear grow. // First handle the trivial case of growing over an unselected node. // Linear grow is simple. We find the first unselected nodes in each direction // and compare the linear distances to them. // find first unselected nodes on both sides // there is no unselected node in this cyclic subpath // do the same for the second direction. Do not check for equality with // this node, because there is at least one unselected node in the subpath, // so we are guaranteed to stop. // Linear shrink is more complicated. We need to find the farthest selected node. // This means we have to check the entire subpath. We go in the direction in which // the distance we traveled is lower. We do this until we run out of nodes (ends of path) // or the two iterators meet. On the way, we store the last selected node and its distance // in each direction (if any). At the end, we choose the one that is farther and deselect it. // both iterators that store last selected nodes are initially empty // Check whether we walked the entire cyclic subpath. // This is initially true because both iterators start from this node, // so this check cannot go in the while condition. // When this happens, we need to check the last node, pointed to by the iterators. // change node size to match type and selection state //spanish: esto muestra los tiradores al seleccionar los nodos // Dragging out handles with Shift + drag on a node. // This should work even if dragtolerance is zero and evp coincides with node position. // determine which handle to drag out based on degeneration and the direction of drag // For a note on how snapping is implemented in Inkscape, see snap.h. // even if we won't really snap, we might still call the one of the // constrainedSnap() methods to enforce the constraints, so we need // to setup the snapmanager anyway; this is also required for someSnapperMightSnap() // do not snap when Shift is pressed * TODO We are doing this every time a snap happens. It should once be done only once * per drag - maybe in the grabbed handler? * TODO Unselected nodes vector must be valid during the snap run, because it is not * TODO Snapping to unselected segments of selected paths doesn't work yet. */ // Build the list of unselected nodes. // Snap candidate point for free snapping; this will consider snapping tangentially // and perpendicularly and therefore the origin or direction vector must be set // We're about to consider a constrained snap, which is already limited to 1D // Therefore tangential or perpendicular snapping will not be considered, and therefore // all calls above to scp_free.addVector() and scp_free.addOrigin() can be neglected // with Ctrl+Alt, constrain to handle lines // project the new position onto a handle line that is closer; // also snap to perpendiculars of handle lines // perpendiculars only snap when they are further than snap increment away // from the second handle constraint // with Ctrl, constrain to axes g_error(
"Node::handleToward(): second node is not adjacent!");
g_error(
"Node::nodeToward(): handle is not a child of this node!");
g_error(
"Node::handleAwayFrom(): second node is not adjacent!");
g_error(
"Node::nodeAwayFrom(): handle is not a child of this node!");
/*if (state_held_control(state)) { return format_tip(C_("Path node tip", "<b>Shift+Ctrl:</b> drag out a handle and snap its angle " "to %f° increments"), snap_increment_degrees()); return C_(
"Path node tip",
"<b>Shift</b>: drag out a handle, click to toggle selection");
return C_(
"Path node tip",
"<b>Shift</b>: click to toggle selection");
return C_(
"Path node tip",
"<b>Ctrl+Alt</b>: move along handle lines, click to delete node");
return C_(
"Path node tip",
"<b>Ctrl</b>: move along axes, click to change node type");
return C_(
"Path node tip",
"<b>Alt</b>: sculpt nodes");
// No modifiers: assemble tip from node type "<b>%s</b>: drag to shape the path (more: Shift, Ctrl, Alt)"),
nodetype);
"<b>%s</b>: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"),
nodetype);
"<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"),
nodetype);
case NODE_AUTO:
return _(
"Auto-smooth node");
// 1. make the list perfectly cyclic // 3. relink begin to list // some gymnastics are required to ensure that the node is valid when deleted; // otherwise the code that updates handle visibility will break // TODO this method is very ugly! // converting SubpathList to an intrusive list might allow us to get rid of it c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :