~danieljabailey/inkscape/arc_node_editor

« back to all changes in this revision

Viewing changes to src/ui/tool/path-manipulator.cpp

  • Committer: Daniel Bailey
  • Date: 2016-07-08 22:45:22 UTC
  • Revision ID: d@nielbailey.com-20160708224522-pkb9q4w17iy842ze
Handle conversion from arcs to beziers in node editor

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include <2geom/bezier-curve.h>
22
22
#include <2geom/bezier-utils.h>
23
23
#include <2geom/path-sink.h>
 
24
#include <2geom/pathvector.h>
24
25
#include <glibmm/i18n.h>
25
26
#include "ui/tool/path-manipulator.h"
26
27
#include "desktop.h"
822
823
                j->retractArcHandles();
823
824
                break;
824
825
            case SEGMENT_CUBIC_BEZIER:
825
 
                if (!j->front()->isDegenerate() || !k->back()->isDegenerate())
826
 
                    break;
 
826
                if (!j->front()->isDegenerate() || !k->back()->isDegenerate()){
 
827
                    // Already a cubic bezier
 
828
                    break;
 
829
                }
 
830
                if (!j->arc_rx()->isDegenerate() || !j->arc_ry()->isDegenerate()){
 
831
                    // This is an elliptical arc that is being converted to a cubic bezier
 
832
                    // Generate the bezier path and use it to replace the current segment
 
833
                    Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(j->getEllipticalArc().toSBasis(), 0.1);
 
834
                    replaceSegmentWithPath(j, cubicbezier_path);
 
835
                    break;
 
836
                }
 
837
                
827
838
                // move both handles to 1/3 of the line
828
839
                j->front()->move(j->position() + (k->position() - j->position()) / 3);
829
840
                k->back()->move(k->position() + (j->position() - k->position()) / 3);
1150
1161
    return match;
1151
1162
}
1152
1163
 
 
1164
/** Replace a segment with a path.
 
1165
 * @param segment The segment to replace
 
1166
 * @param newPath The path to insert in place of 'segment'
 
1167
 *
 
1168
 * Currently, newPath must be composed only of cubic beziers, the caller must
 
1169
 * ensure that the path only contains cubic beziers (until other segments are
 
1170
 * implemented in this function)  */
 
1171
void PathManipulator::replaceSegmentWithPath(NodeList::iterator segment, Geom::Path newPath)
 
1172
{
 
1173
    if (!segment) throw std::invalid_argument("Invalid iterator for replacement");
 
1174
    NodeList &list = NodeList::get(segment);
 
1175
    NodeList::iterator second = segment.next();
 
1176
    if (!second) throw std::invalid_argument("Replace after last node in open path");
 
1177
 
 
1178
    // Retract all handles relating to this segment
 
1179
    segment->retractArcHandles();
 
1180
    segment->front()->retract();
 
1181
    
 
1182
    // get the insertion point
 
1183
    NodeList::iterator insert_at = segment;
 
1184
    ++insert_at;
 
1185
 
 
1186
    // Keep the previous node handy to update its handles when needed
 
1187
    Node *prevNode = &(*insert_at);
 
1188
 
 
1189
    // Path is to be inserted in reverse order
 
1190
    Geom::Path reversedPath = newPath.reversed();
 
1191
 
 
1192
    // Iterate over the path
 
1193
    for (Geom::Path::iterator i = reversedPath.begin(); i != reversedPath.end(); ++i){
 
1194
        const Geom::Curve & thisCurve = *i;
 
1195
 
 
1196
        // Try converting to a bezier
 
1197
        const Geom::BezierCurve * bezier = dynamic_cast<const Geom::BezierCurve*>(&thisCurve);
 
1198
        if (bezier) {
 
1199
            // Check order of bezier (currently only cubic beziers are supported)
 
1200
            if (bezier->order() == 3)
 
1201
            {
 
1202
                // Create one new node
 
1203
                Node *newNode = new Node(_multi_path_manipulator._path_data.node_data, bezier->finalPoint());
 
1204
                // Set the control points for this node and the previous node
 
1205
                newNode->front() ->setPosition((*bezier)[2]);
 
1206
                prevNode->back()->setPosition((*bezier)[1]);
 
1207
                // All new nodes are smooth
 
1208
                newNode->setType(NODE_SMOOTH, false);
 
1209
 
 
1210
                // Insert new node
 
1211
                list.insert(insert_at, newNode);
 
1212
                // Move along to next node
 
1213
                prevNode = newNode;
 
1214
                insert_at--;
 
1215
            }
 
1216
            else{
 
1217
                // TODO, Is there a better exception to raise here?
 
1218
                // TODO, implement this if needed in future
 
1219
                throw std::invalid_argument("Only cubic bezier curves are implemented in PathManipulator::replaceSegment."
 
1220
                    " newPath contains beziers with order!=3.");
 
1221
            }
 
1222
        }
 
1223
        else{
 
1224
            // Not a bezier
 
1225
            // TODO, Is there a better exception to raise here?
 
1226
            // TODO, implement this if needed in future
 
1227
            throw std::invalid_argument("Only cubic bezier curves are implemented in PathManipulator::replaceSegment."
 
1228
                " newPath contains non-bezier segments.");
 
1229
        }
 
1230
    }
 
1231
}
 
1232
 
1153
1233
/** Called by the XML observer when something else than us modifies the path. */
1154
1234
void PathManipulator::_externalChange(unsigned type)
1155
1235
{