/*
* Path.h
* nlivarot
*
* Created by fred on Tue Jun 17 2003.
*
*/
#ifndef my_path
#define my_path
#include <vector>
#include "LivarotDefs.h"
struct PathDescr;
struct PathDescrLineTo;
struct PathDescrArcTo;
struct PathDescrCubicTo;
struct PathDescrBezierTo;
struct PathDescrIntermBezierTo;
/*
* the Path class: a structure to hold path description and their polyline approximation (not kept in sync)
* the path description is built with regular commands like MoveTo() LineTo(), etc
* the polyline approximation is built by a call to Convert() or its variants
* another possibility would be to call directly the AddPoint() functions, but that is not encouraged
* the conversion to polyline can salvage data as to where on the path each polyline's point lies; use
* ConvertWithBackData() for this. after this call, it's easy to rewind the polyline: sequences of points
* of the same path command can be reassembled in a command
*/
// polyline description commands
enum
{
polyline_forced = 2 // a forced point, ie a point that was an angle or an intersection in a previous life
// or more realistically a control point in the path description that created the polyline
// forced points are used as "breakable" points for the polyline -> cubic bezier patch operations
// each time the bezier fitter encounters such a point in the polyline, it decreases its treshhold,
// so that it is more likely to cut the polyline at that position and produce a bezier patch
};
// path creation: 2 phases: first the path is given as a succession of commands (MoveTo, LineTo, CurveTo...); then it
// is converted in a polyline
// a polylone can be stroked or filled to make a polygon
{
// flags for the path construction
enum
{
descr_ready = 0,
descr_adding_bezier = 1, // we're making a bezier spline, so you can expect pending_bezier_* to have a value
descr_delayed_bezier = 4,// the bezier spline we're doing was initiated by a TempBezierTo(), so we'll need an endpoint
};
// some data for the construction: what's pending, and some flags
int descr_flags;
int pending_bezier_cmd;
int pending_bezier_data;
int pending_moveto_cmd;
int pending_moveto_data;
// the path description
// polyline storage: a series of coordinates (and maybe weights)
// also back data: info on where this polyline's segment comes from, ie wich command in the path description: "piece"
// and what abcissis on the chunk of path for this command: "t"
// t=0 means it's at the start of the command's chunk, t=1 it's at the end
struct path_lineto
{
path_lineto(bool m, Geom::Point pp, int pie, double tt) : isMoveTo(m), p(pp), piece(pie), t(tt), closed(false) {}
int isMoveTo;
int piece;
double t;
};
bool back;
Path();
// creation of the path description
void Reset(); // reset to the empty description
// the commands...
int ForcePoint();
int Close();
int ArcTo ( Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise);
int BezierTo ( Geom::Point const &ip); // quadratic bezier spline to this point (control points can be added after this)
int TempBezierTo(); // start a quadratic bezier spline (control points can be added after this)
int EndBezierTo();
int EndBezierTo ( Geom::Point const &ip); // ends a quadratic bezier spline (for curves started with TempBezierTo)
// transforms a description in a polyline (for stroking and filling)
// treshhold is the max length^2 (sort of)
// same function for use when you want to later recompose the curves from the polyline
void ConvertWithBackData (double treshhold);
// creation of the polyline (you can tinker with these function if you want)
void ResetPoints(); // resets to the empty polyline
// transform in a polygon (in a graph, in fact; a subsequent call to ConvertToShape is needed)
// - fills the polyline; justAdd=true doesn't reset the Shape dest, but simply adds the polyline into it
// closeIfNeeded=false prevent the function from closing the path (resulting in a non-eulerian graph
// pathID is a identification number for the path, and is used for recomposing curves from polylines
// give each different Path a different ID, and feed the appropriate orig[] to the ConvertToForme() function
bool closeIfNeeded = true, bool invert = false);
// - stroke the path; usual parameters: type of cap=butt, type of join=join and miter (see LivarotDefs.h)
// doClose treat the path as closed (ie a loop)
// build a Path that is the outline of the Path instance's description (the result is stored in dest)
// it doesn't compute the exact offset (it's way too complicated, but an approximation made of cubic bezier patches
// and segments. the algorithm was found in a plugin for Impress (by Chris Cox), but i can't find it back...
double miter);
// half outline with edges having the same direction as the original
double miter);
// half outline with edges having the opposite direction as the original
double miter);
// polyline to cubic bezier patches
// description simplification
// utilities
// piece is a command no in the command list
// "at" is an abcissis on the path portion associated with this command
// 0=beginning of portion, 1=end of portion.
// last control point before the command i (i included)
// used when dealing with quadratic bezier spline, cause these can contain arbitrarily many commands
// dash the polyline
// the result is stored in the polyline, so you lose the original. make a copy before if needed
void DashPolyline(float head,float tail,float body,int nbD,float *dashs,bool stPlain,float stOffset);
//utilitaire pour inkscape
void LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTransformation, bool append = false);
// decompose le chemin en ses sous-chemin
// killNoSurf=true -> oublie les chemins de surface nulle
// pour recuperer les trous
// nbNest= nombre de contours
// conts= debut de chaque contour
// nesting= parent de chaque contour
// surface du chemin (considere comme ferme)
double Surface();
void PolylineBoundingBox(double &l,double &t,double &r,double &b);
void FastBBox(double &l,double &t,double &r,double &b);
// longueur (totale des sous-chemins)
double Length();
void ConvertForcedToMoveTo();
void ConvertForcedToVoid();
struct cut_position {
int piece;
double t;
};
//Should this take a cut_position as a param?
double PositionToLength(int piece, double t);
// caution: not tested on quadratic b-splines, most certainly buggy
void Affiche();
char *svg_dump_path() const;
bool IsLineSegment(int piece);
// utilitary functions for the path contruction
void CancelBezier ();
void CloseSubpath();
void InsertForcePoint (int at);
void InsertArcTo (Geom::Point const &ip, double iRx, double iRy, double angle, bool iLargeArc, bool iClockwise,int at);
void InsertCubicTo (Geom::Point const &ip, Geom::Point const &iStD, Geom::Point const &iEnD,int at);
// creation of dashes: take the polyline given by spP (length spL) and dash it according to head, body, etc. put the result in
// the polyline of this instance
void DashSubPath(int spL, int spP, std::vector<path_lineto> const &orig_pts, float head,float tail,float body,int nbD,float *dashs,bool stPlain,float stOffset);
// Functions used by the conversion.
// they append points to the polyline
void RecCubicTo ( Geom::Point const &iS, Geom::Point const &iSd, Geom::Point const &iE, Geom::Point const &iEd, double tresh, int lev,
double maxL = -1.0);
void RecBezierTo ( Geom::Point const &iPt, Geom::Point const &iS, Geom::Point const &iE, double treshhold, int lev, double maxL = -1.0);
void RecCubicTo ( Geom::Point const &iS, Geom::Point const &iSd, Geom::Point const &iE, Geom::Point const &iEd, double tresh, int lev,
void RecBezierTo ( Geom::Point const &iPt, Geom::Point const &iS, const Geom::Point &iE, double treshhold, int lev, double st, double et,
int piece);
// don't pay attention
struct offset_orig
{
int piece;
double off_dec;
};
offset_orig & orig);
void RecCubicTo ( Geom::Point const &iS, Geom::Point const &iSd, Geom::Point const &iE, Geom::Point const &iEd, double tresh, int lev,
void RecBezierTo ( Geom::Point const &iPt, Geom::Point const &iS, Geom::Point const &iE, double treshhold, int lev, double st, double et,
static void QuadraticPoint (double t, Geom::Point &oPt, Geom::Point const &iS, Geom::Point const &iM, Geom::Point const &iE);
struct outline_callback_data
{
int piece;
union
{
struct
{
}
c;
struct
{
}
b;
struct
{
}
a;
}
d;
};
struct outline_callbacks
{
};
static void TangentOnCubAt (double at, Geom::Point const &iS, PathDescrCubicTo const &fin, bool before,
double width);
double width);
// fonctions annexes pour le stroke
struct fitting_tables {
double *Xk;
double *Yk;
double *Qk;
double *tk;
double *lk;
char *fk;
double totLen;
};
bool ExtendFit(int off, int N, fitting_tables &data,double treshhold, PathDescrCubicTo & res,int &worstP);
double RaffineTk (Geom::Point pt, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, double it);
void FlushPendingAddition(Path* dest,PathDescr *lastAddition,PathDescrCubicTo &lastCubic,int lastAD);
};
#endif
/*
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:fileencoding=utf-8:textwidth=99 :