index d9bb665f056a18704f6be0c1ae3ed54516963706..d6ca8c5333861da6117494c56aa34d62a8322b07 100644 (file)
*/
#include "livarot/Shape.h"
+#include <libnr/nr-matrix-fns.h>
#include <libnr/nr-point-fns.h>
#include "livarot/Path.h"
#include "livarot/path-description.h"
#include <glib.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
/*
* polygon offset and polyline to path reassembling (when using back data)
{
if (numberOfPoints() <= 1 || numberOfEdges() <= 1)
return;
- if (directedEulerian(this) == false)
- return;
// prepare
dest->Reset ();
@@ -524,16 +526,204 @@ Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int wildPath,in
MakeSweepDestData (false);
}
+
+int
+Shape::MakeTweak (int mode, Shape *a, double power, JoinType join, double miter, bool do_profile, Geom::Point c, Geom::Point vector, double radius, Geom::Matrix *i2doc)
+{
+ Reset (0, 0);
+ MakeBackData(a->_has_back_data);
+
+ bool done_something = false;
+
+ if (power == 0)
+ {
+ _pts = a->_pts;
+ if (numberOfPoints() > maxPt)
+ {
+ maxPt = numberOfPoints();
+ if (_has_points_data) {
+ pData.resize(maxPt);
+ _point_data_initialised = false;
+ _bbox_up_to_date = false;
+ }
+ }
+
+ _aretes = a->_aretes;
+ if (numberOfEdges() > maxAr)
+ {
+ maxAr = numberOfEdges();
+ if (_has_edges_data)
+ eData.resize(maxAr);
+ if (_has_sweep_src_data)
+ swsData.resize(maxAr);
+ if (_has_sweep_dest_data)
+ swdData.resize(maxAr);
+ if (_has_raster_data)
+ swrData.resize(maxAr);
+ if (_has_back_data)
+ ebData.resize(maxAr);
+ }
+ return 0;
+ }
+ if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
+ return shape_input_err;
+
+ a->SortEdges ();
+
+ a->MakeSweepDestData (true);
+ a->MakeSweepSrcData (true);
+
+ for (int i = 0; i < a->numberOfEdges(); i++)
+ {
+ int stB = -1, enB = -1;
+ if (power <= 0 || mode == tweak_mode_push || mode == tweak_mode_repel || mode == tweak_mode_roughen) {
+ stB = a->CyclePrevAt (a->getEdge(i).st, i);
+ enB = a->CycleNextAt (a->getEdge(i).en, i);
+ } else {
+ stB = a->CycleNextAt (a->getEdge(i).st, i);
+ enB = a->CyclePrevAt (a->getEdge(i).en, i);
+ }
+
+ Geom::Point stD, seD, enD;
+ double stL, seL, enL;
+ stD = a->getEdge(stB).dx;
+ seD = a->getEdge(i).dx;
+ enD = a->getEdge(enB).dx;
+
+ stL = sqrt (dot(stD,stD));
+ seL = sqrt (dot(seD,seD));
+ enL = sqrt (dot(enD,enD));
+ MiscNormalize (stD);
+ MiscNormalize (enD);
+ MiscNormalize (seD);
+
+ Geom::Point ptP;
+ int stNo, enNo;
+ ptP = a->getPoint(a->getEdge(i).st).x;
+
+ Geom::Point to_center = ptP * (*i2doc) - c;
+ Geom::Point to_center_normalized = (1/Geom::L2(to_center)) * to_center;
+
+ double this_power;
+ if (do_profile && i2doc) {
+ double alpha = 1;
+ double x;
+ if (mode == tweak_mode_repel) {
+ x = (Geom::L2(to_center)/radius);
+ } else {
+ x = (Geom::L2(ptP * (*i2doc) - c)/radius);
+ }
+ if (x > 1) {
+ this_power = 0;
+ } else if (x <= 0) {
+ if (mode == tweak_mode_repel) {
+ this_power = 0;
+ } else {
+ this_power = power;
+ }
+ } else {
+ this_power = power * (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5);
+ }
+ } else {
+ if (mode == tweak_mode_repel) {
+ this_power = 0;
+ } else {
+ this_power = power;
+ }
+ }
+
+ if (this_power != 0)
+ done_something = true;
+
+ double scaler = 1 / (*i2doc).descrim();
+
+ Geom::Point this_vec(0,0);
+ if (mode == tweak_mode_push) {
+ Geom::Matrix tovec (*i2doc);
+ tovec[4] = tovec[5] = 0;
+ tovec = tovec.inverse();
+ this_vec = this_power * (vector * tovec) ;
+ } else if (mode == tweak_mode_repel) {
+ this_vec = this_power * scaler * to_center_normalized;
+ } else if (mode == tweak_mode_roughen) {
+ double angle = g_random_double_range(0, 2*M_PI);
+ this_vec = g_random_double_range(0, 1) * this_power * scaler * Geom::Point(sin(angle), cos(angle));
+ }
+
+ int usePathID=-1;
+ int usePieceID=0;
+ double useT=0.0;
+ if ( a->_has_back_data ) {
+ if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
+ && a->ebData[stB].tEn == a->ebData[i].tSt ) {
+ usePathID=a->ebData[i].pathID;
+ usePieceID=a->ebData[i].pieceID;
+ useT=a->ebData[i].tSt;
+ } else {
+ usePathID=a->ebData[i].pathID;
+ usePieceID=0;
+ useT=0;
+ }
+ }
+
+ if (mode == tweak_mode_push || mode == tweak_mode_repel || mode == tweak_mode_roughen) {
+ Path::DoLeftJoin (this, 0, join, ptP+this_vec, stD+this_vec, seD+this_vec, miter, stL, seL,
+ stNo, enNo,usePathID,usePieceID,useT);
+ a->swsData[i].stPt = enNo;
+ a->swsData[stB].enPt = stNo;
+ } else {
+ if (power > 0) {
+ Path::DoRightJoin (this, this_power * scaler, join, ptP, stD, seD, miter, stL, seL,
+ stNo, enNo,usePathID,usePieceID,useT);
+ a->swsData[i].stPt = enNo;
+ a->swsData[stB].enPt = stNo;
+ } else {
+ Path::DoLeftJoin (this, -this_power * scaler, join, ptP, stD, seD, miter, stL, seL,
+ stNo, enNo,usePathID,usePieceID,useT);
+ a->swsData[i].stPt = enNo;
+ a->swsData[stB].enPt = stNo;
+ }
+ }
+ }
+
+ if (power < 0 || mode == tweak_mode_push || mode == tweak_mode_repel || mode == tweak_mode_roughen)
+ {
+ for (int i = 0; i < numberOfEdges(); i++)
+ Inverse (i);
+ }
+
+ if ( _has_back_data ) {
+ for (int i = 0; i < a->numberOfEdges(); i++)
+ {
+ int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
+ ebData[nEd]=a->ebData[i];
+ }
+ } else {
+ for (int i = 0; i < a->numberOfEdges(); i++)
+ {
+ AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
+ }
+ }
+
+ a->MakeSweepSrcData (false);
+ a->MakeSweepDestData (false);
+
+ return (done_something? 0 : shape_nothing_to_do);
+}
+
+
// offsets
// take each edge, offset it, and make joins with previous at edge start and next at edge end (previous and
// next being with respect to the clockwise order)
-// you gotta be very careful with the join, has anything but the right one will fuck everything up
+// you gotta be very careful with the join, as anything but the right one will fuck everything up
// see PathStroke.cpp for the "right" joins
int
-Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter)
+Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter, bool do_profile, double cx, double cy, double radius, Geom::Matrix *i2doc)
{
Reset (0, 0);
MakeBackData(a->_has_back_data);
+
+ bool done_something = false;
if (dec == 0)
{
if (numberOfPoints() > maxPt)
{
maxPt = numberOfPoints();
- if (_has_points_data)
+ if (_has_points_data) {
pData.resize(maxPt);
+ _point_data_initialised = false;
+ _bbox_up_to_date = false;
+ }
}
_aretes = a->_aretes;
enB = a->CycleNextAt (a->getEdge(i).en, i);
}
- NR::Point stD, seD, enD;
+ Geom::Point stD, seD, enD;
double stL, seL, enL;
stD = a->getEdge(stB).dx;
seD = a->getEdge(i).dx;
enD = a->getEdge(enB).dx;
-
+
stL = sqrt (dot(stD,stD));
seL = sqrt (dot(seD,seD));
enL = sqrt (dot(enD,enD));
MiscNormalize (enD);
MiscNormalize (seD);
- NR::Point ptP;
+ Geom::Point ptP;
int stNo, enNo;
ptP = a->getPoint(a->getEdge(i).st).x;
+
+ double this_dec;
+ if (do_profile && i2doc) {
+ double alpha = 1;
+ double x = (Geom::L2(ptP * (*i2doc) - Geom::Point(cx,cy))/radius);
+ if (x > 1) {
+ this_dec = 0;
+ } else if (x <= 0) {
+ this_dec = dec;
+ } else {
+ this_dec = dec * (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5);
+ }
+ } else {
+ this_dec = dec;
+ }
+
+ if (this_dec != 0)
+ done_something = true;
+
int usePathID=-1;
int usePieceID=0;
double useT=0.0;
}
if (dec > 0)
{
- Path::DoRightJoin (this, dec, join, ptP, stD, seD, miter, stL, seL,
+ Path::DoRightJoin (this, this_dec, join, ptP, stD, seD, miter, stL, seL,
stNo, enNo,usePathID,usePieceID,useT);
a->swsData[i].stPt = enNo;
a->swsData[stB].enPt = stNo;
}
else
{
- Path::DoLeftJoin (this, -dec, join, ptP, stD, seD, miter, stL, seL,
+ Path::DoLeftJoin (this, -this_dec, join, ptP, stD, seD, miter, stL, seL,
stNo, enNo,usePathID,usePieceID,useT);
a->swsData[i].stPt = enNo;
a->swsData[stB].enPt = stNo;
}
}
+
if (dec < 0)
{
for (int i = 0; i < numberOfEdges(); i++)
Inverse (i);
}
+
if ( _has_back_data ) {
for (int i = 0; i < a->numberOfEdges(); i++)
{
AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
}
}
+
a->MakeSweepSrcData (false);
a->MakeSweepDestData (false);
- return 0;
+ return (done_something? 0 : shape_nothing_to_do);
}
+
+
// we found a contour, now reassemble the edges on it, instead of dumping them in the Path "dest" as a
// polyline. since it was a DFS, the precParc and suivParc make a nice doubly-linked list of the edges in
// the contour. the first and last edges of the contour are startBord and curBord
@@ -765,12 +982,12 @@ Shape::AddContour (Path * dest, int nbP, Path * *orig, int startBord, int curBor
}
int
-Shape::ReFormeLineTo (int bord, int curBord, Path * dest, Path * orig)
+Shape::ReFormeLineTo (int bord, int /*curBord*/, Path * dest, Path * /*orig*/)
{
int nPiece = ebData[bord].pieceID;
int nPath = ebData[bord].pathID;
double /*ts=ebData[bord].tSt, */ te = ebData[bord].tEn;
- NR::Point nx = getPoint(getEdge(bord).en).x;
+ Geom::Point nx = getPoint(getEdge(bord).en).x;
bord = swdData[bord].suivParc;
while (bord >= 0)
{
}
int
-Shape::ReFormeArcTo (int bord, int curBord, Path * dest, Path * from)
+Shape::ReFormeArcTo (int bord, int /*curBord*/, Path * dest, Path * from)
{
int nPiece = ebData[bord].pieceID;
int nPath = ebData[bord].pathID;
double ts = ebData[bord].tSt, te = ebData[bord].tEn;
// double px=pts[getEdge(bord).st].x,py=pts[getEdge(bord).st].y;
- NR::Point nx = getPoint(getEdge(bord).en).x;
+ Geom::Point nx = getPoint(getEdge(bord).en).x;
bord = swdData[bord].suivParc;
while (bord >= 0)
{
}
int
-Shape::ReFormeCubicTo (int bord, int curBord, Path * dest, Path * from)
+Shape::ReFormeCubicTo (int bord, int /*curBord*/, Path * dest, Path * from)
{
int nPiece = ebData[bord].pieceID;
int nPath = ebData[bord].pathID;
double ts = ebData[bord].tSt, te = ebData[bord].tEn;
- NR::Point nx = getPoint(getEdge(bord).en).x;
+ Geom::Point nx = getPoint(getEdge(bord).en).x;
bord = swdData[bord].suivParc;
while (bord >= 0)
{
}
bord = swdData[bord].suivParc;
}
- NR::Point prevx = from->PrevPoint (nPiece - 1);
+ Geom::Point prevx = from->PrevPoint (nPiece - 1);
- NR::Point sDx, eDx;
+ Geom::Point sDx, eDx;
{
PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(from->descr_cmd[nPiece]);
Path::CubicTangent (ts, sDx, prevx,nData->start,nData->p,nData->end);
}
int
-Shape::ReFormeBezierTo (int bord, int curBord, Path * dest, Path * from)
+Shape::ReFormeBezierTo (int bord, int /*curBord*/, Path * dest, Path * from)
{
int nPiece = ebData[bord].pieceID;
int nPath = ebData[bord].pathID;
double ts = ebData[bord].tSt, te = ebData[bord].tEn;
int ps = nPiece, pe = nPiece;
- NR::Point px = getPoint(getEdge(bord).st).x;
- NR::Point nx = getPoint(getEdge(bord).en).x;
+ Geom::Point px = getPoint(getEdge(bord).st).x;
+ Geom::Point nx = getPoint(getEdge(bord).en).x;
int inBezier = -1, nbInterm = -1;
int typ;
typ = from->descr_cmd[nPiece]->getType();
}
else
{
- NR::Point tx;
+ Geom::Point tx;
{
PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe]);
PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
{
if (te > 0.9999)
{
- NR::Point tx;
+ Geom::Point tx;
{
PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+2]);
}
else
{
- NR::Point tx;
+ Geom::Point tx;
{
PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+2]);
}
else
{
- NR::Point tx;
+ Geom::Point tx;
{
PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+2]);
{
if (te < 0.0001)
{
- NR::Point tx;
+ Geom::Point tx;
{
PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps]);
PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
}
else
{
- NR::Point tx;
+ Geom::Point tx;
{
PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps]);
PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
}
void
-Shape::ReFormeBezierChunk (NR::Point px, NR::Point nx,
+Shape::ReFormeBezierChunk (Geom::Point px, Geom::Point nx,
Path * dest, int inBezier, int nbInterm,
Path * from, int p, double ts, double te)
{
PathDescrBezierTo* nBData = dynamic_cast<PathDescrBezierTo*>(from->descr_cmd[inBezier]);
- NR::Point bstx = from->PrevPoint (inBezier - 1);
- NR::Point benx = nBData->p;
+ Geom::Point bstx = from->PrevPoint (inBezier - 1);
+ Geom::Point benx = nBData->p;
- NR::Point mx;
+ Geom::Point mx;
if (p == inBezier)
{
// premier bout
nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p+2]);
benx = (nData->p + mx) / 2;
}
- NR::Point cx;
+ Geom::Point cx;
{
Path::QuadraticPoint ((ts + te) / 2, cx, bstx, mx, benx);
}