summaryrefslogtreecommitdiffstats
path: root/src/sp-ellipse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp-ellipse.cpp')
-rw-r--r--src/sp-ellipse.cpp640
1 files changed, 281 insertions, 359 deletions
diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp
index fc78b9777..80e57afc3 100644
--- a/src/sp-ellipse.cpp
+++ b/src/sp-ellipse.cpp
@@ -24,6 +24,8 @@
#include "style.h"
#include "display/curve.h"
#include <glibmm/i18n.h>
+#include <2geom/angle.h>
+#include <2geom/ellipse.h>
#include <2geom/transforms.h>
#include <2geom/pathvector.h>
#include <2geom/svg-path.h>
@@ -32,29 +34,27 @@
#include "preferences.h"
#include "snap-candidate.h"
-/* Common parent class */
-
-#define noELLIPSE_VERBOSE
-
-
#include "sp-factory.h"
namespace {
- SPObject* createEllipse() {
- return new SPEllipse();
- }
+SPObject *create_ellipse()
+{
+ return new SPEllipse();
+}
- SPObject* createCircle() {
- return new SPCircle();
- }
+SPObject *create_circle()
+{
+ return new SPCircle();
+}
- SPObject* createArc() {
- return new SPArc();
- }
+SPObject *create_arc()
+{
+ return new SPArc();
+}
- bool ellipseRegistered = SPFactory::instance().registerObject("svg:ellipse", createEllipse);
- bool circleRegistered = SPFactory::instance().registerObject("svg:circle", createCircle);
- bool arcRegistered = SPFactory::instance().registerObject("arc", createArc);
+bool ellipse_registered = SPFactory::instance().registerObject("svg:ellipse", create_ellipse);
+bool circle_registered = SPFactory::instance().registerObject("svg:circle", create_circle);
+bool arc_registered = SPFactory::instance().registerObject("arc", create_arc);
}
@@ -64,52 +64,34 @@ namespace {
#define SP_2PI (2 * M_PI)
-#if 1
-/* Hmmm... shouldn't this also qualify */
-/* Whether it is faster or not, well, nobody knows */
-#define sp_round(v,m) (((v) < 0.0) ? ((ceil((v) / (m) - 0.5)) * (m)) : ((floor((v) / (m) + 0.5)) * (m)))
-#else
-/* we do not use C99 round(3) function yet */
-static double sp_round(double x, double y)
+SPGenericEllipse::SPGenericEllipse()
+ : SPShape()
+ , start(0)
+ , end(SP_2PI)
+ , _closed(true)
{
- double remain;
-
- g_assert(y > 0.0);
-
- /* return round(x/y) * y; */
-
- remain = fmod(x, y);
-
- if (remain >= 0.5*y)
- return x - remain + y;
- else
- return x - remain;
}
-#endif
-
-static gboolean sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr);
-SPGenericEllipse::SPGenericEllipse() : SPShape() {
- this->cx.unset();
- this->cy.unset();
- this->rx.unset();
- this->ry.unset();
+SPGenericEllipse::~SPGenericEllipse()
+{
+}
- this->start = 0.0;
- this->end = SP_2PI;
- this->closed = TRUE;
+bool SPGenericEllipse::closed() {
+ return _closed;
}
-SPGenericEllipse::~SPGenericEllipse() {
+void SPGenericEllipse::setClosed(bool value) {
+ _closed = value;
}
-void SPGenericEllipse::update(SPCtx *ctx, guint flags) {
+void SPGenericEllipse::update(SPCtx *ctx, guint flags)
+{
if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
Geom::Rect const &viewbox = ((SPItemCtx const *) ctx)->viewport;
double const dx = viewbox.width();
double const dy = viewbox.height();
- double const dr = sqrt(dx*dx + dy*dy)/sqrt(2);
+ double const dr = hypot(dx, dy) / sqrt(2);
double const em = this->style->font_size.computed;
double const ex = em * 0.5; // fixme: get from pango or libnrtype
@@ -124,13 +106,14 @@ void SPGenericEllipse::update(SPCtx *ctx, guint flags) {
SPShape::update(ctx, flags);
}
-void SPGenericEllipse::update_patheffect(bool write) {
+void SPGenericEllipse::update_patheffect(bool write)
+{
this->set_shape();
if (write) {
Inkscape::XML::Node *repr = this->getRepr();
- if ( this->_curve != NULL ) {
+ if (this->_curve != NULL) {
gchar *str = sp_svg_write_path(this->_curve->get_pathvector());
repr->setAttribute("d", str);
g_free(str);
@@ -142,64 +125,49 @@ void SPGenericEllipse::update_patheffect(bool write) {
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
-#include <2geom/ellipse.h>
+bool SPGenericEllipse::_isSlice() const
+{
+ Geom::AngleInterval a(this->start, this->end, true);
-/* fixme: Think (Lauris) */
-/* Can't we use arcto in this method? */
-void SPGenericEllipse::set_shape() {
+ return !(Geom::are_near(a.extent(), 0) || Geom::are_near(a.extent(), SP_2PI));
+}
+
+void SPGenericEllipse::set_shape()
+{
if (hasBrokenPathEffect()) {
- g_warning ("The ellipse shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as ellipse will remove the bad LPE");
+ g_warning("The ellipse shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as ellipse will remove the bad LPE");
if (this->getRepr()->attribute("d")) {
// unconditionally read the curve from d, if any, to preserve appearance
Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d"));
SPCurve *cold = new SPCurve(pv);
- this->setCurveInsync( cold, TRUE);
+ this->setCurveInsync(cold, TRUE);
cold->unref();
}
return;
}
- if ((this->rx.computed < 1e-18) || (this->ry.computed < 1e-18)) {
- return;
- }
-
- if (fabs(this->end - this->start) < 1e-9) {
- return;
- }
-
- sp_genericellipse_normalize(this);
-
- // figure out if we have a slice, guarding against rounding errors
- double len = fmod(this->end - this->start, SP_2PI);
-
- if (len < 0.0) {
- len += SP_2PI;
+ if (Geom::are_near(this->rx.computed, 0) || Geom::are_near(this->ry.computed, 0)) {
+ return;
}
- bool slice = false;
-
- if (fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8) {
- slice = false;
- this->end = this->start + SP_2PI;
- } else {
- slice = true;
- }
+ this->normalize();
SPCurve *curve = NULL;
// For simplicity, we use a circle with center (0, 0) and radius 1 for our calculations.
- if (slice) {
- Geom::Point startPoint(cos(start), sin(start));
- Geom::Point endPoint(cos(end), sin(end));
- Geom::Point middlePoint = make_angle_bisector_ray(Geom::Ray(Geom::Point(), start), Geom::Ray(Geom::Point(), end)).versor();
+ if (this->_isSlice()) {
+ Geom::Point center(0, 0);
+ Geom::Point start_point = Geom::Point::polar(start);
+ Geom::Point end_point = Geom::Point::polar(end);
+ Geom::Point middle_point = make_angle_bisector_ray(Geom::Ray(center, start), Geom::Ray(center, end)).versor();
Geom::Ellipse ellipse(0, 0, 1, 1, 0);
- Geom::EllipticalArc *arc = ellipse.arc(startPoint, middlePoint, endPoint);
+ Geom::EllipticalArc *arc = ellipse.arc(start_point, middle_point, end_point);
- Geom::Path path(startPoint);
+ Geom::Path path(start_point);
path.append(*arc);
delete arc;
@@ -207,9 +175,9 @@ void SPGenericEllipse::set_shape() {
Geom::PathBuilder pb;
pb.append(path);
- if (this->closed) {
+ if (this->_closed) {
// "pizza slice"
- pb.lineTo(Geom::Point(0, 0));
+ pb.lineTo(center);
pb.closePath();
} else {
// arc only
@@ -234,7 +202,7 @@ void SPGenericEllipse::set_shape() {
/* Reset the shape's curve to the "original_curve"
* This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
- this->setCurveInsync( curve, TRUE);
+ this->setCurveInsync(curve, TRUE);
this->setCurveBeforeLPE(curve);
if (hasPathEffect() && sp_lpe_item_path_effects_enabled(this)) {
@@ -242,7 +210,7 @@ void SPGenericEllipse::set_shape() {
bool success = sp_lpe_item_perform_path_effect(this, c_lpe);
if (success) {
- this->setCurveInsync( c_lpe, TRUE);
+ this->setCurveInsync(c_lpe, TRUE);
}
c_lpe->unref();
@@ -251,70 +219,49 @@ void SPGenericEllipse::set_shape() {
curve->unref();
}
-void SPGenericEllipse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) {
- sp_genericellipse_normalize(this);
+void SPGenericEllipse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
+{
+ this->normalize();
Geom::Affine const i2dt = this->i2dt_affine();
- // figure out if we have a slice, while guarding against rounding errors
- bool slice = false;
- double len = fmod(this->end - this->start, SP_2PI);
-
- if (len < 0.0) {
- len += SP_2PI;
- }
-
- if (fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8) {
- slice = false;
- this->end = this->start + SP_2PI;
- } else {
- slice = true;
- }
-
- double rx = this->rx.computed;
- double ry = this->ry.computed;
- double cx = this->cx.computed;
- double cy = this->cy.computed;
-
- // Snap to the 4 quadrant points of the this, but only if the arc
+ // Snap to the 4 quadrant points of the ellipse, but only if the arc
// spans far enough to include them
if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT)) {
- double angle = 0;
-
- for (angle = 0; angle < SP_2PI; angle += M_PI_2) {
- if (angle >= this->start && angle <= this->end) {
- Geom::Point pt = Geom::Point(cx + cos(angle)*rx, cy + sin(angle)*ry) * i2dt;
+ for (double angle = 0; angle < SP_2PI; angle += M_PI_2) {
+ if (Geom::AngleInterval(this->start, this->end, true).contains(angle)) {
+ Geom::Point pt = this->getPointAtAngle(angle) * i2dt;
p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_ELLIPSE_QUADRANT_POINT, Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT));
}
}
}
- // Add the centre, if we have a closed slice or when explicitly asked for
- bool c1 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && slice && this->closed;
- bool c2 = snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT);
+ double cx = this->cx.computed;
+ double cy = this->cy.computed;
- if (c1 || c2) {
- Geom::Point pt = Geom::Point(cx, cy) * i2dt;
+ bool slice = this->_isSlice();
- if (c1) {
- p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
- }
+ // Add the centre, if we have a closed slice or when explicitly asked for
+ if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && slice && this->_closed) {
+ Geom::Point pt = Geom::Point(cx, cy) * i2dt;
+ p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+ }
- if (c2) {
- p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
- }
+ if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_OBJECT_MIDPOINT)) {
+ Geom::Point pt = Geom::Point(cx, cy) * i2dt;
+ p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
}
// And if we have a slice, also snap to the endpoints
if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP) && slice) {
// Add the start point, if it's not coincident with a quadrant point
- if (fmod(this->start, M_PI_2) != 0.0 ) {
- Geom::Point pt = Geom::Point(cx + cos(this->start)*rx, cy + sin(this->start)*ry) * i2dt;
+ if (!Geom::are_near(std::fmod(this->start, M_PI_2), 0)) {
+ Geom::Point pt = this->getPointAtAngle(this->start) * i2dt;
p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
}
// Add the end point, if it's not coincident with a quadrant point
- if (fmod(this->end, M_PI_2) != 0.0 ) {
- Geom::Point pt = Geom::Point(cx + cos(this->end)*rx, cy + sin(this->end)*ry) * i2dt;
+ if (!Geom::are_near(std::fmod(this->end, M_PI_2), 0)) {
+ Geom::Point pt = this->getPointAtAngle(this->end) * i2dt;
p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
}
}
@@ -323,13 +270,14 @@ void SPGenericEllipse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p,
Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform)
{
/* Calculate ellipse start in parent coords. */
- Geom::Point pos( Geom::Point(this->cx.computed, this->cy.computed) * xform );
+ Geom::Point pos(Geom::Point(this->cx.computed, this->cy.computed) * xform);
/* This function takes care of translation and scaling, we return whatever parts we can't
handle. */
Geom::Affine ret(Geom::Affine(xform).withoutTranslation());
gdouble const sw = hypot(ret[0], ret[1]);
gdouble const sh = hypot(ret[2], ret[3]);
+
if (sw > 1e-9) {
ret[0] /= sw;
ret[1] /= sw;
@@ -337,6 +285,7 @@ Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform)
ret[0] = 1.0;
ret[1] = 0.0;
}
+
if (sh > 1e-9) {
ret[2] /= sh;
ret[3] /= sh;
@@ -348,6 +297,7 @@ Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform)
if (this->rx._set) {
this->rx = this->rx.computed * sw;
}
+
if (this->ry._set) {
this->ry = this->ry.computed * sh;
}
@@ -373,26 +323,16 @@ Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform)
return ret;
}
-void
-sp_genericellipse_normalize(SPGenericEllipse *ellipse)
+void SPGenericEllipse::normalize()
{
- ellipse->start = fmod(ellipse->start, SP_2PI);
- ellipse->end = fmod(ellipse->end, SP_2PI);
+ Geom::AngleInterval a(this->start, this->end, true);
- if (ellipse->start < 0.0) {
- ellipse->start += SP_2PI;
- }
-
- double diff = ellipse->start - ellipse->end;
-
- if (diff >= 0.0) {
- ellipse->end += diff - fmod(diff, SP_2PI) + SP_2PI;
- }
-
- /* Now we keep: 0 <= start < end <= 2*PI */
+ this->start = a.initialAngle().radians0();
+ this->end = a.finalAngle().radians0();
}
-Inkscape::XML::Node* SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
+Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
+{
if (flags & SP_OBJECT_WRITE_EXT) {
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
repr = xml_doc->createElement("svg:path");
@@ -404,7 +344,7 @@ Inkscape::XML::Node* SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed);
if (SP_IS_ARC(this)) {
- sp_arc_set_elliptical_path_attribute(SP_ARC(this), this->getRepr());
+ SP_ARC(this)->sp_arc_set_elliptical_path_attribute(this->getRepr());
}
}
@@ -416,23 +356,27 @@ Inkscape::XML::Node* SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I
}
/* SVG <ellipse> element */
-SPEllipse::SPEllipse() : SPGenericEllipse() {
+SPEllipse::SPEllipse() : SPGenericEllipse()
+{
}
-SPEllipse::~SPEllipse() {
+SPEllipse::~SPEllipse()
+{
}
-void SPEllipse::build(SPDocument *document, Inkscape::XML::Node *repr) {
- SPGenericEllipse::build(document, repr);
+void SPEllipse::build(SPDocument *document, Inkscape::XML::Node *repr)
+{
+ SPGenericEllipse::build(document, repr);
- this->readAttr( "cx" );
- this->readAttr( "cy" );
- this->readAttr( "rx" );
- this->readAttr( "ry" );
+ this->readAttr("cx");
+ this->readAttr("cy");
+ this->readAttr("rx");
+ this->readAttr("ry");
}
-Inkscape::XML::Node* SPEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
+Inkscape::XML::Node *SPEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
+{
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
repr = xml_doc->createElement("svg:ellipse");
}
@@ -448,80 +392,68 @@ Inkscape::XML::Node* SPEllipse::write(Inkscape::XML::Document *xml_doc, Inkscape
}
-void SPEllipse::set(unsigned int key, gchar const* value) {
+void SPEllipse::set(unsigned int key, gchar const *value)
+{
switch (key) {
- case SP_ATTR_CX:
- this->cx.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_CY:
- this->cy.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_RX:
- if (!this->rx.read(value) || (this->rx.value <= 0.0)) {
- this->rx.unset();
- }
-
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_RY:
- if (!this->ry.read(value) || (this->ry.value <= 0.0)) {
- this->ry.unset();
- }
-
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- default:
- SPGenericEllipse::set(key, value);
- break;
- }
-}
-
-const char* SPEllipse::displayName() {
- return _("Ellipse");
-}
+ case SP_ATTR_CX:
+ this->cx.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_CY:
+ this->cy.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_RX:
+ if (!this->rx.read(value) || (this->rx.value <= 0.0)) {
+ this->rx.unset();
+ }
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
-void
-sp_ellipse_position_set(SPEllipse *ellipse, gdouble x, gdouble y, gdouble rx, gdouble ry)
-{
- SPGenericEllipse *ge;
-
- g_return_if_fail(ellipse != NULL);
- g_return_if_fail(SP_IS_ELLIPSE(ellipse));
+ case SP_ATTR_RY:
+ if (!this->ry.read(value) || (this->ry.value <= 0.0)) {
+ this->ry.unset();
+ }
- ge = SP_GENERICELLIPSE(ellipse);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
- ge->cx.computed = x;
- ge->cy.computed = y;
- ge->rx.computed = rx;
- ge->ry.computed = ry;
+ default:
+ SPGenericEllipse::set(key, value);
+ break;
+ }
+}
- ((SPObject *)ge)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+const char *SPEllipse::displayName()
+{
+ return _("Ellipse");
}
+
/* SVG <circle> element */
-SPCircle::SPCircle() : SPGenericEllipse() {
+SPCircle::SPCircle() : SPGenericEllipse()
+{
}
-SPCircle::~SPCircle() {
+SPCircle::~SPCircle()
+{
}
-void SPCircle::build(SPDocument *document, Inkscape::XML::Node *repr) {
+void SPCircle::build(SPDocument *document, Inkscape::XML::Node *repr)
+{
SPGenericEllipse::build(document, repr);
- this->readAttr( "cx" );
- this->readAttr( "cy" );
- this->readAttr( "r" );
+ this->readAttr("cx");
+ this->readAttr("cy");
+ this->readAttr("r");
}
-Inkscape::XML::Node* SPCircle::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
+Inkscape::XML::Node *SPCircle::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
+{
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
repr = xml_doc->createElement("svg:circle");
}
@@ -535,55 +467,60 @@ Inkscape::XML::Node* SPCircle::write(Inkscape::XML::Document *xml_doc, Inkscape:
return repr;
}
-void SPCircle::set(unsigned int key, gchar const* value) {
+void SPCircle::set(unsigned int key, gchar const *value)
+{
switch (key) {
- case SP_ATTR_CX:
- this->cx.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_CY:
- this->cy.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_R:
- if (!this->rx.read(value) || this->rx.value <= 0.0) {
- this->rx.unset();
- }
-
- this->ry = this->rx;
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- default:
- SPGenericEllipse::set(key, value);
- break;
+ case SP_ATTR_CX:
+ this->cx.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_CY:
+ this->cy.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_R:
+ if (!this->rx.read(value) || this->rx.value <= 0.0) {
+ this->rx.unset();
+ }
+
+ this->ry = this->rx;
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ default:
+ SPGenericEllipse::set(key, value);
+ break;
}
}
-const char* SPCircle::displayName() {
- return _("Circle");
+const char *SPCircle::displayName()
+{
+ return _("Circle");
}
/* <path sodipodi:type="arc"> element */
-SPArc::SPArc() : SPGenericEllipse() {
+SPArc::SPArc() : SPGenericEllipse()
+{
}
-SPArc::~SPArc() {
+SPArc::~SPArc()
+{
}
-void SPArc::build(SPDocument *document, Inkscape::XML::Node *repr) {
- SPGenericEllipse::build(document, repr);
+void SPArc::build(SPDocument *document, Inkscape::XML::Node *repr)
+{
+ SPGenericEllipse::build(document, repr);
- this->readAttr( "sodipodi:cx" );
- this->readAttr( "sodipodi:cy" );
- this->readAttr( "sodipodi:rx" );
- this->readAttr( "sodipodi:ry" );
+ this->readAttr("sodipodi:cx");
+ this->readAttr("sodipodi:cy");
+ this->readAttr("sodipodi:rx");
+ this->readAttr("sodipodi:ry");
- this->readAttr( "sodipodi:start" );
- this->readAttr( "sodipodi:end" );
- this->readAttr( "sodipodi:open" );
+ this->readAttr("sodipodi:start");
+ this->readAttr("sodipodi:end");
+ this->readAttr("sodipodi:open");
}
/*
@@ -594,32 +531,33 @@ void SPArc::build(SPDocument *document, Inkscape::XML::Node *repr) {
* See SVG 1.0 Specification W3C Recommendation
* ``F.6 Ellptical arc implementation notes'' for more detail.
*/
-static gboolean
-sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr)
+bool SPArc::sp_arc_set_elliptical_path_attribute(Inkscape::XML::Node *repr)
{
- SPGenericEllipse *ge = SP_GENERICELLIPSE(arc);
-
Inkscape::SVG::PathString str;
- Geom::Point p1 = sp_arc_get_xy(arc, ge->start);
- Geom::Point p2 = sp_arc_get_xy(arc, ge->end);
- double rx = ge->rx.computed;
- double ry = ge->ry.computed;
+ Geom::Point p1 = this->getPointAtAngle(this->start);
+ Geom::Point p2 = this->getPointAtAngle(this->end);
+ double rx = this->rx.computed;
+ double ry = this->ry.computed;
str.moveTo(p1);
- double dt = fmod(ge->end - ge->start, SP_2PI);
+ double dt = fmod(this->end - this->start, SP_2PI);
+
if (fabs(dt) < 1e-6) {
- Geom::Point ph = sp_arc_get_xy(arc, (ge->start + ge->end) / 2.0);
+ Geom::Point ph = getPointAtAngle((this->start + this->end) / 2.0);
+
str.arcTo(rx, ry, 0, true, true, ph)
- .arcTo(rx, ry, 0, true, true, p2)
- .closePath();
+ .arcTo(rx, ry, 0, true, true, p2)
+ .closePath();
} else {
bool fa = (fabs(dt) > M_PI);
bool fs = (dt > 0);
+
str.arcTo(rx, ry, 0, fa, fs, p2);
- if (ge->closed) {
- Geom::Point center = Geom::Point(ge->cx.computed, ge->cy.computed);
+
+ if (this->_closed) {
+ Geom::Point center = Geom::Point(this->cx.computed, this->cy.computed);
str.lineTo(center).closePath();
}
}
@@ -628,7 +566,8 @@ sp_arc_set_elliptical_path_attribute(SPArc *arc, Inkscape::XML::Node *repr)
return true;
}
-Inkscape::XML::Node* SPArc::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
+Inkscape::XML::Node *SPArc::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
+{
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
repr = xml_doc->createElement("svg:path");
}
@@ -642,17 +581,11 @@ Inkscape::XML::Node* SPArc::write(Inkscape::XML::Document *xml_doc, Inkscape::XM
sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed);
// write start and end only if they are non-trivial; otherwise remove
- gdouble len = fmod(this->end - this->start, SP_2PI);
-
- if (len < 0.0) {
- len += SP_2PI;
- }
-
- if (!(fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8)) {
+ if (this->_isSlice()) {
sp_repr_set_svg_double(repr, "sodipodi:start", this->start);
sp_repr_set_svg_double(repr, "sodipodi:end", this->end);
- repr->setAttribute("sodipodi:open", (!this->closed) ? "true" : NULL);
+ repr->setAttribute("sodipodi:open", (!this->_closed) ? "true" : NULL);
} else {
repr->setAttribute("sodipodi:end", NULL);
repr->setAttribute("sodipodi:start", NULL);
@@ -661,73 +594,75 @@ Inkscape::XML::Node* SPArc::write(Inkscape::XML::Document *xml_doc, Inkscape::XM
}
// write d=
- sp_arc_set_elliptical_path_attribute(this, repr);
+ this->sp_arc_set_elliptical_path_attribute(repr);
SPGenericEllipse::write(xml_doc, repr, flags);
return repr;
}
-void SPArc::set(unsigned int key, gchar const* value) {
+void SPArc::set(unsigned int key, gchar const *value)
+{
switch (key) {
- case SP_ATTR_SODIPODI_CX:
- this->cx.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_SODIPODI_CY:
- this->cy.readOrUnset(value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
-
- case SP_ATTR_SODIPODI_RX:
- if (!this->rx.read(value) || this->rx.computed <= 0.0) {
- this->rx.unset();
- }
+ case SP_ATTR_SODIPODI_CX:
+ this->cx.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_SODIPODI_CY:
+ this->cy.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_SODIPODI_RX:
+ if (!this->rx.read(value) || this->rx.computed <= 0.0) {
+ this->rx.unset();
+ }
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
- case SP_ATTR_SODIPODI_RY:
- if (!this->ry.read(value) || this->ry.computed <= 0.0) {
- this->ry.unset();
- }
+ case SP_ATTR_SODIPODI_RY:
+ if (!this->ry.read(value) || this->ry.computed <= 0.0) {
+ this->ry.unset();
+ }
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
- case SP_ATTR_SODIPODI_START:
- if (value) {
- sp_svg_number_read_d(value, &this->start);
- } else {
- this->start = 0;
- }
+ case SP_ATTR_SODIPODI_START:
+ if (value) {
+ sp_svg_number_read_d(value, &this->start);
+ } else {
+ this->start = 0;
+ }
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
- case SP_ATTR_SODIPODI_END:
- if (value) {
- sp_svg_number_read_d(value, &this->end);
- } else {
- this->end = 2 * M_PI;
- }
+ case SP_ATTR_SODIPODI_END:
+ if (value) {
+ sp_svg_number_read_d(value, &this->end);
+ } else {
+ this->end = 2 * M_PI;
+ }
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
- case SP_ATTR_SODIPODI_OPEN:
- this->closed = (!value);
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
- break;
+ case SP_ATTR_SODIPODI_OPEN:
+ this->_closed = (!value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
- default:
- SPGenericEllipse::set(key, value);
- break;
+ default:
+ SPGenericEllipse::set(key, value);
+ break;
}
}
-void SPArc::modified(guint flags) {
+void SPArc::modified(guint flags)
+{
if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
this->set_shape();
}
@@ -735,16 +670,10 @@ void SPArc::modified(guint flags) {
SPGenericEllipse::modified(flags);
}
-
-const char* SPArc::displayName() {
- gdouble len = fmod(this->end - this->start, SP_2PI);
-
- if (len < 0.0) {
- len += SP_2PI;
- }
-
- if (!(fabs(len) < 1e-8 || fabs(len - SP_2PI) < 1e-8)) {
- if (this->closed) {
+const char *SPArc::displayName()
+{
+ if (this->_isSlice()) {
+ if (this->_closed) {
return _("Segment");
} else {
return _("Arc");
@@ -754,40 +683,33 @@ const char* SPArc::displayName() {
}
}
-void
-sp_arc_position_set(SPArc *arc, gdouble x, gdouble y, gdouble rx, gdouble ry)
+void SPArc::sp_arc_position_set(gdouble x, gdouble y, gdouble rx, gdouble ry)
{
- g_return_if_fail(arc != NULL);
- g_return_if_fail(SP_IS_ARC(arc));
-
- SPGenericEllipse *ge = SP_GENERICELLIPSE(arc);
+ this->cx.computed = x;
+ this->cy.computed = y;
+ this->rx.computed = rx;
+ this->ry.computed = ry;
- ge->cx.computed = x;
- ge->cy.computed = y;
- ge->rx.computed = rx;
- ge->ry.computed = ry;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
// those pref values are in degrees, while we want radians
- if (prefs->getDouble("/tools/shapes/arc/start", 0.0) != 0)
- ge->start = prefs->getDouble("/tools/shapes/arc/start", 0.0) * M_PI / 180;
- if (prefs->getDouble("/tools/shapes/arc/end", 0.0) != 0)
- ge->end = prefs->getDouble("/tools/shapes/arc/end", 0.0) * M_PI / 180;
- if (!prefs->getBool("/tools/shapes/arc/open"))
- ge->closed = 1;
- else
- ge->closed = 0;
+ if (prefs->getDouble("/tools/shapes/arc/start", 0.0) != 0) {
+ this->start = Geom::Angle::from_degrees(prefs->getDouble("/tools/shapes/arc/start", 0.0)).radians0();
+ }
- ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-}
+ if (prefs->getDouble("/tools/shapes/arc/end", 0.0) != 0) {
+ this->end = Geom::Angle::from_degrees(prefs->getDouble("/tools/shapes/arc/end", 0.0)).radians0();
+ }
-Geom::Point sp_arc_get_xy(SPArc *arc, gdouble arg)
-{
- SPGenericEllipse *ge = SP_GENERICELLIPSE(arc);
+ this->_closed = !prefs->getBool("/tools/shapes/arc/open");
- return Geom::Point(ge->rx.computed * cos(arg) + ge->cx.computed,
- ge->ry.computed * sin(arg) + ge->cy.computed);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
+Geom::Point SPGenericEllipse::getPointAtAngle(double arg) const
+{
+ return Geom::Point::polar(arg) * Geom::Scale(rx.computed, ry.computed) * Geom::Translate(cx.computed, cy.computed);
+}
/*
Local Variables: