Path.cpp revision 4e33f020dd832c0fa662afd97a40d6eba7f1fade
/*
* Path.cpp
* nlivarot
*
* Created by fred on Tue Jun 17 2003.
*
*/
#include <glib.h>
#include "Path.h"
#include "livarot/path-description.h"
#include <libnr/nr-matrix-ops.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 (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
delete *i;
}
}
// debug function do dump the path contents on stdout
void Path::Affiche()
{
std::cout << "path: " << descr_cmd.size() << " commands." << std::endl;
for (std::vector<PathDescr*>::const_iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
(*i)->dump(std::cout);
std::cout << std::endl;
}
std::cout << std::endl;
}
void Path::Reset()
{
for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
delete *i;
}
descr_cmd.clear();
pending_bezier_cmd = -1;
pending_moveto_cmd = -1;
descr_flags = 0;
}
void Path::Copy(Path * who)
{
ResetPoints();
for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
delete *i;
}
descr_cmd.clear();
for (std::vector<PathDescr*>::const_iterator i = who->descr_cmd.begin();
i != who->descr_cmd.end();
i++)
{
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(NR::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(NR::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(NR::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(NR::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(NR::Point const &iPt, NR::Point const &iStD, NR::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(NR::Point const &iPt, NR::Point const &iStD, NR::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(NR::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(NR::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(NR::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(NR::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<PathDescrBezierTo *>(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(NR::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<PathDescrBezierTo *>(descr_cmd[pending_bezier_cmd]);
nBData->nb++;
return descr_cmd.size() - 1;
}
void Path::InsertIntermBezierTo(NR::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(NR::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(NR::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 de la polyligne
*/
void
Path::SetBackData (bool nVal)
{
if (back == false) {
if (nVal == true && back == false) {
back = true;
ResetPoints();
} else if (nVal == false && back == true) {
back = false;
ResetPoints();
}
} else {
if (nVal == true && back == false) {
back = true;
ResetPoints();
} else if (nVal == false && back == true) {
back = false;
ResetPoints();
}
}
}
void Path::ResetPoints()
{
pts.clear();
}
int Path::AddPoint(NR::Point const &iPt, bool mvto)
{
if (back) {
return AddPoint (iPt, -1, 0.0, mvto);
}
if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
return -1;
}
int const n = pts.size();
pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt));
return n;
}
int Path::ReplacePoint(NR::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(NR::Point const &iPt, int ip, double it, bool mvto)
{
if (back == false) {
return AddPoint (iPt, mvto);
}
if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
return -1;
}
int const n = pts.size();
pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt, ip, it));
return n;
}
int Path::AddForcedPoint(NR::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.push_back(path_lineto(polyline_forced, pts[n - 1].p));
return n;
}
int Path::AddForcedPoint(NR::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.push_back(path_lineto(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<path_lineto>::const_iterator i = pts.begin();
l = r = i->p[NR::X];
t = b = i->p[NR::Y];
i++;
for (; i != pts.end(); i++) {
r = std::max(r, i->p[NR::X]);
l = std::min(l, i->p[NR::X]);
b = std::max(b, i->p[NR::Y]);
t = std::min(t, i->p[NR::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, NR::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 = NR::Point(0,0);
return;
}
PathDescr const *theD = descr_cmd[piece];
int const typ = theD->getType();
NR::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<PathDescrLineTo const *>(theD);
TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
} else if (typ == descr_arcto) {
PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
TangentOnArcAt(at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
} else if (typ == descr_cubicto) {
PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(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<PathDescrBezierTo *>(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;
NR::Point const bStPt = PrevPoint(bez_st - 1);
if (stB->nb == 1 || k <= 0) {
PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(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<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(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<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
NR::Point stP = 0.5 * ( prevI->p + nextI->p );
TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad);
} else {
PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k + 1]);
NR::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, NR::Point &pos, NR::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 = NR::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<PathDescrMoveTo *>(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<PathDescrLineTo const *>(theD);
TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
} else if (typ == descr_arcto) {
PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
TangentOnArcAt (at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
} else if (typ == descr_cubicto) {
PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(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<PathDescrBezierTo*>(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;
NR::Point const bStPt(PrevPoint( bez_st - 1 ));
if (stB->nb == 1 || k <= 0) {
PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo *>(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<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(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<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
NR::Point stP = 0.5 * ( prevI->p + nextI->p );
TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad);
} else {
PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k + 1]);
NR::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);
}
}
}
}
void Path::Transform(const NR::Matrix &trans)
{
for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
(*i)->transform(trans);
}
}
void Path::FastBBox(double &l,double &t,double &r,double &b)
{
l = t = r = b = 0;
bool empty = true;
NR::Point lastP(0, 0);
for (int i = 0; i < int(descr_cmd.size()); i++) {
int const typ = descr_cmd[i]->getType();
switch ( typ ) {
case descr_lineto:
{
PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
if ( empty ) {
l = r = nData->p[NR::X];
t = b = nData->p[NR::Y];
empty = false;
} else {
if ( nData->p[NR::X] < l ) {
l = nData->p[NR::X];
}
if ( nData->p[NR::X] > r ) {
r = nData->p[NR::X];
}
if ( nData->p[NR::Y] < t ) {
t = nData->p[NR::Y];
}
if ( nData->p[NR::Y] > b ) {
b = nData->p[NR::Y];
}
}
lastP = nData->p;
}
break;
case descr_moveto:
{
PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
if ( empty ) {
l = r = nData->p[NR::X];
t = b = nData->p[NR::Y];
empty = false;
} else {
if ( nData->p[NR::X] < l ) {
l = nData->p[NR::X];
}
if ( nData->p[NR::X] > r ) {
r = nData->p[NR::X];
}
if ( nData->p[NR::Y] < t ) {
t = nData->p[NR::Y];
}
if ( nData->p[NR::Y] > b ) {
b = nData->p[NR::Y];
}
}
lastP = nData->p;
}
break;
case descr_arcto:
{
PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
if ( empty ) {
l = r = nData->p[NR::X];
t = b = nData->p[NR::Y];
empty = false;
} else {
if ( nData->p[NR::X] < l ) {
l = nData->p[NR::X];
}
if ( nData->p[NR::X] > r ) {
r = nData->p[NR::X];
}
if ( nData->p[NR::Y] < t ) {
t = nData->p[NR::Y];
}
if ( nData->p[NR::Y] > b ) {
b = nData->p[NR::Y];
}
}
lastP = nData->p;
}
break;
case descr_cubicto:
{
PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
if ( empty ) {
l = r = nData->p[NR::X];
t = b = nData->p[NR::Y];
empty = false;
} else {
if ( nData->p[NR::X] < l ) {
l = nData->p[NR::X];
}
if ( nData->p[NR::X] > r ) {
r = nData->p[NR::X];
}
if ( nData->p[NR::Y] < t ) {
t = nData->p[NR::Y];
}
if ( nData->p[NR::Y] > b ) {
b = nData->p[NR::Y];
}
}
NR::Point np = nData->p - nData->end;
if ( np[NR::X] < l ) {
l = np[NR::X];
}
if ( np[NR::X] > r ) {
r = np[NR::X];
}
if ( np[NR::Y] < t ) {
t = np[NR::Y];
}
if ( np[NR::Y] > b ) {
b = np[NR::Y];
}
np = lastP + nData->start;
if ( np[NR::X] < l ) {
l = np[NR::X];
}
if ( np[NR::X] > r ) {
r = np[NR::X];
}
if ( np[NR::Y] < t ) {
t = np[NR::Y];
}
if ( np[NR::Y] > b ) {
b = np[NR::Y];
}
lastP = nData->p;
}
break;
case descr_bezierto:
{
PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
if ( empty ) {
l = r = nData->p[NR::X];
t = b = nData->p[NR::Y];
empty = false;
} else {
if ( nData->p[NR::X] < l ) {
l = nData->p[NR::X];
}
if ( nData->p[NR::X] > r ) {
r = nData->p[NR::X];
}
if ( nData->p[NR::Y] < t ) {
t = nData->p[NR::Y];
}
if ( nData->p[NR::Y] > b ) {
b = nData->p[NR::Y];
}
}
lastP = nData->p;
}
break;
case descr_interm_bezier:
{
PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
if ( empty ) {
l = r = nData->p[NR::X];
t = b = nData->p[NR::Y];
empty = false;
} else {
if ( nData->p[NR::X] < l ) {
l = nData->p[NR::X];
}
if ( nData->p[NR::X] > r ) {
r = nData->p[NR::X];
}
if ( nData->p[NR::Y] < t ) {
t = nData->p[NR::Y];
}
if ( nData->p[NR::Y] > b ) {
b = nData->p[NR::Y];
}
}
}
break;
}
}
}
char *Path::svg_dump_path() const
{
Inkscape::SVGOStringStream os;
for (int i = 0; i < int(descr_cmd.size()); i++) {
NR::Point const p = (i == 0) ? NR::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 :