diff options
| author | schwieni <mschwienbacher@gmail.com> | 2019-03-12 21:56:50 +0000 |
|---|---|---|
| committer | Markus Schwienbacher <mschwienbacher@gmail.com> | 2019-03-25 17:15:50 +0000 |
| commit | c6c398af81ea30b0ab2a58afe7d11ccd28155e7b (patch) | |
| tree | 920f42e2b9cae5efcd4d26f3e48cca5067dd83dc /src | |
| parent | lpe-pts2ellipse: added Steiner ellipse and inellipse generation from three po... (diff) | |
| download | inkscape-c6c398af81ea30b0ab2a58afe7d11ccd28155e7b.tar.gz inkscape-c6c398af81ea30b0ab2a58afe7d11ccd28155e7b.zip | |
lpe-pts2ellipse: added Steiner ellipse and inellipse generation from three points.
Did some minor cleanup too.
Added me to the AUTHORS file.
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-pts2ellipse.cpp | 168 | ||||
| -rw-r--r-- | src/live_effects/lpe-pts2ellipse.h | 36 |
2 files changed, 85 insertions, 119 deletions
diff --git a/src/live_effects/lpe-pts2ellipse.cpp b/src/live_effects/lpe-pts2ellipse.cpp index f9e23d68a..80f1b6004 100644 --- a/src/live_effects/lpe-pts2ellipse.cpp +++ b/src/live_effects/lpe-pts2ellipse.cpp @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /** \file * LPE "Points to Ellipse" implementation */ @@ -8,22 +9,22 @@ * * Copyright (C) Markus Schwienbacher 2013 <mschwienbacher@gmail.com> * - * Released under GNU GPL, read the file 'COPYING' for more information + * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "live_effects/lpe-pts2ellipse.h" -#include <object/sp-shape.h> +#include <object/sp-item-group.h> #include <object/sp-item.h> #include <object/sp-path.h> -#include <object/sp-item-group.h> +#include <object/sp-shape.h> #include <svg/svg.h> -#include <2geom/path.h> #include <2geom/circle.h> #include <2geom/ellipse.h> -#include <2geom/pathvector.h> #include <2geom/elliptical-arc.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> #include <glib/gi18n.h> @@ -31,26 +32,28 @@ namespace Inkscape { namespace LivePathEffect { static const Util::EnumData<EllipseMethod> EllipseMethodData[] = { - { EM_AUTO, N_("Auto ellipse"), "auto" }, //!< (2..4 points: circle, from 5 points: ellipse) - { EM_CIRCLE, N_("Force circle"), "circle" }, //!< always fit a circle - { EM_ISOMETRIC_CIRCLE, N_("Isometric circle"), "iso_circle" }, //!< use first two edges to generate a sheared ellipse - { EM_STEINER_ELLIPSE, N_("Steiner ellipse"), "steiner_ellipse" }, //!< generate a steiner ellipse from the first three points - { EM_STEINER_INELLIPSE, N_("Steiner inellipse"), "steiner_inellipse" } //!< generate a steiner inellipse from the first three points + { EM_AUTO, N_("Auto ellipse"), "auto" }, //!< (2..4 points: circle, from 5 points: ellipse) + { EM_CIRCLE, N_("Force circle"), "circle" }, //!< always fit a circle + { EM_ISOMETRIC_CIRCLE, N_("Isometric circle"), "iso_circle" }, //!< use first two edges to generate a sheared + //!< ellipse + { EM_STEINER_ELLIPSE, N_("Steiner ellipse"), "steiner_ellipse" }, //!< generate a steiner ellipse from the first + //!< three points + { EM_STEINER_INELLIPSE, N_("Steiner inellipse"), "steiner_inellipse" } //!< generate a steiner inellipse from the + //!< first three points }; static const Util::EnumDataConverter<EllipseMethod> EMConverter(EllipseMethodData, EM_END); -LPEPts2Ellipse::LPEPts2Ellipse(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - method(_("Method:"), _("Methods to generate the ellipse"), - "method", EMConverter, &wr, this, EM_AUTO), - gen_isometric_frame(_("_Frame (isometric rectangle)"), _("Draw parallelogram around the ellipse"), - "gen_isometric_frame", &wr, this, false), - gen_arc(_("_Arc"), _("Generate open arc (open ellipse)"), "gen_arc", &wr, this, false), - other_arc(_("_Other Arc side"), _("Switch sides of the arc"), "arc_other", &wr, this, false), - slice_arc(_("_Slice Arc"), _("Slice the arc"), "slice_arc", &wr, this, false), - draw_axes(_("A_xes"), _("Draw both semi-major and semi-minor axes"), "draw_axes", &wr, this, false), - rot_axes(_("Axes Rotation"), _("Axes rotation angle [deg]"), "rot_axes", &wr, this, 0), - draw_ori_path(_("Source _Path"), _("Show the original source path"), "draw_ori_path", &wr, this, false) +LPEPts2Ellipse::LPEPts2Ellipse(LivePathEffectObject *lpeobject) + : Effect(lpeobject) + , method(_("Method:"), _("Methods to generate the ellipse"), "method", EMConverter, &wr, this, EM_AUTO) + , gen_isometric_frame(_("_Frame (isometric rectangle)"), _("Draw parallelogram around the ellipse"), + "gen_isometric_frame", &wr, this, false) + , gen_arc(_("_Arc"), _("Generate open arc (open ellipse)"), "gen_arc", &wr, this, false) + , other_arc(_("_Other Arc side"), _("Switch sides of the arc"), "arc_other", &wr, this, false) + , slice_arc(_("_Slice Arc"), _("Slice the arc"), "slice_arc", &wr, this, false) + , draw_axes(_("A_xes"), _("Draw both semi-major and semi-minor axes"), "draw_axes", &wr, this, false) + , rot_axes(_("Axes Rotation"), _("Axes rotation angle [deg]"), "rot_axes", &wr, this, 0) + , draw_ori_path(_("Source _Path"), _("Show the original source path"), "draw_ori_path", &wr, this, false) { registerParameter(&method); registerParameter(&gen_arc); @@ -67,13 +70,10 @@ LPEPts2Ellipse::LPEPts2Ellipse(LivePathEffectObject *lpeobject) : show_orig_path = true; } -LPEPts2Ellipse::~LPEPts2Ellipse() -{ -} +LPEPts2Ellipse::~LPEPts2Ellipse() = default; // helper function, transforms a given value into range [0, 2pi] -inline double -range2pi(double a) +inline double range2pi(double a) { a = fmod(a, 2 * M_PI); if (a < 0) { @@ -82,23 +82,14 @@ range2pi(double a) return a; } -inline double -deg2rad(double a) -{ - return a * M_PI / 180.0; -} +inline double deg2rad(double a) { return a * M_PI / 180.0; } -inline double -rad2deg(double a) -{ - return a * 180.0 / M_PI; -} +inline double rad2deg(double a) { return a * 180.0 / M_PI; } // helper function, calculates the angle between a0 and a1 in ccw sense // examples: 0..1->1, -1..1->2, pi/4..-pi/4->1.5pi // full rotations: 0..2pi->2pi, -pi..pi->2pi, pi..-pi->0, 2pi..0->0 -inline double -calc_delta_angle(const double a0, const double a1) +inline double calc_delta_angle(const double a0, const double a1) { double da = range2pi(a1 - a0); if ((fabs(da) < 1e-9) && (a0 < a1)) { @@ -107,10 +98,8 @@ calc_delta_angle(const double a0, const double a1) return da; } -int -unit_arc_path(Geom::Path &path_in, Geom::Affine &affine, - double start = 0.0, double end = 2 * M_PI, // angles - bool slice = false) +int unit_arc_path(Geom::Path &path_in, Geom::Affine &affine, double start = 0.0, double end = 2 * M_PI, // angles + bool slice = false) { double arc_angle = calc_delta_angle(start, end); if (fabs(arc_angle) < 1e-9) { @@ -170,8 +159,7 @@ unit_arc_path(Geom::Path &path_in, Geom::Affine &affine, return 0; } -void -gen_iso_frame_paths(Geom::PathVector &path_out, const Geom::Affine &affine) +void gen_iso_frame_paths(Geom::PathVector &path_out, const Geom::Affine &affine) { Geom::Path rect(Geom::Point(-1, -1)); rect.setStitching(true); @@ -183,8 +171,7 @@ gen_iso_frame_paths(Geom::PathVector &path_out, const Geom::Affine &affine) path_out.push_back(rect); } -void -gen_axes_paths(Geom::PathVector &path_out, const Geom::Affine &affine) +void gen_axes_paths(Geom::PathVector &path_out, const Geom::Affine &affine) { Geom::LineSegment clx(Geom::Point(-1, 0), Geom::Point(1, 0)); Geom::LineSegment cly(Geom::Point(0, -1), Geom::Point(0, 1)); @@ -199,8 +186,7 @@ gen_axes_paths(Geom::PathVector &path_out, const Geom::Affine &affine) path_out.push_back(ply); } -bool -is_ccw(const std::vector<Geom::Point> &pts) +bool is_ccw(const std::vector<Geom::Point> &pts) { // method: sum up the angles between edges size_t n = pts.size(); @@ -227,8 +213,8 @@ is_ccw(const std::vector<Geom::Point> &pts) } } -void -endpoints2angles(const bool ccw_wind, const bool use_other_arc, const Geom::Point &p0, const Geom::Point &p1, Geom::Coord &a0, Geom::Coord &a1) +void endpoints2angles(const bool ccw_wind, const bool use_other_arc, const Geom::Point &p0, const Geom::Point &p1, + Geom::Coord &a0, Geom::Coord &a1) { if (!p0.isZero() && !p1.isZero()) { a0 = atan2(p0); @@ -247,8 +233,7 @@ endpoints2angles(const bool ccw_wind, const bool use_other_arc, const Geom::Poin * algorithms from 2geom. Depending on the settings made by the user regarding things like arc, * slice, circle etc. the final result will be different */ -Geom::PathVector -LPEPts2Ellipse::doEffect_path(Geom::PathVector const &path_in) +Geom::PathVector LPEPts2Ellipse::doEffect_path(Geom::PathVector const &path_in) { Geom::PathVector path_out; @@ -260,12 +245,12 @@ LPEPts2Ellipse::doEffect_path(Geom::PathVector const &path_in) // from: extension/internal/odf.cpp // get all points std::vector<Geom::Point> pts; - for (Geom::PathVector::const_iterator pit = path_in.begin(); pit != path_in.end(); ++pit) { + for(const auto & pit : path_in) { // extract first point of this path - pts.push_back(pit->initialPoint()); + pts.push_back(pit.initialPoint()); // iterate over all curves - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end(); ++cit) { - pts.push_back(cit->finalPoint()); + for (const auto &cit : pit) { + pts.push_back(cit.finalPoint()); } } @@ -277,19 +262,22 @@ LPEPts2Ellipse::doEffect_path(Geom::PathVector const &path_in) // special mode: Use first two edges, interpret them as two sides of a parallelogram and // generate an ellipse residing inside the parallelogram. This effect is quite useful when // generating isometric views. Hence, the name. - switch(method) { + switch (method) { case EM_ISOMETRIC_CIRCLE: if (0 != genIsometricEllipse(pts, path_out)) { return path_in; - } break; + } + break; case EM_STEINER_ELLIPSE: if (0 != genSteinerEllipse(pts, false, path_out)) { return path_in; - } break; + } + break; case EM_STEINER_INELLIPSE: if (0 != genSteinerEllipse(pts, true, path_out)) { return path_in; - } break; + } + break; default: if (0 != genFitEllipse(pts, path_out)) { return path_in; @@ -304,9 +292,7 @@ LPEPts2Ellipse::doEffect_path(Geom::PathVector const &path_in) * slice, circle etc. the final result will be different. We need at least 5 points to fit an * ellipse. With 5 points each point is on the ellipse. For less points we get a circle. */ -int -LPEPts2Ellipse::genFitEllipse(std::vector<Geom::Point> const &pts, - Geom::PathVector &path_out) +int LPEPts2Ellipse::genFitEllipse(std::vector<Geom::Point> const &pts, Geom::PathVector &path_out) { // rotation angle based on user provided rot_axes to position the vertices const double rot_angle = -deg2rad(rot_axes); // negative for ccw rotation @@ -331,7 +317,7 @@ LPEPts2Ellipse::genFitEllipse(std::vector<Geom::Point> const &pts, Geom::Path path; unit_arc_path(path, affine); path_out.push_back(path); - } else if (pts.size() >= 5 && EM_AUTO == method) { //!only_circle.get_value()) { + } else if (pts.size() >= 5 && EM_AUTO == method) { //! only_circle.get_value()) { // do ellipse try { Geom::Ellipse ellipse; @@ -392,9 +378,7 @@ LPEPts2Ellipse::genFitEllipse(std::vector<Geom::Point> const &pts, return 0; } -int -LPEPts2Ellipse::genIsometricEllipse(std::vector<Geom::Point> const &pts, - Geom::PathVector &path_out) +int LPEPts2Ellipse::genIsometricEllipse(std::vector<Geom::Point> const &pts, Geom::PathVector &path_out) { // take the first 3 vertices for the edges @@ -457,64 +441,56 @@ LPEPts2Ellipse::genIsometricEllipse(std::vector<Geom::Point> const &pts, return 0; } -void -evalSteinerEllipse(Geom::Point const &pCenter, - Geom::Point const &pCenter_Pt2, - Geom::Point const &pPt0_Pt1, - const double &angle, - Geom::Point &pRes) +void evalSteinerEllipse(Geom::Point const &pCenter, Geom::Point const &pCenter_Pt2, Geom::Point const &pPt0_Pt1, + const double &angle, Geom::Point &pRes) { // formula for the evaluation of points on the steiner ellipse using parameter angle - pRes = pCenter - + pCenter_Pt2*cos(angle) - + pPt0_Pt1*sin(angle)/sqrt(3); + pRes = pCenter + pCenter_Pt2 * cos(angle) + pPt0_Pt1 * sin(angle) / sqrt(3); } -int -LPEPts2Ellipse::genSteinerEllipse(std::vector<Geom::Point> const &pts, - bool gen_inellipse, - Geom::PathVector &path_out) +int LPEPts2Ellipse::genSteinerEllipse(std::vector<Geom::Point> const &pts, bool gen_inellipse, + Geom::PathVector &path_out) { // take the first 3 vertices for the edges if (pts.size() < 3) { return -1; } // calc center - Geom::Point pCenter = (pts[0]+pts[1]+pts[2])/3; + Geom::Point pCenter = (pts[0] + pts[1] + pts[2]) / 3; // calc main directions of affine triangle - Geom::Point f1 = pts[2]-pCenter; - Geom::Point f2 = (pts[1]-pts[0])/sqrt(3); + Geom::Point f1 = pts[2] - pCenter; + Geom::Point f2 = (pts[1] - pts[0]) / sqrt(3); // calc zero angle t0 const double denominator = dot(f1, f1) - dot(f2, f2); - double t0=0; - if(fabs(denominator) > 1e-12) { + double t0 = 0; + if (fabs(denominator) > 1e-12) { const double cot2t0 = 2.0 * dot(f1, f2) / denominator; - t0 = atan(cot2t0)/2.0; + t0 = atan(cot2t0) / 2.0; } // calc relative points of main axes (for axis directions) - Geom::Point p0(0,0), pRel0, pRel1; - evalSteinerEllipse(p0, pts[2]-pCenter, pts[1]-pts[0], t0, pRel0); - evalSteinerEllipse(p0, pts[2]-pCenter, pts[1]-pts[0], t0+M_PI_2, pRel1); + Geom::Point p0(0, 0), pRel0, pRel1; + evalSteinerEllipse(p0, pts[2] - pCenter, pts[1] - pts[0], t0, pRel0); + evalSteinerEllipse(p0, pts[2] - pCenter, pts[1] - pts[0], t0 + M_PI_2, pRel1); Geom::Coord l0 = pRel0.length(); Geom::Coord l1 = pRel1.length(); // basic rotation double a0 = atan2(pRel0); - bool swapped=false; + bool swapped = false; if (l1 > l0) { - std::swap(l0,l1); + std::swap(l0, l1); a0 += M_PI_2; swapped = true; } // the steiner inellipse is just scaled down by 2 - if(gen_inellipse) { - l0/=2; - l1/=2; + if (gen_inellipse) { + l0 /= 2; + l1 /= 2; } // rotation angle based on user provided rot_axes to position the vertices @@ -547,7 +523,7 @@ LPEPts2Ellipse::genSteinerEllipse(std::vector<Geom::Point> const &pts, /* ######################## */ -} //namespace LivePathEffect +} // namespace LivePathEffect } /* namespace Inkscape */ /* diff --git a/src/live_effects/lpe-pts2ellipse.h b/src/live_effects/lpe-pts2ellipse.h index 1a4844893..46722aa86 100644 --- a/src/live_effects/lpe-pts2ellipse.h +++ b/src/live_effects/lpe-pts2ellipse.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later #ifndef INKSCAPE_LPE_PTS_TO_ELLIPSE_H #define INKSCAPE_LPE_PTS_TO_ELLIPSE_H @@ -11,7 +12,7 @@ * * Copyright (C) Markus Schwienbacher 2013 <mschwienbacher@gmail.com> * - * Released under GNU GPL, read the file 'COPYING' for more information + * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "live_effects/effect.h" @@ -23,36 +24,25 @@ namespace Inkscape { namespace LivePathEffect { -enum EllipseMethod { - EM_AUTO, - EM_CIRCLE, - EM_ISOMETRIC_CIRCLE, - EM_STEINER_ELLIPSE, - EM_STEINER_INELLIPSE, - EM_END -}; +enum EllipseMethod { EM_AUTO, EM_CIRCLE, EM_ISOMETRIC_CIRCLE, EM_STEINER_ELLIPSE, EM_STEINER_INELLIPSE, EM_END }; class LPEPts2Ellipse : public Effect { -public: - explicit LPEPts2Ellipse(LivePathEffectObject *lpeobject); + public: + LPEPts2Ellipse(LivePathEffectObject *lpeobject); ~LPEPts2Ellipse() override; Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override; -private: - LPEPts2Ellipse(const LPEPts2Ellipse &); - LPEPts2Ellipse &operator=(const LPEPts2Ellipse &); + private: + LPEPts2Ellipse(const LPEPts2Ellipse &) = delete; + LPEPts2Ellipse &operator=(const LPEPts2Ellipse &) = delete; - int genIsometricEllipse(std::vector<Geom::Point> const &points_in, - Geom::PathVector &path_out); + int genIsometricEllipse(std::vector<Geom::Point> const &points_in, Geom::PathVector &path_out); - int genFitEllipse(std::vector<Geom::Point> const &points_in, - Geom::PathVector &path_out); + int genFitEllipse(std::vector<Geom::Point> const &points_in, Geom::PathVector &path_out); - int genSteinerEllipse(std::vector<Geom::Point> const &points_in, - bool gen_inellipse, - Geom::PathVector &path_out); + int genSteinerEllipse(std::vector<Geom::Point> const &points_in, bool gen_inellipse, Geom::PathVector &path_out); EnumParam<EllipseMethod> method; BoolParam gen_isometric_frame; @@ -66,8 +56,8 @@ private: std::vector<Geom::Point> points; }; -} //namespace LivePathEffect -} //namespace Inkscape +} // namespace LivePathEffect +} // namespace Inkscape #endif |
