805
// \todo The three functions setSegmentType, setArcSegmentLarge, setArcSegmentSweep could be
806
// refactored to share the code that iterates over all selected segments.
808
/** Make selected segments curves / lines / arcs. */
804
/** Make selected segments curves / lines. */
809
805
void PathManipulator::setSegmentType(SegmentType type)
811
807
if (_num_selected == 0) return;
815
811
if (!(k && j->selected() && k->selected())) continue;
817
813
case SEGMENT_STRAIGHT:
818
if ((j->front()->isDegenerate() && k->back()->isDegenerate())
819
&& (j->arc_rx()->isDegenerate() && j->arc_ry()->isDegenerate()))
814
if (j->front()->isDegenerate() && k->back()->isDegenerate())
821
816
j->front()->move(*j);
822
817
k->back()->move(*k);
823
j->retractArcHandles();
825
819
case SEGMENT_CUBIC_BEZIER:
826
if (!j->front()->isDegenerate() || !k->back()->isDegenerate()){
827
// Already a cubic bezier
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);
820
if (!j->front()->isDegenerate() || !k->back()->isDegenerate())
838
822
// move both handles to 1/3 of the line
839
823
j->front()->move(j->position() + (k->position() - j->position()) / 3);
840
824
k->back()->move(k->position() + (j->position() - k->position()) / 3);
841
j->arc_rx()->move(*j);
842
j->arc_ry()->move(*j);
843
j->retractArcHandles();
845
case SEGMENT_ELIPTICAL_ARC:
846
if (!(j->front()->isDegenerate() && k->back()->isDegenerate())){
847
j->front()->move(*j);
851
if (j->arc_rx()->isDegenerate() && j->arc_ry()->isDegenerate()){
852
Geom::Point midPointOffset = ((k->position() - j->position()) / 2);
853
Geom::Point handleOrigin = j->position()+midPointOffset;
855
j->arc_rx()->setOffset(midPointOffset);
856
j->arc_ry()->setOffset(midPointOffset);
857
j->arc_rx()->move(j->position() + ((k->position() - handleOrigin) / 2));
858
j->updateArcHandleConstriants(j->arc_rx());
866
/** Set the large flag on selected arcs */
867
void PathManipulator::setArcSegmentLarge(bool large){
868
if (_num_selected == 0) return;
869
for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
870
for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
871
NodeList::iterator k = j.next();
872
if (!(k && j->selected() && k->selected())) continue;
873
// This code executes for every selected segment
874
if (!j->arc_rx()->isDegenerate() || !j->arc_ry()->isDegenerate()){
875
// This code executes for every selected ARC segment
876
*(j->arc_large()) = large;
882
/** Set the sweep flag on selected arcs */
883
void PathManipulator::toggleArcSegmentSweep(){
884
if (_num_selected == 0) return;
885
for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
886
for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
887
NodeList::iterator k = j.next();
888
if (!(k && j->selected() && k->selected())) continue;
889
// This code executes for every selected segment
890
if (!j->arc_rx()->isDegenerate() || !j->arc_ry()->isDegenerate()){
891
// This code executes for every selected ARC segment
892
*(j->arc_sweep()) = !*j->arc_sweep();
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'
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)
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");
1178
// Retract all handles relating to this segment
1179
segment->retractArcHandles();
1180
segment->front()->retract();
1182
// get the insertion point
1183
NodeList::iterator insert_at = segment;
1186
// Keep the previous node handy to update its handles when needed
1187
Node *prevNode = &(*insert_at);
1189
// Path is to be inserted in reverse order
1190
Geom::Path reversedPath = newPath.reversed();
1192
// Iterate over the path
1193
for (Geom::Path::iterator i = reversedPath.begin(); i != reversedPath.end(); ++i){
1194
const Geom::Curve & thisCurve = *i;
1196
// Try converting to a bezier
1197
const Geom::BezierCurve * bezier = dynamic_cast<const Geom::BezierCurve*>(&thisCurve);
1199
// Check order of bezier (currently only cubic beziers are supported)
1200
if (bezier->order() == 3)
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);
1211
list.insert(insert_at, newNode);
1212
// Move along to next node
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.");
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.");
1233
1097
/** Called by the XML observer when something else than us modifies the path. */
1234
1098
void PathManipulator::_externalChange(unsigned type)
1286
1150
// sanitize pathvector and store it in SPCurve,
1287
1151
// so that _updateDragPoint doesn't crash on paths with naked movetos
1288
Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers_and_arcs(_spcurve->get_pathvector());
1152
Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(_spcurve->get_pathvector());
1290
1153
for (Geom::PathVector::iterator i = pathv.begin(); i != pathv.end(); ) {
1291
1154
// NOTE: this utilizes the fact that Geom::PathVector is an std::vector.
1292
1155
// When we erase an element, the next one slides into position,
1336
1199
previous_node->front()->setPosition((*bezier)[1]);
1337
1200
current_node ->back() ->setPosition((*bezier)[2]);
1339
Geom::EllipticalArc const *arc = dynamic_cast<Geom::EllipticalArc const*>(&*cit);
1342
Geom::Coord angleX = arc->rotationAngle();
1343
Geom::Coord angleY = angleX + Geom::rad_from_deg(90);
1344
previous_node->moveArcHandles(current_node->position() - previous_node->position(), arc->ray(Geom::X), arc->ray(Geom::Y), angleX, angleY);
1345
*(previous_node->arc_large()) = arc->largeArc();
1346
*(previous_node->arc_sweep()) = arc->sweep();
1348
1202
previous_node = current_node;
1350
1204
// If the path is closed, make the list cyclic
1543
1397
* @relates PathManipulator */
1544
1398
void build_segment(Geom::PathBuilder &builder, Node *prev_node, Node *cur_node)
1546
if (prev_node->arc_rx()->isDegenerate() || prev_node->arc_ry()->isDegenerate() ){
1547
// This is not an eliptical arc, check if it is a straight line or bezier
1548
if (cur_node->back()->isDegenerate() && prev_node->front()->isDegenerate())
1550
// NOTE: It seems like the renderer cannot correctly handle vline / hline segments,
1551
// and trying to display a path using them results in funny artifacts.
1552
builder.lineTo(cur_node->position());
1554
// this is a bezier segment
1556
prev_node->front()->position(),
1557
cur_node->back()->position(),
1558
cur_node->position());
1562
// This is an eliptical arc, get the x and y set by the xy handle
1563
Geom::Coord rx = prev_node->arc_rx()->length();
1564
Geom::Coord ry = prev_node->arc_ry()->length();
1565
Geom::Angle rot = prev_node->arc_rx()->angle();
1571
*prev_node->arc_large(),
1572
*prev_node->arc_sweep(),
1400
if (cur_node->back()->isDegenerate() && prev_node->front()->isDegenerate())
1402
// NOTE: It seems like the renderer cannot correctly handle vline / hline segments,
1403
// and trying to display a path using them results in funny artifacts.
1404
builder.lineTo(cur_node->position());
1406
// this is a bezier segment
1408
prev_node->front()->position(),
1409
cur_node->back()->position(),
1573
1410
cur_node->position());