summaryrefslogtreecommitdiffstats
path: root/src/helper
diff options
context:
space:
mode:
Diffstat (limited to 'src/helper')
-rw-r--r--src/helper/geom-pathstroke.cpp204
-rw-r--r--src/helper/geom.cpp9
-rw-r--r--src/helper/png-write.cpp12
-rw-r--r--src/helper/png-write.h7
4 files changed, 135 insertions, 97 deletions
diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp
index 97e3c6806..a152af62c 100644
--- a/src/helper/geom-pathstroke.cpp
+++ b/src/helper/geom-pathstroke.cpp
@@ -127,87 +127,104 @@ static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.0
namespace {
-// Join functions may:
-// - inspect any curve of the current path
-// - append any type of curve to the current path
-// - inspect the outgoing path
-//
-// Join functions must:
-// - append the outgoing curve
-// OR
-// - end at outgoing.finalPoint
-
-typedef void join_func(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width);
-
-void bevel_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double /*width*/)
+// Internal data structure
+
+struct join_data
+{
+ join_data(Geom::Path &_res, Geom::Path const&_outgoing, Geom::Point _in_tang, Geom::Point _out_tang, double _miter, double _width)
+ : res(_res), outgoing(_outgoing), in_tang(_in_tang)
+ , out_tang(_out_tang), miter(_miter), width(_width) {}
+
+ // I/O
+ Geom::Path &res;
+ Geom::Path const& outgoing;
+
+ // input tangents
+ Geom::Point in_tang;
+ Geom::Point out_tang;
+
+ // line parameters
+ double miter;
+ double width;
+};
+
+// Join functions must append the outgoing path
+
+typedef void join_func(join_data jd);
+
+void bevel_join(join_data jd)
{
- res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
- res.append(outgoing);
+ jd.res.appendNew<Geom::LineSegment>(jd.outgoing.initialPoint());
+ jd.res.append(jd.outgoing);
}
-void round_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double width)
+void round_join(join_data jd)
{
- res.appendNew<Geom::SVGEllipticalArc>(width, width, 0, false, width <= 0, outgoing.initialPoint());
- res.append(outgoing);
+ jd.res.appendNew<Geom::SVGEllipticalArc>(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint());
+ jd.res.append(jd.outgoing);
}
-void miter_join_internal(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width, bool clip)
+void miter_join_internal(join_data jd, bool clip)
{
- Geom::Curve const& incoming = res.back();
- Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.);
- Geom::Point tang2 = outgoing.unitTangentAt(0);
- Geom::Point p = Geom::intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2);
+ using namespace Geom;
+
+ Curve const& incoming = jd.res.back();
+ Curve const& outgoing = jd.outgoing.front();
+ Path &res = jd.res;
+ double width = jd.width, miter = jd.miter;
+
+ Point tang1 = jd.in_tang;
+ Point tang2 = jd.out_tang;
+ Point p = intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2);
bool satisfied = false;
bool inc_ls = res.back_open().degreesOfFreedom() <= 4;
if (p.isFinite()) {
// check size of miter
- Geom::Point point_on_path = incoming.finalPoint() + Geom::rot90(tang1)*width;
- satisfied = Geom::distance(p, point_on_path) <= miter * 2.0 * width;
+ Point point_on_path = incoming.finalPoint() + rot90(tang1)*width;
+ satisfied = distance(p, point_on_path) <= miter * 2.0 * width;
if (satisfied) {
// miter OK, check to see if we can do a relocation
if (inc_ls) {
res.setFinal(p);
} else {
- res.appendNew<Geom::LineSegment>(p);
+ res.appendNew<LineSegment>(p);
}
} else if (clip) {
// miter needs clipping, find two points
- Geom::Point bisector_versor = Geom::Line(point_on_path, p).versor();
- Geom::Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor;
+ Point bisector_versor = Line(point_on_path, p).versor();
+ Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor;
- Geom::Point p1 = Geom::intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw());
- Geom::Point p2 = Geom::intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw());
+ Point p1 = intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw());
+ Point p2 = intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw());
if (inc_ls) {
res.setFinal(p1);
} else {
- res.appendNew<Geom::LineSegment>(p1);
+ res.appendNew<LineSegment>(p1);
}
- res.appendNew<Geom::LineSegment>(p2);
+ res.appendNew<LineSegment>(p2);
}
}
- res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
+ res.appendNew<LineSegment>(outgoing.initialPoint());
// check if we can do another relocation
bool out_ls = outgoing.degreesOfFreedom() <= 4;
- if ( (satisfied || clip) && out_ls) {
+ if ((satisfied || clip) && out_ls) {
res.setFinal(outgoing.finalPoint());
} else {
res.append(outgoing);
}
-}
-void miter_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) {
- miter_join_internal( res, outgoing, miter, width, false );
+ // either way, add the rest of the path
+ res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end());
}
-void miter_clip_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) {
- miter_join_internal( res, outgoing, miter, width, true );
-}
+void miter_join(join_data jd) { miter_join_internal(jd, false); }
+void miter_clip_join(join_data jd) { miter_join_internal(jd, true); }
Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt)
{
@@ -225,15 +242,18 @@ Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point
return sol;
}
-void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width)
+void extrapolate_join(join_data jd)
{
using namespace Geom;
+ Geom::Path &res = jd.res;
Geom::Curve const& incoming = res.back();
+ Geom::Curve const& outgoing = jd.outgoing.front();
Geom::Point startPt = incoming.finalPoint();
Geom::Point endPt = outgoing.initialPoint();
- Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.);
- Geom::Point tang2 = outgoing.unitTangentAt(0);
+ Geom::Point tang1 = jd.in_tang;
+ Geom::Point tang2 = jd.out_tang;
+ double width = jd.width, miter = jd.miter;
Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
@@ -280,7 +300,7 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter
if (solutions != 2)
// no solutions available, fall back to miter
- return miter_clip_join(res, outgoing, miter, width);
+ return miter_clip_join(jd);
// We have a solution, thus sol is defined.
p1 = sol;
@@ -381,53 +401,78 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter
// Straight line segment:
res.appendNew<Geom::LineSegment>(outgoing.finalPoint());
}
-
+
+ // add the rest of the path
+ res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end());
+
delete arc1;
delete arc2;
}
-void join_inside(Geom::Path& res, Geom::Curve const& outgoing)
+void join_inside(join_data jd)
{
- Geom::Curve const& incoming = res.back_open();
- Geom::Crossings cross = Geom::crossings(incoming, outgoing);
-
- if (!cross.empty()) {
- // yeah if we could avoid allocing that'd be great
- Geom::Curve *d1 = incoming.portion(0., cross[0].ta);
- res.erase_last();
- res.append(*d1);
- delete d1;
+ Geom::Path &res = jd.res;
+ Geom::Path const& temp = jd.outgoing;
+ Geom::Crossings cross = Geom::crossings(res, temp);
+
+ int solution = -1; // lol, really hope there aren't more than INT_MAX crossings
+ if (cross.size() == 1) solution = 0;
+ else if (cross.size() > 1) {
+ // I am not sure how well this will work -- we pick the join node closest
+ // to the cross point of the paths
+ Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width;
+ Geom::Coord trial = Geom::L2(res.pointAt(cross[0].ta)-original);
+ solution = 0;
+ for (size_t i = 1; i < cross.size(); ++i) {
+ //printf("Trying %d\n", i);
+ Geom::Coord test = Geom::L2(res.pointAt(cross[i].ta)-original);
+ if (test < trial) {
+ trial = test;
+ solution = i;
+ //printf("Found improved solution: %f\n", trial);
+ }
+ }
+ }
- Geom::Curve *d2 = outgoing.portion(cross[0].tb, 1.);
- res.setFinal(d2->initialPoint());
- res.append(*d2);
- delete d2;
+ if (solution != -1) {
+ Geom::Path d1 = res.portion(0., cross[solution].ta);
+ Geom::Path d2 = temp.portion(cross[solution].tb, temp.size());
+
+ // Watch for bugs in 2geom crossing regarding severe inflection points
+ res.clear();
+ res.append(d1);
+ res.setFinal(d2.initialPoint());
+ res.append(d2);
} else {
- res.appendNew<Geom::LineSegment>(outgoing.initialPoint());
- res.append(outgoing);
+ res.appendNew<Geom::LineSegment>(temp.initialPoint());
+ res.append(temp);
}
}
-bool decide(Geom::Curve const& incoming, Geom::Curve const& outgoing)
+void tangents(Geom::Point tang[2], Geom::Curve const& incoming, Geom::Curve const& outgoing)
{
Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.);
Geom::Point tang2 = outgoing.unitTangentAt(0.);
- return (Geom::cross(tang1, tang2) > 0);
+ tang[0] = tang1, tang[1] = tang2;
}
-void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join)
+void outline_helper(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join)
{
- if (res.size() == 0 || to_add.size() == 0)
+ if (res.size() == 0 || temp.size() == 0)
return;
- Geom::Curve const& outgoing = to_add[0];
+ Geom::Curve const& outgoing = temp.front();
if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) {
// if the points are /that/ close, just ignore this one
- res.setFinal(outgoing.initialPoint());
- res.append(outgoing);
+ res.setFinal(temp.initialPoint());
+ res.append(temp);
return;
}
+ join_data jd(res, temp, in_tang, out_tang, miter, width);
+
+ bool on_outside = (Geom::cross(in_tang, out_tang) > 0);
+
if (on_outside) {
join_func *jf;
switch (join) {
@@ -446,9 +491,9 @@ void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, boo
default:
jf = &miter_join;
}
- jf(res, outgoing, miter, width);
+ jf(jd);
} else {
- join_inside(res, outgoing);
+ join_inside(jd);
}
}
@@ -579,7 +624,7 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi
void offset_curve(Geom::Path& res, Geom::Curve const* current, double width)
{
- double const tolerance = 0.005;
+ double const tolerance = 0.0025;
size_t levels = 8;
if (current->isDegenerate()) return; // don't do anything
@@ -705,6 +750,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin
Geom::Point tang1 = input[0].unitTangentAt(0);
Geom::Point start = input.initialPoint() + tang1 * width;
Geom::Path temp;
+ Geom::Point tang[2];
res.setStitching(true);
temp.setStitching(true);
@@ -723,20 +769,16 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin
if (u == 0) {
res.append(temp);
} else {
- bool on_outside = decide(input[u-1], input[u]);
- outline_helper(res, temp, width, on_outside, miter, join);
- if (temp.size() > 0)
- res.insert(res.end(), ++temp.begin(), temp.end());
+ tangents(tang, input[u-1], input[u]);
+ outline_helper(res, temp, tang[0], tang[1], width, miter, join);
}
// odd number of paths
if (u < k - 1) {
temp = Geom::Path();
offset_curve(temp, &input[u+1], width);
- bool on_outside = decide(input[u], input[u+1]);
- outline_helper(res, temp, width, on_outside, miter, join);
- if (temp.size() > 0)
- res.insert(res.end(), ++temp.begin(), temp.end());
+ tangents(tang, input[u], input[u+1]);
+ outline_helper(res, temp, tang[0], tang[1], width, miter, join);
}
}
@@ -747,8 +789,8 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin
temp.append(c1);
Geom::Path temp2;
temp2.append(c2);
- bool on_outside = decide(input.back(), input.front());
- outline_helper(temp, temp2, width, on_outside, miter, join);
+ tangents(tang, input.back(), input.front());
+ outline_helper(temp, temp2, tang[0], tang[1], width, miter, join);
res.erase(res.begin());
res.erase_last();
//
diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp
index 42d1a3150..ecb330b01 100644
--- a/src/helper/geom.cpp
+++ b/src/helper/geom.cpp
@@ -265,14 +265,13 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000,
Geom::Coord tolerance)
{
Geom::Coord x0, y0, x1, y1, len2;
- int needdist, needwind, needline;
+ int needdist, needwind;
const Geom::Coord Px = pt[X];
const Geom::Coord Py = pt[Y];
needdist = 0;
needwind = 0;
- needline = 0;
if (bbox) cubic_bbox (x000, y000, x001, y001, x011, y011, x111, y111, *bbox);
@@ -302,8 +301,6 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000,
/* fixme: (Lauris) */
if (((y1 - y0) > 5.0) || ((x1 - x0) > 5.0)) {
needdist = 1;
- } else {
- needline = 1;
}
}
}
@@ -314,8 +311,6 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000,
/* fixme: (Lauris) */
if (((y1 - y0) > 5.0) || ((x1 - x0) > 5.0)) {
needwind = 1;
- } else {
- needline = 1;
}
}
}
@@ -344,7 +339,7 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000,
geom_cubic_bbox_wind_distance (x000, y000, x00t, y00t, x0tt, y0tt, xttt, yttt, pt, NULL, wind, best, tolerance);
geom_cubic_bbox_wind_distance (xttt, yttt, x1tt, y1tt, x11t, y11t, x111, y111, pt, NULL, wind, best, tolerance);
- } else if (1 || needline) {
+ } else {
geom_line_wind_distance (x000, y000, x111, y111, pt, wind, best);
}
}
diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp
index 32e50b537..fc365c435 100644
--- a/src/helper/png-write.cpp
+++ b/src/helper/png-write.cpp
@@ -361,19 +361,19 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v
/**
* Hide all items that are not listed in list, recursively, skipping groups and defs.
*/
-static void hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey)
+static void hide_other_items_recursively(SPObject *o, const std::vector<SPItem*> &list, unsigned dkey)
{
if ( SP_IS_ITEM(o)
&& !SP_IS_DEFS(o)
&& !SP_IS_ROOT(o)
&& !SP_IS_GROUP(o)
- && !g_slist_find(list, o) )
+ && list.end()==find(list.begin(),list.end(),o))
{
SP_ITEM(o)->invoke_hide(dkey);
}
// recurse
- if (!g_slist_find(list, o)) {
+ if (list.end()==find(list.begin(),list.end(),o)) {
for ( SPObject *child = o->firstChild() ; child; child = child->getNext() ) {
hide_other_items_recursively(child, list, dkey);
}
@@ -387,7 +387,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
unsigned long bgcolor,
unsigned int (*status) (float, void *),
void *data, bool force_overwrite,
- GSList *items_only)
+ const std::vector<SPItem*> &items_only)
{
return sp_export_png_file(doc, filename, Geom::Rect(Geom::Point(x0,y0),Geom::Point(x1,y1)),
width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only);
@@ -399,7 +399,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
unsigned long bgcolor,
unsigned (*status)(float, void *),
void *data, bool force_overwrite,
- GSList *items_only)
+ const std::vector<SPItem*> &items_only)
{
g_return_val_if_fail(doc != NULL, EXPORT_ERROR);
g_return_val_if_fail(filename != NULL, EXPORT_ERROR);
@@ -457,7 +457,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
// We show all and then hide all items we don't want, instead of showing only requested items,
// because that would not work if the shown item references something in defs
- if (items_only) {
+ if (!items_only.empty()) {
hide_other_items_recursively(doc->getRoot(), items_only, dkey);
}
diff --git a/src/helper/png-write.h b/src/helper/png-write.h
index 8c04b25dc..2657fb635 100644
--- a/src/helper/png-write.h
+++ b/src/helper/png-write.h
@@ -14,8 +14,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glib.h>
#include <2geom/forward.h>
+
+
class SPDocument;
enum ExportResult {
@@ -33,12 +34,12 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
double x0, double y0, double x1, double y1,
unsigned long int width, unsigned long int height, double xdpi, double ydpi,
unsigned long bgcolor,
- unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, GSList *items_only = NULL);
+ unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>());
ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
Geom::Rect const &area,
unsigned long int width, unsigned long int height, double xdpi, double ydpi,
unsigned long bgcolor,
- unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, GSList *items_only = NULL);
+ unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>());
#endif // SEEN_SP_PNG_WRITE_H