summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--src/live_effects/lpe-pts2ellipse.cpp481
-rw-r--r--src/live_effects/lpe-pts2ellipse.h27
3 files changed, 309 insertions, 200 deletions
diff --git a/AUTHORS b/AUTHORS
index 55f154b9f..a0dd0b560 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -143,6 +143,7 @@ Felipe Corrêa da Silva Sanches
Christian Schaller
Marco Scholten
Tom von Schwerdtner
+Markus Schwienbacher
Danilo Šegan
Abhishek Sharma
Tim Sheridan
diff --git a/src/live_effects/lpe-pts2ellipse.cpp b/src/live_effects/lpe-pts2ellipse.cpp
index 48655b25a..f9e23d68a 100644
--- a/src/live_effects/lpe-pts2ellipse.cpp
+++ b/src/live_effects/lpe-pts2ellipse.cpp
@@ -1,4 +1,3 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
/** \file
* LPE "Points to Ellipse" implementation
*/
@@ -9,7 +8,7 @@
*
* Copyright (C) Markus Schwienbacher 2013 <mschwienbacher@gmail.com>
*
- * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ * Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "live_effects/lpe-pts2ellipse.h"
@@ -19,7 +18,6 @@
#include <object/sp-path.h>
#include <object/sp-item-group.h>
#include <svg/svg.h>
-#include <display/curve.h>
#include <2geom/path.h>
#include <2geom/circle.h>
@@ -29,15 +27,15 @@
#include <glib/gi18n.h>
-using namespace Geom;
-
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" },
- { EM_ISONOMETRIC_CIRCLE, N_("Isometric circle"), "iso_circle" }
+ { 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);
@@ -45,11 +43,11 @@ 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(_("_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),
+ 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)
@@ -63,34 +61,37 @@ LPEPts2Ellipse::LPEPts2Ellipse(LivePathEffectObject *lpeobject) :
registerParameter(&rot_axes);
registerParameter(&draw_ori_path);
- rot_axes.param_set_range(-360,360);
- rot_axes.param_set_increments(1,10);
+ rot_axes.param_set_range(-360, 360);
+ rot_axes.param_set_increments(1, 10);
- show_orig_path=true;
+ show_orig_path = true;
}
LPEPts2Ellipse::~LPEPts2Ellipse()
-= default;
+{
+}
// helper function, transforms a given value into range [0, 2pi]
inline double
range2pi(double a)
{
- a = fmod(a, 2*M_PI);
- if(a<0) a+=2*M_PI;
+ a = fmod(a, 2 * M_PI);
+ if (a < 0) {
+ a += 2 * M_PI;
+ }
return a;
}
inline double
deg2rad(double a)
{
- return a*M_PI/180.0;
+ return a * M_PI / 180.0;
}
inline double
rad2deg(double a)
{
- return a*180.0/M_PI;
+ return a * 180.0 / M_PI;
}
// helper function, calculates the angle between a0 and a1 in ccw sense
@@ -99,88 +100,85 @@ rad2deg(double a)
inline double
calc_delta_angle(const double a0, const double a1)
{
- double da=range2pi(a1-a0);
- if((fabs(da)<1e-9) && (a0<a1))
- da=2*M_PI;
+ double da = range2pi(a1 - a0);
+ if ((fabs(da) < 1e-9) && (a0 < a1)) {
+ da = 2 * M_PI;
+ }
return da;
}
int
-unit_arc_path(Geom::Path &path, Geom::Affine &affine,
- double start=0.0, double end=2*M_PI, // angles
- bool slice=false)
+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);
+ double arc_angle = calc_delta_angle(start, end);
if (fabs(arc_angle) < 1e-9) {
g_warning("angle was 0");
return -1;
}
// the delta angle
- double da=M_PI_2;
+ double da = M_PI_2;
// number of segments with da length
- int nda=(int)ceil(arc_angle/M_PI_2);
+ int nda = (int)ceil(arc_angle / M_PI_2);
// recalculate da
- da=arc_angle/(double)nda;
+ da = arc_angle / (double)nda;
- bool closed=false;
- if (fabs(arc_angle - 2*M_PI) < 1e-8) {
+ bool closed = false;
+ if (fabs(arc_angle - 2 * M_PI) < 1e-8) {
closed = true;
- da=M_PI_2;
- nda=4;
+ da = M_PI_2;
+ nda = 4;
}
- start = range2pi(start);
- end=start+arc_angle;
+ double s = range2pi(start);
+ end = s + arc_angle;
- // adopted from: sp-ellipse.cpp
- SPCurve * curve=new SPCurve();
- // start point
- curve->moveto(cos(start), sin(start));
- double s = start;
- for (int i=0; i < nda; s = (++i)*da+start) {
+ double x0 = cos(s);
+ double y0 = sin(s);
+ // construct the path
+ Geom::Path path(Geom::Point(x0, y0));
+ path.setStitching(true);
+ for (int i = 0; i < nda;) {
double e = s + da;
- if (e > end)
+ if (e > end) {
e = end;
- const double len = 4*tan((e - s)/4)/3;
- const double x0 = cos(s);
- const double y0 = sin(s);
+ }
+ const double len = 4 * tan((e - s) / 4) / 3;
const double x1 = x0 + len * cos(s + M_PI_2);
const double y1 = y0 + len * sin(s + M_PI_2);
const double x3 = cos(e);
const double y3 = sin(e);
const double x2 = x3 + len * cos(e - M_PI_2);
const double y2 = y3 + len * sin(e - M_PI_2);
- curve->curveto(x1,y1, x2,y2, x3,y3);
+ path.appendNew<Geom::CubicBezier>(Geom::Point(x1, y1), Geom::Point(x2, y2), Geom::Point(x3, y3));
+ s = (++i) * da + start;
+ x0 = cos(s);
+ y0 = sin(s);
}
if (slice && !closed) {
- curve->lineto(0., 0.);
+ path.appendNew<Geom::LineSegment>(Geom::Point(0.0, 0.0));
}
- curve->transform(affine);
+ path *= affine;
- path.append(*curve->first_path());
+ path_in.append(path);
if ((slice && !closed) || closed) {
- path.close(true);
+ path_in.close(true);
}
- // give to GC
- curve->unref();
return 0;
}
void
gen_iso_frame_paths(Geom::PathVector &path_out, const Geom::Affine &affine)
{
- Geom::Path rect;
- SPCurve curve;
- // unit rectangle
- curve.moveto(-1, -1);
- curve.lineto(1, -1);
- curve.lineto(1, 1);
- curve.lineto(-1, 1);
- //curve.transform(Rotate(-rot_angle)*affine);
- curve.transform(affine);
- rect.append(*curve.first_path());
+ Geom::Path rect(Geom::Point(-1, -1));
+ rect.setStitching(true);
+ rect.appendNew<Geom::LineSegment>(Geom::Point(+1, -1));
+ rect.appendNew<Geom::LineSegment>(Geom::Point(+1, +1));
+ rect.appendNew<Geom::LineSegment>(Geom::Point(-1, +1));
+ rect *= affine;
rect.close(true);
path_out.push_back(rect);
}
@@ -188,57 +186,58 @@ gen_iso_frame_paths(Geom::PathVector &path_out, const Geom::Affine &affine)
void
gen_axes_paths(Geom::PathVector &path_out, const Geom::Affine &affine)
{
- LineSegment clx(Point(-1,0),Point(1,0));
- LineSegment cly(Point(0,-1),Point(0,1));
+ Geom::LineSegment clx(Geom::Point(-1, 0), Geom::Point(1, 0));
+ Geom::LineSegment cly(Geom::Point(0, -1), Geom::Point(0, 1));
Geom::Path plx, ply;
plx.append(clx);
ply.append(cly);
- plx*=affine;
- ply*=affine;
+ plx *= affine;
+ ply *= affine;
path_out.push_back(plx);
path_out.push_back(ply);
}
bool
-is_ccw(const std::vector<Geom::Point> & pts)
+is_ccw(const std::vector<Geom::Point> &pts)
{
// method: sum up the angles between edges
- size_t n=pts.size();
+ size_t n = pts.size();
// edges about vertex 0
- Point e0=pts.front()-pts.back();
- Point e1=pts[1]-pts[0];
- Coord sum=cross(e0,e1);
+ Geom::Point e0(pts.front() - pts.back());
+ Geom::Point e1(pts[1] - pts[0]);
+ Geom::Coord sum = cross(e0, e1);
// the rest
- for(size_t i=1;i<n;i++) {
- e0=e1;
- e1=pts[i]-pts[i-1];
- sum+=cross(e0,e1);
+ for (size_t i = 1; i < n; i++) {
+ e0 = e1;
+ e1 = pts[i] - pts[i - 1];
+ sum += cross(e0, e1);
}
// edges about last vertex (closing)
- e0=e1;
- e1=pts.front()-pts.back();
- sum+=cross(e0,e1);
+ e0 = e1;
+ e1 = pts.front() - pts.back();
+ sum += cross(e0, e1);
// close the
- if(sum<0)
+ if (sum < 0) {
return true;
- else
+ } else {
return false;
+ }
}
void
-endpoints2angles(const bool ccw_wind, const bool use_other_arc, const Point &p0, const Point &p1, Coord &a0, Coord &a1)
+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);
- a1=atan2(p1);
- if(!ccw_wind) {
- std::swap(a0,a1);
+ if (!p0.isZero() && !p1.isZero()) {
+ a0 = atan2(p0);
+ a1 = atan2(p1);
+ if (!ccw_wind) {
+ std::swap(a0, a1);
}
- if(!use_other_arc) {
- std::swap(a0,a1);
+ if (!use_other_arc) {
+ std::swap(a0, a1);
}
}
}
@@ -249,42 +248,52 @@ endpoints2angles(const bool ccw_wind, const bool use_other_arc, const Point &p0,
* slice, circle etc. the final result will be different
*/
Geom::PathVector
-LPEPts2Ellipse::doEffect_path (Geom::PathVector const & path_in)
+LPEPts2Ellipse::doEffect_path(Geom::PathVector const &path_in)
{
- PathVector path_out;
+ Geom::PathVector path_out;
- if(draw_ori_path.get_value()){
- path_out.insert(path_out.end(),path_in.begin(),path_in.end());
+ if (draw_ori_path.get_value()) {
+ path_out.insert(path_out.end(), path_in.begin(), path_in.end());
}
// from: extension/internal/odf.cpp
// get all points
- std::vector<Point> pts;
- for(const auto & pit : path_in) {
+ std::vector<Geom::Point> pts;
+ for (Geom::PathVector::const_iterator pit = path_in.begin(); pit != path_in.end(); ++pit) {
// extract first point of this path
- pts.push_back(pit.initialPoint());
+ pts.push_back(pit->initialPoint());
// iterate over all curves
- for (const auto & cit : pit) {
- pts.push_back(cit.finalPoint());
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end(); ++cit) {
+ pts.push_back(cit->finalPoint());
}
}
// avoid identical start-point and end-point
- if(pts.front() == pts.back()) {
+ if (pts.front() == pts.back()) {
pts.pop_back();
}
// 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.
- //if(gen_isometric.get_value())
- if(method == EM_ISONOMETRIC_CIRCLE) {
- if(0!=genIsometricEllipse (pts, path_out))
- return path_in;
- } else {
- if(0!=genFitEllipse(pts, path_out))
- return path_in;
+ switch(method) {
+ case EM_ISOMETRIC_CIRCLE:
+ if (0 != genIsometricEllipse(pts, path_out)) {
+ return path_in;
+ } break;
+ case EM_STEINER_ELLIPSE:
+ if (0 != genSteinerEllipse(pts, false, path_out)) {
+ return path_in;
+ } break;
+ case EM_STEINER_INELLIPSE:
+ if (0 != genSteinerEllipse(pts, true, path_out)) {
+ return path_in;
+ } break;
+ default:
+ if (0 != genFitEllipse(pts, path_out)) {
+ return path_in;
+ }
}
return path_out;
}
@@ -296,164 +305,258 @@ LPEPts2Ellipse::doEffect_path (Geom::PathVector const & path_in)
* 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)
+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
- Affine affine;
- affine*=Rotate(rot_angle);
- Coord a0=0;
- Coord a1=2*M_PI;
-
- if(pts.size()<2) {
+ Geom::Affine affine;
+ affine *= Geom::Rotate(rot_angle);
+ Geom::Coord a0 = 0;
+ Geom::Coord a1 = 2 * M_PI;
+
+ if (pts.size() < 2) {
return -1;
- } else if(pts.size()==2) {
+ } else if (pts.size() == 2) {
// simple line: circle in the middle of the line to the vertices
- Point line=pts.front()-pts.back();
- double radius=line.length()*0.5;
- if(radius<1e-9)
+ Geom::Point line = pts.front() - pts.back();
+ double radius = line.length() * 0.5;
+ if (radius < 1e-9) {
return -1;
- Point center=middle_point(pts.front(),pts.back());
- Circle circle(center[0],center[1],radius);
- affine*=Scale(circle.radius());
- affine*=Translate(circle.center());
+ }
+ Geom::Point center = middle_point(pts.front(), pts.back());
+ Geom::Circle circle(center[0], center[1], radius);
+ affine *= Geom::Scale(circle.radius());
+ affine *= Geom::Translate(circle.center());
Geom::Path path;
- unit_arc_path(path,affine);
+ 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 {
- Ellipse ellipse;
+ Geom::Ellipse ellipse;
ellipse.fit(pts);
- affine*=Scale(ellipse.ray(X),ellipse.ray(Y));
- affine*=Rotate(ellipse.rotationAngle());
- affine*=Translate(ellipse.center());
- if(gen_arc.get_value()) {
- Affine inv_affine=affine.inverse();
- Point p0=pts.front()*inv_affine;
- Point p1=pts.back()*inv_affine;
- const bool ccw_wind=is_ccw(pts);
- endpoints2angles(ccw_wind,other_arc.get_value(),p0,p1,a0,a1);
+ affine *= Geom::Scale(ellipse.ray(Geom::X), ellipse.ray(Geom::Y));
+ affine *= Geom::Rotate(ellipse.rotationAngle());
+ affine *= Geom::Translate(ellipse.center());
+ if (gen_arc.get_value()) {
+ Geom::Affine inv_affine = affine.inverse();
+ Geom::Point p0 = pts.front() * inv_affine;
+ Geom::Point p1 = pts.back() * inv_affine;
+ const bool ccw_wind = is_ccw(pts);
+ endpoints2angles(ccw_wind, other_arc.get_value(), p0, p1, a0, a1);
}
Geom::Path path;
- unit_arc_path(path,affine,a0,a1,slice_arc.get_value());
+ unit_arc_path(path, affine, a0, a1, slice_arc.get_value());
path_out.push_back(path);
- if(draw_axes.get_value()) {
- gen_axes_paths(path_out,affine);
+ if (draw_axes.get_value()) {
+ gen_axes_paths(path_out, affine);
}
- } catch(...) {
+ } catch (...) {
return -1;
}
} else {
// do a circle (3,4 points, or only_circle set)
try {
- Circle circle;
+ Geom::Circle circle;
circle.fit(pts);
- affine*=Scale(circle.radius());
- affine*=Translate(circle.center());
-
- if(gen_arc.get_value())
- {
- Point p0=pts.front()-circle.center();
- Point p1=pts.back()-circle.center();
- const bool ccw_wind=is_ccw(pts);
- endpoints2angles(ccw_wind,other_arc.get_value(),p0,p1,a0,a1);
+ affine *= Geom::Scale(circle.radius());
+ affine *= Geom::Translate(circle.center());
+
+ if (gen_arc.get_value()) {
+ Geom::Point p0 = pts.front() - circle.center();
+ Geom::Point p1 = pts.back() - circle.center();
+ const bool ccw_wind = is_ccw(pts);
+ endpoints2angles(ccw_wind, other_arc.get_value(), p0, p1, a0, a1);
}
Geom::Path path;
- unit_arc_path(path,affine,a0,a1,slice_arc.get_value());
+ unit_arc_path(path, affine, a0, a1, slice_arc.get_value());
path_out.push_back(path);
- } catch(...) {
+ } catch (...) {
return -1;
}
}
// draw frame?
- if(gen_isometric_frame.get_value()) {
- gen_iso_frame_paths(path_out,affine);
+ if (gen_isometric_frame.get_value()) {
+ gen_iso_frame_paths(path_out, affine);
}
// draw axes?
- if(draw_axes.get_value()) {
- gen_axes_paths(path_out,affine);
+ if (draw_axes.get_value()) {
+ gen_axes_paths(path_out, affine);
}
return 0;
}
int
-LPEPts2Ellipse::genIsometricEllipse (std::vector<Geom::Point> const & pts,
- Geom::PathVector & path_out)
+LPEPts2Ellipse::genIsometricEllipse(std::vector<Geom::Point> const &pts,
+ Geom::PathVector &path_out)
{
// take the first 3 vertices for the edges
- if(pts.size() < 3) return -1;
+ if (pts.size() < 3) {
+ return -1;
+ }
// calc edges
- Point e0=pts[0]-pts[1];
- Point e1=pts[2]-pts[1];
+ Geom::Point e0 = pts[0] - pts[1];
+ Geom::Point e1 = pts[2] - pts[1];
- Coord ce=cross(e0,e1);
+ Geom::Coord ce = cross(e0, e1);
// parallel or one is zero?
- if(fabs(ce)<1e-9) return -1;
+ if (fabs(ce) < 1e-9) {
+ return -1;
+ }
// unit vectors along edges
- Point u0=unit_vector(e0);
- Point u1=unit_vector(e1);
+ Geom::Point u0 = unit_vector(e0);
+ Geom::Point u1 = unit_vector(e1);
// calc angles
- Coord a0=atan2(e0);
+ Geom::Coord a0 = atan2(e0);
// Coord a1=M_PI_2-atan2(e1)-a0;
- Coord a1=acos(dot(u0,u1))-M_PI_2;
+ Geom::Coord a1 = acos(dot(u0, u1)) - M_PI_2;
// if(fabs(a1)<1e-9) return -1;
- if(ce<0) a1=-a1;
+ if (ce < 0) {
+ a1 = -a1;
+ }
// lengths: l0= length of edge 0; l1= height of parallelogram
- Coord l0=e0.length()*0.5;
- Point e0n=e1-dot(u0,e1)*u0;
- Coord l1=e0n.length()*0.5;
+ Geom::Coord l0 = e0.length() * 0.5;
+ Geom::Point e0n = e1 - dot(u0, e1) * u0;
+ Geom::Coord l1 = e0n.length() * 0.5;
// center of the ellipse
- Point pos=pts[1]+0.5*(e0+e1);
+ Geom::Point pos = pts[1] + 0.5 * (e0 + e1);
+
+ // rotation angle based on user provided rot_axes to position the vertices
+ const double rot_angle = -deg2rad(rot_axes); // negative for ccw rotation
+
+ // build up the affine transformation
+ Geom::Affine affine;
+ affine *= Geom::Rotate(rot_angle);
+ affine *= Geom::Scale(l0, l1);
+ affine *= Geom::HShear(-tan(a1));
+ affine *= Geom::Rotate(a0);
+ affine *= Geom::Translate(pos);
+
+ Geom::Path path;
+ unit_arc_path(path, affine);
+ path_out.push_back(path);
+
+ // draw frame?
+ if (gen_isometric_frame.get_value()) {
+ gen_iso_frame_paths(path_out, affine);
+ }
+
+ // draw axes?
+ if (draw_axes.get_value()) {
+ gen_axes_paths(path_out, affine);
+ }
+
+ return 0;
+}
+
+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);
+}
+
+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;
+ // calc main directions of affine triangle
+ 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) {
+ const double cot2t0 = 2.0 * dot(f1, f2) / denominator;
+ 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::Coord l0 = pRel0.length();
+ Geom::Coord l1 = pRel1.length();
+
+ // basic rotation
+ double a0 = atan2(pRel0);
+
+ bool swapped=false;
+
+ if (l1 > l0) {
+ 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;
+ }
// rotation angle based on user provided rot_axes to position the vertices
const double rot_angle = -deg2rad(rot_axes); // negative for ccw rotation
// build up the affine transformation
- Affine affine;
- affine*=Rotate(rot_angle);
- affine*=Scale(l0,l1);
- affine*=HShear(-tan(a1));
- affine*=Rotate(a0);
- affine*=Translate(pos);
+ Geom::Affine affine;
+ affine *= Geom::Rotate(rot_angle);
+ affine *= Geom::Scale(l0, l1);
+ affine *= Geom::Rotate(a0);
+ affine *= Geom::Translate(pCenter);
Geom::Path path;
- unit_arc_path(path,affine);
+ unit_arc_path(path, affine);
path_out.push_back(path);
// draw frame?
- if(gen_isometric_frame.get_value()) {
- gen_iso_frame_paths(path_out,affine);
+ if (gen_isometric_frame.get_value()) {
+ gen_iso_frame_paths(path_out, affine);
}
// draw axes?
- if(draw_axes.get_value()) {
- gen_axes_paths(path_out,affine);
+ if (draw_axes.get_value()) {
+ gen_axes_paths(path_out, affine);
}
return 0;
}
+
/* ######################## */
} //namespace LivePathEffect
} /* namespace Inkscape */
- /*
- 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 :
+/*
+ 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 :
diff --git a/src/live_effects/lpe-pts2ellipse.h b/src/live_effects/lpe-pts2ellipse.h
index f9fd90109..1a4844893 100644
--- a/src/live_effects/lpe-pts2ellipse.h
+++ b/src/live_effects/lpe-pts2ellipse.h
@@ -1,4 +1,3 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef INKSCAPE_LPE_PTS_TO_ELLIPSE_H
#define INKSCAPE_LPE_PTS_TO_ELLIPSE_H
@@ -12,7 +11,7 @@
*
* Copyright (C) Markus Schwienbacher 2013 <mschwienbacher@gmail.com>
*
- * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ * Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "live_effects/effect.h"
@@ -27,27 +26,33 @@ namespace LivePathEffect {
enum EllipseMethod {
EM_AUTO,
EM_CIRCLE,
- EM_ISONOMETRIC_CIRCLE,
+ EM_ISOMETRIC_CIRCLE,
+ EM_STEINER_ELLIPSE,
+ EM_STEINER_INELLIPSE,
EM_END
};
class LPEPts2Ellipse : public Effect {
public:
- LPEPts2Ellipse(LivePathEffectObject *lpeobject);
+ explicit LPEPts2Ellipse(LivePathEffectObject *lpeobject);
~LPEPts2Ellipse() override;
- Geom::PathVector doEffect_path (Geom::PathVector const & path_in) override;
+ Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override;
private:
- LPEPts2Ellipse(const LPEPts2Ellipse&) = delete;
- LPEPts2Ellipse& operator=(const LPEPts2Ellipse&) = delete;
+ LPEPts2Ellipse(const LPEPts2Ellipse &);
+ LPEPts2Ellipse &operator=(const LPEPts2Ellipse &);
- 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);
EnumParam<EllipseMethod> method;
BoolParam gen_isometric_frame;