diff options
| author | Andrius Ramanauskas <knutux@gmail.com> | 2006-04-19 05:14:26 +0000 |
|---|---|---|
| committer | knutux <knutux@users.sourceforge.net> | 2006-04-19 05:14:26 +0000 |
| commit | cd3043cf07c274cd641b8483b55177e9a5cb1e10 (patch) | |
| tree | f860995235a5dc981868ab4f3482e861322ffe01 /src/livarot/PathConversion.cpp | |
| parent | fix name and size (diff) | |
| download | inkscape-cd3043cf07c274cd641b8483b55177e9a5cb1e10.tar.gz inkscape-cd3043cf07c274cd641b8483b55177e9a5cb1e10.zip | |
Rendering optimisation, which gives best results for zoomed in drawings with complex (multi-node) paths. Optimisation focus - eliminating cubicTo and LineTo nodes outside of visible area, so no unneeded calculations is needed and less memory is consumed (this avoids crashes which were occurring previously if zooming into a complex drawing)
(bzr r541)
Diffstat (limited to 'src/livarot/PathConversion.cpp')
| -rw-r--r-- | src/livarot/PathConversion.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/src/livarot/PathConversion.cpp b/src/livarot/PathConversion.cpp index e6f7acb0c..d81785d20 100644 --- a/src/livarot/PathConversion.cpp +++ b/src/livarot/PathConversion.cpp @@ -400,6 +400,271 @@ void Path::Convert(double treshhold) } } +#define POINT_RELATION_TO_AREA(pt, area) ((pt)[0] < (area)->x0 ? 1 : ((pt)[0] > (area)->x1 ? 2 : ((pt)[1] < (area)->y0 ? 3 : ((pt)[1] > (area)->y1 ? 4 : 0)))) + +void Path::Convert(NRRectL *area, double treshhold) +{ + if ( descr_flags & descr_adding_bezier ) { + CancelBezier(); + } + + if ( descr_flags & descr_doing_subpath ) { + CloseSubpath(); + } + + SetBackData(false); + ResetPoints(); + if ( descr_cmd.empty() ) { + return; + } + + NR::Point curX; + int curP = 1; + int lastMoveTo = 0; + short last_point_relation = 0; + short curent_point_relation = 0; + bool start_elimination = false; + bool replace = false; + + // le moveto + { + int const firstTyp = descr_cmd[0]->getType(); + if ( firstTyp == descr_moveto ) { + curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p; + } else { + curP = 0; + curX[0] = curX[1] = 0; + } + + last_point_relation = POINT_RELATION_TO_AREA(curX, area); + lastMoveTo = AddPoint(curX, true); + } + descr_cmd[0]->associated = lastMoveTo; + + // et le reste, 1 par 1 + while ( curP < int(descr_cmd.size()) ) { + + int const nType = descr_cmd[curP]->getType(); + NR::Point nextX; + + switch (nType) { + case descr_forced: { + descr_cmd[curP]->associated = AddForcedPoint(curX); + last_point_relation = 0; + curP++; + break; + } + + case descr_moveto: { + PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]); + nextX = nData->p; + lastMoveTo = AddPoint(nextX, true); + descr_cmd[curP]->associated = lastMoveTo; + last_point_relation = 0; + + // et on avance + curP++; + break; + } + + case descr_close: { + nextX = pts[lastMoveTo].p; + descr_cmd[curP]->associated = AddPoint(nextX, false); + if ( descr_cmd[curP]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[curP]->associated = 0; + } else { + descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated; + } + } + last_point_relation = 0; + curP++; + break; + } + + case descr_lineto: { + PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]); + nextX = nData->p; + curent_point_relation = POINT_RELATION_TO_AREA(nextX, area); + replace = false; + if (curent_point_relation > 0 && curent_point_relation == last_point_relation) { + if (!start_elimination) { + start_elimination = true; + } else { + replace = true; + descr_cmd[curP]->associated = ReplacePoint(nextX); + } + } else { + start_elimination = false; + } + + if (!replace) { + descr_cmd[curP]->associated = AddPoint(nextX, false); + } + + if ( descr_cmd[curP]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[curP]->associated = 0; + } else { + descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated; + } + } + last_point_relation = curent_point_relation; + // et on avance + curP++; + break; + } + + case descr_cubicto: { + PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]); + nextX = nData->p; + + curent_point_relation = POINT_RELATION_TO_AREA(nextX, area); + replace = false; + if (curent_point_relation > 0 && curent_point_relation == last_point_relation && + curent_point_relation == POINT_RELATION_TO_AREA(curX + (nData->start), area) && + curent_point_relation == POINT_RELATION_TO_AREA(nextX + (nData->end), area)) + { + if (!start_elimination) { + start_elimination = true; + } else { + replace = true; + descr_cmd[curP]->associated = ReplacePoint(nextX); + } + } else { + start_elimination = false; + } + + if (!replace) { + RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8); + descr_cmd[curP]->associated = AddPoint(nextX,false); + } + + if ( descr_cmd[curP]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[curP]->associated = 0; + } else { + descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated; + } + } + last_point_relation = curent_point_relation; + // et on avance + curP++; + break; + } + + case descr_arcto: { + PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]); + nextX = nData->p; + DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold); + descr_cmd[curP]->associated = AddPoint(nextX, false); + if ( descr_cmd[curP]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[curP]->associated = 0; + } else { + descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated; + } + } + last_point_relation = 0; + // et on avance + curP++; + break; + } + + case descr_bezierto: { + PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]); + int nbInterm = nBData->nb; + nextX = nBData->p; + int curBD = curP; + + curP++; + int ip = curP; + PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]); + + if ( nbInterm == 1 ) { + NR::Point const midX = nData->p; + RecBezierTo(midX, curX, nextX, treshhold, 8); + } else if ( nbInterm > 1 ) { + NR::Point bx = curX; + NR::Point cx = curX; + NR::Point dx = curX; + + dx = nData->p; + ip++; + nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]); + + cx = 2 * bx - dx; + + for (int k = 0; k < nbInterm - 1; k++) { + bx = cx; + cx = dx; + + dx = nData->p; + ip++; + nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]); + + NR::Point stx = (bx + cx) / 2; + if ( k > 0 ) { + descr_cmd[ip - 2]->associated = AddPoint(stx, false); + if ( descr_cmd[ip - 2]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[ip - 2]->associated = 0; + } else { + descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated; + } + } + } + + { + NR::Point const mx = (cx + dx) / 2; + RecBezierTo(cx, stx, mx, treshhold, 8); + } + } + + { + bx = cx; + cx = dx; + + dx = nextX; + dx = 2 * dx - cx; + + NR::Point stx = (bx + cx) / 2; + + descr_cmd[ip - 1]->associated = AddPoint(stx, false); + if ( descr_cmd[ip - 1]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[ip - 1]->associated = 0; + } else { + descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated; + } + } + + { + NR::Point mx = (cx + dx) / 2; + RecBezierTo(cx, stx, mx, treshhold, 8); + } + } + } + + descr_cmd[curBD]->associated = AddPoint(nextX, false); + if ( descr_cmd[curBD]->associated < 0 ) { + if ( curP == 0 ) { + descr_cmd[curBD]->associated = 0; + } else { + descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated; + } + } + + last_point_relation = 0; + // et on avance + curP += nbInterm; + break; + } + } + + curX = nextX; + } +} void Path::ConvertEvenLines(double treshhold) |
