int Path::EndBezierTo() { if (descr_flags & descr_delayed_bezier) { CancelBezier (); } else { pending_bezier_cmd = -1; descr_flags &= ~(descr_adding_bezier); descr_flags &= ~(descr_delayed_bezier); } return -1; }
int Path::TempBezierTo() { if (descr_flags & descr_adding_bezier) { CancelBezier(); } if ( (descr_flags & descr_doing_subpath) == 0) { // No starting point -> bad. return -1; } pending_bezier_cmd = descr_cmd.size(); descr_cmd.push_back(new PathDescrBezierTo(Geom::Point(0, 0), 0)); descr_flags |= descr_adding_bezier; descr_flags |= descr_delayed_bezier; return descr_cmd.size() - 1; }
int Path::Close() { if ( descr_flags & descr_adding_bezier ) { CancelBezier(); } if ( descr_flags & descr_doing_subpath ) { CloseSubpath(); } else { // Nothing to close. return -1; } descr_cmd.push_back(new PathDescrClose); descr_flags &= ~(descr_doing_subpath); pending_moveto_cmd = -1; return descr_cmd.size() - 1; }
// Variation on the fitting theme: try to merge path commands into cubic bezier patches. // The goal is to reduce the number of path commands, especially when operations on path produce // lots of small path elements; ideally you could get rid of very small segments at reduced visual cost. void Path::Coalesce(double tresh) { if ( descr_flags & descr_adding_bezier ) { CancelBezier(); } if ( descr_flags & descr_doing_subpath ) { CloseSubpath(); } if (descr_cmd.size() <= 2) { return; } SetBackData(false); Path* tempDest = new Path(); tempDest->SetBackData(false); ConvertEvenLines(0.25*tresh); int lastP = 0; int lastAP = -1; // As the elements are stored in a separate array, it's no longer worth optimizing // the rewriting in the same array. // [[comme les elements sont stockes dans un tableau a part, plus la peine d'optimiser // la réécriture dans la meme tableau]] int lastA = descr_cmd[0]->associated; int prevA = lastA; Geom::Point firstP; /* FIXME: the use of this variable probably causes a leak or two. ** It's a hack anyway, and probably only needs to be a type rather than ** a full PathDescr. */ PathDescr *lastAddition = new PathDescrMoveTo(Geom::Point(0, 0)); bool containsForced = false; PathDescrCubicTo pending_cubic(Geom::Point(0, 0), Geom::Point(0, 0), Geom::Point(0, 0)); for (int curP = 0; curP < int(descr_cmd.size()); curP++) { int typ = descr_cmd[curP]->getType(); int nextA = lastA; if (typ == descr_moveto) { if (lastAddition->flags != descr_moveto) { FlushPendingAddition(tempDest,lastAddition,pending_cubic,lastAP); } lastAddition = descr_cmd[curP]; lastAP = curP; FlushPendingAddition(tempDest, lastAddition, pending_cubic, lastAP); // Added automatically (too bad about multiple moveto's). // [fr: (tant pis pour les moveto multiples)] containsForced = false; PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]); firstP = nData->p; lastA = descr_cmd[curP]->associated; prevA = lastA; lastP = curP; } else if (typ == descr_close) { nextA = descr_cmd[curP]->associated; if (lastAddition->flags != descr_moveto) { PathDescrCubicTo res(Geom::Point(0, 0), Geom::Point(0, 0), Geom::Point(0, 0)); int worstP = -1; if (AttemptSimplify(lastA, nextA - lastA + 1, (containsForced) ? 0.05 * tresh : tresh, res, worstP)) { lastAddition = new PathDescrCubicTo(Geom::Point(0, 0), Geom::Point(0, 0), Geom::Point(0, 0)); pending_cubic = res; lastAP = -1; } FlushPendingAddition(tempDest, lastAddition, pending_cubic, lastAP); FlushPendingAddition(tempDest, descr_cmd[curP], pending_cubic, curP); } else { FlushPendingAddition(tempDest,descr_cmd[curP],pending_cubic,curP); } containsForced = false; lastAddition = new PathDescrMoveTo(Geom::Point(0, 0)); prevA = lastA = nextA; lastP = curP; lastAP = curP; } else if (typ == descr_forced) { nextA = descr_cmd[curP]->associated; if (lastAddition->flags != descr_moveto) { PathDescrCubicTo res(Geom::Point(0, 0), Geom::Point(0, 0), Geom::Point(0, 0)); int worstP = -1; if (AttemptSimplify(lastA, nextA - lastA + 1, 0.05 * tresh, res, worstP)) { // plus sensible parce que point force // ca passe /* (Possible translation: More sensitive because contains a forced point.) */ containsForced = true; } else { // Force the addition. FlushPendingAddition(tempDest, lastAddition, pending_cubic, lastAP); lastAddition = new PathDescrMoveTo(Geom::Point(0, 0)); prevA = lastA = nextA; lastP = curP; lastAP = curP; containsForced = false; } } } else if (typ == descr_lineto || typ == descr_cubicto || typ == descr_arcto) { nextA = descr_cmd[curP]->associated; if (lastAddition->flags != descr_moveto) { PathDescrCubicTo res(Geom::Point(0, 0), Geom::Point(0, 0), Geom::Point(0, 0)); int worstP = -1; if (AttemptSimplify(lastA, nextA - lastA + 1, tresh, res, worstP)) { lastAddition = new PathDescrCubicTo(Geom::Point(0, 0), Geom::Point(0, 0), Geom::Point(0, 0)); pending_cubic = res; lastAddition->associated = lastA; lastP = curP; lastAP = -1; } else { lastA = descr_cmd[lastP]->associated; // pourrait etre surecrit par la ligne suivante /* (possible translation: Could be overwritten by the next line.) */ FlushPendingAddition(tempDest, lastAddition, pending_cubic, lastAP); lastAddition = descr_cmd[curP]; if ( typ == descr_cubicto ) { pending_cubic = *(dynamic_cast<PathDescrCubicTo*>(descr_cmd[curP])); } lastAP = curP; containsForced = false; } } else { lastA = prevA /*descr_cmd[curP-1]->associated */ ; lastAddition = descr_cmd[curP]; if ( typ == descr_cubicto ) { pending_cubic = *(dynamic_cast<PathDescrCubicTo*>(descr_cmd[curP])); } lastAP = curP; containsForced = false; } prevA = nextA; } else if (typ == descr_bezierto) { if (lastAddition->flags != descr_moveto) { FlushPendingAddition(tempDest, lastAddition, pending_cubic, lastAP); lastAddition = new PathDescrMoveTo(Geom::Point(0, 0)); } lastAP = -1; lastA = descr_cmd[curP]->associated; lastP = curP; PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo*>(descr_cmd[curP]); for (int i = 1; i <= nBData->nb; i++) { FlushPendingAddition(tempDest, descr_cmd[curP + i], pending_cubic, curP + i); } curP += nBData->nb; prevA = nextA; } else if (typ == descr_interm_bezier) { continue; } else { continue; } } if (lastAddition->flags != descr_moveto) { FlushPendingAddition(tempDest, lastAddition, pending_cubic, lastAP); } Copy(tempDest); delete tempDest; }