diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2013-10-02 22:35:52 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2013-10-02 22:35:52 +0000 |
| commit | 9240dbde4547c7e7529f31645ea916faae72bafa (patch) | |
| tree | 82c7e2e222dd3bd92dea9a21ed60c0479f0149b8 /src/sp-ellipse.cpp | |
| parent | update to trunk (diff) | |
| parent | Fix segment welding in the node tool hanging when a two-point segment (diff) | |
| download | inkscape-9240dbde4547c7e7529f31645ea916faae72bafa.tar.gz inkscape-9240dbde4547c7e7529f31645ea916faae72bafa.zip | |
update to trunk
(bzr r12588.1.10)
Diffstat (limited to 'src/sp-ellipse.cpp')
| -rw-r--r-- | src/sp-ellipse.cpp | 640 |
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: |
