30#include <glib/gi18n.h>
33namespace LivePathEffect {
36 {
EM_AUTO, N_(
"Auto ellipse"),
"auto" },
37 {
EM_CIRCLE, N_(
"Force circle"),
"circle" },
54 _(
"Methods to generate the ellipse\n- Auto ellipse: fits a circle (2, 3 or 4 nodes in the path) or an ellipse (at least 5 "
55 "nodes)\n- Force circle: (at least 2 nodes) always create a circle\n- Isometric circle: (3 nodes) use "
56 "first two segments as edges\n- Perspective circle: (4 nodes) circle in a square in perspective view\n- Steiner "
57 "ellipse: (3 nodes) ellipse on a triangle\n- Steiner inellipse: (3 nodes) ellipse inside a triangle"),
59 , gen_isometric_frame(_(
"_Frame (isometric rectangle)"), _(
"Draw parallelogram around the ellipse"),
60 "gen_isometric_frame", &wr, this, false)
61 , gen_perspective_frame(
62 _(
"_Perspective square"),
63 _(
"Draw square surrounding the circle in perspective view\n(only in method \"Perspective circle\")"),
64 "gen_perspective_frame", &wr, this, false)
66 _(
"Generate open arc (open ellipse) based on first and last node\n(only for methods \"Auto ellipse\" "
67 "and \"Force circle\")"),
68 "gen_arc", &wr, this, false)
69 , other_arc(_(
"_Other arc side"), _(
"Switch sides of the arc"),
"arc_other", &wr, this, false)
70 , slice_arc(_(
"_Slice arc"), _(
"Create a circle / ellipse segment"),
"slice_arc", &wr, this, false)
71 , draw_axes(_(
"A_xes"), _(
"Draw both semi-major and semi-minor axes"),
"draw_axes", &wr, this, false)
72 , draw_perspective_axes(_(
"Perspective axes"),
73 _(
"Draw the axes in perspective view\n(only in method \"Perspective circle\")"),
74 "draw_perspective_axes", &wr, this, false)
75 , rot_axes(_(
"Axes rotation"), _(
"Axes rotation angle [deg]"),
"rot_axes", &wr, this, 0)
76 , draw_ori_path(_(
"Source _path"), _(
"Show the original source path"),
"draw_ori_path", &wr, this, false)
94 gsl_x = gsl_vector_alloc(8);
95 gsl_p = gsl_permutation_alloc(8);
99 gsl_permutation_free(
gsl_p);
100 gsl_vector_free(
gsl_x);
106 a = fmod(a, 2 * M_PI);
113inline double deg2rad(
double a) {
return a * M_PI / 180.0; }
115inline double rad2deg(
double a) {
return a * 180.0 / M_PI; }
123 if ((fabs(da) < 1e-9) && (a0 < a1)) {
132 if (fabs(arc_angle) < 1e-9) {
133 g_warning(
"angle was 0");
140 int nda = (int)ceil(arc_angle / M_PI_2);
142 da = arc_angle / (double)nda;
145 if (fabs(arc_angle - 2 * M_PI) < 1e-8) {
159 for (
int i = 0; i < nda;) {
164 const double len = 4 * tan((e - s) / 4) / 3;
165 const double x1 = x0 +
len *
cos(s + M_PI_2);
166 const double y1 = y0 +
len *
sin(s + M_PI_2);
167 const double x3 =
cos(e);
168 const double y3 =
sin(e);
169 const double x2 = x3 +
len *
cos(e - M_PI_2);
170 const double y2 = y3 +
len *
sin(e - M_PI_2);
172 s = (++i) * da +
start;
177 if (slice && !closed) {
183 if ((slice && !closed) || closed) {
202 double projmatrix[3][3])
204 Geom::Point pts0[4] = { { -1.0, -1.0 }, { +1.0, -1.0 }, { +1.0, +1.0 }, { -1.0, +1.0 } };
209 for (
auto &i : pts0) {
217 for (
int i = 1; i < 4; i++)
239 double projmatrix[3][3])
243 double dA = 2.0 * M_PI / 4.0;
244 for (
auto &i : pts) {
245 const double angle = rot_angle + dA * h++;
265 size_t n = pts.size();
271 for (
size_t i = 1; i < n; i++) {
273 e1 = pts[i] - pts[i - 1];
278 e1 = pts.front() - pts.back();
298 if (!use_other_arc) {
322 for (
const auto &pit : path_in) {
324 points.push_back(pit.initialPoint());
326 for (
const auto &cit : pit) {
327 points.push_back(cit.finalPoint());
415 if (pts.size() < 2) {
417 }
else if (pts.size() == 2) {
420 double radius = line.
length() * 0.5;
443 const bool ccw_wind =
is_ccw(pts);
462 const bool ccw_wind =
is_ccw(pts);
490 if (pts.size() < 3) {
499 if (fabs(ce) < 1e-9) {
553 pRes = pCenter + pCenter_Pt2 *
cos(angle) + pPt0_Pt1 *
sin(angle) /
sqrt(3);
560 if (pts.size() < 3) {
564 Geom::Point pCenter = (pts[0] + pts[1] + pts[2]) / 3;
570 const double denominator =
dot(f1, f1) -
dot(f2, f2);
572 if (fabs(denominator) > 1e-12) {
573 const double cot2t0 = 2.0 *
dot(f1, f2) / denominator;
574 t0 = atan(cot2t0) / 2.0;
585 double a0 =
atan2(pRel0);
587 bool swapped =
false;
633 return Geom::Point(
Geom::Coord((x * m[0][0] + y * m[0][1] + m[0][2]) / (x * m[2][0] + y * m[2][1] + m[2][2])),
634 Geom::Coord((x * m[1][0] + y * m[1][1] + m[1][2]) / (x * m[2][0] + y * m[2][1] + m[2][2])));
647 Geom::Point e[] = { pts[0] - pts[1], pts[1] - pts[2], pts[2] - pts[3], pts[3] - pts[0] };
651 if (!((
c[0] > 0 &&
c[1] > 0 &&
c[2] > 0 &&
c[3] > 0) || (
c[0] < 0 &&
c[1] < 0 &&
c[2] < 0 &&
c[3] < 0)))
658 Geom::Point pts0[4] = { { -1.0, -1.0 }, { +1.0, -1.0 }, { +1.0, +1.0 }, { -1.0, +1.0 } };
661 double eqnVec[8] = { 0 };
662 double eqnMat[64] = { 0 };
663 for (
unsigned int i = 0; i < 4; ++i) {
664 eqnMat[8 * (i + 0) + 0] = pts0[i][
X];
665 eqnMat[8 * (i + 0) + 1] = pts0[i][
Y];
666 eqnMat[8 * (i + 0) + 2] = 1;
667 eqnMat[8 * (i + 0) + 6] = -pts[i][
X] * pts0[i][
X];
668 eqnMat[8 * (i + 0) + 7] = -pts[i][
X] * pts0[i][
Y];
669 eqnMat[8 * (i + 4) + 3] = pts0[i][
X];
670 eqnMat[8 * (i + 4) + 4] = pts0[i][
Y];
671 eqnMat[8 * (i + 4) + 5] = 1;
672 eqnMat[8 * (i + 4) + 6] = -pts[i][
Y] * pts0[i][
X];
673 eqnMat[8 * (i + 4) + 7] = -pts[i][
Y] * pts0[i][
Y];
674 eqnVec[i] = pts[i][
X];
675 eqnVec[i + 4] = pts[i][
Y];
678 gsl_matrix_view m = gsl_matrix_view_array(eqnMat, 8, 8);
679 gsl_vector_view b = gsl_vector_view_array(eqnVec, 8);
681 gsl_linalg_LU_decomp(&m.matrix,
gsl_p, &s);
682 gsl_linalg_LU_solve(&m.matrix,
gsl_p, &b.vector,
gsl_x);
685 double projmatrix[3][3];
686 for (
auto &matRow : projmatrix) {
687 for (
double &matElement : matRow) {
689 projmatrix[2][2] = 1.0;
691 matElement = gsl_vector_get(
gsl_x, h++);
699 double dA = 2.0 * M_PI / 5.0;
701 const double angle = dA * h++;
727 bool ccw_wind =
false;
730 const double ra = ccw_wind ? rot_angle : -rot_angle;
Path - a sequence of contiguous curves.
3x3 matrix representing an affine transformation.
Affine inverse() const
Compute the inverse matrix.
Bezier curve with compile-time specified order.
Set of all points at a fixed distance from the center.
Set of points with a constant sum of distances from two foci.
Angle rotationAngle() const
Get the angle the X ray makes with the +X axis.
void fit(std::vector< Point > const &points)
Create an ellipse passing through the specified points At least five points have to be specified.
Coord ray(Dim2 d) const
Get one ray of the ellipse.
void push_back(Path const &path)
Append a path at the end.
iterator insert(iterator pos, Path const &p)
Sequence of contiguous curves, aka spline.
void setStitching(bool x)
Enable or disable the throwing of exceptions when stitching discontinuities.
void close(bool closed=true)
Set whether the path is closed.
void append(Curve *curve)
Add a new curve to the end of the path.
void appendNew(Args &&... args)
Append a new curve to the path.
Two-dimensional point that doubles as a vector.
constexpr bool isZero() const
Check whether both coordinates are zero.
Coord length() const
Compute the distance from origin.
Rotation around the origin.
void registerParameter(Parameter *param)
std::vector< Geom::Point > five_pts
static Geom::Point projectPoint(Geom::Point p, double m[][3])
static void gen_perspective_frame_paths(Geom::PathVector &path_out, const double rot_angle, double projmatrix[3][3])
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
Generates an ellipse (or circle) from the vertices of a given path.
BoolParam draw_perspective_axes
static void gen_iso_frame_paths(Geom::PathVector &path_out, const Geom::Affine &affine)
int genPerspectiveEllipse(std::vector< Geom::Point > const &points_in, Geom::PathVector &path_out)
static void gen_perspective_axes_paths(Geom::PathVector &path_out, const double rot_angle, double projmatrix[3][3])
BoolParam gen_isometric_frame
BoolParam gen_perspective_frame
int genIsometricEllipse(std::vector< Geom::Point > const &points_in, Geom::PathVector &path_out)
std::vector< Geom::Point > points
static int unit_arc_path(Geom::Path &path_in, Geom::Affine &affine, double start=0.0, double end=2.0 *M_PI, bool slice=false)
int genFitEllipse(std::vector< Geom::Point > const &points_in, Geom::PathVector &path_out)
Generates an ellipse (or circle) from the vertices of a given path.
int genSteinerEllipse(std::vector< Geom::Point > const &points_in, bool gen_inellipse, Geom::PathVector &path_out)
static void gen_axes_paths(Geom::PathVector &path_out, const Geom::Affine &affine)
static bool is_ccw(const std::vector< Geom::Point > &pts)
LPEPts2Ellipse(LivePathEffectObject *lpeobject)
EnumParam< EllipseMethod > method
~LPEPts2Ellipse() override
virtual void param_widget_is_enabled(bool is_enabled)
void param_set_range(double min, double max)
void param_set_increments(double step, double page)
Simplified management of enumerations of svg items with UI labels.
double Coord
Floating point type used to store coordinates.
LPE "Points to Ellipse" implementation.
SBasisN< n > cos(LinearN< n > bo, int k)
double atan2(Point const &p)
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
T dot(D2< T > const &a, D2< T > const &b)
Point unit_vector(Point const &a)
SBasisN< n > sin(LinearN< n > bo, int k)
Point middle_point(LineSegment const &_segment)
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)
static const Util::EnumData< EllipseMethod > EllipseMethodData[]
static const Util::EnumDataConverter< EllipseMethod > EMConverter(EllipseMethodData, EM_END)
double range2pi(double a)
void evalSteinerEllipse(Geom::Point const &pCenter, Geom::Point const &pCenter_Pt2, Geom::Point const &pPt0_Pt1, const double &angle, Geom::Point &pRes)
double calc_delta_angle(const double a0, const double a1)
Helper class to stream background task notifications as a series of messages.
PathVector - a sequence of subpaths.
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.
double sum(const double alpha[16], const double &x, const double &y)
Simplified management of enumerations of svg items with UI labels.