From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/livarot/Path.cpp | 945 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 945 insertions(+) create mode 100644 src/livarot/Path.cpp (limited to 'src/livarot/Path.cpp') diff --git a/src/livarot/Path.cpp b/src/livarot/Path.cpp new file mode 100644 index 0000000..352bc0a --- /dev/null +++ b/src/livarot/Path.cpp @@ -0,0 +1,945 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: + * see git history + * Fred + * + * Copyright (C) 2018 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include +#include "Path.h" + +#include <2geom/pathvector.h> + +#include "livarot/path-description.h" + +/* + * manipulation of the path data: path description and polyline + * grunt work... + * at the end of this file, 2 utilitary functions to get the point and tangent to path associated with a (command no;abcissis) + */ + + +Path::Path() +{ + descr_flags = 0; + pending_bezier_cmd = -1; + pending_moveto_cmd = -1; + + back = false; +} + +Path::~Path() +{ + for (auto & i : descr_cmd) { + delete i; + } +} + +// debug function do dump the path contents on stdout +void Path::Affiche() +{ + std::cout << "path: " << descr_cmd.size() << " commands." << std::endl; + for (auto i : descr_cmd) { + i->dump(std::cout); + std::cout << std::endl; + } + + std::cout << std::endl; +} + +void Path::Reset() +{ + for (auto & i : descr_cmd) { + delete i; + } + + descr_cmd.clear(); + pending_bezier_cmd = -1; + pending_moveto_cmd = -1; + descr_flags = 0; +} + +void Path::Copy(Path * who) +{ + ResetPoints(); + + for (auto & i : descr_cmd) { + delete i; + } + + descr_cmd.clear(); + + for (auto i : who->descr_cmd) + { + descr_cmd.push_back(i->clone()); + } +} + +void Path::CloseSubpath() +{ + descr_flags &= ~(descr_doing_subpath); + pending_moveto_cmd = -1; +} + +int Path::ForcePoint() +{ + if (descr_flags & descr_adding_bezier) { + EndBezierTo (); + } + + if ( (descr_flags & descr_doing_subpath) == 0 ) { + return -1; + } + + if (descr_cmd.empty()) { + return -1; + } + + descr_cmd.push_back(new PathDescrForced); + return descr_cmd.size() - 1; +} + + +void Path::InsertForcePoint(int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + ForcePoint(); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrForced); +} + +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; +} + +int Path::MoveTo(Geom::Point const &iPt) +{ + if ( descr_flags & descr_adding_bezier ) { + EndBezierTo(iPt); + } + if ( descr_flags & descr_doing_subpath ) { + CloseSubpath(); + } + pending_moveto_cmd = descr_cmd.size(); + + descr_cmd.push_back(new PathDescrMoveTo(iPt)); + + descr_flags |= descr_doing_subpath; + return descr_cmd.size() - 1; +} + +void Path::InsertMoveTo(Geom::Point const &iPt, int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + MoveTo(iPt); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrMoveTo(iPt)); +} + +int Path::LineTo(Geom::Point const &iPt) +{ + if (descr_flags & descr_adding_bezier) { + EndBezierTo (iPt); + } + if (!( descr_flags & descr_doing_subpath )) { + return MoveTo (iPt); + } + + descr_cmd.push_back(new PathDescrLineTo(iPt)); + return descr_cmd.size() - 1; +} + +void Path::InsertLineTo(Geom::Point const &iPt, int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + LineTo(iPt); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrLineTo(iPt)); +} + +int Path::CubicTo(Geom::Point const &iPt, Geom::Point const &iStD, Geom::Point const &iEnD) +{ + if (descr_flags & descr_adding_bezier) { + EndBezierTo(iPt); + } + if ( (descr_flags & descr_doing_subpath) == 0) { + return MoveTo (iPt); + } + + descr_cmd.push_back(new PathDescrCubicTo(iPt, iStD, iEnD)); + return descr_cmd.size() - 1; +} + + +void Path::InsertCubicTo(Geom::Point const &iPt, Geom::Point const &iStD, Geom::Point const &iEnD, int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + CubicTo(iPt,iStD,iEnD); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrCubicTo(iPt, iStD, iEnD)); +} + +int Path::ArcTo(Geom::Point const &iPt, double iRx, double iRy, double angle, + bool iLargeArc, bool iClockwise) +{ + if (descr_flags & descr_adding_bezier) { + EndBezierTo(iPt); + } + if ( (descr_flags & descr_doing_subpath) == 0 ) { + return MoveTo(iPt); + } + + descr_cmd.push_back(new PathDescrArcTo(iPt, iRx, iRy, angle, iLargeArc, iClockwise)); + return descr_cmd.size() - 1; +} + + +void Path::InsertArcTo(Geom::Point const &iPt, double iRx, double iRy, double angle, + bool iLargeArc, bool iClockwise, int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + ArcTo(iPt, iRx, iRy, angle, iLargeArc, iClockwise); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrArcTo(iPt, iRx, iRy, + angle, iLargeArc, iClockwise)); +} + +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; +} + +void Path::CancelBezier() +{ + descr_flags &= ~(descr_adding_bezier); + descr_flags &= ~(descr_delayed_bezier); + if (pending_bezier_cmd < 0) { + return; + } + + /* FIXME: I think there's a memory leak here */ + descr_cmd.resize(pending_bezier_cmd); + pending_bezier_cmd = -1; +} + +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::EndBezierTo(Geom::Point const &iPt) +{ + if ( (descr_flags & descr_adding_bezier) == 0 ) { + return LineTo(iPt); + } + if ( (descr_flags & descr_doing_subpath) == 0 ) { + return MoveTo(iPt); + } + if ( (descr_flags & descr_delayed_bezier) == 0 ) { + return EndBezierTo(); + } + PathDescrBezierTo *nData = dynamic_cast(descr_cmd[pending_bezier_cmd]); + nData->p = iPt; + pending_bezier_cmd = -1; + descr_flags &= ~(descr_adding_bezier); + descr_flags &= ~(descr_delayed_bezier); + return -1; +} + + +int Path::IntermBezierTo(Geom::Point const &iPt) +{ + if ( (descr_flags & descr_adding_bezier) == 0 ) { + return LineTo (iPt); + } + + if ( (descr_flags & descr_doing_subpath) == 0) { + return MoveTo (iPt); + } + + descr_cmd.push_back(new PathDescrIntermBezierTo(iPt)); + + PathDescrBezierTo *nBData = dynamic_cast(descr_cmd[pending_bezier_cmd]); + nBData->nb++; + return descr_cmd.size() - 1; +} + + +void Path::InsertIntermBezierTo(Geom::Point const &iPt, int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + IntermBezierTo(iPt); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrIntermBezierTo(iPt)); +} + + +int Path::BezierTo(Geom::Point const &iPt) +{ + if ( descr_flags & descr_adding_bezier ) { + EndBezierTo(iPt); + } + + if ( (descr_flags & descr_doing_subpath) == 0 ) { + return MoveTo (iPt); + } + + pending_bezier_cmd = descr_cmd.size(); + + descr_cmd.push_back(new PathDescrBezierTo(iPt, 0)); + descr_flags |= descr_adding_bezier; + descr_flags &= ~(descr_delayed_bezier); + return descr_cmd.size() - 1; +} + + +void Path::InsertBezierTo(Geom::Point const &iPt, int iNb, int at) +{ + if ( at < 0 || at > int(descr_cmd.size()) ) { + return; + } + + if ( at == int(descr_cmd.size()) ) { + BezierTo(iPt); + return; + } + + descr_cmd.insert(descr_cmd.begin() + at, new PathDescrBezierTo(iPt, iNb)); +} + + +/* + * points of the polyline + */ +void +Path::SetBackData (bool nVal) +{ + if (! back) { + if (nVal) { + back = true; + ResetPoints(); + } + } else { + if (! nVal) { + back = false; + ResetPoints(); + } + } +} + + +void Path::ResetPoints() +{ + pts.clear(); +} + + +int Path::AddPoint(Geom::Point const &iPt, bool mvto) +{ + if (back) { + return AddPoint (iPt, -1, 0.0, mvto); + } + + if ( !mvto && !pts.empty() && pts.back().p == iPt ) { + return -1; + } + + int const n = pts.size(); + pts.emplace_back(mvto ? polyline_moveto : polyline_lineto, iPt); + return n; +} + + +int Path::ReplacePoint(Geom::Point const &iPt) +{ + if (pts.empty()) { + return -1; + } + + int const n = pts.size() - 1; + pts[n] = path_lineto(polyline_lineto, iPt); + return n; +} + + +int Path::AddPoint(Geom::Point const &iPt, int ip, double it, bool mvto) +{ + if (! back) { + return AddPoint (iPt, mvto); + } + + if ( !mvto && !pts.empty() && pts.back().p == iPt ) { + return -1; + } + + int const n = pts.size(); + pts.emplace_back(mvto ? polyline_moveto : polyline_lineto, iPt, ip, it); + return n; +} + +int Path::AddForcedPoint(Geom::Point const &iPt) +{ + if (back) { + return AddForcedPoint (iPt, -1, 0.0); + } + + if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) { + return -1; + } + + int const n = pts.size(); + pts.emplace_back(polyline_forced, pts[n - 1].p); + return n; +} + + +int Path::AddForcedPoint(Geom::Point const &iPt, int /*ip*/, double /*it*/) +{ + /* FIXME: ip & it aren't used. Is this deliberate? */ + if (!back) { + return AddForcedPoint (iPt); + } + + if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) { + return -1; + } + + int const n = pts.size(); + pts.emplace_back(polyline_forced, pts[n - 1].p, pts[n - 1].piece, pts[n - 1].t); + return n; +} + +void Path::PolylineBoundingBox(double &l, double &t, double &r, double &b) +{ + l = t = r = b = 0.0; + if ( pts.empty() ) { + return; + } + + std::vector::const_iterator i = pts.begin(); + l = r = i->p[Geom::X]; + t = b = i->p[Geom::Y]; + ++i; + + for (; i != pts.end(); ++i) { + r = std::max(r, i->p[Geom::X]); + l = std::min(l, i->p[Geom::X]); + b = std::max(b, i->p[Geom::Y]); + t = std::min(t, i->p[Geom::Y]); + } +} + + +/** + * \param piece Index of a one of our commands. + * \param at Distance along the segment that corresponds to `piece' (0 <= at <= 1) + * \param pos Filled in with the point at `at' on `piece'. + */ + +void Path::PointAt(int piece, double at, Geom::Point &pos) +{ + if (piece < 0 || piece >= int(descr_cmd.size())) { + // this shouldn't happen: the piece we are asked for doesn't + // exist in the path + pos = Geom::Point(0,0); + return; + } + + PathDescr const *theD = descr_cmd[piece]; + int const typ = theD->getType(); + Geom::Point tgt; + double len; + double rad; + + if (typ == descr_moveto) { + + return PointAt (piece + 1, 0.0, pos); + + } else if (typ == descr_close || typ == descr_forced) { + + return PointAt (piece - 1, 1.0, pos); + + } else if (typ == descr_lineto) { + + PathDescrLineTo const *nData = dynamic_cast(theD); + TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len); + + } else if (typ == descr_arcto) { + + PathDescrArcTo const *nData = dynamic_cast(theD); + TangentOnArcAt(at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad); + + } else if (typ == descr_cubicto) { + + PathDescrCubicTo const *nData = dynamic_cast(theD); + TangentOnCubAt(at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad); + + } else if (typ == descr_bezierto || typ == descr_interm_bezier) { + + int bez_st = piece; + while (bez_st >= 0) { + int nt = descr_cmd[bez_st]->getType(); + if (nt == descr_bezierto) + break; + bez_st--; + } + if ( bez_st < 0 ) { + // Didn't find the beginning of the spline (bad). + // [pas trouvé le dubut de la spline (mauvais)] + return PointAt(piece - 1, 1.0, pos); + } + + PathDescrBezierTo *stB = dynamic_cast(descr_cmd[bez_st]); + if ( piece > bez_st + stB->nb ) { + // The spline goes past the authorized number of commands (bad). + // [la spline sort du nombre de commandes autorisé (mauvais)] + return PointAt(piece - 1, 1.0, pos); + } + + int k = piece - bez_st; + Geom::Point const bStPt = PrevPoint(bez_st - 1); + if (stB->nb == 1 || k <= 0) { + PathDescrIntermBezierTo *nData = dynamic_cast(descr_cmd[bez_st + 1]); + TangentOnBezAt(at, bStPt, *nData, *stB, false, pos, tgt, len, rad); + } else { + // forcement plus grand que 1 + if (k == 1) { + PathDescrIntermBezierTo *nextI = dynamic_cast(descr_cmd[bez_st + 1]); + PathDescrIntermBezierTo *nnextI = dynamic_cast(descr_cmd[bez_st + 2]); + PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1); + TangentOnBezAt(at, bStPt, *nextI, fin, false, pos, tgt, len, rad); + } else if (k == stB->nb) { + PathDescrIntermBezierTo *nextI = dynamic_cast(descr_cmd[bez_st + k]); + PathDescrIntermBezierTo *prevI = dynamic_cast(descr_cmd[bez_st + k - 1]); + Geom::Point stP = 0.5 * ( prevI->p + nextI->p ); + TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad); + } else { + PathDescrIntermBezierTo *nextI = dynamic_cast(descr_cmd[bez_st + k]); + PathDescrIntermBezierTo *prevI = dynamic_cast(descr_cmd[bez_st + k - 1]); + PathDescrIntermBezierTo *nnextI = dynamic_cast(descr_cmd[bez_st + k + 1]); + Geom::Point stP = 0.5 * ( prevI->p + nextI->p ); + PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1); + TangentOnBezAt(at, stP, *nextI, fin, false, pos, tgt, len, rad); + } + } + } +} + + +void Path::PointAndTangentAt(int piece, double at, Geom::Point &pos, Geom::Point &tgt) +{ + if (piece < 0 || piece >= int(descr_cmd.size())) { + // this shouldn't happen: the piece we are asked for doesn't exist in the path + pos = Geom::Point(0, 0); + return; + } + + PathDescr const *theD = descr_cmd[piece]; + int typ = theD->getType(); + double len; + double rad; + if (typ == descr_moveto) { + + return PointAndTangentAt(piece + 1, 0.0, pos, tgt); + + } else if (typ == descr_close ) { + + int cp = piece - 1; + while ( cp >= 0 && (descr_cmd[cp]->getType()) != descr_moveto ) { + cp--; + } + if ( cp >= 0 ) { + PathDescrMoveTo *nData = dynamic_cast(descr_cmd[cp]); + PathDescrLineTo dst(nData->p); + TangentOnSegAt(at, PrevPoint (piece - 1), dst, pos, tgt, len); + } + + } else if ( typ == descr_forced) { + + return PointAndTangentAt(piece - 1, 1.0, pos,tgt); + + } else if (typ == descr_lineto) { + + PathDescrLineTo const *nData = dynamic_cast(theD); + TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len); + + } else if (typ == descr_arcto) { + + PathDescrArcTo const *nData = dynamic_cast(theD); + TangentOnArcAt (at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad); + + } else if (typ == descr_cubicto) { + + PathDescrCubicTo const *nData = dynamic_cast(theD); + TangentOnCubAt (at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad); + + } else if (typ == descr_bezierto || typ == descr_interm_bezier) { + int bez_st = piece; + while (bez_st >= 0) { + int nt = descr_cmd[bez_st]->getType(); + if (nt == descr_bezierto) break; + bez_st--; + } + if ( bez_st < 0 ) { + return PointAndTangentAt(piece - 1, 1.0, pos, tgt); + // Didn't find the beginning of the spline (bad). + // [pas trouvé le dubut de la spline (mauvais)] + } + + PathDescrBezierTo* stB = dynamic_cast(descr_cmd[bez_st]); + if ( piece > bez_st + stB->nb ) { + return PointAndTangentAt(piece - 1, 1.0, pos, tgt); + // The spline goes past the number of authorized commands (bad). + // [la spline sort du nombre de commandes autorisé (mauvais)] + } + + int k = piece - bez_st; + Geom::Point const bStPt(PrevPoint( bez_st - 1 )); + if (stB->nb == 1 || k <= 0) { + PathDescrIntermBezierTo* nData = dynamic_cast(descr_cmd[bez_st + 1]); + TangentOnBezAt (at, bStPt, *nData, *stB, false, pos, tgt, len, rad); + } else { + // forcement plus grand que 1 + if (k == 1) { + PathDescrIntermBezierTo *nextI = dynamic_cast(descr_cmd[bez_st + 1]); + PathDescrIntermBezierTo *nnextI = dynamic_cast(descr_cmd[bez_st + 2]); + PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1); + TangentOnBezAt(at, bStPt, *nextI, fin, false, pos, tgt, len, rad); + } else if (k == stB->nb) { + PathDescrIntermBezierTo *prevI = dynamic_cast(descr_cmd[bez_st + k - 1]); + PathDescrIntermBezierTo *nextI = dynamic_cast(descr_cmd[bez_st + k]); + Geom::Point stP = 0.5 * ( prevI->p + nextI->p ); + TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad); + } else { + PathDescrIntermBezierTo *prevI = dynamic_cast(descr_cmd[bez_st + k - 1]); + PathDescrIntermBezierTo *nextI = dynamic_cast(descr_cmd[bez_st + k]); + PathDescrIntermBezierTo *nnextI = dynamic_cast(descr_cmd[bez_st + k + 1]); + Geom::Point stP = 0.5 * ( prevI->p + nextI->p ); + PathDescrBezierTo fin(0.5 * (nnextI->p + nnextI->p), 1); + TangentOnBezAt(at, stP, *nextI, fin, false, pos, tgt, len, rad); + } + } + } +} + +/** + * Apply a transform in-place. + * + * Note: Converts to Geom::PathVector, applies the transform, and converts back. + */ +void Path::Transform(const Geom::Affine &trans) +{ + LoadPathVector(MakePathVector() * trans); +} + +void Path::FastBBox(double &l,double &t,double &r,double &b) +{ + l = t = r = b = 0; + bool empty = true; + Geom::Point lastP(0, 0); + + for (auto & i : descr_cmd) { + int const typ = i->getType(); + switch ( typ ) { + case descr_lineto: + { + PathDescrLineTo *nData = dynamic_cast(i); + if ( empty ) { + l = r = nData->p[Geom::X]; + t = b = nData->p[Geom::Y]; + empty = false; + } else { + if ( nData->p[Geom::X] < l ) { + l = nData->p[Geom::X]; + } + if ( nData->p[Geom::X] > r ) { + r = nData->p[Geom::X]; + } + if ( nData->p[Geom::Y] < t ) { + t = nData->p[Geom::Y]; + } + if ( nData->p[Geom::Y] > b ) { + b = nData->p[Geom::Y]; + } + } + lastP = nData->p; + } + break; + + case descr_moveto: + { + PathDescrMoveTo *nData = dynamic_cast(i); + if ( empty ) { + l = r = nData->p[Geom::X]; + t = b = nData->p[Geom::Y]; + empty = false; + } else { + if ( nData->p[Geom::X] < l ) { + l = nData->p[Geom::X]; + } + if ( nData->p[Geom::X] > r ) { + r = nData->p[Geom::X]; + } + if ( nData->p[Geom::Y] < t ) { + t = nData->p[Geom::Y]; + } + if ( nData->p[Geom::Y] > b ) { + b = nData->p[Geom::Y]; + } + } + lastP = nData->p; + } + break; + + case descr_arcto: + { + PathDescrArcTo *nData = dynamic_cast(i); + if ( empty ) { + l = r = nData->p[Geom::X]; + t = b = nData->p[Geom::Y]; + empty = false; + } else { + if ( nData->p[Geom::X] < l ) { + l = nData->p[Geom::X]; + } + if ( nData->p[Geom::X] > r ) { + r = nData->p[Geom::X]; + } + if ( nData->p[Geom::Y] < t ) { + t = nData->p[Geom::Y]; + } + if ( nData->p[Geom::Y] > b ) { + b = nData->p[Geom::Y]; + } + } + lastP = nData->p; + } + break; + + case descr_cubicto: + { + PathDescrCubicTo *nData = dynamic_cast(i); + if ( empty ) { + l = r = nData->p[Geom::X]; + t = b = nData->p[Geom::Y]; + empty = false; + } else { + if ( nData->p[Geom::X] < l ) { + l = nData->p[Geom::X]; + } + if ( nData->p[Geom::X] > r ) { + r = nData->p[Geom::X]; + } + if ( nData->p[Geom::Y] < t ) { + t = nData->p[Geom::Y]; + } + if ( nData->p[Geom::Y] > b ) { + b = nData->p[Geom::Y]; + } + } + +/* bug 249665: "...the calculation of the bounding-box for cubic-paths +has some extra steps to make it work correctly in Win32 that unfortunately +are unnecessary in Linux, generating wrong results. This only shows in +Type1 fonts because they use cubic-paths instead of the +bezier-paths used by True-Type fonts." +*/ + +#ifdef _WIN32 + Geom::Point np = nData->p - nData->end; + if ( np[Geom::X] < l ) { + l = np[Geom::X]; + } + if ( np[Geom::X] > r ) { + r = np[Geom::X]; + } + if ( np[Geom::Y] < t ) { + t = np[Geom::Y]; + } + if ( np[Geom::Y] > b ) { + b = np[Geom::Y]; + } + + np = lastP + nData->start; + if ( np[Geom::X] < l ) { + l = np[Geom::X]; + } + if ( np[Geom::X] > r ) { + r = np[Geom::X]; + } + if ( np[Geom::Y] < t ) { + t = np[Geom::Y]; + } + if ( np[Geom::Y] > b ) { + b = np[Geom::Y]; + } +#endif + + lastP = nData->p; + } + break; + + case descr_bezierto: + { + PathDescrBezierTo *nData = dynamic_cast(i); + if ( empty ) { + l = r = nData->p[Geom::X]; + t = b = nData->p[Geom::Y]; + empty = false; + } else { + if ( nData->p[Geom::X] < l ) { + l = nData->p[Geom::X]; + } + if ( nData->p[Geom::X] > r ) { + r = nData->p[Geom::X]; + } + if ( nData->p[Geom::Y] < t ) { + t = nData->p[Geom::Y]; + } + if ( nData->p[Geom::Y] > b ) { + b = nData->p[Geom::Y]; + } + } + lastP = nData->p; + } + break; + + case descr_interm_bezier: + { + PathDescrIntermBezierTo *nData = dynamic_cast(i); + if ( empty ) { + l = r = nData->p[Geom::X]; + t = b = nData->p[Geom::Y]; + empty = false; + } else { + if ( nData->p[Geom::X] < l ) { + l = nData->p[Geom::X]; + } + if ( nData->p[Geom::X] > r ) { + r = nData->p[Geom::X]; + } + if ( nData->p[Geom::Y] < t ) { + t = nData->p[Geom::Y]; + } + if ( nData->p[Geom::Y] > b ) { + b = nData->p[Geom::Y]; + } + } + } + break; + } + } +} + +char *Path::svg_dump_path() const +{ + Inkscape::SVGOStringStream os; + + for (int i = 0; i < int(descr_cmd.size()); i++) { + Geom::Point const p = (i == 0) ? Geom::Point(0, 0) : PrevPoint(i - 1); + descr_cmd[i]->dumpSVG(os, p); + } + + return g_strdup (os.str().c_str()); +} + +// Find out if the segment that corresponds to 'piece' is a straight line +bool Path::IsLineSegment(int piece) +{ + if (piece < 0 || piece >= int(descr_cmd.size())) { + return false; + } + + PathDescr const *theD = descr_cmd[piece]; + int const typ = theD->getType(); + + return (typ == descr_lineto); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : -- cgit v1.2.3