diff options
| author | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:56:11 +0000 |
|---|---|---|
| committer | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:56:11 +0000 |
| commit | 132e83fd6f6124731dc773ae2978d115ca492ef2 (patch) | |
| tree | b561a4dbbacd7eecbdbae3fa220a353375ccecf8 /src/helper | |
| parent | updated to trunk (diff) | |
| parent | [Bug #1695016] Xaml export misses some radialGradients. (diff) | |
| download | inkscape-132e83fd6f6124731dc773ae2978d115ca492ef2.tar.gz inkscape-132e83fd6f6124731dc773ae2978d115ca492ef2.zip | |
merged with latest version of lpe-bool and trunk
(bzr r14862.2.3)
Diffstat (limited to 'src/helper')
| -rw-r--r-- | src/helper/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | src/helper/Makefile_insert | 45 | ||||
| -rw-r--r-- | src/helper/action-context.cpp | 1 | ||||
| -rw-r--r-- | src/helper/action.cpp | 2 | ||||
| -rw-r--r-- | src/helper/geom-nodetype.cpp | 2 | ||||
| -rw-r--r-- | src/helper/geom-pathstroke.cpp | 230 | ||||
| -rw-r--r-- | src/helper/geom-pathstroke.h | 17 | ||||
| -rw-r--r-- | src/helper/geom-pathvectorsatellites.cpp | 244 | ||||
| -rw-r--r-- | src/helper/geom-pathvectorsatellites.h | 58 | ||||
| -rw-r--r-- | src/helper/geom-satellite.cpp | 245 | ||||
| -rw-r--r-- | src/helper/geom-satellite.h | 110 | ||||
| -rw-r--r-- | src/helper/geom.cpp | 14 | ||||
| -rw-r--r-- | src/helper/geom.h | 2 | ||||
| -rw-r--r-- | src/helper/gettext.cpp | 110 | ||||
| -rw-r--r-- | src/helper/gettext.h | 46 | ||||
| -rw-r--r-- | src/helper/pixbuf-ops.cpp | 10 | ||||
| -rw-r--r-- | src/helper/png-write.cpp | 87 | ||||
| -rw-r--r-- | src/helper/png-write.h | 6 | ||||
| -rw-r--r-- | src/helper/stock-items.cpp | 30 |
19 files changed, 1094 insertions, 175 deletions
diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index ff4760c24..443648c5c 100644 --- a/src/helper/CMakeLists.txt +++ b/src/helper/CMakeLists.txt @@ -10,10 +10,13 @@ set(sp_marshal_SRC set(helper_SRC action.cpp - action-context.cpp + action-context.cpp geom.cpp geom-nodetype.cpp geom-pathstroke.cpp + geom-pathvectorsatellites.cpp + geom-satellite.cpp + gettext.cpp gnome-utils.cpp pixbuf-ops.cpp png-write.cpp @@ -28,11 +31,14 @@ set(helper_SRC # ------- # Headers action.h - action-context.h + action-context.h geom-curves.h geom-nodetype.h geom-pathstroke.h + geom-pathvectorsatellites.h + geom-satellite.h geom.h + gettext.h gnome-utils.h mathfns.h pixbuf-ops.h diff --git a/src/helper/Makefile_insert b/src/helper/Makefile_insert deleted file mode 100644 index e59fcfb70..000000000 --- a/src/helper/Makefile_insert +++ /dev/null @@ -1,45 +0,0 @@ -## Makefile.am fragment sourced by src/Makefile.am. - -helper/unit-menu.$(OBJEXT): helper/sp-marshal.h - -ink_common_sources += \ - helper/action.cpp \ - helper/action.h \ - helper/action-context.cpp \ - helper/action-context.h \ - helper/geom.cpp \ - helper/geom.h \ - helper/geom-curves.h \ - helper/geom-nodetype.cpp \ - helper/geom-nodetype.h \ - helper/geom-pathstroke.cpp \ - helper/geom-pathstroke.h \ - helper/gnome-utils.cpp \ - helper/gnome-utils.h \ - helper/mathfns.h \ - helper/png-write.cpp \ - helper/png-write.h \ - helper/sp-marshal.cpp \ - helper/sp-marshal.h \ - helper/window.cpp \ - helper/window.h \ - helper/stock-items.cpp \ - helper/stock-items.h - -# cmp exits with status 0 when there are no differences. "if" executes the commands -# after "then" when the exit status of the if command is 0 (this is crazy). -helper/sp-marshal.h: helper/sp-marshal.list - glib-genmarshal --prefix=sp_marshal --header $(srcdir)/helper/sp-marshal.list > helper/tmp.sp-marshal.h - if cmp -s helper/sp-marshal.h helper/tmp.sp-marshal.h; \ - then rm helper/tmp.sp-marshal.h; \ - else mv helper/tmp.sp-marshal.h helper/sp-marshal.h; fi - -helper/sp-marshal.cpp: helper/sp-marshal.list helper/sp-marshal.h - ( echo '#include "helper/sp-marshal.h"' && \ - glib-genmarshal --prefix=sp_marshal --body $(srcdir)/helper/sp-marshal.list ) \ - > helper/tmp.sp-marshal.cpp; \ - if cmp -s helper/sp-marshal.cpp helper/tmp.sp-marshal.cpp; \ - then rm helper/tmp.sp-marshal.cpp; \ - else mv helper/tmp.sp-marshal.cpp helper/sp-marshal.cpp; fi - -helper/sp-marshal.cpp helper/sp-marshal.h: helper/sp-marshal.list diff --git a/src/helper/action-context.cpp b/src/helper/action-context.cpp index d52e43d96..1ea12776b 100644 --- a/src/helper/action-context.cpp +++ b/src/helper/action-context.cpp @@ -14,7 +14,6 @@ #include "layer-model.h" #include "selection.h" #include "helper/action-context.h" -#include "ui/view/view.h" namespace Inkscape { diff --git a/src/helper/action.cpp b/src/helper/action.cpp index 060bf317c..e37575a9c 100644 --- a/src/helper/action.cpp +++ b/src/helper/action.cpp @@ -9,8 +9,6 @@ * This code is in public domain */ -#include <string.h> - #include "debug/logger.h" #include "debug/timestamp.h" #include "debug/simple-event.h" diff --git a/src/helper/geom-nodetype.cpp b/src/helper/geom-nodetype.cpp index fe8e8af0e..da620b3fd 100644 --- a/src/helper/geom-nodetype.cpp +++ b/src/helper/geom-nodetype.cpp @@ -12,8 +12,6 @@ #include "helper/geom-nodetype.h" #include <2geom/curve.h> -#include <2geom/point.h> -#include <vector> namespace Geom { diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index d2e9f9a1b..50627fd0b 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -1,6 +1,7 @@ /* Authors: * Liam P. White * Tavmjong Bah + * Alexander Brock * * Copyright (C) 2014-2015 Authors * @@ -9,13 +10,9 @@ #include <iomanip> #include <2geom/path-sink.h> -#include <2geom/point.h> -#include <2geom/bezier-curve.h> -#include <2geom/elliptical-arc.h> #include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis #include <2geom/path-intersection.h> #include <2geom/circle.h> -#include <math.h> #include "helper/geom-pathstroke.h" @@ -750,33 +747,36 @@ void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, doub len = l; } -void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels) -{ +double _offset_cubic_stable_sub( + Geom::CubicBezier const& bez, + Geom::CubicBezier& c, + const Geom::Point& start_normal, + const Geom::Point& end_normal, + const Geom::Point& start_new, + const Geom::Point& end_new, + const double start_rad, + const double end_rad, + const double start_len, + const double end_len, + const double width, + const double width_correction) { using Geom::X; using Geom::Y; - Geom::Point start_pos = bez.initialPoint(); - Geom::Point end_pos = bez.finalPoint(); - - Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0)); - Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.)); - - // offset the start and end control points out by the width - Geom::Point start_new = start_pos + start_normal*width; - Geom::Point end_new = end_pos + end_normal*width; - - // -------- - double start_rad, end_rad; - double start_len, end_len; // tangent lengths - get_cubic_data(bez, 0, start_len, start_rad); - get_cubic_data(bez, 1, end_len, end_rad); - double start_off = 1, end_off = 1; // correction of the lengths of the tangent to the offset if (!Geom::are_near(start_rad, 0)) - start_off += width / start_rad; + start_off += (width + width_correction) / start_rad; if (!Geom::are_near(end_rad, 0)) - end_off += width / end_rad; + end_off += (width + width_correction) / end_rad; + + // We don't change the direction of the control points + if (start_off < 0) { + start_off = 0; + } + if (end_off < 0) { + end_off = 0; + } start_off *= start_len; end_off *= end_len; // -------- @@ -787,23 +787,137 @@ void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, dou mid2_new = Geom::Point(end_new[X] - mid2_new[X]/3., end_new[Y] - mid2_new[Y]/3.); // create the estimate curve - Geom::CubicBezier c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new); + c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new); + + // check the tolerance for our estimate to be a parallel curve + + double worst_residual = 0; + for (size_t ii = 3; ii <= 7; ii+=2) { + const double t = static_cast<double>(ii) / 10; + const Geom::Point req = bez.pointAt(t); + const Geom::Point chk = c.pointAt(c.nearestTime(req)); + const double current_residual = (chk-req).length() - std::abs(width); + if (std::abs(current_residual) > std::abs(worst_residual)) { + worst_residual = current_residual; + } + } + return worst_residual; +} + +void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels) +{ + using Geom::X; + using Geom::Y; + + const Geom::Point start_pos = bez.initialPoint(); + const Geom::Point end_pos = bez.finalPoint(); + + const Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0)); + const Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.)); + + // offset the start and end control points out by the width + const Geom::Point start_new = start_pos + start_normal*width; + const Geom::Point end_new = end_pos + end_normal*width; + + // -------- + double start_rad, end_rad; + double start_len, end_len; // tangent lengths + get_cubic_data(bez, 0, start_len, start_rad); + get_cubic_data(bez, 1, end_len, end_rad); + + + Geom::CubicBezier c; + + double best_width_correction = 0; + double best_residual = _offset_cubic_stable_sub( + bez, c, + start_normal, end_normal, + start_new, end_new, + start_rad, end_rad, + start_len, end_len, + width, best_width_correction); + double stepsize = std::abs(width)/2; + bool seen_success = false; + double stepsize_threshold = 0; + // std::cout << "Residual from " << best_residual << " "; + size_t ii = 0; + for (; ii < 100 && stepsize > stepsize_threshold; ++ii) { + bool success = false; + const double width_correction = best_width_correction - (best_residual > 0 ? 1 : -1) * stepsize; + Geom::CubicBezier current_curve; + const double residual = _offset_cubic_stable_sub( + bez, current_curve, + start_normal, end_normal, + start_new, end_new, + start_rad, end_rad, + start_len, end_len, + width, width_correction); + if (std::abs(residual) < std::abs(best_residual)) { + best_residual = residual; + best_width_correction = width_correction; + c = current_curve; + success = true; + if (std::abs(best_residual) < tol/4) { + break; + } + } + + if (success) { + if (!seen_success) { + seen_success = true; + //std::cout << "Stepsize factor: " << std::abs(width) / stepsize << std::endl; + stepsize_threshold = stepsize / 1000; + } + } + else { + stepsize /= 2; + } + if (std::abs(best_width_correction) >= std::abs(width)/2) { + //break; // Seems to prevent some numerical instabilities, not clear if useful + } + } // reached maximum recursive depth // don't bother with any more correction if (levels == 0) { - p.append(c); + try { + p.append(c); + } + catch (...) { + if ((p.finalPoint() - c.initialPoint()).length() < 1e-6) { + c.setInitial(p.finalPoint()); + } + else { + auto line = Geom::LineSegment(p.finalPoint(), c.initialPoint()); + p.append(line); + } + p.append(c); + } + return; } - // check the tolerance for our estimate to be a parallel curve - Geom::Point chk = c.pointAt(.5); - Geom::Point req = bez.pointAt(.5) + Geom::rot90(bez.unitTangentAt(.5))*width; // required accuracy - - Geom::Point const diff = req - chk; - double const err = Geom::dot(diff, diff); + // We find the point on our new curve (c) for which the distance between + // (c) and (bez) differs the most from the desired distance (width). + double worst_err = std::abs(best_residual); + double worst_time = .5; + for (size_t ii = 1; ii <= 9; ++ii) { + const double t = static_cast<double>(ii) / 10; + const Geom::Point req = bez.pointAt(t); + // We use the exact solution with nearestTime because it is numerically + // much more stable than simply assuming that the point on (c) closest + // to bez.pointAt(t) is given by c.pointAt(t) + const Geom::Point chk = c.pointAt(c.nearestTime(req)); + + Geom::Point const diff = req - chk; + const double err = std::abs(diff.length() - std::abs(width)); + if (err > worst_err) { + worst_err = err; + worst_time = t; + } + } - if (err < tol) { + if (worst_err < tol) { if (Geom::are_near(start_new, p.finalPoint())) { p.setFinal(start_new); // if it isn't near, we throw } @@ -813,7 +927,7 @@ void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, dou return; } else { // split the curve in two - std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(.5); + std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(worst_time); offset_cubic(p, s.first, width, tol, levels - 1); offset_cubic(p, s.second, width, tol, levels - 1); } @@ -831,9 +945,8 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi offset_cubic(p, cub, width, tol, levels); } -void offset_curve(Geom::Path& res, Geom::Curve const* current, double width) +void offset_curve(Geom::Path& res, Geom::Curve const* current, double width, double tolerance) { - double const tolerance = 0.0025; size_t levels = 8; if (current->isDegenerate()) return; // don't do anything @@ -859,14 +972,14 @@ void offset_curve(Geom::Path& res, Geom::Curve const* current, double width) default: { Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), tolerance); for (size_t i = 0; i < sbasis_path.size(); ++i) - offset_curve(res, &sbasis_path[i], width); + offset_curve(res, &sbasis_path[i], width, tolerance); break; } } } else { Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), 0.1); for (size_t i = 0; i < sbasis_path.size(); ++i) - offset_curve(res, &sbasis_path[i], width); + offset_curve(res, &sbasis_path[i], width, tolerance); } } @@ -906,13 +1019,19 @@ void peak_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path con namespace Inkscape { -Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join, LineCapType butt) +Geom::PathVector outline( + Geom::Path const& input, + double width, + double miter, + LineJoinType join, + LineCapType butt, + double tolerance) { if (input.size() == 0) return Geom::PathVector(); // nope, don't even try Geom::PathBuilder res; - Geom::Path with_dir = half_outline(input, width/2., miter, join); - Geom::Path against_dir = half_outline(input.reversed(), width/2., miter, join); + Geom::Path with_dir = half_outline(input, width/2., miter, join, tolerance); + Geom::Path against_dir = half_outline(input.reversed(), width/2., miter, join, tolerance); res.moveTo(with_dir[0].initialPoint()); res.append(with_dir); @@ -951,8 +1070,21 @@ Geom::PathVector outline(Geom::Path const& input, double width, double miter, Li return res.peek(); } -Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join) +Geom::Path half_outline( + Geom::Path const& input, + double width, + double miter, + LineJoinType join, + double tolerance) { + if (tolerance <= 0) { + if (std::abs(width) > 0) { + tolerance = 5.0 * (std::abs(width)/100); + } + else { + tolerance = 1e-4; + } + } Geom::Path res; if (input.size() == 0) return res; @@ -967,12 +1099,13 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin res.start(start); // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well - const size_t k = (input.back_closed().isDegenerate() && input.closed()) - ?input.size_default()-1:input.size_default(); + const Geom::Curve &closingline = input.back_closed(); + const size_t k = (are_near(closingline.initialPoint(), closingline.finalPoint()) && input.closed() ) + ?input.size_open():input.size_default(); for (size_t u = 0; u < k; u += 2) { temp.clear(); - offset_curve(temp, &input[u], width); + offset_curve(temp, &input[u], width, tolerance); // on the first run through, there isn't a join if (u == 0) { @@ -985,12 +1118,11 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin // odd number of paths if (u < k - 1) { temp.clear(); - offset_curve(temp, &input[u+1], width); + offset_curve(temp, &input[u+1], width, tolerance); tangents(tang, input[u], input[u+1]); outline_join(res, temp, tang[0], tang[1], width, miter, join); } } - if (input.closed()) { Geom::Curve const &c1 = res.back(); Geom::Curve const &c2 = res.front(); @@ -1002,7 +1134,6 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin outline_join(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); - // res.append(temp); res.close(); } @@ -1014,9 +1145,8 @@ void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, { if (res.size() == 0 || temp.size() == 0) return; - Geom::Curve const& outgoing = temp.front(); - if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { + if (Geom::are_near(res.finalPoint(), outgoing.initialPoint(), 0.01)) { // if the points are /that/ close, just ignore this one res.setFinal(temp.initialPoint()); res.append(temp); diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h index 6a753a6fd..4e4b8b91e 100644 --- a/src/helper/geom-pathstroke.h +++ b/src/helper/geom-pathstroke.h @@ -42,12 +42,19 @@ enum LineCapType { * @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. * @param[in] join Line join type used during offset. Member of LineJoinType enum. * @param[in] cap Line cap type used during stroking. Member of LineCapType enum. + * @param[in] tolerance Tolerance, values smaller than 0 lead to automatic tolerance depending on width. * * @return Stroked path. * If the input path is closed, the resultant vector will contain two paths. * Otherwise, there should be only one in the output. */ -Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT); +Geom::PathVector outline( + Geom::Path const& input, + double width, + double miter, + LineJoinType join = JOIN_BEVEL, + LineCapType cap = BUTT_FLAT, + double tolerance = -1); /** * Offset the input path by @a width. @@ -57,10 +64,16 @@ Geom::PathVector outline(Geom::Path const& input, double width, double miter, Li * @param[in] width Amount to offset. * @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. * @param[in] join Line join type used during offset. Member of LineJoinType enum. + * @param[in] tolerance Tolerance, values smaller than 0 lead to automatic tolerance depending on width. * * @return Offsetted output. */ -Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL); +Geom::Path half_outline( + Geom::Path const& input, + double width, + double miter, + LineJoinType join = JOIN_BEVEL, + double tolerance = -1); /** * Builds a join on the provided path. diff --git a/src/helper/geom-pathvectorsatellites.cpp b/src/helper/geom-pathvectorsatellites.cpp new file mode 100644 index 000000000..e995c0a9b --- /dev/null +++ b/src/helper/geom-pathvectorsatellites.cpp @@ -0,0 +1,244 @@ +/** + * \file + * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector + */ /* + * Authors: + * Jabiertxof + * Nathan Hurst + * Johan Engelen + * Josh Andler + * suv + * Mc- + * Liam P. White + * Krzysztof Kosiński + * This code is in public domain + */ + +#include <helper/geom-pathvectorsatellites.h> +#include "util/units.h" + +Geom::PathVector PathVectorSatellites::getPathVector() const +{ + return _pathvector; +} + +void PathVectorSatellites::setPathVector(Geom::PathVector pathv) +{ + _pathvector = pathv; +} + +Satellites PathVectorSatellites::getSatellites() +{ + return _satellites; +} + +void PathVectorSatellites::setSatellites(Satellites satellites) +{ + _satellites = satellites; +} + +size_t PathVectorSatellites::getTotalSatellites() +{ + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + counter++; + } + } + return counter; +} + +std::pair<size_t, size_t> PathVectorSatellites::getIndexData(size_t index) +{ + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if (index == counter) { + return std::make_pair(i,j); + } + counter++; + } + } + return std::make_pair(0,0); +} + +void PathVectorSatellites::setSelected(std::vector<size_t> selected) +{ + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if (find (selected.begin(), selected.end(), counter) != selected.end()) { + _satellites[i][j].setSelected(true); + } else { + _satellites[i][j].setSelected(false); + } + counter++; + } + } +} + +void PathVectorSatellites::updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected) +{ + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + if (only_selected) { + if (_satellites[i][j].selected) { + _satellites[i][j].steps = steps; + } + } else { + _satellites[i][j].steps = steps; + } + } + } +} + +void PathVectorSatellites::updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected, + bool use_knot_distance, bool flexible) +{ + double power = 0; + if (!flexible) { + power = radius; + } else { + power = radius / 100; + } + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + boost::optional<size_t> previous_index = boost::none; + if (j == 0 && _pathvector[i].closed()) { + previous_index = _pathvector[i].size() - 1; + } else if (!_pathvector[i].closed() || j != 0) { + previous_index = j - 1; + } + if (!_pathvector[i].closed() && j == 0) { + _satellites[i][j].amount = 0; + continue; + } + if (_pathvector[i].size() == j) { + continue; + } + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + + Geom::Point satellite_point = _pathvector[i].pointAt(j); + if (_satellites[i][j].selected || !only_selected) { + if (!use_knot_distance && !flexible) { + if (previous_index) { + _satellites[i][j].amount = _satellites[i][j].radToLen(power, _pathvector[i][*previous_index], _pathvector[i][j]); + if (power && !_satellites[i][j].amount) { + g_warning("Seems a too high radius value"); + } + } else { + _satellites[i][j].amount = 0.0; + } + } else { + _satellites[i][j].amount = power; + } + } + } + } +} + +void PathVectorSatellites::convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius) +{ + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if (!_pathvector[i].closed() && j == 0) { + _satellites[i][j].amount = 0; + continue; + } + if (_pathvector[i].size() == j) { + continue; + } + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + _satellites[i][j].amount = Inkscape::Util::Quantity::convert(_satellites[i][j].amount, in.c_str(), to.c_str()); + } + } +} + +void PathVectorSatellites::updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius, + bool only_selected) +{ + for (size_t i = 0; i < _satellites.size(); ++i) { + for (size_t j = 0; j < _satellites[i].size(); ++j) { + if ((!apply_no_radius && _satellites[i][j].amount == 0) || + (!apply_with_radius && _satellites[i][j].amount != 0)) + { + continue; + } + if (_pathvector[i].size() == j) { + if (!only_selected) { + _satellites[i][j].satellite_type = satellitetype; + } + continue; + } + if (only_selected) { + Geom::Point satellite_point = _pathvector[i].pointAt(j); + if (_satellites[i][j].selected) { + _satellites[i][j].satellite_type = satellitetype; + } + } else { + _satellites[i][j].satellite_type = satellitetype; + } + } + } +} + +void PathVectorSatellites::recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S) +{ + Satellites satellites; + bool found = false; + //TODO evaluate fix on nodes at same position + size_t number_nodes = pathv.nodes().size(); + size_t previous_number_nodes = _pathvector.nodes().size(); + for (size_t i = 0; i < pathv.size(); i++) { + std::vector<Satellite> path_satellites; + for (size_t j = 0; j < pathv[i].size_closed(); j++) { + found = false; + for (size_t k = 0; k < _pathvector.size(); k++) { + for (size_t l = 0; l < _pathvector[k].size_closed(); l++) { + if (Geom::are_near(_pathvector[k][l].initialPoint(), pathv[i][j].initialPoint())) + { + path_satellites.push_back(_satellites[k][l]); + found = true; + break; + } + } + if (found) { + break; + } + } + + if (!found && previous_number_nodes < number_nodes) { + path_satellites.push_back(S); + } + } + satellites.push_back(path_satellites); + } + setPathVector(pathv); + setSatellites(satellites); +} + +/* + 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 +// : diff --git a/src/helper/geom-pathvectorsatellites.h b/src/helper/geom-pathvectorsatellites.h new file mode 100644 index 000000000..d86e6cb25 --- /dev/null +++ b/src/helper/geom-pathvectorsatellites.h @@ -0,0 +1,58 @@ +/** + * \file + * \brief PathVectorSatellites a class to manage satellites -per node extra data- in a pathvector + */ /* + * Authors: + * Jabiertxof + * Nathan Hurst + * Johan Engelen + * Josh Andler + * suv + * Mc- + * Liam P. White + * Krzysztof Kosiński + * This code is in public domain + */ + +#ifndef SEEN_PATHVECTORSATELLITES_H +#define SEEN_PATHVECTORSATELLITES_H + +#include <helper/geom-satellite.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> + +typedef std::vector<std::vector<Satellite> > Satellites; +///@brief PathVectorSatellites a class to manage satellites in a pathvector +class PathVectorSatellites { +public: + Geom::PathVector getPathVector() const; + void setPathVector(Geom::PathVector pathv); + Satellites getSatellites(); + void setSatellites(Satellites satellites); + size_t getTotalSatellites(); + void setSelected(std::vector<size_t> selected); + void updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected); + void updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected, + bool use_knot_distance, bool flexible); + void convertUnit(Glib::ustring in, Glib::ustring to, bool apply_no_radius, bool apply_with_radius); + void updateSatelliteType(SatelliteType satellitetype, bool apply_no_radius, bool apply_with_radius, bool only_selected); + std::pair<size_t, size_t> getIndexData(size_t index); + void recalculateForNewPathVector(Geom::PathVector const pathv, Satellite const S); +private: + Geom::PathVector _pathvector; + Satellites _satellites; +}; + +#endif //SEEN_PATHVECTORSATELLITES_H +/* + 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 +// : diff --git a/src/helper/geom-satellite.cpp b/src/helper/geom-satellite.cpp new file mode 100644 index 000000000..8a92273d0 --- /dev/null +++ b/src/helper/geom-satellite.cpp @@ -0,0 +1,245 @@ +/** + * \file + * \brief Satellite a per node holder of data. + */ /* + * Authors: + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * + * This code is in public domain + */ + +#include <helper/geom-satellite.h> +#include <2geom/curve.h> +#include <2geom/nearest-time.h> +#include <2geom/path-intersection.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/ray.h> +#include <boost/optional.hpp> +//log cache +#ifdef _WIN32 +#include <Windows.h> +#else +#include <sys/time.h> +#include <ctime> +#endif + +///@brief Satellite a per node holder of data. +Satellite::Satellite() {} + + +Satellite::Satellite(SatelliteType satellite_type) + : satellite_type(satellite_type), + is_time(false), + selected(false), + has_mirror(false), + hidden(true), + amount(0.0), + angle(0.0), + steps(0) +{} + +Satellite::~Satellite() {} + +///Calculate the time in curve_in with a size of A +//TODO: find a better place to it +double timeAtArcLength(double const A, Geom::Curve const &curve_in) +{ + if ( A == 0 || curve_in.isDegenerate()) { + return 0; + } + + Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis(); + double t = 0; + double length_part = curve_in.length(); + if (A >= length_part || curve_in.isLineSegment()) { + if (length_part != 0) { + t = A / length_part; + } + } else if (!curve_in.isLineSegment()) { + std::vector<double> t_roots = roots(Geom::arcLengthSb(d2_in) - A); + if (!t_roots.empty()) { + t = t_roots[0]; + } + } + return t; +} + +///Calculate the size in curve_in with a point at A +//TODO: find a better place to it +double arcLengthAt(double const A, Geom::Curve const &curve_in) +{ + if ( A == 0 || curve_in.isDegenerate()) { + return 0; + } + + double s = 0; + double length_part = curve_in.length(); + if (A > length_part || curve_in.isLineSegment()) { + s = (A * length_part); + } else if (!curve_in.isLineSegment()) { + Geom::Curve *curve = curve_in.portion(0.0, A); + s = curve->length(); + delete curve; + } + return s; +} + +///Convert a arc radius of a fillet/chamfer to his satellite length -point position where fillet/chamfer knot be on original curve +double Satellite::radToLen( + double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out) const +{ + double len = 0; + Geom::D2<Geom::SBasis> d2_in = curve_in.toSBasis(); + Geom::D2<Geom::SBasis> d2_out = curve_out.toSBasis(); + Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve0 = + Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_in) + + rot90(unitVector(derivative(d2_in))) * (A); + Geom::Piecewise<Geom::D2<Geom::SBasis> > offset_curve1 = + Geom::Piecewise<Geom::D2<Geom::SBasis> >(d2_out) + + rot90(unitVector(derivative(d2_out))) * (A); + Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0]; + Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0]; + Geom::Crossings cs = Geom::crossings(p0, p1); + if (cs.size() > 0) { + Geom::Point cp = p0(cs[0].ta); + double p0pt = nearest_time(cp, curve_out); + len = arcLengthAt(p0pt, curve_out); + } else { + if (A > 0) { + len = radToLen(A * -1, curve_in, curve_out); + } + } + return len; +} + +///Convert a satelite length -point position where fillet/chamfer knot be on original curve- to a arc radius of fillet/chamfer +double Satellite::lenToRad( + double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out, + Satellite const previousSatellite) const +{ + double time_in = (previousSatellite).time(A, true, curve_in); + double time_out = timeAtArcLength(A, curve_out); + Geom::Point start_arc_point = curve_in.pointAt(time_in); + Geom::Point end_arc_point = curve_out.pointAt(time_out); + Geom::Curve *knot_curve1 = curve_in.portion(0, time_in); + Geom::Curve *knot_curve2 = curve_out.portion(time_out, 1); + Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve1); + Geom::Ray ray1(start_arc_point, curve_in.pointAt(1)); + if (cubic1) { + ray1.setPoints((*cubic1)[2], start_arc_point); + } + Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve2); + Geom::Ray ray2(curve_out.pointAt(0), end_arc_point); + if (cubic2) { + ray2.setPoints(end_arc_point, (*cubic2)[1]); + } + bool ccw_toggle = cross(curve_in.pointAt(1) - start_arc_point, + end_arc_point - start_arc_point) < 0; + double distance_arc = + Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)); + double angle = angle_between(ray1, ray2, ccw_toggle); + double divisor = std::sin(angle / 2.0); + if (divisor > 0) { + return distance_arc / divisor; + } + return 0; +} + +///Get the time position of the satellite in curve_in +double Satellite::time(Geom::Curve const &curve_in, bool inverse) const +{ + double t = amount; + if (!is_time) { + t = time(t, inverse, curve_in); + } else if (inverse) { + t = 1-t; + } + if (t > 1) { + t = 1; + } + return t; +} + +///Get the time from a length A in other curve, a bolean inverse gived to reverse time +double Satellite::time(double A, bool inverse, + Geom::Curve const &curve_in) const +{ + if (A == 0 && inverse) { + return 1; + } + if (A == 0 && !inverse) { + return 0; + } + if (!inverse) { + return timeAtArcLength(A, curve_in); + } + double length_part = curve_in.length(); + A = length_part - A; + return timeAtArcLength(A, curve_in); +} + +///Get the length of the satellite in curve_in +double Satellite::arcDistance(Geom::Curve const &curve_in) const +{ + double s = amount; + if (is_time) { + s = arcLengthAt(s, curve_in); + } + return s; +} + +///Get the point position of the satellite +Geom::Point Satellite::getPosition(Geom::Curve const &curve_in, bool inverse) const +{ + double t = time(curve_in, inverse); + return curve_in.pointAt(t); +} + +///Set the position of the satellite from a gived point P +void Satellite::setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse) +{ + Geom::Curve * curve = const_cast<Geom::Curve *>(&curve_in); + if (inverse) { + curve = curve->reverse(); + } + double A = Geom::nearest_time(p, *curve); + if (!is_time) { + A = arcLengthAt(A, *curve); + } + amount = A; +} + + +///Map a satellite type with gchar +void Satellite::setSatelliteType(gchar const *A) +{ + std::map<std::string, SatelliteType> gchar_map_to_satellite_type = + boost::assign::map_list_of("F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE); + std::map<std::string, SatelliteType>::iterator it = gchar_map_to_satellite_type.find(std::string(A)); + if (it != gchar_map_to_satellite_type.end()) { + satellite_type = it->second; + } +} + +///Map a gchar with satelliteType +gchar const *Satellite::getSatelliteTypeGchar() const +{ + std::map<SatelliteType, gchar const *> satellite_type_to_gchar_map = + boost::assign::map_list_of(FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO"); + return satellite_type_to_gchar_map.at(satellite_type); +} + +/* + 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 +// : diff --git a/src/helper/geom-satellite.h b/src/helper/geom-satellite.h new file mode 100644 index 000000000..b8ca2a490 --- /dev/null +++ b/src/helper/geom-satellite.h @@ -0,0 +1,110 @@ +/** + * \file + * \brief Satellite a per node holder of data. + */ /* + * Authors: + * 2015 Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * + * This code is in public domain + */ + +#ifndef SEEN_SATELLITE_H +#define SEEN_SATELLITE_H + +#include <map> +#include <boost/assign.hpp> +#include <2geom/sbasis-geometric.h> +#include "util/enums.h" + + +enum SatelliteType { + FILLET = 0, //Fillet + INVERSE_FILLET, //Inverse Fillet + CHAMFER, //Chamfer + INVERSE_CHAMFER, //Inverse Chamfer + INVALID_SATELLITE // Invalid Satellite +}; +/** + * @brief Satellite a per node holder of data. + */ + +class Satellite { +public: + + Satellite(); + Satellite(SatelliteType satellite_type); + + virtual ~Satellite(); + void setIsTime(bool set_is_time) + { + is_time = set_is_time; + } + void setSelected(bool set_selected) + { + selected = set_selected; + } + void setHasMirror(bool set_has_mirror) + { + has_mirror = set_has_mirror; + } + void setHidden(bool set_hidden) + { + hidden = set_hidden; + } + void setAmount(double set_amount) + { + amount = set_amount; + } + void setAngle(double set_angle) + { + angle = set_angle; + } + void setSteps(size_t set_steps) + { + steps = set_steps; + } + double lenToRad(double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out, + Satellite const previousSatellite) const; + double radToLen(double const A, Geom::Curve const &curve_in, + Geom::Curve const &curve_out) const; + + double time(Geom::Curve const &curve_in, bool inverse = false) const; + double time(double A, bool inverse, Geom::Curve const &curve_in) const; + double arcDistance(Geom::Curve const &curve_in) const; + + void setPosition(Geom::Point const p, Geom::Curve const &curve_in, bool inverse = false); + Geom::Point getPosition(Geom::Curve const &curve_in, bool inverse = false) const; + + void setSatelliteType(gchar const *A); + gchar const *getSatelliteTypeGchar() const; + SatelliteType satellite_type; + //The value stored could be a time value of the satellite in the curve or a lenght of distance to the node from the satellite + //"is_time" tell is if is a time or lenght value + bool is_time; + bool selected; + bool has_mirror; + bool hidden; + //in "amount" we store the time or distance used in the satellite + double amount; + double angle; + size_t steps; +}; + +double timeAtArcLength(double const A, Geom::Curve const &curve_in); +double arcLengthAt(double const A, Geom::Curve const &curve_in); + +#endif // SEEN_SATELLITE_H + +/* + 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 +// : diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index ecb330b01..e1f05c3ce 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -12,15 +12,8 @@ #include <algorithm> #include "helper/geom.h" #include "helper/geom-curves.h" -#include <typeinfo> -#include <2geom/pathvector.h> -#include <2geom/path.h> #include <2geom/curves.h> -#include <2geom/transforms.h> -#include <2geom/rect.h> -#include <2geom/coord.h> #include <2geom/sbasis-to-bezier.h> -#include <math.h> // for M_PI using Geom::X; using Geom::Y; @@ -850,6 +843,13 @@ recursive_bezier4(const double x1, const double y1, recursive_bezier4(x1234, y1234, x234, y234, x34, y34, x4, y4, m_points, level + 1); } +void +swap(Geom::Point &A, Geom::Point &B){ + Geom::Point tmp = A; + A = B; + B = tmp; +} + /* Local Variables: mode:c++ diff --git a/src/helper/geom.h b/src/helper/geom.h index d49e2070c..b3d907e51 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -32,7 +32,7 @@ void recursive_bezier4(const double x1, const double y1, const double x2, const const double x3, const double y3, const double x4, const double y4, std::vector<Geom::Point> &pointlist, int level); - +void swap(Geom::Point &A, Geom::Point &B); #endif // INKSCAPE_HELPER_GEOM_H /* diff --git a/src/helper/gettext.cpp b/src/helper/gettext.cpp new file mode 100644 index 000000000..91dfdbcb8 --- /dev/null +++ b/src/helper/gettext.cpp @@ -0,0 +1,110 @@ +/** + * \file + * \brief helper functions for gettext + *//* + * Authors: + * Eduard Braun <eduard.braun2@gmx.de> + * + * Copyright 2017 Authors + * + * This file is part of Inkscape. + * + * Inkscape is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Inkscape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Inkscape. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef WIN32 +#include <windows.h> +#endif + +#include <string> +#include <glibmm.h> +#include <glibmm/i18n.h> + +namespace Inkscape { + +/** does all required gettext initialization and takes care of the respective locale directory paths */ +void initialize_gettext() { +#ifdef WIN32 + gchar *datadir = g_win32_get_package_installation_directory_of_module(NULL); + + // obtain short path to executable dir and pass it + // to bindtextdomain (it doesn't understand UTF-8) + gchar *shortdatadir = g_win32_locale_filename_from_utf8(datadir); + gchar *localepath = g_build_filename(shortdatadir, PACKAGE_LOCALE_DIR, NULL); + bindtextdomain(GETTEXT_PACKAGE, localepath); + g_free(shortdatadir); + g_free(localepath); + + g_free(datadir); +#else +# ifdef ENABLE_BINRELOC + bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR("")); +# else + bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); + // needed by Python/Gettext + g_setenv("PACKAGE_LOCALE_DIR", PACKAGE_LOCALE_DIR, TRUE); +# endif +#endif + + // Allow the user to override the locale directory by setting + // the environment variable INKSCAPE_LOCALEDIR. + char const *inkscape_localedir = g_getenv("INKSCAPE_LOCALEDIR"); + if (inkscape_localedir != NULL) { + bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir); + } + + // common setup + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); +} + +/** set gettext codeset to UTF8 */ +void bind_textdomain_codeset_utf8() { + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); +} + +/** set gettext codeset to codeset of the system console + * - on *nix this is typically the current locale, + * - on Windows we don't care and simply use UTF8 + * any conversion would need to happen in our console wrappers (see winconsole.cpp) anyway + * as we have no easy way of determining console encoding from inkscape/inkview.exe process; + * for now do something even easier - switch console encoding to UTF8 and be done with it! + * this also works nicely on MSYS consoles where UTF8 encoding is used by default, too */ +void bind_textdomain_codeset_console() { +#ifdef WIN32 + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); +#else + std::string charset; + Glib::get_charset(charset); + bind_textdomain_codeset(GETTEXT_PACKAGE, charset.c_str()); +#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:
\ No newline at end of file diff --git a/src/helper/gettext.h b/src/helper/gettext.h new file mode 100644 index 000000000..689bddbbb --- /dev/null +++ b/src/helper/gettext.h @@ -0,0 +1,46 @@ +/** + * \file + * \brief helper functions for gettext + *//* + * Authors: + * Eduard Braun <eduard.braun2@gmx.de> + * + * Copyright 2017 Authors + * + * This file is part of Inkscape. + * + * Inkscape is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Inkscape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Inkscape. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SEEN_GETTEXT_HELPER_H +#define SEEN_GETTEXT_HELPER_H + +namespace Inkscape { + void initialize_gettext(); + void bind_textdomain_codeset_utf8(); + void bind_textdomain_codeset_console(); +} + +#endif // SEEN_GETTEXT_HELPER_H + +/* + 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:
\ No newline at end of file diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index 9639096fb..bab998fdb 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -12,10 +12,9 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include <config.h> #endif -#include <png.h> #include <boost/scoped_ptr.hpp> #include <2geom/transforms.h> @@ -24,11 +23,8 @@ #include "display/cairo-utils.h" #include "display/drawing.h" #include "display/drawing-context.h" -#include "display/drawing-item.h" #include "document.h" -#include "sp-item.h" #include "sp-root.h" -#include "sp-use.h" #include "sp-defs.h" #include "util/units.h" @@ -53,8 +49,8 @@ static void hide_other_items_recursively(SPObject *o, GSList *list, unsigned dke // recurse if (!g_slist_find(list, o)) { - for ( SPObject *child = o->firstChild() ; child; child = child->getNext() ) { - hide_other_items_recursively(child, list, dkey); + for (auto& child: o->children) { + hide_other_items_recursively(&child, list, dkey); } } } diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 9430feeff..e06c539d3 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -14,19 +14,17 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include <config.h> #endif #include <png.h> #include "ui/interface.h" #include <2geom/rect.h> #include <2geom/transforms.h> -#include <glib.h> #include "png-write.h" #include "io/sys.h" #include "display/drawing.h" #include "display/drawing-context.h" -#include "display/drawing-item.h" #include "document.h" #include "sp-item.h" #include "sp-root.h" @@ -125,8 +123,8 @@ void PngTextList::add(gchar const* key, gchar const* text) static bool sp_png_write_rgba_striped(SPDocument *doc, gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi, - int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data), - void *data) + int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth, int antialias), + void *data, bool interlace, int color_type, int bit_depth, int zlib, int antialiasing) { g_return_val_if_fail(filename != NULL, false); g_return_val_if_fail(data != NULL, false); @@ -186,22 +184,28 @@ sp_png_write_rgba_striped(SPDocument *doc, * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ + + png_set_compression_level(png_ptr, zlib); + png_set_IHDR(png_ptr, info_ptr, width, height, - 8, /* bit_depth */ - PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, + bit_depth, + color_type, + interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - /* otherwise, if we are dealing with a color image then */ - sig_bit.red = 8; - sig_bit.green = 8; - sig_bit.blue = 8; - /* if the image has an alpha channel then */ - sig_bit.alpha = 8; - png_set_sBIT(png_ptr, info_ptr, &sig_bit); + if ((color_type&2) && bit_depth == 16) { + // otherwise, if we are dealing with a color image then + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + // if the image has an alpha channel then + if (color_type&4) + sig_bit.alpha = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + } PngTextList textList; @@ -250,7 +254,10 @@ sp_png_write_rgba_striped(SPDocument *doc, /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ /* note that if sRGB is present the cHRM chunk must be ignored * on read and must be written in accordance with the sRGB profile */ - png_set_pHYs(png_ptr, info_ptr, unsigned(xdpi / 0.0254 + 0.5), unsigned(ydpi / 0.0254 + 0.5), PNG_RESOLUTION_METER); + if(xdpi < 0.0254 ) xdpi = 0.0255; + if(ydpi < 0.0254 ) ydpi = 0.0255; + + png_set_pHYs(png_ptr, info_ptr, unsigned(xdpi / 0.0254 ), unsigned(ydpi / 0.0254 ), PNG_RESOLUTION_METER); /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); @@ -273,15 +280,18 @@ sp_png_write_rgba_striped(SPDocument *doc, */ png_bytep* row_pointers = new png_bytep[ebp->sheight]; - - r = 0; - while (r < static_cast<png_uint_32>(height)) { - void *to_free; - int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data); - if (!n) break; - png_write_rows(png_ptr, row_pointers, n); - g_free(to_free); - r += n; + int number_of_passes = interlace ? png_set_interlace_handling(png_ptr) : 1; + + for(int i=0;i<number_of_passes; ++i){ + r = 0; + while (r < static_cast<png_uint_32>(height)) { + void *to_free; + int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data, color_type, bit_depth, antialiasing); + if (!n) break; + png_write_rows(png_ptr, row_pointers, n); + g_free(to_free); + r += n; + } } delete[] row_pointers; @@ -310,7 +320,7 @@ sp_png_write_rgba_striped(SPDocument *doc, * */ static int -sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data) +sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth, int antialiasing) { struct SPEBP *ebp = (struct SPEBP *) data; @@ -342,18 +352,17 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v dc.setOperator(CAIRO_OPERATOR_OVER); /* Render */ - ebp->drawing->render(dc, bbox); + ebp->drawing->render(dc, bbox, 0, antialiasing); cairo_surface_destroy(s); - *to_free = px; - // PNG stores data as unpremultiplied big-endian RGBA, which means // it's identical to the GdkPixbuf format. convert_pixels_argb32_to_pixbuf(px, ebp->width, num_rows, stride); - - for (int r = 0; r < num_rows; r++) { - rows[r] = px + r * stride; - } + + // If a custom bit depth or color type is asked, then convert rgb to grayscale, etc. + const guchar* new_data = pixbuf_to_png(rows, px, num_rows, ebp->width, stride, color_type, bit_depth); + *to_free = (void*) new_data; + free(px); return num_rows; } @@ -374,8 +383,8 @@ static void hide_other_items_recursively(SPObject *o, const std::vector<SPItem*> // recurse 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); + for (auto& child: o->children) { + hide_other_items_recursively(&child, list, dkey); } } } @@ -387,10 +396,10 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned int (*status) (float, void *), void *data, bool force_overwrite, - const std::vector<SPItem*> &items_only) + const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib, int antialiasing) { 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); + width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only, interlace, color_type, bit_depth, zlib, antialiasing); } ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, @@ -399,7 +408,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned (*status)(float, void *), void *data, bool force_overwrite, - const std::vector<SPItem*> &items_only) + const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib, int antialiasing) { g_return_val_if_fail(doc != NULL, EXPORT_ERROR); g_return_val_if_fail(filename != NULL, EXPORT_ERROR); @@ -470,7 +479,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, ebp.px = g_try_new(guchar, 4 * ebp.sheight * width); if (ebp.px) { - write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp); + write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp, interlace, color_type, bit_depth, zlib, antialiasing); g_free(ebp.px); } diff --git a/src/helper/png-write.h b/src/helper/png-write.h index 2657fb635..06498f46e 100644 --- a/src/helper/png-write.h +++ b/src/helper/png-write.h @@ -34,12 +34,14 @@ 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, const std::vector<SPItem*> &items_only = std::vector<SPItem*>()); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>(), + bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6, int antialiasing = 2); 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, const std::vector<SPItem*> &items_only = std::vector<SPItem*>()); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>(), + bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6, int antialiasing = 2); #endif // SEEN_SP_PNG_WRITE_H diff --git a/src/helper/stock-items.cpp b/src/helper/stock-items.cpp index 5a56b89ff..647e42916 100644 --- a/src/helper/stock-items.cpp +++ b/src/helper/stock-items.cpp @@ -204,37 +204,37 @@ SPObject *get_stock_item(gchar const *urn, gboolean stock) } SPObject *object = NULL; if (!strcmp(base, "marker") && !stock) { - for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) + for (auto& child: defs->children) { - if (child->getRepr()->attribute("inkscape:stockid") && - !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && - SP_IS_MARKER(child)) + if (child.getRepr()->attribute("inkscape:stockid") && + !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) && + SP_IS_MARKER(&child)) { - object = child; + object = &child; } } } else if (!strcmp(base,"pattern") && !stock) { - for ( SPObject *child = defs->firstChild() ; child; child = child->getNext() ) + for (auto& child: defs->children) { - if (child->getRepr()->attribute("inkscape:stockid") && - !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && - SP_IS_PATTERN(child)) + if (child.getRepr()->attribute("inkscape:stockid") && + !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) && + SP_IS_PATTERN(&child)) { - object = child; + object = &child; } } } else if (!strcmp(base,"gradient") && !stock) { - for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) + for (auto& child: defs->children) { - if (child->getRepr()->attribute("inkscape:stockid") && - !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && - SP_IS_GRADIENT(child)) + if (child.getRepr()->attribute("inkscape:stockid") && + !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) && + SP_IS_GRADIENT(&child)) { - object = child; + object = &child; } } |
