diff options
| author | Marc Jeanmougin <marc@jeanmougin.fr> | 2015-04-26 09:46:39 +0000 |
|---|---|---|
| committer | Marc Jeanmougin <mc@M0nst3r.bouyguesbox.fr> | 2015-04-26 09:46:39 +0000 |
| commit | ac6617a55b9f7c05db084eeaa5684fb42d5e1406 (patch) | |
| tree | 1fc8e668890618463d48298074559c7fe6bc5040 /src | |
| parent | merge (diff) | |
| parent | extensions. ink2canvas.py - do not parse html comments. (Bug 1446204) (diff) | |
| download | inkscape-ac6617a55b9f7c05db084eeaa5684fb42d5e1406.tar.gz inkscape-ac6617a55b9f7c05db084eeaa5684fb42d5e1406.zip | |
merging
(bzr r13922.1.13)
Diffstat (limited to 'src')
146 files changed, 4303 insertions, 4187 deletions
diff --git a/src/2geom/line.h b/src/2geom/line.h index ade67f818..cbd68fa08 100644 --- a/src/2geom/line.h +++ b/src/2geom/line.h @@ -35,6 +35,7 @@ #define LIB2GEOM_SEEN_LINE_H #include <cmath> +#include <iostream> #include <boost/optional.hpp> #include <2geom/bezier-curve.h> // for LineSegment #include <2geom/rect.h> @@ -258,9 +259,19 @@ public: dist = -dot(n, m_origin); return n; } - /// @} + + friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Line &in_line); +/// @} }; // end class Line +/** @brief Output operator for lines. + * Prints out representation (point + versor) + */ +inline std::ostream &operator<< (std::ostream &out_file, const Geom::Line &in_line) { + out_file << "X: " << in_line.m_origin[X] << " Y: " << in_line.m_origin[Y] + << " dX: " << in_line.m_versor[X] << " dY: " << in_line.m_versor[Y]; + return out_file; +} inline double distance(Point const& _point, Line const& _line) @@ -365,6 +376,10 @@ inline Line make_angle_bisector_line(Point const& A, Point const& O, Point const& B) { Point M = middle_point(A,B); + if (are_near(O,M)) { + Line l(A,B); + M += (make_orthogonal_line(O,l)).versor(); + } return Line(O,M); } diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index 0525be04b..a2e4253d2 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -37,6 +37,7 @@ #include <2geom/choose.h> #include <2geom/path-sink.h> #include <2geom/exception.h> +#include <2geom/convex-cover.h> #include <iostream> @@ -203,11 +204,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) THROW_RANGEERROR("size of sb is too small"); } - bz.resize(4, Point(0,0)); - bz[0][X] = sb[X][0][0]; - bz[0][Y] = sb[Y][0][0]; - bz[3][X] = sb[X][0][1]; - bz[3][Y] = sb[Y][0][1]; + sbasis_to_bezier(bz, sb, 4); // zeroth-order estimate + Geom::ConvexHull bezhull(bz); // calculate first derivatives of x and y wrt t @@ -231,17 +229,23 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) midx += (sb[X][i][0] + sb[X][i][1])/div; div *= 4; } - midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; div = 2; for (size_t i = 0; i < sb[Y].size(); ++i) { midy += (sb[Y][i][0] + sb[Y][i][1])/div; div *= 4; } - midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; + +// is midpoint in hull: if not, the solution will be ill-conditioned, LP Bug 1428683 + + if (!bezhull.contains_point(Geom::Point(midx, midy))) + return; // calculate Bezier control arms + midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; // re-define relative to center + midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; + if ((std::abs(xprime[0]) < EPSILON) && (std::abs(yprime[0]) < EPSILON) && ((std::abs(xprime[1]) > EPSILON) || (std::abs(yprime[1]) > EPSILON))) { // degenerate handle at 0 : use distance of closest approach numer = midx*xprime[1] + midy*yprime[1]; @@ -258,7 +262,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) dely[0] = yprime[0]*numer/denom; delx[1] = 0; dely[1] = 0; - } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > EPSILON) { // general case : fit mid fxn value + } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > // general case : fit mid fxn value + 0.002 * std::abs(xprime[1]*xprime[0] + yprime[1]*yprime[0])) { // approx. 0.1 degree of angle denom = xprime[1]*yprime[0] - yprime[1]*xprime[0]; for (int i = 0; i < 2; ++i) { numer = xprime[1 - i]*midy - yprime[1 - i]*midx; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b1e3931b..27c5e49db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,3 @@ - # ----------------------------------------------------------------------------- # Define the main source # ----------------------------------------------------------------------------- @@ -33,8 +32,8 @@ set(sp_SRC sp-gradient-reference.cpp sp-gradient.cpp sp-guide.cpp - sp-hatch.cpp sp-hatch-path.cpp + sp-hatch.cpp sp-image.cpp sp-item-group.cpp sp-item-notify-moveto.cpp @@ -48,9 +47,9 @@ set(sp_SRC sp-marker.cpp sp-mask.cpp sp-mesh-array.cpp - sp-mesh-gradient.cpp sp-mesh-patch.cpp sp-mesh-row.cpp + sp-mesh.cpp sp-metadata.cpp sp-missing-glyph.cpp sp-namedview.cpp @@ -75,6 +74,9 @@ set(sp_SRC sp-style-elem.cpp sp-switch.cpp sp-symbol.cpp + sp-tag-use-reference.cpp + sp-tag-use.cpp + sp-tag.cpp sp-text.cpp sp-title.cpp sp-tref-reference.cpp @@ -119,8 +121,8 @@ set(sp_SRC sp-guide-attachment.h sp-guide-constraint.h sp-guide.h - sp-hatch.h sp-hatch-path.h + sp-hatch.h sp-image.h sp-item-group.h sp-item-notify-moveto.h @@ -131,13 +133,13 @@ set(sp_SRC sp-line.h sp-linear-gradient.h sp-lpe-item.h - sp-marker.h sp-marker-loc.h + sp-marker.h sp-mask.h sp-mesh-array.h - sp-mesh-gradient.h sp-mesh-patch.h sp-mesh-row.h + sp-mesh.h sp-metadata.h sp-missing-glyph.h sp-namedview.h @@ -203,21 +205,17 @@ set(inkscape_SRC filter-enums.cpp gc-anchored.cpp gc-finalized.cpp - gc.cpp gradient-chemistry.cpp gradient-drag.cpp graphlayout.cpp guide-snapper.cpp help.cpp id-clash.cpp - # ige-mac-menu.c inkscape.cpp - inkscape.rc - interface.cpp knot-holder-entity.cpp + knot-ptr.cpp knot.cpp knotholder.cpp - knot-ptr.cpp layer-fns.cpp layer-manager.cpp layer-model.cpp @@ -257,8 +255,8 @@ set(inkscape_SRC snapped-line.cpp snapped-point.cpp snapper.cpp - style.cpp style-internal.cpp + style.cpp svg-view-widget.cpp svg-view.cpp text-chemistry.cpp @@ -313,18 +311,12 @@ set(inkscape_SRC event.h extract-uri-test.h extract-uri.h - factory.h file.h fill-or-stroke.h filter-chemistry.h filter-enums.h - gc-alloc.h - gc-allocator.h gc-anchored.h - gc-core.h gc-finalized.h - gc-managed.h - gc-soft-ptr.h gradient-chemistry.h gradient-drag.h graphlayout.h @@ -333,16 +325,14 @@ set(inkscape_SRC helper-fns.h icon-size.h id-clash.h - # ige-mac-menu.h inkscape-version.h inkscape.h - interface.h isinf.h knot-enums.h knot-holder-entity.h + knot-ptr.h knot.h knotholder.h - knot-ptr.h layer-fns.h layer-manager.h layer-model.h @@ -351,7 +341,6 @@ set(inkscape_SRC macros.h main-cmdlineact.h marker-test.h - marker.h media.h menus-skeleton.h message-context.h @@ -376,7 +365,6 @@ set(inkscape_SRC profile-manager.h proj_pt.h rdf.h - registrytool.h remove-last.h removeoverlap.h require-config.h @@ -403,10 +391,10 @@ set(inkscape_SRC splivarot.h streq.h strneq.h - style-test.h - style.h style-enums.h style-internal.h + style-test.h + style.h svg-profile.h svg-view-widget.h svg-view.h @@ -430,8 +418,10 @@ set(inkscape_SRC if(WIN32) list(APPEND inkscape_SRC + inkscape.rc registrytool.cpp #deptool.cpp + winconsole.cpp winmain.cpp ) endif() @@ -471,7 +461,6 @@ list(APPEND inkscape_SRC # All folders for internal inkscape # these call add_inkscape_source add_subdirectory(debug) -add_subdirectory(dialogs) add_subdirectory(display) add_subdirectory(extension) add_subdirectory(filters) @@ -545,6 +534,8 @@ target_link_libraries(inkscape uemf_LIB 2geom_LIB depixelize_LIB + util_LIB + gc_LIB ${INKSCAPE_LIBS} ) @@ -553,4 +544,3 @@ target_link_libraries(inkscape # make executable for INKVIEW #add_executable(inkview inkview.cpp) # ... - diff --git a/src/Makefile_insert b/src/Makefile_insert index 2bd457529..800752df4 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -154,8 +154,8 @@ ink_common_sources += \ sp-marker-loc.h \ sp-mask.cpp sp-mask.h \ sp-metadata.cpp sp-metadata.h \ + sp-mesh.cpp sp-mesh.h \ sp-mesh-array.cpp sp-mesh-array.h \ - sp-mesh-gradient.cpp sp-mesh-gradient.h \ sp-mesh-patch.cpp sp-mesh-patch.h \ sp-mesh-row.cpp sp-mesh-row.h \ sp-missing-glyph.cpp sp-missing-glyph.h \ diff --git a/src/attributes.cpp b/src/attributes.cpp index 0b18b80cf..568f0528a 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -291,7 +291,7 @@ static SPStyleProp const props[] = { {SP_ATTR_FY, "fy"}, /* SPMeshPatch */ {SP_ATTR_TENSOR, "tensor"}, - {SP_ATTR_SMOOTH, "smooth"}, + //{SP_ATTR_TYPE, "type"}, /* SPPattern */ {SP_ATTR_PATTERNUNITS, "patternUnits"}, {SP_ATTR_PATTERNCONTENTUNITS, "patternContentUnits"}, diff --git a/src/attributes.h b/src/attributes.h index 645aad00b..91c8868f9 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -293,7 +293,7 @@ enum SPAttributeEnum { SP_ATTR_FY, /* SPMeshPatch */ SP_ATTR_TENSOR, - SP_ATTR_SMOOTH, + //SP_ATTR_TYPE, /* SPPattern */ SP_ATTR_PATTERNUNITS, SP_ATTR_PATTERNCONTENTUNITS, diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index 6e728b03d..eadd7e528 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -210,9 +210,9 @@ Drawing::_pickItemsForCaching() } std::set<DrawingItem*> to_cache; - for (i = _candidate_items.begin(); i != _candidate_items.end(); ++i) { - i->item->setCached(true); - to_cache.insert(i->item); + for (CandidateList::iterator j = _candidate_items.begin(); j != i; ++j) { + j->item->setCached(true); + to_cache.insert(j->item); } // Everything which is now in _cached_items but not in to_cache must be uncached // Note that calling setCached on an item modifies _cached_items diff --git a/src/document.cpp b/src/document.cpp index 2c301f5f8..f06953e34 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -611,7 +611,25 @@ Inkscape::Util::Unit const& SPDocument::getSVGUnit() const return nv ? nv->getSVGUnit() : *unit_table.getUnit("px"); } -/// Returns document scale as defined by width/height and viewBox (real world to user-units). +/// Sets document scale (by changing viewBox) +void SPDocument::setDocumentScale( double scaleX, double scaleY ) { + + root->viewBox = Geom::Rect::from_xywh( + root->viewBox.left(), + root->viewBox.top(), + root->width.computed * scaleX, + root->height.computed * scaleY ); + root->viewBox_set = true; + root->updateRepr(); +} + +/// Sets document scale (by changing viewBox, x and y scaling equal) +void SPDocument::setDocumentScale( double scale ) { + setDocumentScale( scale, scale ); +} + +/// Returns document scale as defined by width/height (in pixels) and viewBox (real world to +/// user-units). Geom::Scale SPDocument::getDocumentScale() const { Geom::Scale scale; @@ -660,10 +678,12 @@ void SPDocument::setWidthAndHeight(const Inkscape::Util::Quantity &width, const root->height.value = height.quantity; root->height.unit = (SVGLength::Unit) height.unit->svgUnit(); - if (root->viewBox_set && changeSize) + // viewBox scaled by relative change in page size (maintains document scale). + if (root->viewBox_set && changeSize) { root->viewBox.setMax(Geom::Point( root->viewBox.left() + (root->width.value / old_width_converted ) * root->viewBox.width(), root->viewBox.top() + (root->height.value / old_height_converted) * root->viewBox.height())); + } root->updateRepr(); } @@ -744,6 +764,17 @@ void SPDocument::setHeight(const Inkscape::Util::Quantity &height, bool changeSi root->updateRepr(); } +Geom::Rect SPDocument::getViewBox() const +{ + Geom::Rect viewBox; + if (root->viewBox_set) { + viewBox = root->viewBox; + } else { + viewBox = Geom::Rect::from_xywh( 0, 0, getWidth().value("px"), getHeight().value("px")); + } + return viewBox; +} + void SPDocument::setViewBox(const Geom::Rect &viewBox) { root->viewBox_set = true; diff --git a/src/document.h b/src/document.h index cf958f03e..16b9bb28d 100644 --- a/src/document.h +++ b/src/document.h @@ -242,9 +242,12 @@ public: SPDocument *doUnref(); Inkscape::Util::Unit const* getDisplayUnit() const; Inkscape::Util::Unit const& getSVGUnit() const; + void setDocumentScale( const double scaleX, const double scaleY ); + void setDocumentScale( const double scale ); Geom::Scale getDocumentScale() const; Inkscape::Util::Quantity getWidth() const; Inkscape::Util::Quantity getHeight() const; + Geom::Rect getViewBox() const; Geom::Point getDimensions() const; Geom::OptRect preferredBounds() const; void setWidthAndHeight(const Inkscape::Util::Quantity &width, const Inkscape::Util::Quantity &height, bool changeSize=true); diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index d76c187a2..2d6619e1e 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -42,6 +42,7 @@ #include "sp-hatch.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" +#include "sp-mesh.h" #include "sp-pattern.h" #include "sp-mask.h" #include "sp-clippath.h" @@ -1259,6 +1260,10 @@ CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const pain sp_color_get_rgb_floatv(&rg->vector.stops[i].color, rgb); cairo_pattern_add_color_stop_rgba(pattern, rg->vector.stops[i].offset, rgb[0], rgb[1], rgb[2], rg->vector.stops[i].opacity * alpha); } + } else if (SP_IS_MESH (paintserver)) { + SPMesh *mg = SP_MESH(paintserver); + + pattern = mg->pattern_new(_cr, pbox, 1.0); } else if (SP_IS_PATTERN (paintserver)) { pattern = _createPatternPainter(paintserver, pbox); } else if ( dynamic_cast<SPHatch const *>(paintserver) ) { diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index a2cea014b..49e145de0 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -515,7 +515,7 @@ static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx) SPStyle* style = item->style; if((ctx->getFilterToBitmap() == TRUE) && (style->filter.set != 0)) { - sp_asbitmap_render(item, ctx); + return sp_asbitmap_render(item, ctx); } SPRoot *root = dynamic_cast<SPRoot *>(item); diff --git a/src/extension/internal/filter/color.h b/src/extension/internal/filter/color.h index 19af6e969..c3c26bf8b 100644 --- a/src/extension/internal/filter/color.h +++ b/src/extension/internal/filter/color.h @@ -3,13 +3,14 @@ /* Change the 'COLOR' above to be your file name */ /* - * Copyright (C) 2013 Authors: + * Copyright (C) 2013-2015 Authors: * Ivan Louette (filters) * Nicolas Dufour (UI) <nicoduf@yahoo.fr> * * Color filters * Brilliance * Channel painting + * Color blindness * Color shift * Colorize * Component transfer @@ -231,6 +232,80 @@ ChannelPaint::get_filter_text (Inkscape::Extension::Extension * ext) }; /* Channel Painting filter */ /** + \brief Custom predefined Color Blindness filter. + + Color Blindness filter. + Based on https://openclipart.org/detail/22299/Color%20Blindness%20filters + + Filter's parameters: + * Blindness type (enum, default Achromatomaly) -> colormatrix +*/ +class ColorBlindness : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + ColorBlindness ( ) : Filter() { }; + virtual ~ColorBlindness ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Color Blindness") "</name>\n" + "<id>org.inkscape.effect.filter.ColorBlindness</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"type\" gui-text=\"" N_("Blindness type:") "\" type=\"enum\">\n" + "<_item value=\"0.618 0.32 0.062 0 0 0.163 0.775 0.062 0 0 0.163 0.32 0.516 0 0 0 0 0 1 0 \">" N_("Rod monochromacy (atypical achromatopsia)") "</_item>\n" + "<_item value=\"0.299 0.587 0.114 0 0 0.299 0.587 0.114 0 0 0.299 0.587 0.114 0 0 0 0 0 1 0 \">" N_("Cone monochromacy (typical achromatopsia)") "</_item>\n" + "<_item value=\"0.8 0.2 0 0 0 0.2583 0.74167 0 0 0 0 0.14167 0.85833 0 0 0 0 0 1 0 \">" N_("Geen weak (deuteranomaly)") "</_item>\n" + "<_item value=\"0.625 0.375 0 0 0 0.7 0.3 0 0 0 0 0.3 0.7 0 0 0 0 0 1 0 \">" N_("Green blind (deuteranopia)") "</_item>\n" + "<_item value=\"0.8166 0.1833 0 0 0 0.333 0.666 0 0 0 0 0.125 0.875 0 0 0 0 0 1 0 \">" N_("Red weak (protanomaly)") "</_item>\n" + "<_item value=\"0.566 0.43333 0 0 0 0.55833 0.4416 0 0 0 0 0.24167 0.75833 0 0 0 0 0 1 0 \">" N_("Red blind (protanopia)") "</_item>\n" + "<_item value=\"0.966 0.033 0 0 0 0 0.733 0.266 0 0 0 0.1833 0.816 0 0 0 0 0 1 0 \">" N_("Blue weak (tritanomaly)") "</_item>\n" + "<_item value=\"0.95 0.05 0 0 0 0.2583 0.4333 0.5667 0 0 0 0.475 0.525 0 0 0 0 0 1 0 \">" N_("Blue blind (tritanopia)") "</_item>\n" + "</param>\n" + "</page>\n" + "<page name=\"helptab\" _gui-text=\"Help\">\n" + "<param name=\"help\" xml:space=\"preserve\" type=\"description\">\n" +"Filters based on https://openclipart.org/detail/22299/Color%20Blindness%20filters\n" +"\n" +"These filters don't correctly reflect actual color blindness for two main reasons:\n" +" * Everyone is different, and is not affected exactly the same way.\n" +" * The filters are in the RGB color space, and ignore confusion lines.\n" + "</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Color") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Simulate color blindness") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new ColorBlindness()); + }; +}; + +gchar const * +ColorBlindness::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream type; + type << ext->get_param_enum("type"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" style=\"color-interpolation-filters:sRGB;\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Color Blindness\">\n" + "<feColorMatrix values=\"%s\" type=\"matrix\" result=\"colormatrix1\" />\n" + "</filter>\n", type.str().c_str()); + + return _filter; +}; /* Color Blindness filter */ + +/** \brief Custom predefined Color shift filter. Rotate and desaturate hue diff --git a/src/extension/internal/filter/filter-all.cpp b/src/extension/internal/filter/filter-all.cpp index 0273d1669..35504d37f 100644 --- a/src/extension/internal/filter/filter-all.cpp +++ b/src/extension/internal/filter/filter-all.cpp @@ -54,6 +54,7 @@ Filter::filters_all (void ) // Color Brilliance::init(); ChannelPaint::init(); + ColorBlindness::init(); ColorShift::init(); Colorize::init(); ComponentTransfer::init(); diff --git a/src/extension/param/radiobutton.cpp b/src/extension/param/radiobutton.cpp index f9515197c..740acf1d1 100644 --- a/src/extension/param/radiobutton.cpp +++ b/src/extension/param/radiobutton.cpp @@ -249,28 +249,35 @@ void ParamRadioButtonWdg::changed(void) class ComboWdg : public Gtk::ComboBoxText { +private: + ParamRadioButton* _base; + SPDocument* _doc; + Inkscape::XML::Node* _node; + sigc::signal<void> * _changeSignal; + public: - ComboWdg(ParamRadioButton* base, SPDocument * doc, Inkscape::XML::Node * node) : - Gtk::ComboBoxText(), - base(base), - doc(doc), - node(node) + ComboWdg(ParamRadioButton* base, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) : + _base(base), + _doc(doc), + _node(node), + _changeSignal(changeSignal) { + this->signal_changed().connect(sigc::mem_fun(this, &ComboWdg::changed)); } virtual ~ComboWdg() {} + void changed (void); +}; -protected: - ParamRadioButton* base; - SPDocument* doc; - Inkscape::XML::Node* node; - - virtual void on_changed() { - if ( base ) { - Glib::ustring value = base->value_from_label(get_active_text()); - base->set(value.c_str(), doc, node); - } +void ComboWdg::changed(void) +{ + if ( _base ) { + Glib::ustring value = _base->value_from_label(get_active_text()); + _base->set(value.c_str(), _doc, _node); } -}; + if (_changeSignal != NULL) { + _changeSignal->emit(); + } +} /** * Returns the value for the options label parameter @@ -317,7 +324,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node Gtk::ComboBoxText* cbt = 0; bool comboSet = false; if (_mode == MINIMAL) { - cbt = Gtk::manage(new ComboWdg(this, doc, node)); + cbt = Gtk::manage(new ComboWdg(this, doc, node, changeSignal)); cbt->show(); vbox->pack_start(*cbt, false, false); } diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index b59b38475..d90972961 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -41,7 +41,7 @@ #include "sp-gradient-vector.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh-gradient.h" +#include "sp-mesh.h" #include "sp-stop.h" #include "gradient-drag.h" #include "gradient-chemistry.h" @@ -151,7 +151,7 @@ static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGr repr = xml_doc->createElement("svg:radialGradient"); } else { // Rows/patches added in sp_gradient_reset_to_userspace for new meshes. - repr = xml_doc->createElement("svg:meshGradient"); + repr = xml_doc->createElement("svg:mesh"); } // privates are garbage-collectable @@ -413,7 +413,7 @@ SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item) // IN SPMeshNodeArray::create() //sp_repr_set_svg_double(repr, "x", bbox->min()[Geom::X]); //sp_repr_set_svg_double(repr, "y", bbox->min()[Geom::Y]); - SPMeshGradient* mg = SP_MESHGRADIENT( gr ); + SPMesh* mg = SP_MESH( gr ); mg->array.create( mg, item, bbox ); } @@ -758,10 +758,10 @@ guint32 sp_item_gradient_stop_query_style(SPItem *item, GrPointType point_type, break; } return 0; - } else if (SP_IS_MESHGRADIENT(gradient)) { + } else if (SP_IS_MESH(gradient)) { // Mesh gradient - SPMeshGradient *mg = SP_MESHGRADIENT(gradient); + SPMesh *mg = SP_MESH(gradient); switch (point_type) { case POINT_MG_CORNER: { @@ -859,7 +859,7 @@ void sp_item_gradient_stop_set_style(SPItem *item, GrPointType point_type, guint } else { // Mesh gradient - SPMeshGradient *mg = SP_MESHGRADIENT(gradient); + SPMesh *mg = SP_MESH(gradient); bool changed = false; switch (point_type) { @@ -1209,8 +1209,8 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } } - } else if (SP_IS_MESHGRADIENT(gradient)) { - SPMeshGradient *mg = SP_MESHGRADIENT(gradient); + } else if (SP_IS_MESH(gradient)) { + SPMesh *mg = SP_MESH(gradient); //Geom::Affine new_transform; //bool transform_set = false; @@ -1240,7 +1240,7 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi } if( write_repr ) { //std::cout << "Write mesh repr" << std::endl; - sp_meshgradient_repr_write( mg ); + sp_mesh_repr_write( mg ); } } @@ -1346,8 +1346,8 @@ Geom::Point getGradientCoords(SPItem *item, GrPointType point_type, guint point_ g_warning( "Bad radial gradient handle type" ); break; } - } else if (SP_IS_MESHGRADIENT(gradient)) { - SPMeshGradient *mg = SP_MESHGRADIENT(gradient); + } else if (SP_IS_MESH(gradient)) { + SPMesh *mg = SP_MESH(gradient); switch (point_type) { case POINT_MG_CORNER: diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 5a49435d4..169710114 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -43,7 +43,7 @@ #include "knot.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh-gradient.h" +#include "sp-mesh.h" #include "sp-mesh-row.h" #include "sp-mesh-patch.h" #include "gradient-chemistry.h" @@ -414,7 +414,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler //r1_knot = false; } } - } else if (SP_IS_MESHGRADIENT(gradient)) { + } else if (SP_IS_MESH(gradient)) { // add_stop_near_point() // Find out which curve pointer is over and use that curve to determine @@ -422,7 +422,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler // This is silly as we already should know which line we are over... // but that information is not saved (sp_gradient_context_is_over_line). - SPMeshGradient *mg = SP_MESHGRADIENT(gradient); + SPMesh *mg = SP_MESH(gradient); Geom::Affine transform = Geom::Affine(mg->gradientTransform)*(Geom::Affine)item->i2dt_affine(); guint rows = mg->array.patch_rows(); @@ -550,7 +550,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler } else { - SPMeshGradient *mg = SP_MESHGRADIENT(gradient); + SPMesh *mg = SP_MESH(gradient); if( divide_row > -1 ) { mg->array.split_row( divide_row, divide_coord ); @@ -559,7 +559,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler } // Update repr - sp_meshgradient_repr_write( mg ); + sp_mesh_repr_write( mg ); mg->array.built = false; mg->ensureArray(); // How do we do this? @@ -1349,7 +1349,7 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) // Must be a mesh gradient SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke); - if ( !SP_IS_MESHGRADIENT( gradient ) ) continue; + if ( !SP_IS_MESH( gradient ) ) continue; selected_corners[ gradient ].push_back( draggable->point_i ); } @@ -1374,8 +1374,8 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op ) // Must be a mesh gradient SPGradient *gradient = getGradient(item, fill_or_stroke); - if ( !SP_IS_MESHGRADIENT( gradient ) ) continue; - SPMeshGradient *mg = SP_MESHGRADIENT( gradient ); + if ( !SP_IS_MESH( gradient ) ) continue; + SPMesh *mg = SP_MESH( gradient ); // pc_old is the old corner position in desktop coordinates, we need it in gradient coordinate. gradient = sp_gradient_convert_to_userspace (gradient, item, (fill_or_stroke == Inkscape::FOR_FILL) ? "fill" : "stroke"); @@ -1958,7 +1958,7 @@ void GrDrag::addDraggersLinear(SPLinearGradient *lg, SPItem *item, Inkscape::Pai /** *Add draggers for the mesh gradient mg on item */ -void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke) +void GrDrag::addDraggersMesh(SPMesh *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke) { std::vector< std::vector< SPMeshNode* > > nodes = mg->array.nodes; @@ -1977,7 +1977,7 @@ void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTa // Make sure we have at least one patch defined. if( mg->array.patch_rows() == 0 || mg->array.patch_columns() == 0 ) { - std::cout << "Empty Mesh Gradient, No Draggers to Add" << std::endl; + std::cout << "Empty Mesh, No Draggers to Add" << std::endl; return; } @@ -2032,7 +2032,7 @@ void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTa } default: - std::cout << "Bad Mesh Gradient draggable type" << std::endl; + std::cout << "Bad Mesh draggable type" << std::endl; break; } } @@ -2097,8 +2097,8 @@ void GrDrag::updateDraggers() addDraggersLinear( SP_LINEARGRADIENT(server), item, Inkscape::FOR_FILL ); } else if ( SP_IS_RADIALGRADIENT(server) ) { addDraggersRadial( SP_RADIALGRADIENT(server), item, Inkscape::FOR_FILL ); - } else if ( SP_IS_MESHGRADIENT(server) ) { - addDraggersMesh( SP_MESHGRADIENT(server), item, Inkscape::FOR_FILL ); + } else if ( SP_IS_MESH(server) ) { + addDraggersMesh( SP_MESH(server), item, Inkscape::FOR_FILL ); } } } @@ -2113,8 +2113,8 @@ void GrDrag::updateDraggers() addDraggersLinear( SP_LINEARGRADIENT(server), item, Inkscape::FOR_STROKE ); } else if ( SP_IS_RADIALGRADIENT(server) ) { addDraggersRadial( SP_RADIALGRADIENT(server), item, Inkscape::FOR_STROKE ); - } else if ( SP_IS_MESHGRADIENT(server) ) { - addDraggersMesh( SP_MESHGRADIENT(server), item, Inkscape::FOR_STROKE ); + } else if ( SP_IS_MESH(server) ) { + addDraggersMesh( SP_MESH(server), item, Inkscape::FOR_STROKE ); } } } @@ -2169,9 +2169,9 @@ void GrDrag::updateLines() Geom::Point center = getGradientCoords(item, POINT_RG_CENTER, 0, Inkscape::FOR_FILL); addLine(item, center, getGradientCoords(item, POINT_RG_R1, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL); addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL); - } else if ( SP_IS_MESHGRADIENT(server) ) { + } else if ( SP_IS_MESH(server) ) { - SPMeshGradient *mg = SP_MESHGRADIENT(server); + SPMesh *mg = SP_MESH(server); guint rows = mg->array.patch_rows(); guint columns = mg->array.patch_columns(); @@ -2231,10 +2231,10 @@ void GrDrag::updateLines() Geom::Point center = getGradientCoords(item, POINT_RG_CENTER, 0, Inkscape::FOR_STROKE); addLine(item, center, getGradientCoords(item, POINT_RG_R1, 0, Inkscape::FOR_STROKE), Inkscape::FOR_STROKE); addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_STROKE), Inkscape::FOR_STROKE); - } else if ( SP_IS_MESHGRADIENT(server) ) { + } else if ( SP_IS_MESH(server) ) { // MESH FIXME: TURN ROUTINE INTO FUNCTION AND CALL FOR BOTH FILL AND STROKE. - SPMeshGradient *mg = SP_MESHGRADIENT(server); + SPMesh *mg = SP_MESH(server); guint rows = mg->array.patch_rows(); guint columns = mg->array.patch_columns(); diff --git a/src/gradient-drag.h b/src/gradient-drag.h index 964ea8093..da264b4bb 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -33,7 +33,7 @@ class SPKnot; class SPDesktop; class SPCSSAttr; class SPLinearGradient; -class SPMeshGradient; +class SPMesh; class SPItem; class SPObject; class SPRadialGradient; @@ -206,7 +206,7 @@ private: void addDraggersRadial(SPRadialGradient *rg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); void addDraggersLinear(SPLinearGradient *lg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); - void addDraggersMesh( SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); + void addDraggersMesh( SPMesh *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); bool styleSet( const SPCSSAttr *css ); diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index 74ce2c85d..ff4760c24 100644 --- a/src/helper/CMakeLists.txt +++ b/src/helper/CMakeLists.txt @@ -13,6 +13,7 @@ set(helper_SRC action-context.cpp geom.cpp geom-nodetype.cpp + geom-pathstroke.cpp gnome-utils.cpp pixbuf-ops.cpp png-write.cpp @@ -30,6 +31,7 @@ set(helper_SRC action-context.h geom-curves.h geom-nodetype.h + geom-pathstroke.h geom.h gnome-utils.h mathfns.h diff --git a/src/helper/Makefile_insert b/src/helper/Makefile_insert index 5cb4cea8d..e59fcfb70 100644 --- a/src/helper/Makefile_insert +++ b/src/helper/Makefile_insert @@ -12,6 +12,8 @@ ink_common_sources += \ helper/geom-curves.h \ helper/geom-nodetype.cpp \ helper/geom-nodetype.h \ + helper/geom-pathstroke.cpp \ + helper/geom-pathstroke.h \ helper/gnome-utils.cpp \ helper/gnome-utils.h \ helper/mathfns.h \ diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp new file mode 100644 index 000000000..eb0c432c6 --- /dev/null +++ b/src/helper/geom-pathstroke.cpp @@ -0,0 +1,770 @@ +/* Author: + * Liam P. White + * + * Copyright (C) 2014-2015 Author + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <iomanip> +#include <2geom/path-sink.h> +#include <2geom/point.h> +#include <2geom/bezier-curve.h> +#include <2geom/svg-elliptical-arc.h> +#include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis +#include <2geom/path-intersection.h> + +#include "helper/geom-pathstroke.h" + +namespace Geom { +// 2geom/circle-circle.cpp, no header +int circle_circle_intersection(Point X0, double r0, Point X1, double r1, Point &p0, Point &p1); + +/** + * Determine the intersection points between a circle C0 and a line defined + * by two points, X0 and X1. + * + * Which intersection point is assigned to p0 or p1 is unspecified, and callers + * should not depend on any particular intersection always being assigned to p0. + * + * Returns: + * If the line and circle do not cross, 0 is returned. + * If solution(s) exist, 2 is returned, and the results are written to p0 and p1. + */ +static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Point &p1) +{ + /* equation of a circle: (x - h)^2 + (y - k)^2 = r^2 */ + Coord r = C0.ray(); + Coord h = C0.center()[X]; + Coord k = C0.center()[Y]; + + Coord x0, y0; + Coord x1, y1; + + if (are_near(X1[X], X0[X])) { + /* slope is undefined (vertical line) */ + Coord c = X0[X]; + Coord det = r*r - (c-h)*(c-h); + + /* no intersection */ + if (det < 0) + return 0; + + /* solve for y */ + y0 = k + std::sqrt(det); + y1 = k - std::sqrt(det); + + // x == c (always) + x0 = c; + x1 = c; + } else { + /* equation of a line: y = mx + b */ + Coord m = (X1[Y] - X0[Y]) / (X1[X] - X0[X]); + Coord b = X0[Y] - m*X0[X]; + + /* obtain quadratic for x: */ + Coord A = m*m + 1; + Coord B = 2*h - 2*b*m + 2*k*m; + Coord C = b*b + h*h + k*k - r*r - 2*b*k; + + Coord det = B*B - 4*A*C; + + /* no intersection, circle and line do not cross */ + if (det < 0) + return 0; + + /* solve quadratic */ + x0 = (B + std::sqrt(det)) / (2*A); + x1 = (B - std::sqrt(det)) / (2*A); + + /* substitute the calculated x times to determine the y values */ + y0 = m*x0 + b; + y1 = m*x1 + b; + } + + p0 = Point(x0, y0); + p1 = Point(x1, y1); + + return 2; +} + +static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b) +{ + Coord denom = cross(vector_b, vector_a); + if (!are_near(denom,0.)) { + Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + return origin_a + vector_a*t; + } + return Point(infinity(), infinity()); +} + +/** +* Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. +* Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). +*/ +static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.01 ) +{ + D2<SBasis> dM=derivative(curve); + if ( are_near(L2sq(dM(t)),0.) ) { + dM=derivative(dM); + } + if ( are_near(L2sq(dM(t)),0.) ) { // try second time + dM=derivative(dM); + } + Piecewise<D2<SBasis> > unitv = unitVector(dM,tol); + Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv); + Piecewise<SBasis> k = cross(derivative(unitv),unitv); + k = divide(k,dMlength,tol,3); + double curv = k(t); // note that this value is signed + + Geom::Point normal = unitTangentAt(curve, t).cw(); + double radius = 1/curv; + Geom::Point center = curve(t) + radius*normal; + return Geom::Circle(center, fabs(radius)); +} + +} + +namespace { + +// Join functions may: +// - inspect any curve of the current path +// - append any type of curve to the current path +// - inspect the outgoing path +// +// Join functions must: +// - append the outgoing curve +// OR +// - end at outgoing.finalPoint + +typedef void join_func(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width); + +void bevel_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double /*width*/) +{ + res.appendNew<Geom::LineSegment>(outgoing.initialPoint()); + res.append(outgoing); +} + +void round_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double width) +{ + res.appendNew<Geom::SVGEllipticalArc>(width, width, 0, false, width <= 0, outgoing.initialPoint()); + res.append(outgoing); +} + +void miter_join_internal(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width, bool clip) +{ + Geom::Curve const& incoming = res.back(); + Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); + Geom::Point tang2 = outgoing.unitTangentAt(0); + Geom::Point p = Geom::intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); + + bool satisfied = false; + bool inc_ls = res.back_open().degreesOfFreedom() <= 4; + + if (p.isFinite()) { + // check size of miter + Geom::Point point_on_path = incoming.finalPoint() + Geom::rot90(tang1)*width; + satisfied = Geom::distance(p, point_on_path) <= miter * 2.0 * width; + if (satisfied) { + // miter OK, check to see if we can do a relocation + if (inc_ls) { + res.setFinal(p); + } else { + res.appendNew<Geom::LineSegment>(p); + } + } else if (clip) { + // miter needs clipping, find two points + Geom::Point bisector_versor = Geom::Line(point_on_path, p).versor(); + Geom::Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor; + + Geom::Point p1 = Geom::intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw()); + Geom::Point p2 = Geom::intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw()); + + if (inc_ls) { + res.setFinal(p1); + } else { + res.appendNew<Geom::LineSegment>(p1); + } + res.appendNew<Geom::LineSegment>(p2); + } + } + + res.appendNew<Geom::LineSegment>(outgoing.initialPoint()); + + // check if we can do another relocation + bool out_ls = outgoing.degreesOfFreedom() <= 4; + + if ( (satisfied || clip) && out_ls) { + res.setFinal(outgoing.finalPoint()); + } else { + res.append(outgoing); + } +} + +void miter_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) { + miter_join_internal( res, outgoing, miter, width, false ); +} + +void miter_clip_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) { + miter_join_internal( res, outgoing, miter, width, true ); +} + +Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt) +{ + Geom::Point sol; + if ( dot(tang2,points[0]-endPt) > 0 ) { + // points[0] is bad, choose points[1] + sol = points[1]; + } else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] + // points[1] is bad, choose points[0] + sol = points[0]; + } else { + // both points are good, choose nearest + sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? points[0] : points[1]; + } + return sol; +} + +void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) +{ + using namespace Geom; + + Geom::Curve const& incoming = res.back(); + Geom::Point startPt = incoming.finalPoint(); + Geom::Point endPt = outgoing.initialPoint(); + Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); + Geom::Point tang2 = outgoing.unitTangentAt(0); + + Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.); + Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0); + + bool inc_ls = !circle1.center().isFinite(); + bool out_ls = !circle2.center().isFinite(); + + Geom::Point points[2]; + + int solutions = 0; + Geom::EllipticalArc *arc1 = NULL; + Geom::EllipticalArc *arc2 = NULL; + Geom::Point sol; + Geom::Point p1; + Geom::Point p2; + + if (!inc_ls && !out_ls) { + // Two circles + solutions = Geom::circle_circle_intersection(circle1.center(), circle1.ray(), + circle2.center(), circle2.ray(), + points[0], points[1]); + if (solutions == 2) { + sol = pick_solution(points, tang2, endPt); + arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol, true); + arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + } + } else if (inc_ls && !out_ls) { + // Line and circle + solutions = Geom::circle_line_intersection(circle2, incoming.initialPoint(), incoming.finalPoint(), points[0], points[1]); + + if (solutions == 2) { + sol = pick_solution(points, tang2, endPt); + arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + } + } else if (!inc_ls && out_ls) { + // Circle and line + solutions = Geom::circle_line_intersection(circle1, outgoing.initialPoint(), outgoing.finalPoint(), points[0], points[1]); + + if (solutions == 2) { + sol = pick_solution(points, tang2, endPt); + arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol, true); + } + } + + if (solutions != 2) + // no solutions available, fall back to miter + return miter_clip_join(res, outgoing, miter, width); + + // We have a solution, thus sol is defined. + p1 = sol; + + // See if we need to clip. Miter length is measured along a circular arc that is tangent to the + // bisector of the incoming and out going angles and passes through the end point (sol) of the + // line join. + + // Center of circle is intersection of a line orthogonal to bisector and a line bisecting + // a chord connecting the path end point (point_on_path) and the join end point (sol). + Geom::Point point_on_path = startPt + Geom::rot90(tang1)*width; + Geom::Line bisector = make_angle_bisector_line(startPt, point_on_path, endPt); + Geom::Line ortho = make_orthogonal_line(point_on_path, bisector); + + Geom::LineSegment chord(point_on_path, sol); + Geom::Line bisector_chord = make_bisector_line(chord); + + Geom::Line limit_line; + double miter_limit = 2.0 * width * miter; + bool clipped = false; + + if (are_parallel(bisector_chord, ortho)) { + // No intersection (can happen if curvatures are equal but opposite) + if (Geom::distance(point_on_path, sol) > miter_limit) { + clipped = true; + Geom::Point limit_point = point_on_path + miter_limit * bisector.versor(); + limit_line = make_parallel_line( limit_point, ortho ); + } + } else { + Geom::Point center = + Geom::intersection_point( bisector_chord.pointAt(0), bisector_chord.versor(), + ortho.pointAt(0), ortho.versor() ); + Geom::Coord radius = distance(center, point_on_path); + Geom::Circle circle_center(center, radius); + + double limit_angle = miter_limit / radius; + + Geom::Ray start_ray(center, point_on_path); + Geom::Ray end_ray(center, sol); + Geom::Line limit_line(center, 0); // Angle set below + + if (Geom::cross(start_ray.versor(), end_ray.versor()) > 0) { + limit_line.setAngle(start_ray.angle() - limit_angle); + } else { + limit_line.setAngle(start_ray.angle() + limit_angle); + } + + Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol, true); + if (arc_center && arc_center->sweepAngle() > limit_angle) { + // We need to clip + clipped = true; + + if (!inc_ls) { + // Incoming circular + solutions = Geom::circle_line_intersection(circle1, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]); + + if (solutions == 2) { + p1 = pick_solution(points, tang2, endPt); + delete arc1; + arc1 = circle1.arc(startPt, 0.5*(p1+startPt), p1, true); + } + } else { + p1 = Geom::intersection_point(startPt, tang1, limit_line.pointAt(0), limit_line.versor()); + } + + if (!out_ls) { + // Outgoing circular + solutions = Geom::circle_line_intersection(circle2, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]); + + if (solutions == 2) { + p2 = pick_solution(points, tang1, endPt); + delete arc2; + arc2 = circle2.arc(p2, 0.5*(p2+endPt), endPt, true); + } + } else { + p2 = Geom::intersection_point(endPt, tang2, limit_line.pointAt(0), limit_line.versor()); + } + } + } + + // Add initial + if (arc1) { + res.append(*arc1); + } else { + // Straight line segment: move last point + res.setFinal(p1); + } + + if (clipped) { + res.appendNew<Geom::LineSegment>(p2); + } + + // Add outgoing + if (arc2) { + res.append(*arc2); + res.append(outgoing); + } else { + // Straight line segment: + res.appendNew<Geom::LineSegment>(outgoing.finalPoint()); + } + + delete arc1; + delete arc2; +} + +void join_inside(Geom::Path& res, Geom::Curve const& outgoing) +{ + Geom::Curve const& incoming = res.back_open(); + Geom::Crossings cross = Geom::crossings(incoming, outgoing); + + if (!cross.empty()) { + // yeah if we could avoid allocing that'd be great + Geom::Curve *d1 = incoming.portion(0., cross[0].ta); + res.erase_last(); + res.append(*d1); + delete d1; + + Geom::Curve *d2 = outgoing.portion(cross[0].tb, 1.); + res.setFinal(d2->initialPoint()); + res.append(*d2); + delete d2; + } else { + res.appendNew<Geom::LineSegment>(outgoing.initialPoint()); + res.append(outgoing); + } +} + +bool decide(Geom::Curve const& incoming, Geom::Curve const& outgoing) +{ + Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); + Geom::Point tang2 = outgoing.unitTangentAt(0.); + return (Geom::cross(tang1, tang2) < 0); +} + +void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join) +{ + if (res.size() == 0 || to_add.size() == 0) + return; + + Geom::Curve const& outgoing = to_add[0]; + if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { + // if the points are /that/ close, just ignore this one + res.setFinal(outgoing.initialPoint()); + res.append(outgoing); + return; + } + + if (on_outside) { + join_func *jf; + switch (join) { + case Inkscape::JOIN_BEVEL: + jf = &bevel_join; + break; + case Inkscape::JOIN_ROUND: + jf = &round_join; + break; + case Inkscape::JOIN_EXTRAPOLATE: + jf = &extrapolate_join; + break; + case Inkscape::JOIN_MITER_CLIP: + jf = &miter_clip_join; + break; + default: + jf = &miter_join; + } + jf(res, outgoing, miter, width); + } else { + join_inside(res, outgoing); + } +} + +// Offsetting a line segment is mathematically stable and quick to do +Geom::LineSegment offset_line(Geom::LineSegment const& l, double width) +{ + Geom::Point tang1 = Geom::rot90(l.unitTangentAt(0)); + Geom::Point tang2 = Geom::rot90(unitTangentAt(reverse(l.toSBasis()), 0.)); + + Geom::Point start = l.initialPoint() + tang1 * width; + Geom::Point end = l.finalPoint() - tang2 * width; + + return Geom::LineSegment(start, end); +} + +void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, double& rad) +{ + // get derivatives + std::vector<Geom::Point> derivs = bez.pointAndDerivatives(time, 3); + + Geom::Point der1 = derivs[1]; // first deriv (tangent vector) + Geom::Point der2 = derivs[2]; // second deriv (tangent's tangent) + double l = Geom::L2(der1); // length + + len = rad = 0; + + // TODO: we might want to consider using Geom::touching_circle to determine the + // curvature radius here. Less code duplication, but slower + + if (Geom::are_near(l, 0, 1e-4)) { + l = Geom::L2(der2); + Geom::Point der3 = derivs.at(3); // try second time + if (Geom::are_near(l, 0, 1e-4)) { + l = Geom::L2(der3); + if (Geom::are_near(l, 0)) { + return; // this isn't a segment... + } + rad = 1e8; + } else { + rad = -l * (Geom::dot(der2, der2) / Geom::cross(der3, der2)); + } + } else { + rad = -l * (Geom::dot(der1, der1) / Geom::cross(der2, der1)); + } + len = l; +} + +void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels) +{ + using Geom::X; + using Geom::Y; + + Geom::Point start_pos = bez.initialPoint(); + Geom::Point end_pos = bez.finalPoint(); + + Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0)); + Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.)); + + // offset the start and end control points out by the width + Geom::Point start_new = start_pos + start_normal*width; + Geom::Point end_new = end_pos + end_normal*width; + + // -------- + double start_rad, end_rad; + double start_len, end_len; // tangent lengths + get_cubic_data(bez, 0, start_len, start_rad); + get_cubic_data(bez, 1, end_len, end_rad); + + double start_off = 1, end_off = 1; + // correction of the lengths of the tangent to the offset + if (!Geom::are_near(start_rad, 0)) + start_off += width / start_rad; + if (!Geom::are_near(end_rad, 0)) + end_off += width / end_rad; + start_off *= start_len; + end_off *= end_len; + // -------- + + Geom::Point mid1_new = start_normal.ccw()*start_off; + mid1_new = Geom::Point(start_new[X] + mid1_new[X]/3., start_new[Y] + mid1_new[Y]/3.); + Geom::Point mid2_new = end_normal.ccw()*end_off; + mid2_new = Geom::Point(end_new[X] - mid2_new[X]/3., end_new[Y] - mid2_new[Y]/3.); + + // create the estimate curve + Geom::CubicBezier c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new); + + // reached maximum recursive depth + // don't bother with any more correction + if (levels == 0) { + p.append(c, Geom::Path::STITCH_DISCONTINUOUS); + return; + } + + // check the tolerance for our estimate to be a parallel curve + Geom::Point chk = c.pointAt(.5); + Geom::Point req = bez.pointAt(.5) + Geom::rot90(bez.unitTangentAt(.5))*width; // required accuracy + + Geom::Point const diff = req - chk; + double const err = Geom::dot(diff, diff); + + if (err < tol) { + if (Geom::are_near(start_new, p.finalPoint())) { + p.setFinal(start_new); // if it isn't near, we throw + } + + // we're good, curve is accurate enough + p.append(c); + return; + } else { + // split the curve in two + std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(.5); + offset_cubic(p, s.first, width, tol, levels - 1); + offset_cubic(p, s.second, width, tol, levels - 1); + } +} + +void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double width, double tol, size_t levels) +{ + // cheat + // it's faster + // seriously + std::vector<Geom::Point> points = bez.points(); + Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]); + Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]); + Geom::CubicBezier cub = Geom::CubicBezier(points[0], b1, b2, points[2]); + offset_cubic(p, cub, width, tol, levels); +} + +void offset_curve(Geom::Path& res, Geom::Curve const* current, double width) +{ + double const tolerance = 0.005; + size_t levels = 8; + + if (current->isDegenerate()) return; // don't do anything + + // TODO: we can handle SVGEllipticalArc here as well, do that! + + if (Geom::BezierCurve const *b = dynamic_cast<Geom::BezierCurve const*>(current)) { + size_t order = b->order(); + switch (order) { + case 1: + res.append(offset_line(static_cast<Geom::LineSegment const&>(*current), width)); + break; + case 2: { + Geom::QuadraticBezier const& q = static_cast<Geom::QuadraticBezier const&>(*current); + offset_quadratic(res, q, width, tolerance, levels); + break; + } + case 3: { + Geom::CubicBezier const& cb = static_cast<Geom::CubicBezier const&>(*current); + offset_cubic(res, cb, width, tolerance, levels); + break; + } + default: { + Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), tolerance); + for (size_t i = 0; i < sbasis_path.size(); ++i) + offset_curve(res, &sbasis_path[i], width); + break; + } + } + } else { + Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), 0.1); + for (size_t i = 0; i < sbasis_path.size(); ++i) + offset_curve(res, &sbasis_path[i], width); + } +} + +typedef void cap_func(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width); + +void flat_cap(Geom::PathBuilder& res, Geom::Path const&, Geom::Path const& against_dir, double) +{ + res.lineTo(against_dir.initialPoint()); +} + +void round_cap(Geom::PathBuilder& res, Geom::Path const&, Geom::Path const& against_dir, double width) +{ + res.arcTo(width / 2., width / 2., 0., true, false, against_dir.initialPoint()); +} + +void square_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width) +{ + width /= 2.; + Geom::Point normal_1 = -Geom::unitTangentAt(Geom::reverse(with_dir.back().toSBasis()), 0.); + Geom::Point normal_2 = -against_dir[0].unitTangentAt(0.); + res.lineTo(with_dir.finalPoint() + normal_1*width); + res.lineTo(against_dir.initialPoint() + normal_2*width); + res.lineTo(against_dir.initialPoint()); +} + +void peak_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width) +{ + width /= 2.; + Geom::Point normal_1 = -Geom::unitTangentAt(Geom::reverse(with_dir.back().toSBasis()), 0.); + Geom::Point normal_2 = -against_dir[0].unitTangentAt(0.); + Geom::Point midpoint = ((with_dir.finalPoint() + normal_1*width) + (against_dir.initialPoint() + normal_2*width)) * 0.5; + res.lineTo(midpoint); + res.lineTo(against_dir.initialPoint()); +} + +} // namespace + +namespace Inkscape { + +Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join, LineCapType butt) +{ + if (input.size() == 0) return Geom::PathVector(); // nope, don't even try + + Geom::PathBuilder res; + Geom::Path with_dir = half_outline(input, width/2., miter, join); + Geom::Path against_dir = half_outline(input.reverse(), width/2., miter, join); + + res.moveTo(with_dir[0].initialPoint()); + res.append(with_dir); + + cap_func *cf; + switch (butt) { + case BUTT_ROUND: + cf = &round_cap; + break; + case BUTT_SQUARE: + cf = &square_cap; + break; + case BUTT_PEAK: + cf = &peak_cap; + break; + default: + cf = &flat_cap; + } + + // glue caps + if (!input.closed()) { + cf(res, with_dir, against_dir, width); + } else { + res.closePath(); + res.moveTo(against_dir.initialPoint()); + } + + res.append(against_dir); + + if (!input.closed()) { + cf(res, against_dir, with_dir, width); + } + + res.closePath(); + res.flush(); + return res.peek(); +} + +Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join) +{ + Geom::Path res; + if (input.size() == 0) return res; + + Geom::Point tang1 = input[0].unitTangentAt(0); + Geom::Point start = input.initialPoint() + tang1 * width; + Geom::Path temp; + + res.start(start); + + // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well + const size_t k = (input.back_closed().isDegenerate() && input.closed()) + ?input.size_default()-1:input.size_default(); + for (size_t u = 0; u < k; u += 2) { + temp = Geom::Path(); + + offset_curve(temp, &input[u], width); + + // on the first run through, there isn't a join + if (u == 0) { + res.append(temp); + } else { + bool on_outside = decide(input[u-1], input[u]); + outline_helper(res, temp, width, on_outside, miter, join); + if (temp.size() > 0) + res.insert(res.end(), ++temp.begin(), temp.end()); + } + + // odd number of paths + if (u < k - 1) { + temp = Geom::Path(); + offset_curve(temp, &input[u+1], width); + bool on_outside = decide(input[u], input[u+1]); + outline_helper(res, temp, width, on_outside, miter, join); + if (temp.size() > 0) + res.insert(res.end(), ++temp.begin(), temp.end()); + } + } + + if (input.closed()) { + Geom::Curve const &c1 = res.back(); + Geom::Curve const &c2 = res.front(); + temp = Geom::Path(); + temp.append(c1); + Geom::Path temp2; + temp2.append(c2); + bool on_outside = decide(input.back(), input.front()); + outline_helper(temp, temp2, width, on_outside, miter, join); + res.erase(res.begin()); + res.erase_last(); + // + res.append(temp); + res.close(); + } + + return res; +} + +} // 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:encoding=utf-8 : diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h new file mode 100644 index 000000000..0cfb9f817 --- /dev/null +++ b/src/helper/geom-pathstroke.h @@ -0,0 +1,58 @@ +#ifndef INKSCAPE_HELPER_PATH_STROKE_H +#define INKSCAPE_HELPER_PATH_STROKE_H + +/* Author: + * Liam P. White + * + * Copyright (C) 2014-2015 Author + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <2geom/path.h> +#include <2geom/pathvector.h> + +namespace Inkscape { + +enum LineJoinType { + JOIN_BEVEL, + JOIN_ROUND, + JOIN_MITER, + JOIN_MITER_CLIP, + JOIN_EXTRAPOLATE, +}; + +enum LineCapType { + BUTT_FLAT, + BUTT_ROUND, + BUTT_SQUARE, + BUTT_PEAK, // ? +}; + +/** + * Offset the input path by @a width. + * Joins may behave oddly if the width is negative. + * + * @param input + * @param width Amount to offset. + * @param miter Miter limit. Only used with JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. + * @param join + */ +Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL); + +Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT); + +} // namespace Inkscape + +#endif // INKSCAPE_HELPER_PATH_STROKE_H + +/* + 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:fileencoding=utf-8 : diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 6eba6e949..91689375f 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -556,6 +556,55 @@ pathv_to_linear( Geom::PathVector const &pathv, double /*maxdisp*/) return output; } +/* + * Converts all segments in all paths to Geom Cubic bezier. + * This is used in lattice2 LPE, maybe is better move the function to the effect + * But maybe could be usable by others, so i put here. + * The straight curve part is needed as it for the effect to work apropiately + */ +Geom::PathVector +pathv_to_cubicbezier( Geom::PathVector const &pathv) +{ + Geom::PathVector output; + double cubicGap = 0.01; + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { + output.push_back( Geom::Path() ); + output.back().start( pit->initialPoint() ); + output.back().close( pit->closed() ); + bool end_open = false; + if (pit->closed()) { + const Geom::Curve &closingline = pit->back_closed(); + if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { + end_open = true; + } + } + Geom::Path pitCubic = (Geom::Path)(*pit); + if(end_open && pit->closed()){ + pitCubic.close(false); + pitCubic.appendNew<Geom::LineSegment>( pitCubic.initialPoint() ); + pitCubic.close(true); + } + for (Geom::Path::const_iterator cit = pitCubic.begin(); cit != pitCubic.end_open(); ++cit) { + if (is_straight_curve(*cit)) { + Geom::CubicBezier b(cit->initialPoint(), cit->pointAt(0.3334) + Geom::Point(cubicGap,cubicGap), cit->finalPoint(), cit->finalPoint()); + output.back().append(b); + } else { + Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); + if (curve && curve->order() == 3) { + Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); + output.back().append(b); + } else { + // convert all other curve types to cubicbeziers + Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(cit->toSBasis(), 0.1); + output.back().append(cubicbezier_path); + } + } + } + } + + return output; +} + // The next routine is modified from curv4_div::recursive_bezier from file agg_curves.cpp //---------------------------------------------------------------------------- // Anti-Grain Geometry (AGG) - Version 2.5 diff --git a/src/helper/geom.h b/src/helper/geom.h index caff95733..3232d9fd5 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -27,6 +27,7 @@ void pathv_matrix_point_bbox_wind_distance ( Geom::PathVector const & pathv, Geo Geom::PathVector pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ); Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double maxdisp ); +Geom::PathVector pathv_to_cubicbezier( Geom::PathVector const &pathv); void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, std::vector<Geom::Point> &pointlist, diff --git a/src/inkgc/CMakeLists.txt b/src/inkgc/CMakeLists.txt index 22dd464e1..a4b96d5ee 100644 --- a/src/inkgc/CMakeLists.txt +++ b/src/inkgc/CMakeLists.txt @@ -1,11 +1,10 @@ - set(libgc_SRC gc.cpp - + # ------- # Headers gc-alloc.h - gc-anchored.h + ../gc-anchored.h gc-core.h gc-managed.h gc-soft-ptr.h diff --git a/src/knotholder.cpp b/src/knotholder.cpp index f46daa09e..a2d1cf017 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -165,7 +165,8 @@ KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) if (saved_item) { //increasingly aggressive sanity checks if (saved_item->document) { - if (object_verb <= SP_VERB_LAST && object_verb >= SP_VERB_INVALID) { + // enum is unsigned so can't be less than SP_VERB_INVALID + if (object_verb <= SP_VERB_LAST) { DocumentUndo::done(saved_item->document, object_verb, _("Change handle")); } diff --git a/src/libcroco/cr-statement.c b/src/libcroco/cr-statement.c index fb8df867f..4666f26ec 100644 --- a/src/libcroco/cr-statement.c +++ b/src/libcroco/cr-statement.c @@ -2011,7 +2011,7 @@ cr_statement_ruleset_set_sel_list (CRStatement * a_this, * cr_statement_ruleset_get_declarations: * *@a_this: the current instance of #CRStatement. - *@a_decl_list: out parameter. A pointer to the the returned + *@a_decl_list: out parameter. A pointer to the returned *list of declaration. Must not be NULL. * *Gets a pointer to the list of declaration contained diff --git a/src/livarot/ShapeMisc.cpp b/src/livarot/ShapeMisc.cpp index c0bfe9428..4f63007e7 100644 --- a/src/livarot/ShapeMisc.cpp +++ b/src/livarot/ShapeMisc.cpp @@ -371,9 +371,9 @@ Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int /*wildPath* int searchInd = 0; int lastPtUsed = 0; + int parentContour=-1; do { - int parentContour=-1; int childEdge = -1; bool foundChild = false; int startBord = -1; @@ -389,8 +389,10 @@ Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int /*wildPath* if (askTo < 0 || askTo >= numberOfEdges() ) { parentContour=-1; } else { - parentContour = GPOINTER_TO_INT(swdData[askTo].misc); - parentContour-=1; // pour compenser le decalage + if (getEdge(askTo).prevS >= 0) { + parentContour = GPOINTER_TO_INT(swdData[askTo].misc); + parentContour-=1; // pour compenser le decalage + } childEdge = getPoint(fi).incidentEdge[FIRST]; } } diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index c8a02c810..c4b92e579 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -1,4 +1,3 @@ - set(live_effects_SRC effect.cpp lpe-angle_bisector.cpp @@ -6,6 +5,7 @@ set(live_effects_SRC lpe-bendpath.cpp lpe-boolops.cpp lpe-bounding-box.cpp + lpe-bspline.cpp lpe-circle_3pts.cpp lpe-circle_with_radius.cpp lpe-clone-original.cpp @@ -13,7 +13,7 @@ set(live_effects_SRC lpe-copy_rotate.cpp lpe-curvestitch.cpp lpe-dynastroke.cpp - lpe-ellipse-5pts.cpp + lpe-ellipse_5pts.cpp lpe-envelope.cpp lpe-extrude.cpp lpe-fill-between-many.cpp @@ -21,8 +21,11 @@ set(live_effects_SRC lpe-fillet-chamfer.cpp lpe-gears.cpp lpe-interpolate.cpp + lpe-interpolate_points.cpp + lpe-jointype.cpp lpe-knot.cpp lpe-lattice.cpp + lpe-lattice2.cpp lpe-line_segment.cpp lpe-mirror_symmetry.cpp lpe-offset.cpp @@ -30,43 +33,43 @@ set(live_effects_SRC lpe-path_length.cpp lpe-patternalongpath.cpp lpe-perp_bisector.cpp - lpe-perspective_path.cpp lpe-perspective-envelope.cpp + lpe-perspective_path.cpp lpe-powerstroke.cpp lpe-recursiveskeleton.cpp lpe-rough-hatches.cpp + lpe-roughen.cpp lpe-ruler.cpp lpe-show_handles.cpp lpe-simplify.cpp - # lpe-skeleton.cpp + lpe-skeleton.cpp lpe-sketch.cpp lpe-spiro.cpp - lpe-roughen.cpp lpe-tangent_to_curve.cpp + lpe-taperstroke.cpp lpe-test-doEffect-stack.cpp - lpe-bspline.cpp lpe-text_label.cpp - lpe-vonkoch.cpp lpegroupbbox.cpp lpeobject-reference.cpp + lpe-vonkoch.cpp lpeobject.cpp - spiro.cpp spiro-converters.cpp + spiro.cpp parameter/array.cpp parameter/bool.cpp parameter/filletchamferpointarray.cpp - parameter/parameter.cpp - parameter/path.cpp parameter/originalpath.cpp parameter/originalpatharray.cpp + parameter/parameter.cpp parameter/path-reference.cpp + parameter/path.cpp parameter/point.cpp parameter/powerstrokepointarray.cpp parameter/random.cpp parameter/text.cpp - paramter/transformedpoint.cpp parameter/togglebutton.cpp + parameter/transformedpoint.cpp parameter/unit.cpp parameter/vector.cpp @@ -80,6 +83,7 @@ set(live_effects_SRC lpe-bendpath.h lpe-boolops.h lpe-bounding-box.h + lpe-bspline.h lpe-circle_3pts.h lpe-circle_with_radius.h lpe-clone-original.h @@ -87,7 +91,7 @@ set(live_effects_SRC lpe-copy_rotate.h lpe-curvestitch.h lpe-dynastroke.h - lpe-ellipse-5pts.h + lpe-ellipse_5pts.h lpe-envelope.h lpe-extrude.h lpe-fill-between-many.h @@ -95,8 +99,11 @@ set(live_effects_SRC lpe-fillet-chamfer.h lpe-gears.h lpe-interpolate.h + lpe-interpolate_points.h + lpe-jointype.h lpe-knot.h lpe-lattice.h + lpe-lattice2.h lpe-line_segment.h lpe-mirror_symmetry.h lpe-offset.h @@ -104,47 +111,47 @@ set(live_effects_SRC lpe-path_length.h lpe-patternalongpath.h lpe-perp_bisector.h - lpe-perspective_path.h lpe-perspective-envelope.h - lpe-powerstroke.h + lpe-perspective_path.h lpe-powerstroke-interpolators.h + lpe-powerstroke.h lpe-recursiveskeleton.h lpe-rough-hatches.h + lpe-roughen.h lpe-ruler.h - lpe-simplify.h lpe-show_handles.h + lpe-simplify.h lpe-skeleton.h lpe-sketch.h lpe-spiro.h - lpe-roughen.h lpe-tangent_to_curve.h + lpe-taperstroke.h lpe-test-doEffect-stack.h - lpe-bspline.h lpe-text_label.h lpe-vonkoch.h lpegroupbbox.h lpeobject-reference.h lpeobject.h - spiro.h spiro-converters.h + spiro.h parameter/array.h parameter/bool.h - parameter/filletchamferpointarray.h parameter/enum.h + parameter/filletchamferpointarray.h + parameter/originalpath.h + parameter/originalpatharray.h parameter/parameter.h parameter/path-reference.h parameter/path.h - parameter/originalpath.h - parameter/originalpatharray.h parameter/point.h parameter/powerstrokepointarray.h parameter/random.h parameter/text.h parameter/togglebutton.h + parameter/transformedpoint.h parameter/unit.h parameter/vector.h - ) # add_inkscape_lib(live_effects_LIB "${live_effects_SRC}") diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 8f0a3ac57..dace45739 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -109,8 +109,6 @@ ink_common_sources += \ live_effects/lpe-fill-between-many.h \ live_effects/lpe-ellipse_5pts.cpp \ live_effects/lpe-ellipse_5pts.h \ - live_effects/pathoutlineprovider.cpp \ - live_effects/pathoutlineprovider.h \ live_effects/lpe-jointype.cpp \ live_effects/lpe-jointype.h \ live_effects/lpe-taperstroke.cpp \ diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 827f70749..1da364580 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -363,6 +363,10 @@ Effect::Effect(LivePathEffectObject *lpeobject) show_orig_path(false), lpeobj(lpeobject), concatenate_before_pwd2(false), + sp_lpe_item(NULL), + defaultUnit("px"), + current_zoom(1), + sp_curve(NULL), provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden { @@ -450,7 +454,7 @@ void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); - defaultUnit = &sp_lpe_item->document->getDisplayUnit()->abbr; + defaultUnit = sp_lpe_item->document->getDisplayUnit()->abbr; /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); pathvector_before_effect = sp_curve->get_pathvector();*/ doOnApply(lpeitem); @@ -459,11 +463,13 @@ void Effect::doOnApply_impl(SPLPEItem const* lpeitem) void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast<SPLPEItem *>(lpeitem); - defaultUnit = &sp_lpe_item->document->getDisplayUnit()->abbr; + defaultUnit = sp_lpe_item->document->getDisplayUnit()->abbr; //printf("(SPLPEITEM*) %p\n", sp_lpe_item); - sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); - pathvector_before_effect = sp_curve->get_pathvector(); - + SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item); + if(shape){ + sp_curve = shape->getCurve(); + pathvector_before_effect = sp_curve->get_pathvector(); + } doBeforeEffect(lpeitem); } diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 7da76b267..ac1f0b8dc 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -159,7 +159,7 @@ protected: bool concatenate_before_pwd2; SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. - Glib::ustring const * defaultUnit; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. + Glib::ustring defaultUnit; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. double current_zoom; std::vector<Geom::Point> selectedNodesPoints; SPCurve * sp_curve; diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 2bed90139..ecbfef76a 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -1,88 +1,57 @@ /* * Released under GNU GPL, read the file 'COPYING' for more information */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - #include <gtkmm.h> - -#if WITH_GLIBMM_2_32 -# include <glibmm/threads.h> -#endif - -#include <glib.h> -#include <glibmm/i18n.h> - - -#include "display/curve.h" -#include <2geom/bezier-curve.h> -#include <2geom/point.h> -#include "helper/geom-curves.h" #include "live_effects/lpe-bspline.h" -#include "live_effects/lpeobject.h" -#include "live_effects/parameter/parameter.h" #include "ui/widget/scalar.h" -#include "xml/repr.h" -#include "svg/svg.h" +#include "display/curve.h" +#include "helper/geom-curves.h" #include "sp-path.h" -#include "style.h" -#include "document-private.h" -#include "document.h" -#include "document-undo.h" -#include "verbs.h" -#include "sp-lpe-item.h" -#include "sp-namedview.h" -#include "display/sp-canvas.h" -#include <typeinfo> -#include <vector> -#include "util/units.h" -// For handling un-continuous paths: -#include "message-stack.h" -#include "inkscape.h" - -using Inkscape::DocumentUndo; +#include "svg/svg.h" +#include "xml/repr.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { -const double handleCubicGap = 0.01; -const double noPower = 0.0; -const double defaultStartPower = 0.3334; -const double defaultEndPower = 0.6667; +const double HANDLE_CUBIC_GAP = 0.01; +const double NO_POWER = 0.0; +const double DEFAULT_START_POWER = 0.3334; +const double DEFAULT_END_POWER = 0.6667; LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject), - // initialise your parameters here: - //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, - //Geom::Point(100,100)), steps(_("Steps with CTRL:"), _("Change number of steps with CTRL pressed"), "steps", &wr, this, 2), - ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), - onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), - showHelper(_("Show helper paths"), _("Show helper paths"), "showHelper", &wr, this, false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, defaultStartPower) + helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 0), + ignore_cusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignore_cusp", &wr, this, true), + only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, DEFAULT_START_POWER) { - registerParameter(dynamic_cast<Parameter *>(&weight)); - registerParameter(dynamic_cast<Parameter *>(&steps)); - registerParameter(dynamic_cast<Parameter *>(&ignoreCusp)); - registerParameter(dynamic_cast<Parameter *>(&onlySelected)); - registerParameter(dynamic_cast<Parameter *>(&showHelper)); + registerParameter(&weight); + registerParameter(&steps); + registerParameter(&helper_size); + registerParameter(&ignore_cusp); + registerParameter(&only_selected); - weight.param_set_range(noPower, 1); + weight.param_set_range(NO_POWER, 1); weight.param_set_increments(0.1, 0.1); weight.param_set_digits(4); steps.param_set_range(1, 10); steps.param_set_increments(1, 1); steps.param_set_digits(0); + + helper_size.param_set_range(0.0, 999.0); + helper_size.param_set_increments(5, 5); + helper_size.param_set_digits(2); } LPEBSpline::~LPEBSpline() {} void LPEBSpline::doBeforeEffect (SPLPEItem const* /*lpeitem*/) { - if(!hp.empty()){ + if(!hp.empty()) { hp.clear(); } } @@ -100,32 +69,32 @@ void LPEBSpline::doOnApply(SPLPEItem const* lpeitem) void LPEBSpline::doEffect(SPCurve *curve) { - if (curve->get_segment_count() < 1){ + if (curve->get_segment_count() < 1) { return; } // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); - double radiusHelperNodes = 6.0; - radiusHelperNodes /= current_zoom; - radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", *defaultUnit); + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - if (path_it->empty()) + if (path_it->empty()) { continue; - + } + hp.push_back(*path_it); Geom::Path::const_iterator curve_it1 = path_it->begin(); Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); Geom::Path::const_iterator curve_endit = path_it->end_default(); - SPCurve *nCurve = new SPCurve(); + SPCurve *curve_n = new SPCurve(); Geom::Point previousNode(0, 0); Geom::Point node(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::D2<Geom::SBasis> SBasisIn; - Geom::D2<Geom::SBasis> SBasisOut; - Geom::D2<Geom::SBasis> SBasisHelper; + Geom::Point point_at1(0, 0); + Geom::Point point_at2(0, 0); + Geom::Point next_point_at1(0, 0); + Geom::D2<Geom::SBasis> sbasis_in; + Geom::D2<Geom::SBasis> sbasis_out; + Geom::D2<Geom::SBasis> sbasis_helper; Geom::CubicBezier const *cubic = NULL; if (path_it->closed()) { // if the path is closed, maybe we have to stop a bit earlier because the @@ -141,27 +110,27 @@ void LPEBSpline::doEffect(SPCurve *curve) curve_endit = path_it->end_open(); } } - nCurve->moveto(curve_it1->initialPoint()); + curve_n->moveto(curve_it1->initialPoint()); while (curve_it1 != curve_endit) { SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - SBasisIn = in->first_segment()->toSBasis(); + sbasis_in = in->first_segment()->toSBasis(); if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { - pointAt1 = SBasisIn.valueAt(defaultStartPower); + point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); + point_at1 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); } if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) { - pointAt2 = SBasisIn.valueAt(defaultEndPower); + point_at2 = sbasis_in.valueAt(DEFAULT_END_POWER); } else { - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); + point_at2 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); } } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); + point_at1 = in->first_segment()->initialPoint(); + point_at2 = in->first_segment()->finalPoint(); } in->reset(); delete in; @@ -171,14 +140,14 @@ void LPEBSpline::doEffect(SPCurve *curve) out->lineto(curve_it2->finalPoint()); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2); if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); + sbasis_out = out->first_segment()->toSBasis(); if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { - nextPointAt1 = SBasisIn.valueAt(defaultStartPower); + next_point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + next_point_at1 = sbasis_out.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); } } else { - nextPointAt1 = out->first_segment()->initialPoint(); + next_point_at1 = out->first_segment()->initialPoint(); } out->reset(); delete out; @@ -187,14 +156,14 @@ void LPEBSpline::doEffect(SPCurve *curve) SPCurve *start = new SPCurve(); start->moveto(path_it->begin()->initialPoint()); start->lineto(path_it->begin()->finalPoint()); - Geom::D2<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis(); - SPCurve *lineHelper = new SPCurve(); + Geom::D2<Geom::SBasis> sbasis_start = start->first_segment()->toSBasis(); + SPCurve *line_helper = new SPCurve(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*path_it->begin()); if (cubic) { - lineHelper->moveto(SBasisStart.valueAt( + line_helper->moveto(sbasis_start.valueAt( Geom::nearest_point((*cubic)[1], *start->first_segment()))); } else { - lineHelper->moveto(start->first_segment()->initialPoint()); + line_helper->moveto(start->first_segment()->initialPoint()); } start->reset(); delete start; @@ -202,69 +171,69 @@ void LPEBSpline::doEffect(SPCurve *curve) SPCurve *end = new SPCurve(); end->moveto(curve_it1->initialPoint()); end->lineto(curve_it1->finalPoint()); - Geom::D2<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis(); + Geom::D2<Geom::SBasis> sbasis_end = end->first_segment()->toSBasis(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - lineHelper->lineto(SBasisEnd.valueAt( + line_helper->lineto(sbasis_end.valueAt( Geom::nearest_point((*cubic)[2], *end->first_segment()))); } else { - lineHelper->lineto(end->first_segment()->finalPoint()); + line_helper->lineto(end->first_segment()->finalPoint()); } end->reset(); delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - node = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, node); - nCurve->move_endpoints(node, node); + sbasis_helper = line_helper->first_segment()->toSBasis(); + line_helper->reset(); + delete line_helper; + node = sbasis_helper.valueAt(0.5); + curve_n->curveto(point_at1, point_at2, node); + curve_n->move_endpoints(node, node); } else if ( curve_it2 == curve_endit) { - nCurve->curveto(pointAt1, pointAt2, curve_it1->finalPoint()); - nCurve->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint()); + curve_n->curveto(point_at1, point_at2, curve_it1->finalPoint()); + curve_n->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint()); } else { - SPCurve *lineHelper = new SPCurve(); - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; + SPCurve *line_helper = new SPCurve(); + line_helper->moveto(point_at2); + line_helper->lineto(next_point_at1); + sbasis_helper = line_helper->first_segment()->toSBasis(); + line_helper->reset(); + delete line_helper; previousNode = node; - node = SBasisHelper.valueAt(0.5); + node = sbasis_helper.valueAt(0.5); Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) { node = curve_it1->finalPoint(); } - nCurve->curveto(pointAt1, pointAt2, node); + curve_n->curveto(point_at1, point_at2, node); } - if(!are_near(node,curve_it1->finalPoint()) && showHelper){ - drawHandle(node, radiusHelperNodes); + if(!are_near(node,curve_it1->finalPoint()) && helper_size > 0.0) { + drawHandle(node, helper_size); } ++curve_it1; ++curve_it2; } //y cerramos la curva if (path_it->closed()) { - nCurve->closepath_current(); + curve_n->closepath_current(); } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; + curve->append(curve_n, false); + curve_n->reset(); + delete curve_n; } - if(showHelper){ + if(helper_size > 0.0) { Geom::PathVector const pathv = curve->get_pathvector(); - hp.push_back(pathv[0]); + hp.push_back(pathv[0]); } } void -LPEBSpline::drawHandle(Geom::Point p, double radiusHelperNodes) +LPEBSpline::drawHandle(Geom::Point p, double helper_size) { char const * svgd = "M 1,0.5 A 0.5,0.5 0 0 1 0.5,1 0.5,0.5 0 0 1 0,0.5 0.5,0.5 0 0 1 0.5,0 0.5,0.5 0 0 1 1,0.5 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); Geom::Affine aff = Geom::Affine(); - aff *= Geom::Scale(radiusHelperNodes); + aff *= Geom::Scale(helper_size); pathv *= aff; - pathv += p - Geom::Point(0.5*radiusHelperNodes, 0.5*radiusHelperNodes); + pathv += p - Geom::Point(0.5*helper_size, 0.5*helper_size); hp.push_back(pathv[0]); } @@ -287,40 +256,40 @@ Gtk::Widget *LPEBSpline::newWidget() Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); if (param->param_key == "weight") { Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); - Gtk::Button *defaultWeight = + Gtk::Button *default_weight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); - defaultWeight->signal_clicked() + default_weight->signal_clicked() .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight)); - buttons->pack_start(*defaultWeight, true, true, 2); - Gtk::Button *makeCusp = + buttons->pack_start(*default_weight, true, true, 2); + Gtk::Button *make_cusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->signal_clicked() + make_cusp->signal_clicked() .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp)); - buttons->pack_start(*makeCusp, true, true, 2); + buttons->pack_start(*make_cusp, true, true, 2); vbox->pack_start(*buttons, true, true, 2); } if (param->param_key == "weight" || param->param_key == "steps") { - Inkscape::UI::Widget::Scalar *widgRegistered = + Inkscape::UI::Widget::Scalar *widg_registered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); - widgRegistered->signal_value_changed() + widg_registered->signal_value_changed() .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); - widg = dynamic_cast<Gtk::Widget *>(widgRegistered); + widg = dynamic_cast<Gtk::Widget *>(widg_registered); if (widg) { - Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg); - std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); - Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); - entryWidg->set_width_chars(6); + Gtk::HBox * hbox_weight_steps = dynamic_cast<Gtk::HBox *>(widg); + std::vector< Gtk::Widget* > childList = hbox_weight_steps->get_children(); + Gtk::Entry* entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]); + entry_widget->set_width_chars(6); } } - if (param->param_key == "onlySelected") { - Gtk::CheckButton *widgRegistered = + if (param->param_key == "only_selected") { + Gtk::CheckButton *widg_registered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widg = dynamic_cast<Gtk::Widget *>(widgRegistered); + widg = dynamic_cast<Gtk::Widget *>(widg_registered); } - if (param->param_key == "ignoreCusp") { - Gtk::CheckButton *widgRegistered = + if (param->param_key == "ignore_cusp") { + Gtk::CheckButton *widg_registered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widg = dynamic_cast<Gtk::Widget *>(widgRegistered); + widg = dynamic_cast<Gtk::Widget *>(widg_registered); } Glib::ustring *tip = param->param_getTooltip(); if (widg) { @@ -341,12 +310,12 @@ Gtk::Widget *LPEBSpline::newWidget() void LPEBSpline::toDefaultWeight() { - changeWeight(defaultStartPower); + changeWeight(DEFAULT_START_POWER); } void LPEBSpline::toMakeCusp() { - changeWeight(noPower); + changeWeight(NO_POWER); } void LPEBSpline::toWeight() @@ -354,20 +323,22 @@ void LPEBSpline::toWeight() changeWeight(weight); } -void LPEBSpline::changeWeight(double weightValue) +void LPEBSpline::changeWeight(double weight_ammount) { - SPPath *path = SP_PATH(sp_lpe_item); - SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve, weightValue); - gchar *str = sp_svg_write_path(curve->get_pathvector()); - path->getRepr()->setAttribute("inkscape:original-d", str); + SPPath *path = dynamic_cast<SPPath *>(sp_lpe_item); + if(path) { + SPCurve *curve = path->get_curve_for_edit(); + doBSplineFromWidget(curve, weight_ammount); + gchar *str = sp_svg_write_path(curve->get_pathvector()); + path->getRepr()->setAttribute("inkscape:original-d", str); + } } -void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) +void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount) { using Geom::X; using Geom::Y; - + if (curve->get_segment_count() < 1) return; // Make copy of old path as it is changed during processing @@ -377,20 +348,20 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - if (path_it->empty()){ + if (path_it->empty()) { continue; } Geom::Path::const_iterator curve_it1 = path_it->begin(); Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); Geom::Path::const_iterator curve_endit = path_it->end_default(); - SPCurve *nCurve = new SPCurve(); - Geom::Point pointAt0(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point pointAt3(0, 0); - Geom::D2<Geom::SBasis> SBasisIn; - Geom::D2<Geom::SBasis> SBasisOut; + SPCurve *curve_n = new SPCurve(); + Geom::Point point_at0(0, 0); + Geom::Point point_at1(0, 0); + Geom::Point point_at2(0, 0); + Geom::Point point_at3(0, 0); + Geom::D2<Geom::SBasis> sbasis_in; + Geom::D2<Geom::SBasis> sbasis_out; Geom::CubicBezier const *cubic = NULL; if (path_it->closed()) { // if the path is closed, maybe we have to stop a bit earlier because the @@ -406,120 +377,120 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) curve_endit = path_it->end_open(); } } - nCurve->moveto(curve_it1->initialPoint()); + curve_n->moveto(curve_it1->initialPoint()); while (curve_it1 != curve_endit) { SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - pointAt0 = in->first_segment()->initialPoint(); - pointAt3 = in->first_segment()->finalPoint(); - SBasisIn = in->first_segment()->toSBasis(); - if (!onlySelected) { + point_at0 = in->first_segment()->initialPoint(); + point_at3 = in->first_segment()->finalPoint(); + sbasis_in = in->first_segment()->toSBasis(); + if (!only_selected) { if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != noPower) { - pointAt1 = - Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); + if (!ignore_cusp || !Geom::are_near((*cubic)[1], point_at0)) { + point_at1 = sbasis_in.valueAt(weight_ammount); + if (weight_ammount != NO_POWER) { + point_at1 = + Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } } else { - pointAt1 = in->first_segment()->initialPoint(); + point_at1 = in->first_segment()->initialPoint(); } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != noPower) { - pointAt2 = - Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); + if (!ignore_cusp || !Geom::are_near((*cubic)[2], point_at3)) { + point_at2 = sbasis_in.valueAt(1 - weight_ammount); + if (weight_ammount != NO_POWER) { + point_at2 = + Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); } } else { - pointAt2 = in->first_segment()->finalPoint(); + point_at2 = in->first_segment()->finalPoint(); } } else { - if (!ignoreCusp && weightValue != noPower) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != noPower) { - pointAt1 = - Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); + if (!ignore_cusp && weight_ammount != NO_POWER) { + point_at1 = sbasis_in.valueAt(weight_ammount); + if (weight_ammount != NO_POWER) { + point_at1 = + Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != noPower) { - pointAt2 = - Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); + point_at2 = sbasis_in.valueAt(1 - weight_ammount); + if (weight_ammount != NO_POWER) { + point_at2 = + Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); } } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); + point_at1 = in->first_segment()->initialPoint(); + point_at2 = in->first_segment()->finalPoint(); } } } else { if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - if (isNodePointSelected(pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != noPower) { - pointAt1 = - Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); + if (!ignore_cusp || !Geom::are_near((*cubic)[1], point_at0)) { + if (isNodePointSelected(point_at0)) { + point_at1 = sbasis_in.valueAt(weight_ammount); + if (weight_ammount != NO_POWER) { + point_at1 = + Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } } else { - pointAt1 = (*cubic)[1]; + point_at1 = (*cubic)[1]; } } else { - pointAt1 = in->first_segment()->initialPoint(); + point_at1 = in->first_segment()->initialPoint(); } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - if (isNodePointSelected(pointAt3)) { - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != noPower) { - pointAt2 = - Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); + if (!ignore_cusp || !Geom::are_near((*cubic)[2], point_at3)) { + if (isNodePointSelected(point_at3)) { + point_at2 = sbasis_in.valueAt(1 - weight_ammount); + if (weight_ammount != NO_POWER) { + point_at2 = + Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); } } else { - pointAt2 = (*cubic)[2]; + point_at2 = (*cubic)[2]; } } else { - pointAt2 = in->first_segment()->finalPoint(); + point_at2 = in->first_segment()->finalPoint(); } } else { - if (!ignoreCusp && weightValue != noPower) { - if (isNodePointSelected(pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = - Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); + if (!ignore_cusp && weight_ammount != NO_POWER) { + if (isNodePointSelected(point_at0)) { + point_at1 = sbasis_in.valueAt(weight_ammount); + point_at1 = + Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } else { - pointAt1 = in->first_segment()->initialPoint(); + point_at1 = in->first_segment()->initialPoint(); } - if (isNodePointSelected(pointAt3)) { - pointAt2 = SBasisIn.valueAt(weightValue); - pointAt2 = - Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); + if (isNodePointSelected(point_at3)) { + point_at2 = sbasis_in.valueAt(weight_ammount); + point_at2 = + Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); } else { - pointAt2 = in->first_segment()->finalPoint(); + point_at2 = in->first_segment()->finalPoint(); } } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); + point_at1 = in->first_segment()->initialPoint(); + point_at2 = in->first_segment()->finalPoint(); } } } in->reset(); delete in; - nCurve->curveto(pointAt1, pointAt2, pointAt3); + curve_n->curveto(point_at1, point_at2, point_at3); ++curve_it1; ++curve_it2; } if (path_it->closed()) { - nCurve->move_endpoints(path_it->begin()->initialPoint(), + curve_n->move_endpoints(path_it->begin()->initialPoint(), path_it->begin()->initialPoint()); } else { - nCurve->move_endpoints(path_it->begin()->initialPoint(), pointAt3); + curve_n->move_endpoints(path_it->begin()->initialPoint(), point_at3); } if (path_it->closed()) { - nCurve->closepath_current(); + curve_n->closepath_current(); } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; + curve->append(curve_n, false); + curve_n->reset(); + delete curve_n; } } diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index a17c0c4ac..fc0f66353 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -6,9 +6,8 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - #include "live_effects/effect.h" -#include "live_effects/parameter/bool.h" + #include <vector> namespace Inkscape { @@ -19,7 +18,8 @@ public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); - virtual LPEPathFlashType pathFlashType() const { + virtual LPEPathFlashType pathFlashType() const + { return SUPPRESS_FLASH; } virtual void doOnApply(SPLPEItem const* lpeitem); @@ -38,9 +38,9 @@ public: ScalarParam steps; private: - BoolParam ignoreCusp; - BoolParam onlySelected; - BoolParam showHelper; + ScalarParam helper_size; + BoolParam ignore_cusp; + BoolParam only_selected; ScalarParam weight; Geom::PathVector hp; diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 0fa2ebedc..fd9b853d5 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -69,7 +69,7 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : registerParameter(&rotation_angle); registerParameter(&num_copies); registerParameter(&origin); - + num_copies.param_make_integer(true); num_copies.param_set_range(0, 1000); } @@ -88,6 +88,7 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) A = Point(boundingbox_X.min(), boundingbox_Y.middle()); B = Point(boundingbox_X.middle(), boundingbox_Y.middle()); origin.param_setValue(A); + origin.param_update_default(A); dist_angle_handle = L2(B - A); dir = unit_vector(B - A); } diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index d2bdf2d8d..c8458b8cb 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -223,7 +223,7 @@ void LPEFilletChamfer::updateFillet() { double power = 0; if (!flexible) { - power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), *defaultUnit) * -1; + power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), defaultUnit) * -1; } else { power = radius; } diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index bf2526986..0111a0f99 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -8,7 +8,7 @@ */ #include "live_effects/parameter/enum.h" -#include "live_effects/pathoutlineprovider.h" +#include "helper/geom-pathstroke.h" #include "sp-shape.h" #include "style.h" @@ -28,19 +28,19 @@ namespace Inkscape { namespace LivePathEffect { static const Util::EnumData<unsigned> JoinTypeData[] = { - {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, - {LINEJOIN_ROUND, N_("Rounded"), "round"}, - {LINEJOIN_POINTY, N_("Miter"), "miter"}, - {LINEJOIN_REFLECTED, N_("Reflected"), "extrapolated"}, - {LINEJOIN_EXTRAPOLATED, N_("Extrapolated arc"), "extrp_arc"} + {JOIN_BEVEL, N_("Beveled"), "bevel"}, + {JOIN_ROUND, N_("Rounded"), "round"}, + {JOIN_MITER, N_("Miter"), "miter"}, + {JOIN_MITER_CLIP, N_("Miter Clip"), "miter-clip"}, + {JOIN_EXTRAPOLATE, N_("Extrapolated arc"), "extrp_arc"}, }; static const Util::EnumData<unsigned> CapTypeData[] = { - {BUTT_STRAIGHT, N_("Butt"), "butt"}, + {BUTT_FLAT, N_("Butt"), "butt"}, {BUTT_ROUND, N_("Rounded"), "round"}, {BUTT_SQUARE, N_("Square"), "square"}, - {BUTT_POINTY, N_("Peak"), "peak"}, - {BUTT_LEANED, N_("Leaned"), "leaned"} + {BUTT_PEAK, N_("Peak"), "peak"}, + //{BUTT_LEANED, N_("Leaned"), "leaned"} }; static const Util::EnumDataConverter<unsigned> CapTypeConverter(CapTypeData, sizeof(CapTypeData)/sizeof(*CapTypeData)); @@ -50,9 +50,9 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : Effect(lpeobject), line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.), linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), - linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), - start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.), - end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.), + linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, JOIN_EXTRAPOLATE), + //start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.), + //end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.), miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) { @@ -60,17 +60,16 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : registerParameter(&linecap_type); registerParameter(&line_width); registerParameter(&linejoin_type); - registerParameter(&start_lean); - registerParameter(&end_lean); + //registerParameter(&start_lean); + //registerParameter(&end_lean); registerParameter(&miter_limit); registerParameter(&attempt_force_join); - was_initialized = false; - start_lean.param_set_range(-1,1); - start_lean.param_set_increments(0.1, 0.1); - start_lean.param_set_digits(4); - end_lean.param_set_range(-1,1); - end_lean.param_set_increments(0.1, 0.1); - end_lean.param_set_digits(4); + //start_lean.param_set_range(-1,1); + //start_lean.param_set_increments(0.1, 0.1); + //start_lean.param_set_digits(4); + //end_lean.param_set_range(-1,1); + //end_lean.param_set_increments(0.1, 0.1); + //end_lean.param_set_digits(4); } LPEJoinType::~LPEJoinType() @@ -87,38 +86,30 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; SPCSSAttr *css = sp_repr_css_attr_new (); - if (true) { - if (lpeitem->style->stroke.isPaintserver()) { - SPPaintServer * server = lpeitem->style->getStrokePaintServer(); - if (server) { - Glib::ustring str; - str += "url(#"; - str += server->getId(); - str += ")"; - sp_repr_css_set_property (css, "fill", str.c_str()); - } - } else if (lpeitem->style->stroke.isColor()) { - gchar c[64]; - sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); - sp_repr_css_set_property (css, "fill", c); - } else { - sp_repr_css_set_property (css, "fill", "none"); + if (lpeitem->style->stroke.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getStrokePaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "fill", str.c_str()); } + } else if (lpeitem->style->stroke.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "fill", c); } else { - sp_repr_css_unset_property (css, "fill"); + sp_repr_css_set_property (css, "fill", "none"); } + sp_repr_css_set_property(css, "fill-rule", "nonzero"); sp_repr_css_set_property(css, "stroke", "none"); sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); - if (!was_initialized) - { - was_initialized = true; - line_width.param_set_value(width); - } - } else { - g_warning("LPE Join Type can only be applied to paths (not groups)."); + + line_width.param_set_value(width); } } @@ -126,30 +117,25 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) { - if (SP_IS_SHAPE(lpeitem)) { SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem); SPCSSAttr *css = sp_repr_css_attr_new (); - if (true) { - if (lpeitem->style->fill.isPaintserver()) { - SPPaintServer * server = lpeitem->style->getFillPaintServer(); - if (server) { - Glib::ustring str; - str += "url(#"; - str += server->getId(); - str += ")"; - sp_repr_css_set_property (css, "stroke", str.c_str()); - } - } else if (lpeitem->style->fill.isColor()) { - gchar c[64]; - sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); - sp_repr_css_set_property (css, "stroke", c); - } else { - sp_repr_css_set_property (css, "stroke", "none"); + if (lpeitem->style->fill.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getFillPaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "stroke", str.c_str()); } + } else if (lpeitem->style->fill.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->fill.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->fill_opacity.value))); + sp_repr_css_set_property (css, "stroke", c); } else { - sp_repr_css_unset_property (css, "stroke"); + sp_repr_css_set_property (css, "stroke", "none"); } Inkscape::CSSOStringStream os; @@ -164,15 +150,18 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) } } -// NOTE: I originally had all the outliner functions defined in here, but they were actually useful -// enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a -// wrapper around it. std::vector<Geom::Path> LPEJoinType::doEffect_path(std::vector<Geom::Path> const & path_in) { - return Outline::PathVectorOutline(path_in, line_width, static_cast<ButtTypeMod>(linecap_type.get_value()), - static_cast<LineJoinType>(linejoin_type.get_value()), - (attempt_force_join ? std::numeric_limits<double>::max() : miter_limit), - start_lean/2 ,end_lean/2); + Geom::PathVector ret; + for (size_t i = 0; i < path_in.size(); ++i) { + Geom::PathVector tmp = Inkscape::outline(path_in[i], line_width, + (attempt_force_join ? std::numeric_limits<double>::max() : miter_limit), + static_cast<LineJoinType>(linejoin_type.get_value()), + static_cast<LineCapType>(linecap_type.get_value())); + ret.insert(ret.begin(), tmp.begin(), tmp.end()); + } + + return ret; } } // namespace LivePathEffect diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h index 73705666d..bca0961c9 100644 --- a/src/live_effects/lpe-jointype.h +++ b/src/live_effects/lpe-jointype.h @@ -33,11 +33,10 @@ private: ScalarParam line_width;
EnumParam<unsigned> linecap_type;
EnumParam<unsigned> linejoin_type;
- ScalarParam start_lean;
- ScalarParam end_lean;
+ //ScalarParam start_lean;
+ //ScalarParam end_lean;
ScalarParam miter_limit;
BoolParam attempt_force_join;
- bool was_initialized;
};
} //namespace LivePathEffect
diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 6ec4b969b..ec2f9c419 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -404,7 +404,7 @@ LPEKnot::doEffect_path (std::vector<Geom::Path> const &path_in) for (unsigned comp=0; comp<path_in.size(); comp++){ //find the relevant path component in gpaths (required to allow groups!) - //Q: do we always recieve the group members in the same order? can we rest on that? + //Q: do we always receive the group members in the same order? can we rest on that? unsigned i0 = 0; for (i0=0; i0<gpaths.size(); i0++){ if (path_in[comp]==gpaths[i0]) break; diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index a241a8a2e..c05bae7e1 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -236,6 +236,21 @@ LPELattice::resetDefaults(SPItem const* item) grid_point15[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min(); grid_point15[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min(); + grid_point1.param_update_default(grid_point1); + grid_point2.param_update_default(grid_point2); + grid_point3.param_update_default(grid_point3); + grid_point4.param_update_default(grid_point4); + grid_point5.param_update_default(grid_point5); + grid_point6.param_update_default(grid_point6); + grid_point7.param_update_default(grid_point7); + grid_point8.param_update_default(grid_point8); + grid_point9.param_update_default(grid_point9); + grid_point10.param_update_default(grid_point10); + grid_point11.param_update_default(grid_point11); + grid_point12.param_update_default(grid_point12); + grid_point13.param_update_default(grid_point13); + grid_point14.param_update_default(grid_point14); + grid_point15.param_update_default(grid_point15); } /** diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index e1cd91340..abd6e7786 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -1,6 +1,6 @@ /** \file * LPE <lattice2> implementation - + */ /* * Authors: @@ -11,7 +11,7 @@ * ~suv * Jabiertxo Arraiza * -* Copyright (C) 2007-2008 Authors +* Copyright (C) 2007-2008 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -23,18 +23,17 @@ #include "sp-path.h" #include "display/curve.h" #include "svg/svg.h" - +#include "helper/geom.h" +#include <2geom/path.h> #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> +#include "helper/geom-curves.h" #include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/d2.h> #include <2geom/piecewise.h> #include <2geom/transforms.h> -#include "ui/tools-switch.h" - -#include "desktop.h" // TODO: should be factored out (see below) using namespace Geom; @@ -43,61 +42,63 @@ namespace LivePathEffect { LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) : Effect(lpeobject), - // initialise your parameters here: - grid_point0(_("Control handle 0:"), _("Control handle 0 - Ctrl+Alt+Click to reset"), "gridpoint0", &wr, this), - grid_point1(_("Control handle 1:"), _("Control handle 1 - Ctrl+Alt+Click to reset"), "gridpoint1", &wr, this), - grid_point2(_("Control handle 2:"), _("Control handle 2 - Ctrl+Alt+Click to reset"), "gridpoint2", &wr, this), - grid_point3(_("Control handle 3:"), _("Control handle 3 - Ctrl+Alt+Click to reset"), "gridpoint3", &wr, this), - grid_point4(_("Control handle 4:"), _("Control handle 4 - Ctrl+Alt+Click to reset"), "gridpoint4", &wr, this), - grid_point5(_("Control handle 5:"), _("Control handle 5 - Ctrl+Alt+Click to reset"), "gridpoint5", &wr, this), - grid_point6(_("Control handle 6:"), _("Control handle 6 - Ctrl+Alt+Click to reset"), "gridpoint6", &wr, this), - grid_point7(_("Control handle 7:"), _("Control handle 7 - Ctrl+Alt+Click to reset"), "gridpoint7", &wr, this), - grid_point8x9(_("Control handle 8x9:"), _("Control handle 8x9 - Ctrl+Alt+Click to reset"), "gridpoint8x9", &wr, this), - grid_point10x11(_("Control handle 10x11:"), _("Control handle 10x11 - Ctrl+Alt+Click to reset"), "gridpoint10x11", &wr, this), - grid_point12(_("Control handle 12:"), _("Control handle 12 - Ctrl+Alt+Click to reset"), "gridpoint12", &wr, this), - grid_point13(_("Control handle 13:"), _("Control handle 13 - Ctrl+Alt+Click to reset"), "gridpoint13", &wr, this), - grid_point14(_("Control handle 14:"), _("Control handle 14 - Ctrl+Alt+Click to reset"), "gridpoint14", &wr, this), - grid_point15(_("Control handle 15:"), _("Control handle 15 - Ctrl+Alt+Click to reset"), "gridpoint15", &wr, this), - grid_point16(_("Control handle 16:"), _("Control handle 16 - Ctrl+Alt+Click to reset"), "gridpoint16", &wr, this), - grid_point17(_("Control handle 17:"), _("Control handle 17 - Ctrl+Alt+Click to reset"), "gridpoint17", &wr, this), - grid_point18(_("Control handle 18:"), _("Control handle 18 - Ctrl+Alt+Click to reset"), "gridpoint18", &wr, this), - grid_point19(_("Control handle 19:"), _("Control handle 19 - Ctrl+Alt+Click to reset"), "gridpoint19", &wr, this), - grid_point20x21(_("Control handle 20x21:"), _("Control handle 20x21 - Ctrl+Alt+Click to reset"), "gridpoint20x21", &wr, this), - grid_point22x23(_("Control handle 22x23:"), _("Control handle 22x23 - Ctrl+Alt+Click to reset"), "gridpoint22x23", &wr, this), - grid_point24x26(_("Control handle 24x26:"), _("Control handle 24x26 - Ctrl+Alt+Click to reset"), "gridpoint24x26", &wr, this), - grid_point25x27(_("Control handle 25x27:"), _("Control handle 25x27 - Ctrl+Alt+Click to reset"), "gridpoint25x27", &wr, this), - grid_point28x30(_("Control handle 28x30:"), _("Control handle 28x30 - Ctrl+Alt+Click to reset"), "gridpoint28x30", &wr, this), - grid_point29x31(_("Control handle 29x31:"), _("Control handle 29x31 - Ctrl+Alt+Click to reset"), "gridpoint29x31", &wr, this), - grid_point32x33x34x35(_("Control handle 32x33x34x35:"), _("Control handle 32x33x34x35 - Ctrl+Alt+Click to reset"), "gridpoint32x33x34x35", &wr, this) - - + horizontal_mirror(_("Mirror movements in horizontal"), _("Mirror movements in horizontal"), "horizontal_mirror", &wr, this, false), + vertical_mirror(_("Mirror movements in vertical"), _("Mirror movements in vertical"), "vertical_mirror", &wr, this, false), + grid_point_0(_("Control 0:"), _("Control 0 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint0", &wr, this), + grid_point_1(_("Control 1:"), _("Control 1 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint1", &wr, this), + grid_point_2(_("Control 2:"), _("Control 2 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint2", &wr, this), + grid_point_3(_("Control 3:"), _("Control 3 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint3", &wr, this), + grid_point_4(_("Control 4:"), _("Control 4 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint4", &wr, this), + grid_point_5(_("Control 5:"), _("Control 5 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint5", &wr, this), + grid_point_6(_("Control 6:"), _("Control 6 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint6", &wr, this), + grid_point_7(_("Control 7:"), _("Control 7 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint7", &wr, this), + grid_point_8x9(_("Control 8x9:"), _("Control 8x9 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint8x9", &wr, this), + grid_point_10x11(_("Control 10x11:"), _("Control 10x11 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint10x11", &wr, this), + grid_point_12(_("Control 12:"), _("Control 12 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint12", &wr, this), + grid_point_13(_("Control 13:"), _("Control 13 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint13", &wr, this), + grid_point_14(_("Control 14:"), _("Control 14 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint14", &wr, this), + grid_point_15(_("Control 15:"), _("Control 15 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint15", &wr, this), + grid_point_16(_("Control 16:"), _("Control 16 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint16", &wr, this), + grid_point_17(_("Control 17:"), _("Control 17 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint17", &wr, this), + grid_point_18(_("Control 18:"), _("Control 18 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint18", &wr, this), + grid_point_19(_("Control 19:"), _("Control 19 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint19", &wr, this), + grid_point_20x21(_("Control 20x21:"), _("Control 20x21 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint20x21", &wr, this), + grid_point_22x23(_("Control 22x23:"), _("Control 22x23 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint22x23", &wr, this), + grid_point_24x26(_("Control 24x26:"), _("Control 24x26 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint24x26", &wr, this), + grid_point_25x27(_("Control 25x27:"), _("Control 25x27 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint25x27", &wr, this), + grid_point_28x30(_("Control 28x30:"), _("Control 28x30 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint28x30", &wr, this), + grid_point_29x31(_("Control 29x31:"), _("Control 29x31 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint29x31", &wr, this), + grid_point_32x33x34x35(_("Control 32x33x34x35:"), _("Control 32x33x34x35 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint32x33x34x35", &wr, this), + expanded(false) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&grid_point0) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point1) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point2) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point3) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point4) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point5) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point6) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point7) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point8x9) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point10x11) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point12) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point13) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point14) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point15) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point16) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point17) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point18) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point19) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point20x21) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point22x23) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point24x26) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point25x27) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point28x30) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point29x31) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point32x33x34x35) ); + registerParameter(&horizontal_mirror); + registerParameter(&vertical_mirror); + registerParameter(&grid_point_0); + registerParameter(&grid_point_1); + registerParameter(&grid_point_2); + registerParameter(&grid_point_3); + registerParameter(&grid_point_4); + registerParameter(&grid_point_5); + registerParameter(&grid_point_6); + registerParameter(&grid_point_7); + registerParameter(&grid_point_8x9); + registerParameter(&grid_point_10x11); + registerParameter(&grid_point_12); + registerParameter(&grid_point_13); + registerParameter(&grid_point_14); + registerParameter(&grid_point_15); + registerParameter(&grid_point_16); + registerParameter(&grid_point_17); + registerParameter(&grid_point_18); + registerParameter(&grid_point_19); + registerParameter(&grid_point_20x21); + registerParameter(&grid_point_22x23); + registerParameter(&grid_point_24x26); + registerParameter(&grid_point_25x27); + registerParameter(&grid_point_28x30); + registerParameter(&grid_point_29x31); + registerParameter(&grid_point_32x33x34x35); } LPELattice2::~LPELattice2() @@ -107,8 +108,12 @@ LPELattice2::~LPELattice2() Geom::Piecewise<Geom::D2<Geom::SBasis> > LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { + PathVector pathv = path_from_piecewise(pwd2_in,0.001); + //this is because strange problems whith sb2 and LineSegment + PathVector cubic = pathv_to_cubicbezier(pathv); + Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in_linear_and_cubic = paths_to_pw(cubic); D2<SBasis2d> sb2; - + //Initialisation of the sb2 for(unsigned dim = 0; dim < 2; dim++) { sb2[dim].us = 3; @@ -118,47 +123,48 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd } //Grouping the point params in a convenient vector - std::vector<Geom::Point *> handles(36); - - handles[0] = &grid_point0; - handles[1] = &grid_point1; - handles[2] = &grid_point2; - handles[3] = &grid_point3; - handles[4] = &grid_point4; - handles[5] = &grid_point5; - handles[6] = &grid_point6; - handles[7] = &grid_point7; - handles[8] = &grid_point8x9; - handles[9] = &grid_point8x9; - handles[10] = &grid_point10x11; - handles[11] = &grid_point10x11; - handles[12] = &grid_point12; - handles[13] = &grid_point13; - handles[14] = &grid_point14; - handles[15] = &grid_point15; - handles[16] = &grid_point16; - handles[17] = &grid_point17; - handles[18] = &grid_point18; - handles[19] = &grid_point19; - handles[20] = &grid_point20x21; - handles[21] = &grid_point20x21; - handles[22] = &grid_point22x23; - handles[23] = &grid_point22x23; - handles[24] = &grid_point24x26; - handles[25] = &grid_point25x27; - handles[26] = &grid_point24x26; - handles[27] = &grid_point25x27; - handles[28] = &grid_point28x30; - handles[29] = &grid_point29x31; - handles[30] = &grid_point28x30; - handles[31] = &grid_point29x31; - handles[32] = &grid_point32x33x34x35; - handles[33] = &grid_point32x33x34x35; - handles[34] = &grid_point32x33x34x35; - handles[35] = &grid_point32x33x34x35; + + std::vector<Geom::Point > handles(36); + + handles[0] = grid_point_0; + handles[1] = grid_point_1; + handles[2] = grid_point_2; + handles[3] = grid_point_3; + handles[4] = grid_point_4; + handles[5] = grid_point_5; + handles[6] = grid_point_6; + handles[7] = grid_point_7; + handles[8] = grid_point_8x9; + handles[9] = grid_point_8x9; + handles[10] = grid_point_10x11; + handles[11] = grid_point_10x11; + handles[12] = grid_point_12; + handles[13] = grid_point_13; + handles[14] = grid_point_14; + handles[15] = grid_point_15; + handles[16] = grid_point_16; + handles[17] = grid_point_17; + handles[18] = grid_point_18; + handles[19] = grid_point_19; + handles[20] = grid_point_20x21; + handles[21] = grid_point_20x21; + handles[22] = grid_point_22x23; + handles[23] = grid_point_22x23; + handles[24] = grid_point_24x26; + handles[25] = grid_point_25x27; + handles[26] = grid_point_24x26; + handles[27] = grid_point_25x27; + handles[28] = grid_point_28x30; + handles[29] = grid_point_29x31; + handles[30] = grid_point_28x30; + handles[31] = grid_point_29x31; + handles[32] = grid_point_32x33x34x35; + handles[33] = grid_point_32x33x34x35; + handles[34] = grid_point_32x33x34x35; + handles[35] = grid_point_32x33x34x35; Geom::Point origin = Geom::Point(boundingbox_X.min(),boundingbox_Y.min()); - + double width = boundingbox_X.extent(); double height = boundingbox_Y.extent(); @@ -172,31 +178,31 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd for(unsigned iu = 0; iu < 2; iu++) { unsigned corner = iu + 2*iv; unsigned i = ui + vi*sb2[dim].us; - + //This is the offset from the Upperleft point Geom::Point base( (ui + iu*(4-2*ui))*width/4., (vi + iv*(4-2*vi))*height/4.); - + //Special action for corners if(vi == 0 && ui == 0) { base = Geom::Point(0,0); } - + // i = Upperleft corner of the considerated rectangle // corner = actual corner of the rectangle // origin = Upperleft point - double dl = dot((*handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir); + double dl = dot((handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir); sb2[dim][i][corner] = dl/( dim ? height : width )*pow(4.0,ui+vi); } } } } } - + Piecewise<D2<SBasis> > output; output.push_cut(0.); - for(unsigned i = 0; i < pwd2_in.size(); i++) { - D2<SBasis> B = pwd2_in[i]; + for(unsigned i = 0; i < pwd2_in_linear_and_cubic.size(); i++) { + D2<SBasis> B = pwd2_in_linear_and_cubic[i]; B[Geom::X] -= origin[Geom::X]; B[Geom::X]*= 1/width; B[Geom::Y] -= origin[Geom::Y]; @@ -211,6 +217,7 @@ LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd return output; } + Gtk::Widget * LPELattice2::newWidget() { @@ -218,23 +225,32 @@ LPELattice2::newWidget() Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); vbox->set_border_width(5); - Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset grid")))); - resetButton->set_alignment(0.0, 0.5); - resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPELattice2::resetGrid)); - Gtk::Widget* resetButtonWidget = dynamic_cast<Gtk::Widget *>(resetButton); - resetButtonWidget->set_tooltip_text("Reset grid"); - vbox->pack_start(*resetButtonWidget, true, true,2); + vbox->set_homogeneous(false); + vbox->set_spacing(6); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); + Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + vbox_expander->set_border_width(0); + vbox_expander->set_spacing(2); + Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset grid")))); + reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPELattice2::resetGrid)); + reset_button->set_size_request(140,30); + vbox->pack_start(*hbox, true,true,2); + hbox->pack_start(*reset_button, false, false,2); std::vector<Parameter *>::iterator it = param_vector.begin(); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter * param = *it; Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); - if(param->param_key == "grid"){ + if(param->param_key == "grid") { widg = NULL; } Glib::ustring * tip = param->param_getTooltip(); if (widg) { - vbox->pack_start(*widg, true, true, 2); + if (param->param_key == "horizontal_mirror" || param->param_key == "vertical_mirror") { + vbox->pack_start(*widg, true, true, 2); + } else { + vbox_expander->pack_start(*widg, true, true, 2); + } if (tip) { widg->set_tooltip_text(*tip); } else { @@ -246,14 +262,98 @@ LPELattice2::newWidget() ++it; } + + expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show Points")))); + expander->add(*vbox_expander); + expander->set_expanded(expanded); + vbox->pack_start(*expander, true, true, 2); + expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPELattice2::onExpanderChanged) ); return dynamic_cast<Gtk::Widget *>(vbox); } void +LPELattice2::onExpanderChanged() +{ + expanded = expander->get_expanded(); + if(expander->get_expanded()) { + expander->set_label (Glib::ustring(_("Hide Points"))); + } else { + expander->set_label (Glib::ustring(_("Show Points"))); + } +} +void +LPELattice2::vertical(PointParam ¶m_one, PointParam ¶m_two, Geom::Line vert) +{ + Geom::Point A = param_one; + Geom::Point B = param_two; + double Y = (A[Geom::Y] + B[Geom::Y])/2; + A[Geom::Y] = Y; + B[Geom::Y] = Y; + Geom::Point nearest = vert.pointAt(vert.nearestPoint(A)); + double distance_one = Geom::distance(A,nearest); + double distance_two = Geom::distance(B,nearest); + double distance_middle = (distance_one + distance_two)/2; + if(A[Geom::X] > B[Geom::X]) { + distance_middle *= -1; + } + A[Geom::X] = nearest[Geom::X] - distance_middle; + B[Geom::X] = nearest[Geom::X] + distance_middle; + param_one.param_setValue(A, true); + param_two.param_setValue(B, true); +} + +void +LPELattice2::horizontal(PointParam ¶m_one, PointParam ¶m_two, Geom::Line horiz) +{ + Geom::Point A = param_one; + Geom::Point B = param_two; + double X = (A[Geom::X] + B[Geom::X])/2; + A[Geom::X] = X; + B[Geom::X] = X; + Geom::Point nearest = horiz.pointAt(horiz.nearestPoint(A)); + double distance_one = Geom::distance(A,nearest); + double distance_two = Geom::distance(B,nearest); + double distance_middle = (distance_one + distance_two)/2; + if(A[Geom::Y] > B[Geom::Y]) { + distance_middle *= -1; + } + A[Geom::Y] = nearest[Geom::Y] - distance_middle; + B[Geom::Y] = nearest[Geom::Y] + distance_middle; + param_one.param_setValue(A, true); + param_two.param_setValue(B, true); +} + +void LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); setDefaults(); + Geom::Line vert(grid_point_8x9.param_get_default(),grid_point_10x11.param_get_default()); + Geom::Line horiz(grid_point_24x26.param_get_default(),grid_point_25x27.param_get_default()); + if(vertical_mirror) { + vertical(grid_point_0, grid_point_1,vert); + vertical(grid_point_2, grid_point_3,vert); + vertical(grid_point_4, grid_point_5,vert); + vertical(grid_point_6, grid_point_7,vert); + vertical(grid_point_12, grid_point_13,vert); + vertical(grid_point_14, grid_point_15,vert); + vertical(grid_point_16, grid_point_17,vert); + vertical(grid_point_18, grid_point_19,vert); + vertical(grid_point_24x26, grid_point_25x27,vert); + vertical(grid_point_28x30, grid_point_29x31,vert); + } + if(horizontal_mirror) { + horizontal(grid_point_0, grid_point_2,horiz); + horizontal(grid_point_1, grid_point_3,horiz); + horizontal(grid_point_4, grid_point_6,horiz); + horizontal(grid_point_5, grid_point_7,horiz); + horizontal(grid_point_8x9, grid_point_10x11,horiz); + horizontal(grid_point_12, grid_point_14,horiz); + horizontal(grid_point_13, grid_point_15,horiz); + horizontal(grid_point_16, grid_point_18,horiz); + horizontal(grid_point_17, grid_point_19,horiz); + horizontal(grid_point_20x21, grid_point_22x23,horiz); + } SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); item->apply_to_clippath(item); item->apply_to_mask(item); @@ -287,116 +387,111 @@ LPELattice2::setDefaults() (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); Geom::Point gp8x9((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); Geom::Point gp10x11((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); Geom::Point gp12((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); Geom::Point gp13((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); Geom::Point gp14((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); Geom::Point gp15((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); Geom::Point gp16((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); Geom::Point gp17((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); Geom::Point gp18((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); Geom::Point gp19((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); Geom::Point gp20x21((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); Geom::Point gp22x23((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); Geom::Point gp24x26((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); Geom::Point gp25x27((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); Geom::Point gp28x30((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); Geom::Point gp29x31((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); Geom::Point gp32x33x34x35((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), - (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); - - grid_point0.param_update_default(gp0); - grid_point1.param_update_default(gp1); - grid_point2.param_update_default(gp2); - grid_point3.param_update_default(gp3); - grid_point4.param_update_default(gp4); - grid_point5.param_update_default(gp5); - grid_point6.param_update_default(gp6); - grid_point7.param_update_default(gp7); - grid_point8x9.param_update_default(gp8x9); - grid_point10x11.param_update_default(gp10x11); - grid_point12.param_update_default(gp12); - grid_point13.param_update_default(gp13); - grid_point14.param_update_default(gp14); - grid_point15.param_update_default(gp15); - grid_point16.param_update_default(gp16); - grid_point17.param_update_default(gp17); - grid_point18.param_update_default(gp18); - grid_point19.param_update_default(gp19); - grid_point20x21.param_update_default(gp20x21); - grid_point22x23.param_update_default(gp22x23); - grid_point24x26.param_update_default(gp24x26); - grid_point25x27.param_update_default(gp25x27); - grid_point28x30.param_update_default(gp28x30); - grid_point29x31.param_update_default(gp29x31); - grid_point32x33x34x35.param_update_default(gp32x33x34x35); + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + grid_point_0.param_update_default(gp0); + grid_point_1.param_update_default(gp1); + grid_point_2.param_update_default(gp2); + grid_point_3.param_update_default(gp3); + grid_point_4.param_update_default(gp4); + grid_point_5.param_update_default(gp5); + grid_point_6.param_update_default(gp6); + grid_point_7.param_update_default(gp7); + grid_point_8x9.param_update_default(gp8x9); + grid_point_10x11.param_update_default(gp10x11); + grid_point_12.param_update_default(gp12); + grid_point_13.param_update_default(gp13); + grid_point_14.param_update_default(gp14); + grid_point_15.param_update_default(gp15); + grid_point_16.param_update_default(gp16); + grid_point_17.param_update_default(gp17); + grid_point_18.param_update_default(gp18); + grid_point_19.param_update_default(gp19); + grid_point_20x21.param_update_default(gp20x21); + grid_point_22x23.param_update_default(gp22x23); + grid_point_24x26.param_update_default(gp24x26); + grid_point_25x27.param_update_default(gp25x27); + grid_point_28x30.param_update_default(gp28x30); + grid_point_29x31.param_update_default(gp29x31); + grid_point_32x33x34x35.param_update_default(gp32x33x34x35); } void LPELattice2::resetGrid() { - grid_point0.param_set_and_write_default(); - grid_point1.param_set_and_write_default(); - grid_point2.param_set_and_write_default(); - grid_point3.param_set_and_write_default(); - grid_point4.param_set_and_write_default(); - grid_point5.param_set_and_write_default(); - grid_point6.param_set_and_write_default(); - grid_point7.param_set_and_write_default(); - grid_point8x9.param_set_and_write_default(); - grid_point10x11.param_set_and_write_default(); - grid_point12.param_set_and_write_default(); - grid_point13.param_set_and_write_default(); - grid_point14.param_set_and_write_default(); - grid_point15.param_set_and_write_default(); - grid_point16.param_set_and_write_default(); - grid_point17.param_set_and_write_default(); - grid_point18.param_set_and_write_default(); - grid_point19.param_set_and_write_default(); - grid_point20x21.param_set_and_write_default(); - grid_point22x23.param_set_and_write_default(); - grid_point24x26.param_set_and_write_default(); - grid_point25x27.param_set_and_write_default(); - grid_point28x30.param_set_and_write_default(); - grid_point29x31.param_set_and_write_default(); - grid_point32x33x34x35.param_set_and_write_default(); - //todo:this hack is only to reposition the knots on reser grid button - //Better update path effect in LPEITEM - SPDesktop * desktop = SP_ACTIVE_DESKTOP; - tools_switch(desktop, TOOLS_SELECT); - tools_switch(desktop, TOOLS_NODES); + grid_point_0.param_set_default(); + grid_point_1.param_set_default(); + grid_point_2.param_set_default(); + grid_point_3.param_set_default(); + grid_point_4.param_set_default(); + grid_point_5.param_set_default(); + grid_point_6.param_set_default(); + grid_point_7.param_set_default(); + grid_point_8x9.param_set_default(); + grid_point_10x11.param_set_default(); + grid_point_12.param_set_default(); + grid_point_13.param_set_default(); + grid_point_14.param_set_default(); + grid_point_15.param_set_default(); + grid_point_16.param_set_default(); + grid_point_17.param_set_default(); + grid_point_18.param_set_default(); + grid_point_19.param_set_default(); + grid_point_20x21.param_set_default(); + grid_point_22x23.param_set_default(); + grid_point_24x26.param_set_default(); + grid_point_25x27.param_set_default(); + grid_point_28x30.param_set_default(); + grid_point_29x31.param_set_default(); + grid_point_32x33x34x35.param_set_default(); } void @@ -426,55 +521,55 @@ LPELattice2::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom: hp_vec.clear(); SPCurve *c = new SPCurve(); - calculateCurve(grid_point0,grid_point4, c,true, true); - calculateCurve(grid_point4,grid_point8x9, c,true, false); - calculateCurve(grid_point8x9,grid_point5, c,true, false); - calculateCurve(grid_point5,grid_point1, c,true, false); - - calculateCurve(grid_point12,grid_point16, c,true, true); - calculateCurve(grid_point16,grid_point20x21, c,true, false); - calculateCurve(grid_point20x21,grid_point17, c,true, false); - calculateCurve(grid_point17,grid_point13, c,true, false); - - calculateCurve(grid_point24x26,grid_point28x30, c,true, true); - calculateCurve(grid_point28x30,grid_point32x33x34x35, c,true, false); - calculateCurve(grid_point32x33x34x35,grid_point29x31, c,true, false); - calculateCurve(grid_point29x31,grid_point25x27, c,true, false); - - calculateCurve(grid_point14,grid_point18, c,true, true); - calculateCurve(grid_point18,grid_point22x23, c,true, false); - calculateCurve(grid_point22x23,grid_point19, c,true, false); - calculateCurve(grid_point19,grid_point15, c,true, false); - - calculateCurve(grid_point2,grid_point6, c,true, true); - calculateCurve(grid_point6,grid_point10x11, c,true, false); - calculateCurve(grid_point10x11,grid_point7, c,true, false); - calculateCurve(grid_point7,grid_point3, c,true, false); - - calculateCurve(grid_point0,grid_point12, c,false, true); - calculateCurve(grid_point12,grid_point24x26, c,false, false); - calculateCurve(grid_point24x26,grid_point14, c,false, false); - calculateCurve(grid_point14,grid_point2, c,false, false); - - calculateCurve(grid_point4,grid_point16, c,false, true); - calculateCurve(grid_point16,grid_point28x30, c,false, false); - calculateCurve(grid_point28x30,grid_point18, c,false, false); - calculateCurve(grid_point18,grid_point6, c,false, false); - - calculateCurve(grid_point8x9,grid_point20x21, c,false, true); - calculateCurve(grid_point20x21,grid_point32x33x34x35, c,false, false); - calculateCurve(grid_point32x33x34x35,grid_point22x23, c,false, false); - calculateCurve(grid_point22x23,grid_point10x11, c,false, false); - - calculateCurve(grid_point5,grid_point17, c, false, true); - calculateCurve(grid_point17,grid_point29x31, c,false, false); - calculateCurve(grid_point29x31,grid_point19, c,false, false); - calculateCurve(grid_point19,grid_point7, c,false, false); - - calculateCurve(grid_point1,grid_point13, c, false, true); - calculateCurve(grid_point13,grid_point25x27, c,false, false); - calculateCurve(grid_point25x27,grid_point15, c,false, false); - calculateCurve(grid_point15,grid_point3, c, false, false); + calculateCurve(grid_point_0,grid_point_4, c,true, true); + calculateCurve(grid_point_4,grid_point_8x9, c,true, false); + calculateCurve(grid_point_8x9,grid_point_5, c,true, false); + calculateCurve(grid_point_5,grid_point_1, c,true, false); + + calculateCurve(grid_point_12,grid_point_16, c,true, true); + calculateCurve(grid_point_16,grid_point_20x21, c,true, false); + calculateCurve(grid_point_20x21,grid_point_17, c,true, false); + calculateCurve(grid_point_17,grid_point_13, c,true, false); + + calculateCurve(grid_point_24x26,grid_point_28x30, c,true, true); + calculateCurve(grid_point_28x30,grid_point_32x33x34x35, c,true, false); + calculateCurve(grid_point_32x33x34x35,grid_point_29x31, c,true, false); + calculateCurve(grid_point_29x31,grid_point_25x27, c,true, false); + + calculateCurve(grid_point_14,grid_point_18, c,true, true); + calculateCurve(grid_point_18,grid_point_22x23, c,true, false); + calculateCurve(grid_point_22x23,grid_point_19, c,true, false); + calculateCurve(grid_point_19,grid_point_15, c,true, false); + + calculateCurve(grid_point_2,grid_point_6, c,true, true); + calculateCurve(grid_point_6,grid_point_10x11, c,true, false); + calculateCurve(grid_point_10x11,grid_point_7, c,true, false); + calculateCurve(grid_point_7,grid_point_3, c,true, false); + + calculateCurve(grid_point_0,grid_point_12, c,false, true); + calculateCurve(grid_point_12,grid_point_24x26, c,false, false); + calculateCurve(grid_point_24x26,grid_point_14, c,false, false); + calculateCurve(grid_point_14,grid_point_2, c,false, false); + + calculateCurve(grid_point_4,grid_point_16, c,false, true); + calculateCurve(grid_point_16,grid_point_28x30, c,false, false); + calculateCurve(grid_point_28x30,grid_point_18, c,false, false); + calculateCurve(grid_point_18,grid_point_6, c,false, false); + + calculateCurve(grid_point_8x9,grid_point_20x21, c,false, true); + calculateCurve(grid_point_20x21,grid_point_32x33x34x35, c,false, false); + calculateCurve(grid_point_32x33x34x35,grid_point_22x23, c,false, false); + calculateCurve(grid_point_22x23,grid_point_10x11, c,false, false); + + calculateCurve(grid_point_5,grid_point_17, c, false, true); + calculateCurve(grid_point_17,grid_point_29x31, c,false, false); + calculateCurve(grid_point_29x31,grid_point_19, c,false, false); + calculateCurve(grid_point_19,grid_point_7, c,false, false); + + calculateCurve(grid_point_1,grid_point_13, c, false, true); + calculateCurve(grid_point_13,grid_point_25x27, c,false, false); + calculateCurve(grid_point_25x27,grid_point_15, c,false, false); + calculateCurve(grid_point_15,grid_point_3, c, false, false); hp_vec.push_back(c->get_pathvector()); } diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h index 461f835c6..ff2e75641 100644 --- a/src/live_effects/lpe-lattice2.h +++ b/src/live_effects/lpe-lattice2.h @@ -18,10 +18,10 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include <gtkmm.h> #include "live_effects/parameter/enum.h" #include "live_effects/effect.h" -#include "live_effects/parameter/pointreseteable.h" +#include "live_effects/parameter/point.h" #include "live_effects/lpegroupbbox.h" namespace Inkscape { @@ -34,7 +34,7 @@ public: virtual ~LPELattice2(); virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); - + virtual void resetDefaults(SPItem const* item); virtual void doBeforeEffect(SPLPEItem const* lpeitem); @@ -43,44 +43,50 @@ public: virtual void calculateCurve(Geom::Point a,Geom::Point b, SPCurve *c, bool horizontal, bool move); - virtual void setDefaults(); + virtual void vertical(PointParam ¶mA,PointParam ¶mB, Geom::Line vert); - virtual void resetGrid(); + virtual void horizontal(PointParam ¶mA,PointParam ¶mB,Geom::Line horiz); - //virtual void original_bbox(SPLPEItem const* lpeitem, bool absolute = false); + virtual void setDefaults(); + + virtual void onExpanderChanged(); - //virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/); + virtual void resetGrid(); - //virtual std::vector<Geom::PathVector> getHelperPaths(SPLPEItem const* lpeitem); protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); private: - PointReseteableParam grid_point0; - PointReseteableParam grid_point1; - PointReseteableParam grid_point2; - PointReseteableParam grid_point3; - PointReseteableParam grid_point4; - PointReseteableParam grid_point5; - PointReseteableParam grid_point6; - PointReseteableParam grid_point7; - PointReseteableParam grid_point8x9; - PointReseteableParam grid_point10x11; - PointReseteableParam grid_point12; - PointReseteableParam grid_point13; - PointReseteableParam grid_point14; - PointReseteableParam grid_point15; - PointReseteableParam grid_point16; - PointReseteableParam grid_point17; - PointReseteableParam grid_point18; - PointReseteableParam grid_point19; - PointReseteableParam grid_point20x21; - PointReseteableParam grid_point22x23; - PointReseteableParam grid_point24x26; - PointReseteableParam grid_point25x27; - PointReseteableParam grid_point28x30; - PointReseteableParam grid_point29x31; - PointReseteableParam grid_point32x33x34x35; + BoolParam horizontal_mirror; + BoolParam vertical_mirror; + PointParam grid_point_0; + PointParam grid_point_1; + PointParam grid_point_2; + PointParam grid_point_3; + PointParam grid_point_4; + PointParam grid_point_5; + PointParam grid_point_6; + PointParam grid_point_7; + PointParam grid_point_8x9; + PointParam grid_point_10x11; + PointParam grid_point_12; + PointParam grid_point_13; + PointParam grid_point_14; + PointParam grid_point_15; + PointParam grid_point_16; + PointParam grid_point_17; + PointParam grid_point_18; + PointParam grid_point_19; + PointParam grid_point_20x21; + PointParam grid_point_22x23; + PointParam grid_point_24x26; + PointParam grid_point_25x27; + PointParam grid_point_28x30; + PointParam grid_point_29x31; + PointParam grid_point_32x33x34x35; + + bool expanded; + Gtk::Expander * expander; LPELattice2(const LPELattice2&); LPELattice2& operator=(const LPELattice2&); diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index dc91775b7..ba7179476 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -42,7 +42,9 @@ LPEOffset::~LPEOffset() void LPEOffset::doOnApply(SPLPEItem const* lpeitem) { - offset_pt.param_set_and_write_new_value(*(SP_SHAPE(lpeitem)->_curve->first_point())); + Geom::Point offset = *(SP_SHAPE(lpeitem)->_curve->first_point()); + offset_pt.param_update_default(offset); + offset_pt.param_setValue(offset,true); } static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp index bb37fd42c..aa7405607 100644 --- a/src/live_effects/lpe-parallel.cpp +++ b/src/live_effects/lpe-parallel.cpp @@ -72,8 +72,9 @@ LPEParallel::doOnApply (SPLPEItem const* lpeitem) A = *(curve->first_point()); B = *(curve->last_point()); dir = unit_vector(B - A); - - offset_pt.param_set_and_write_new_value((A + B)/2 + dir.ccw() * 100); + Geom::Point offset = (A + B)/2 + dir.ccw() * 100; + offset_pt.param_update_default(offset); + offset_pt.param_setValue(offset, true); } Geom::Piecewise<Geom::D2<Geom::SBasis> > diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index b5ef26e2f..08100bb2d 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -1,6 +1,6 @@ /** \file * LPE <perspective-envelope> implementation - + */ /* * Authors: @@ -8,8 +8,8 @@ * Aaron Spike, aaron@ekips.org from envelope and perspective phyton code * Dmitry Platonov, shadowjack@mail.ru, 2006 perspective approach & math * Jose Hevia (freon) Transform algorithm from envelope - * - * Copyright (C) 2007-2014 Authors + * + * Copyright (C) 2007-2014 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -19,9 +19,7 @@ #include "helper/geom.h" #include "display/curve.h" #include "svg/svg.h" -#include "ui/tools-switch.h" #include <gsl/gsl_linalg.h> -#include "desktop.h" using namespace Geom; @@ -29,8 +27,8 @@ namespace Inkscape { namespace LivePathEffect { enum DeformationType { - DEFORMATION_PERSPECTIVE, - DEFORMATION_ENVELOPE + DEFORMATION_PERSPECTIVE, + DEFORMATION_ENVELOPE }; static const Util::EnumData<unsigned> DeformationTypeData[] = { @@ -42,54 +40,65 @@ static const Util::EnumDataConverter<unsigned> DeformationTypeConverter(Deformat LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject) : Effect(lpeobject), - // initialise your parameters here: + horizontal_mirror(_("Mirror movements in horizontal"), _("Mirror movements in horizontal"), "horizontal_mirror", &wr, this, false), + vertical_mirror(_("Mirror movements in vertical"), _("Mirror movements in vertical"), "vertical_mirror", &wr, this, false), deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_PERSPECTIVE), - Up_Left_Point(_("Top Left"), _("Top Left - Ctrl+Alt+Click to reset"), "Up_Left_Point", &wr, this), - Up_Right_Point(_("Top Right"), _("Top Right - Ctrl+Alt+Click to reset"), "Up_Right_Point", &wr, this), - Down_Left_Point(_("Down Left"), _("Down Left - Ctrl+Alt+Click to reset"), "Down_Left_Point", &wr, this), - Down_Right_Point(_("Down Right"), _("Down Right - Ctrl+Alt+Click to reset"), "Down_Right_Point", &wr, this) + up_left_point(_("Top Left"), _("Top Left - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "up_left_point", &wr, this), + up_right_point(_("Top Right"), _("Top Right - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "up_right_point", &wr, this), + down_left_point(_("Down Left"), _("Down Left - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "down_left_point", &wr, this), + down_right_point(_("Down Right"), _("Down Right - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "down_right_point", &wr, this) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&deform_type)); - registerParameter( dynamic_cast<Parameter *>(&Up_Left_Point) ); - registerParameter( dynamic_cast<Parameter *>(&Up_Right_Point) ); - registerParameter( dynamic_cast<Parameter *>(&Down_Left_Point) ); - registerParameter( dynamic_cast<Parameter *>(&Down_Right_Point) ); + registerParameter(&deform_type); + registerParameter(&horizontal_mirror); + registerParameter(&vertical_mirror); + registerParameter(&up_left_point); + registerParameter(&up_right_point); + registerParameter(&down_left_point); + registerParameter(&down_right_point); } LPEPerspectiveEnvelope::~LPEPerspectiveEnvelope() { } -void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { +void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) +{ using Geom::X; using Geom::Y; + if(are_near(up_left_point, up_right_point) && + are_near(up_right_point, down_left_point) && + are_near(down_left_point, down_right_point)) { + g_warning("Perspective/Envelope LPE::doBeforeEffect - lpeobj with invalid parameter, the same value in 4 handles!"); + resetGrid(); + return; + } double projmatrix[3][3]; - if(deform_type == DEFORMATION_PERSPECTIVE){ + if(deform_type == DEFORMATION_PERSPECTIVE) { std::vector<Geom::Point> handles(4); - handles[0] = Down_Left_Point; - handles[1] = Up_Left_Point; - handles[2] = Up_Right_Point; - handles[3] = Down_Right_Point; - std::vector<Geom::Point> sourceHandles(4); - sourceHandles[0] = Geom::Point(boundingbox_X.min(), boundingbox_Y.max()); - sourceHandles[1] = Geom::Point(boundingbox_X.min(), boundingbox_Y.min()); - sourceHandles[2] = Geom::Point(boundingbox_X.max(), boundingbox_Y.min()); - sourceHandles[3] = Geom::Point(boundingbox_X.max(), boundingbox_Y.max()); + handles[0] = down_left_point; + handles[1] = up_left_point; + handles[2] = up_right_point; + handles[3] = down_right_point; + std::vector<Geom::Point> source_handles(4); + source_handles[0] = Geom::Point(boundingbox_X.min(), boundingbox_Y.max()); + source_handles[1] = Geom::Point(boundingbox_X.min(), boundingbox_Y.min()); + source_handles[2] = Geom::Point(boundingbox_X.max(), boundingbox_Y.min()); + source_handles[3] = Geom::Point(boundingbox_X.max(), boundingbox_Y.max()); double solmatrix[8][8] = {{0}}; double free_term[8] = {0}; double gslSolmatrix[64]; - for(unsigned int i = 0; i < 4; ++i){ - solmatrix[i][0] = sourceHandles[i][X]; - solmatrix[i][1] = sourceHandles[i][Y]; + for(unsigned int i = 0; i < 4; ++i) { + solmatrix[i][0] = source_handles[i][X]; + solmatrix[i][1] = source_handles[i][Y]; solmatrix[i][2] = 1; - solmatrix[i][6] = -handles[i][X] * sourceHandles[i][X]; - solmatrix[i][7] = -handles[i][X] * sourceHandles[i][Y]; - solmatrix[i+4][3] = sourceHandles[i][X]; - solmatrix[i+4][4] = sourceHandles[i][Y]; + solmatrix[i][6] = -handles[i][X] * source_handles[i][X]; + solmatrix[i][7] = -handles[i][X] * source_handles[i][Y]; + solmatrix[i+4][3] = source_handles[i][X]; + solmatrix[i+4][4] = source_handles[i][Y]; solmatrix[i+4][5] = 1; - solmatrix[i+4][6] = -handles[i][Y] * sourceHandles[i][X]; - solmatrix[i+4][7] = -handles[i][Y] * sourceHandles[i][Y]; + solmatrix[i+4][6] = -handles[i][Y] * source_handles[i][X]; + solmatrix[i+4][7] = -handles[i][Y] * source_handles[i][Y]; free_term[i] = handles[i][X]; free_term[i+4] = handles[i][Y]; } @@ -112,7 +121,7 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { h = 0; for( int i = 0; i < 3; i++ ) { for( int j = 0; j < 3; j++ ) { - if(h==8){ + if(h==8) { projmatrix[2][2] = 1.0; continue; } @@ -126,19 +135,19 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); curve->reset(); Geom::CubicBezier const *cubic = NULL; - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point pointAt3(0, 0); + Geom::Point point_at1(0, 0); + Geom::Point point_at2(0, 0); + Geom::Point point_at3(0, 0); for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacÃo... if (path_it->empty()) - continue; + continue; //Itreadores SPCurve *nCurve = new SPCurve(); Geom::Path::const_iterator curve_it1 = path_it->begin(); Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); Geom::Path::const_iterator curve_endit = path_it->end_default(); - + if (path_it->closed()) { const Geom::Curve &closingline = path_it->back_closed(); @@ -146,40 +155,40 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { curve_endit = path_it->end_open(); } } - if(deform_type == DEFORMATION_PERSPECTIVE){ - nCurve->moveto(project_point(curve_it1->initialPoint(),projmatrix)); - }else{ - nCurve->moveto(project_point(curve_it1->initialPoint())); + if(deform_type == DEFORMATION_PERSPECTIVE) { + nCurve->moveto(projectPoint(curve_it1->initialPoint(),projmatrix)); + } else { + nCurve->moveto(projectPoint(curve_it1->initialPoint())); } while (curve_it1 != curve_endit) { - cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); - if (cubic) { - pointAt1 = (*cubic)[1]; - pointAt2 = (*cubic)[2]; - } else { - pointAt1 = curve_it1->initialPoint(); - pointAt2 = curve_it1->finalPoint(); - } - pointAt3 = curve_it1->finalPoint(); - if(deform_type == DEFORMATION_PERSPECTIVE){ - pointAt1 = project_point(pointAt1,projmatrix); - pointAt2 = project_point(pointAt2,projmatrix); - pointAt3 = project_point(pointAt3,projmatrix); - }else{ - pointAt1 = project_point(pointAt1); - pointAt2 = project_point(pointAt2); - pointAt3 = project_point(pointAt3); - } - nCurve->curveto(pointAt1, pointAt2, pointAt3); - ++curve_it1; - if(curve_it2 != curve_endit) { - ++curve_it2; - } + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + point_at1 = (*cubic)[1]; + point_at2 = (*cubic)[2]; + } else { + point_at1 = curve_it1->initialPoint(); + point_at2 = curve_it1->finalPoint(); + } + point_at3 = curve_it1->finalPoint(); + if(deform_type == DEFORMATION_PERSPECTIVE) { + point_at1 = projectPoint(point_at1,projmatrix); + point_at2 = projectPoint(point_at2,projmatrix); + point_at3 = projectPoint(point_at3,projmatrix); + } else { + point_at1 = projectPoint(point_at1); + point_at2 = projectPoint(point_at2); + point_at3 = projectPoint(point_at3); + } + nCurve->curveto(point_at1, point_at2, point_at3); + ++curve_it1; + if(curve_it2 != curve_endit) { + ++curve_it2; + } } //y cerramos la curva if (path_it->closed()) { - nCurve->move_endpoints(pointAt3, pointAt3); - nCurve->closepath_current(); + nCurve->move_endpoints(point_at3, point_at3); + nCurve->closepath_current(); } curve->append(nCurve, false); nCurve->reset(); @@ -187,41 +196,44 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { } } -Geom::Point -LPEPerspectiveEnvelope::project_point(Geom::Point p){ +Geom::Point +LPEPerspectiveEnvelope::projectPoint(Geom::Point p) +{ double width = boundingbox_X.extent(); double height = boundingbox_Y.extent(); double delta_x = boundingbox_X.min() - p[X]; double delta_y = boundingbox_Y.max() - p[Y]; - Geom::Coord xratio = (delta_x * -1) / width; - Geom::Coord yratio = delta_y / height; + Geom::Coord x_ratio = (delta_x * -1) / width; + Geom::Coord y_ratio = delta_y / height; Geom::Line* horiz = new Geom::Line(); Geom::Line* vert = new Geom::Line(); - vert->setPoints (pointAtRatio(yratio,Down_Left_Point,Up_Left_Point),pointAtRatio(yratio,Down_Right_Point,Up_Right_Point)); - horiz->setPoints (pointAtRatio(xratio,Down_Left_Point,Down_Right_Point),pointAtRatio(xratio,Up_Left_Point,Up_Right_Point)); + vert->setPoints (pointAtRatio(y_ratio,down_left_point,up_left_point),pointAtRatio(y_ratio,down_right_point,up_right_point)); + horiz->setPoints (pointAtRatio(x_ratio,down_left_point,down_right_point),pointAtRatio(x_ratio,up_left_point,up_right_point)); OptCrossing crossPoint = intersection(*horiz,*vert); - if(crossPoint){ + if(crossPoint) { return horiz->pointAt(Geom::Coord(crossPoint->ta)); - }else{ + } else { return p; } } -Geom::Point -LPEPerspectiveEnvelope::project_point(Geom::Point p, double m[][3]){ +Geom::Point +LPEPerspectiveEnvelope::projectPoint(Geom::Point p, double m[][3]) +{ Geom::Coord x = p[0]; Geom::Coord y = p[1]; 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])), - Geom::Coord((x*m[1][0] + y*m[1][1] + m[1][2])/(x*m[2][0]+y*m[2][1]+m[2][2]))); + Geom::Coord((x*m[0][0] + y*m[0][1] + m[0][2])/(x*m[2][0]+y*m[2][1]+m[2][2])), + Geom::Coord((x*m[1][0] + y*m[1][1] + m[1][2])/(x*m[2][0]+y*m[2][1]+m[2][2]))); } Geom::Point -LPEPerspectiveEnvelope::pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B){ - Geom::Coord x = A[X] + (ratio * (B[X]-A[X])); - Geom::Coord y = A[Y]+ (ratio * (B[Y]-A[Y])); - return Point(x, y); +LPEPerspectiveEnvelope::pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B) +{ + Geom::Coord x = A[X] + (ratio * (B[X]-A[X])); + Geom::Coord y = A[Y]+ (ratio * (B[Y]-A[Y])); + return Point(x, y); } @@ -235,36 +247,35 @@ LPEPerspectiveEnvelope::newWidget() vbox->set_homogeneous(false); vbox->set_spacing(6); std::vector<Parameter *>::iterator it = param_vector.begin(); - Gtk::HBox * hboxUpHandles = Gtk::manage(new Gtk::HBox(false,0)); - Gtk::HBox * hboxDownHandles = Gtk::manage(new Gtk::HBox(false,0)); + Gtk::HBox * hbox_up_handles = Gtk::manage(new Gtk::HBox(false,0)); + Gtk::HBox * hbox_down_handles = Gtk::manage(new Gtk::HBox(false,0)); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter * param = *it; Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); - if (param->param_key == "Up_Left_Point" || - param->param_key == "Up_Right_Point" || - param->param_key == "Down_Left_Point" || - param->param_key == "Down_Right_Point") - { - Gtk::HBox * pointParameter = dynamic_cast<Gtk::HBox *>(widg); - std::vector< Gtk::Widget* > childList = pointParameter->get_children(); - Gtk::HBox * pointParameterHBox = dynamic_cast<Gtk::HBox *>(childList[0]); - std::vector< Gtk::Widget* > childList2 = pointParameterHBox->get_children(); - pointParameterHBox->remove(childList2[0][0]); + if (param->param_key == "up_left_point" || + param->param_key == "up_right_point" || + param->param_key == "down_left_point" || + param->param_key == "down_right_point") { + Gtk::HBox * point_hbox = dynamic_cast<Gtk::HBox *>(widg); + std::vector< Gtk::Widget* > child_list = point_hbox->get_children(); + Gtk::HBox * point_hboxHBox = dynamic_cast<Gtk::HBox *>(child_list[0]); + std::vector< Gtk::Widget* > child_list2 = point_hboxHBox->get_children(); + point_hboxHBox->remove(child_list2[0][0]); Glib::ustring * tip = param->param_getTooltip(); if (widg) { - if(param->param_key == "Up_Left_Point"){ + if(param->param_key == "up_left_point") { Gtk::Label* handles = Gtk::manage(new Gtk::Label(Glib::ustring(_("Handles:")),Gtk::ALIGN_START)); vbox->pack_start(*handles, false, false, 2); - hboxUpHandles->pack_start(*widg, true, true, 2); - hboxUpHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); - }else if(param->param_key == "Up_Right_Point"){ - hboxUpHandles->pack_start(*widg, true, true, 2); - }else if(param->param_key == "Down_Left_Point"){ - hboxDownHandles->pack_start(*widg, true, true, 2); - hboxDownHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); - }else{ - hboxDownHandles->pack_start(*widg, true, true, 2); + hbox_up_handles->pack_start(*widg, true, true, 2); + hbox_up_handles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); + } else if(param->param_key == "up_right_point") { + hbox_up_handles->pack_start(*widg, true, true, 2); + } else if(param->param_key == "down_left_point") { + hbox_down_handles->pack_start(*widg, true, true, 2); + hbox_down_handles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); + } else { + hbox_down_handles->pack_start(*widg, true, true, 2); } if (tip) { widg->set_tooltip_text(*tip); @@ -273,7 +284,7 @@ LPEPerspectiveEnvelope::newWidget() widg->set_has_tooltip(false); } } - }else{ + } else { Glib::ustring * tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -289,25 +300,77 @@ LPEPerspectiveEnvelope::newWidget() ++it; } - vbox->pack_start(*hboxUpHandles,true, true, 2); - Gtk::HBox * hboxMiddle = Gtk::manage(new Gtk::HBox(true,2)); - hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); - hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); - vbox->pack_start(*hboxMiddle, false, true, 2); - vbox->pack_start(*hboxDownHandles, true, true, 2); + vbox->pack_start(*hbox_up_handles,true, true, 2); + Gtk::HBox * hbox_middle = Gtk::manage(new Gtk::HBox(true,2)); + hbox_middle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); + hbox_middle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); + vbox->pack_start(*hbox_middle, false, true, 2); + vbox->pack_start(*hbox_down_handles, true, true, 2); Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); - Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR)); - resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPEPerspectiveEnvelope::resetGrid)); - resetButton->set_size_request(140,45); + Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR)); + reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPerspectiveEnvelope::resetGrid)); + reset_button->set_size_request(140,30); vbox->pack_start(*hbox, true,true,2); - hbox->pack_start(*resetButton, false, false,2); + hbox->pack_start(*reset_button, false, false,2); return dynamic_cast<Gtk::Widget *>(vbox); } void +LPEPerspectiveEnvelope::vertical(PointParam ¶m_one, PointParam ¶m_two, Geom::Line vert) +{ + Geom::Point A = param_one; + Geom::Point B = param_two; + double Y = (A[Geom::Y] + B[Geom::Y])/2; + A[Geom::Y] = Y; + B[Geom::Y] = Y; + Geom::Point nearest = vert.pointAt(vert.nearestPoint(A)); + double distance_one = Geom::distance(A,nearest); + double distance_two = Geom::distance(B,nearest); + double distance_middle = (distance_one + distance_two)/2; + if(A[Geom::X] > B[Geom::X]) { + distance_middle *= -1; + } + A[Geom::X] = nearest[Geom::X] - distance_middle; + B[Geom::X] = nearest[Geom::X] + distance_middle; + param_one.param_setValue(A, true); + param_two.param_setValue(B, true); +} + +void +LPEPerspectiveEnvelope::horizontal(PointParam ¶m_one, PointParam ¶m_two, Geom::Line horiz) +{ + Geom::Point A = param_one; + Geom::Point B = param_two; + double X = (A[Geom::X] + B[Geom::X])/2; + A[Geom::X] = X; + B[Geom::X] = X; + Geom::Point nearest = horiz.pointAt(horiz.nearestPoint(A)); + double distance_one = Geom::distance(A,nearest); + double distance_two = Geom::distance(B,nearest); + double distance_middle = (distance_one + distance_two)/2; + if(A[Geom::Y] > B[Geom::Y]) { + distance_middle *= -1; + } + A[Geom::Y] = nearest[Geom::Y] - distance_middle; + B[Geom::Y] = nearest[Geom::Y] + distance_middle; + param_one.param_setValue(A, true); + param_two.param_setValue(B, true); +} + +void LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); + Geom::Line vert(Geom::Point(boundingbox_X.middle(),boundingbox_Y.max()), Geom::Point(boundingbox_X.middle(), boundingbox_Y.min())); + Geom::Line horiz(Geom::Point(boundingbox_X.min(),boundingbox_Y.middle()), Geom::Point(boundingbox_X.max(), boundingbox_Y.middle())); + if(vertical_mirror) { + vertical(up_left_point, up_right_point,vert); + vertical(down_left_point, down_right_point,vert); + } + if(horizontal_mirror) { + horizontal(up_left_point, down_left_point,horiz); + horizontal(up_right_point, down_right_point,horiz); + } SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); item->apply_to_clippath(item); item->apply_to_mask(item); @@ -317,29 +380,24 @@ LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) void LPEPerspectiveEnvelope::setDefaults() { - Geom::Point Up_Left(boundingbox_X.min(), boundingbox_Y.min()); - Geom::Point Up_Right(boundingbox_X.max(), boundingbox_Y.min()); - Geom::Point Down_Left(boundingbox_X.min(), boundingbox_Y.max()); - Geom::Point Down_Right(boundingbox_X.max(), boundingbox_Y.max()); - - Up_Left_Point.param_update_default(Up_Left); - Up_Right_Point.param_update_default(Up_Right); - Down_Right_Point.param_update_default(Down_Right); - Down_Left_Point.param_update_default(Down_Left); + Geom::Point up_left(boundingbox_X.min(), boundingbox_Y.min()); + Geom::Point up_right(boundingbox_X.max(), boundingbox_Y.min()); + Geom::Point down_left(boundingbox_X.min(), boundingbox_Y.max()); + Geom::Point down_right(boundingbox_X.max(), boundingbox_Y.max()); + + up_left_point.param_update_default(up_left); + up_right_point.param_update_default(up_right); + down_right_point.param_update_default(down_right); + down_left_point.param_update_default(down_left); } void LPEPerspectiveEnvelope::resetGrid() { - Up_Left_Point.param_set_and_write_default(); - Up_Right_Point.param_set_and_write_default(); - Down_Right_Point.param_set_and_write_default(); - Down_Left_Point.param_set_and_write_default(); - //todo:this hack is only to reposition the knots on reser grid button - //Better update path effect in LPEITEM - SPDesktop * desktop = SP_ACTIVE_DESKTOP; - tools_switch(desktop, TOOLS_SELECT); - tools_switch(desktop, TOOLS_NODES); + up_left_point.param_set_default(); + up_right_point.param_set_default(); + down_right_point.param_set_default(); + down_left_point.param_set_default(); } void @@ -358,11 +416,11 @@ LPEPerspectiveEnvelope::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v SPCurve *c = new SPCurve(); c->reset(); - c->moveto(Up_Left_Point); - c->lineto(Up_Right_Point); - c->lineto(Down_Right_Point); - c->lineto(Down_Left_Point); - c->lineto(Up_Left_Point); + c->moveto(up_left_point); + c->lineto(up_right_point); + c->lineto(down_right_point); + c->lineto(down_left_point); + c->lineto(up_left_point); hp_vec.push_back(c->get_pathvector()); } diff --git a/src/live_effects/lpe-perspective-envelope.h b/src/live_effects/lpe-perspective-envelope.h index 2f253882e..dd14dc212 100644 --- a/src/live_effects/lpe-perspective-envelope.h +++ b/src/live_effects/lpe-perspective-envelope.h @@ -3,7 +3,7 @@ /** \file * LPE <perspective-envelope> implementation , see lpe-perspective-envelope.cpp. - + */ /* * Authors: @@ -11,15 +11,15 @@ * Aaron Spike, aaron@ekips.org from envelope and perspective phyton code * Dmitry Platonov, shadowjack@mail.ru, 2006 perspective approach & math * Jose Hevia (freon) Transform algorithm from envelope - * - * Copyright (C) 2007-2014 Authors + * + * Copyright (C) 2007-2014 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #include "live_effects/parameter/enum.h" #include "live_effects/effect.h" -#include "live_effects/parameter/pointreseteable.h" +#include "live_effects/parameter/point.h" #include "live_effects/lpegroupbbox.h" namespace Inkscape { @@ -34,14 +34,18 @@ public: virtual void doEffect(SPCurve *curve); - virtual Geom::Point project_point(Geom::Point p); + virtual Geom::Point projectPoint(Geom::Point p); - virtual Geom::Point project_point(Geom::Point p, double m[][3]); + virtual Geom::Point projectPoint(Geom::Point p, double m[][3]); virtual Geom::Point pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B); virtual void resetDefaults(SPItem const* item); + virtual void vertical(PointParam ¶mA,PointParam ¶mB, Geom::Line vert); + + virtual void horizontal(PointParam ¶mA,PointParam ¶mB,Geom::Line horiz); + virtual void doBeforeEffect(SPLPEItem const* lpeitem); virtual Gtk::Widget * newWidget(); @@ -54,11 +58,13 @@ protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); private: + BoolParam horizontal_mirror; + BoolParam vertical_mirror; EnumParam<unsigned> deform_type; - PointReseteableParam Up_Left_Point; - PointReseteableParam Up_Right_Point; - PointReseteableParam Down_Left_Point; - PointReseteableParam Down_Right_Point; + PointParam up_left_point; + PointParam up_right_point; + PointParam down_left_point; + PointParam down_right_point; LPEPerspectiveEnvelope(const LPEPerspectiveEnvelope&); LPEPerspectiveEnvelope& operator=(const LPEPerspectiveEnvelope&); diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index f7fe9592d..5d9d224e8 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -297,7 +297,8 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) } else { sp_repr_css_unset_property (css, "fill"); } - + + sp_repr_css_set_property(css, "fill-rule", "nonzero"); sp_repr_css_set_property(css, "stroke", "none"); sp_desktop_apply_css_recursive(item, css, true); @@ -330,25 +331,21 @@ void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem) if (SP_IS_SHAPE(lpeitem)) { SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem); SPCSSAttr *css = sp_repr_css_attr_new (); - if (true) { - if (lpeitem->style->fill.isPaintserver()) { - SPPaintServer * server = lpeitem->style->getFillPaintServer(); - if (server) { - Glib::ustring str; - str += "url(#"; - str += server->getId(); - str += ")"; - sp_repr_css_set_property (css, "stroke", str.c_str()); - } - } else if (lpeitem->style->fill.isColor()) { - gchar c[64]; - sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); - sp_repr_css_set_property (css, "stroke", c); - } else { - sp_repr_css_set_property (css, "stroke", "none"); + if (lpeitem->style->fill.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getFillPaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "stroke", str.c_str()); } + } else if (lpeitem->style->fill.isColor()) { + char c[64] = {0}; + sp_svg_write_color (c, sizeof(c), lpeitem->style->fill.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->fill_opacity.value))); + sp_repr_css_set_property (css, "stroke", c); } else { - sp_repr_css_unset_property (css, "stroke"); + sp_repr_css_set_property (css, "stroke", "none"); } Inkscape::CSSOStringStream os; diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 8cef9a3a3..9d1c3152b 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -39,36 +39,36 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) unit(_("Unit"), _("Unit"), "unit", &wr, this), method(_("Method"), _("Division method"), "method", DMConverter, &wr, this, DM_SEGMENTS), - maxSegmentSize(_("Max. segment size"), _("Max. segment size"), - "maxSegmentSize", &wr, this, 10.), + max_segment_size(_("Max. segment size"), _("Max. segment size"), + "max_segment_size", &wr, this, 10.), segments(_("Number of segments"), _("Number of segments"), "segments", &wr, this, 2), - displaceX(_("Max. displacement in X"), _("Max. displacement in X"), - "displaceX", &wr, this, 10.), - displaceY(_("Max. displacement in Y"), _("Max. displacement in Y"), - "displaceY", &wr, this, 10.), - globalRandomize(_("Global randomize"), _("Global randomize"), - "globalRandomize", &wr, this, 1.), - shiftNodes(_("Shift nodes"), _("Shift nodes"), "shiftNodes", &wr, this, + displace_x(_("Max. displacement in X"), _("Max. displacement in X"), + "displace_x", &wr, this, 10.), + displace_y(_("Max. displacement in Y"), _("Max. displacement in Y"), + "displace_y", &wr, this, 10.), + global_randomize(_("Global randomize"), _("Global randomize"), + "global_randomize", &wr, this, 1.), + shift_nodes(_("Shift nodes"), _("Shift nodes"), "shift_nodes", &wr, this, true), - shiftNodeHandles(_("Shift node handles"), _("Shift node handles"), - "shiftNodeHandles", &wr, this, true) + shift_node_handles(_("Shift node handles"), _("Shift node handles"), + "shift_node_handles", &wr, this, true) { registerParameter(&unit); registerParameter(&method); - registerParameter(&maxSegmentSize); + registerParameter(&max_segment_size); registerParameter(&segments); - registerParameter(&displaceX); - registerParameter(&displaceY); - registerParameter(&globalRandomize); - registerParameter(&shiftNodes); - registerParameter(&shiftNodeHandles); - displaceX.param_set_range(0., Geom::infinity()); - displaceY.param_set_range(0., Geom::infinity()); - globalRandomize.param_set_range(0., Geom::infinity()); - maxSegmentSize.param_set_range(0., Geom::infinity()); - maxSegmentSize.param_set_increments(1, 1); - maxSegmentSize.param_set_digits(1); + registerParameter(&displace_x); + registerParameter(&displace_y); + registerParameter(&global_randomize); + registerParameter(&shift_nodes); + registerParameter(&shift_node_handles); + displace_x.param_set_range(0., Geom::infinity()); + displace_y.param_set_range(0., Geom::infinity()); + global_randomize.param_set_range(0., Geom::infinity()); + max_segment_size.param_set_range(0., Geom::infinity()); + max_segment_size.param_set_increments(1, 1); + max_segment_size.param_set_digits(1); segments.param_set_range(1, Geom::infinity()); segments.param_set_increments(1, 1); segments.param_set_digits(0); @@ -78,9 +78,9 @@ LPERoughen::~LPERoughen() {} void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem) { - displaceX.resetRandomizer(); - displaceY.resetRandomizer(); - globalRandomize.resetRandomizer(); + displace_x.resetRandomizer(); + displace_y.resetRandomizer(); + global_randomize.resetRandomizer(); srand(1); SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); item->apply_to_clippath(item); @@ -99,37 +99,37 @@ Gtk::Widget *LPERoughen::newWidget() Parameter *param = *it; Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); if (param->param_key == "unit") { - Gtk::Label *unitLabel = Gtk::manage(new Gtk::Label( + Gtk::Label *unit_label = Gtk::manage(new Gtk::Label( Glib::ustring(_("<b>Roughen unit</b>")), Gtk::ALIGN_START)); - unitLabel->set_use_markup(true); - vbox->pack_start(*unitLabel, false, false, 2); + unit_label->set_use_markup(true); + vbox->pack_start(*unit_label, false, false, 2); vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } if (param->param_key == "method") { - Gtk::Label *methodLabel = Gtk::manage(new Gtk::Label( + Gtk::Label *method_label = Gtk::manage(new Gtk::Label( Glib::ustring(_("<b>Add nodes</b> Subdivide each segment")), Gtk::ALIGN_START)); - methodLabel->set_use_markup(true); - vbox->pack_start(*methodLabel, false, false, 2); + method_label->set_use_markup(true); + vbox->pack_start(*method_label, false, false, 2); vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } - if (param->param_key == "displaceX") { - Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( + if (param->param_key == "displace_x") { + Gtk::Label *displace_x_label = Gtk::manage(new Gtk::Label( Glib::ustring(_("<b>Jitter nodes</b> Move nodes/handles")), Gtk::ALIGN_START)); - displaceXLabel->set_use_markup(true); - vbox->pack_start(*displaceXLabel, false, false, 2); + displace_x_label->set_use_markup(true); + vbox->pack_start(*displace_x_label, false, false, 2); vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } - if (param->param_key == "globalRandomize") { - Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( + if (param->param_key == "global_randomize") { + Gtk::Label *global_rand = Gtk::manage(new Gtk::Label( Glib::ustring(_("<b>Extra roughen</b> Add a extra layer of rough")), Gtk::ALIGN_START)); - displaceXLabel->set_use_markup(true); - vbox->pack_start(*displaceXLabel, false, false, 2); + global_rand->set_use_markup(true); + vbox->pack_start(*global_rand, false, false, 2); vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } @@ -150,23 +150,23 @@ Gtk::Widget *LPERoughen::newWidget() return dynamic_cast<Gtk::Widget *>(vbox); } -double LPERoughen::sign(double randNumber) +double LPERoughen::sign(double random_number) { if (rand() % 100 < 49) { - randNumber *= -1.; + random_number *= -1.; } - return randNumber; + return random_number; } Geom::Point LPERoughen::randomize() { Inkscape::Util::Unit const *svg_units = SP_ACTIVE_DESKTOP->namedview->svg_units; - double displaceXParsed = Inkscape::Util::Quantity::convert( - displaceX * globalRandomize, unit.get_abbreviation(), svg_units->abbr); - double displaceYParsed = Inkscape::Util::Quantity::convert( - displaceY * globalRandomize, unit.get_abbreviation(), svg_units->abbr); + double displace_x_parsed = Inkscape::Util::Quantity::convert( + displace_x * global_randomize, unit.get_abbreviation(), svg_units->abbr); + double displace_y_parsed = Inkscape::Util::Quantity::convert( + displace_y * global_randomize, unit.get_abbreviation(), svg_units->abbr); - Geom::Point output = Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); + Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed)); return output; } @@ -193,32 +193,32 @@ void LPERoughen::doEffect(SPCurve *curve) } } Geom::Point initialMove(0, 0); - if (shiftNodes) { + if (shift_nodes) { initialMove = randomize(); } Geom::Point initialPoint = curve_it1->initialPoint() + initialMove; nCurve->moveto(initialPoint); - Geom::Point A0(0, 0); - Geom::Point A1(0, 0); - Geom::Point A2(0, 0); - Geom::Point A3(0, 0); + Geom::Point point0(0, 0); + Geom::Point point1(0, 0); + Geom::Point point2(0, 0); + Geom::Point point3(0, 0); bool first = true; while (curve_it1 != curve_endit) { Geom::CubicBezier const *cubic = NULL; - A0 = curve_it1->initialPoint(); - A1 = curve_it1->initialPoint(); - A2 = curve_it1->finalPoint(); - A3 = curve_it1->finalPoint(); + point0 = curve_it1->initialPoint(); + point1 = curve_it1->initialPoint(); + point2 = curve_it1->finalPoint(); + point3 = curve_it1->finalPoint(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - A1 = (*cubic)[1]; - if (shiftNodes && first) { - A1 = (*cubic)[1] + initialMove; + point1 = (*cubic)[1]; + if (shift_nodes && first) { + point1 = (*cubic)[1] + initialMove; } - A2 = (*cubic)[2]; - nCurve->curveto(A1, A2, A3); + point2 = (*cubic)[2]; + nCurve->curveto(point1, point2, point3); } else { - nCurve->lineto(A3); + nCurve->lineto(point3); } double length = Inkscape::Util::Quantity::convert( curve_it1->length(0.001), svg_units->abbr, unit.get_abbreviation()); @@ -226,7 +226,7 @@ void LPERoughen::doEffect(SPCurve *curve) if (method == DM_SEGMENTS) { splits = segments; } else { - splits = ceil(length / maxSegmentSize); + splits = ceil(length / max_segment_size); } for (unsigned int t = splits; t >= 1; t--) { if (t == 1 && splits != 1) { @@ -265,42 +265,42 @@ SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) { SPCurve *out = new SPCurve(); Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A); - Geom::Point A1(0, 0); - Geom::Point A2(0, 0); - Geom::Point A3(0, 0); - Geom::Point B1(0, 0); - Geom::Point B2(0, 0); - Geom::Point B3(0, 0); - if (shiftNodes) { - A3 = randomize(); - B3 = randomize(); + Geom::Point point1(0, 0); + Geom::Point point2(0, 0); + Geom::Point point3(0, 0); + Geom::Point point_b1(0, 0); + Geom::Point point_b2(0, 0); + Geom::Point point_b3(0, 0); + if (shift_nodes) { + point3 = randomize(); + point_b3 = randomize(); } - if (shiftNodeHandles) { - A1 = randomize(); - A2 = randomize(); - B1 = randomize(); - B2 = randomize(); + if (shift_node_handles) { + point1 = randomize(); + point2 = randomize(); + point_b1 = randomize(); + point_b2 = randomize(); } else { - A2 = A3; - B1 = A3; - B2 = B3; + point2 = point3; + point_b1 = point3; + point_b2 = point_b3; } if (cubic) { std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); std::vector<Geom::Point> seg1 = div.first.points(), seg2 = div.second.points(); out->moveto(seg1[0]); - out->curveto(seg1[1] + A1, seg1[2] + A2, seg1[3] + A3); - out->curveto(seg2[1] + B1, seg2[2], seg2[3]); - } else if (shiftNodeHandles) { + out->curveto(seg1[1] + point1, seg1[2] + point2, seg1[3] + point3); + out->curveto(seg2[1] + point_b1, seg2[2], seg2[3]); + } else if (shift_node_handles) { out->moveto(A->initialPoint()); - out->curveto(A->pointAt(t / 3) + A1, A->pointAt((t / 3) * 2) + A2, - A->pointAt(t) + A3); - out->curveto(A->pointAt(t + (t / 3)) + B1, A->pointAt(t + ((t / 3) * 2)), + out->curveto(A->pointAt(t / 3) + point1, A->pointAt((t / 3) * 2) + point2, + A->pointAt(t) + point3); + out->curveto(A->pointAt(t + (t / 3)) + point_b1, A->pointAt(t + ((t / 3) * 2)), A->finalPoint()); } else { out->moveto(A->initialPoint()); - out->lineto(A->pointAt(t) + A3); + out->lineto(A->pointAt(t) + point3); out->lineto(A->finalPoint()); } return out; @@ -310,33 +310,33 @@ SPCurve *LPERoughen::jitter(const Geom::Curve *A) { SPCurve *out = new SPCurve(); Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A); - Geom::Point A1(0, 0); - Geom::Point A2(0, 0); - Geom::Point A3(0, 0); - if (shiftNodes) { - A3 = randomize(); + Geom::Point point1(0, 0); + Geom::Point point2(0, 0); + Geom::Point point3(0, 0); + if (shift_nodes) { + point3 = randomize(); } - if (shiftNodeHandles) { - A1 = randomize(); - A2 = randomize(); + if (shift_node_handles) { + point1 = randomize(); + point2 = randomize(); } else { - A2 = A3; + point2 = point3; } if (cubic) { out->moveto((*cubic)[0]); - out->curveto((*cubic)[1] + A1, (*cubic)[2] + A2, (*cubic)[3] + A3); - } else if (shiftNodeHandles) { + out->curveto((*cubic)[1] + point1, (*cubic)[2] + point2, (*cubic)[3] + point3); + } else if (shift_node_handles) { out->moveto(A->initialPoint()); - out->curveto(A->pointAt(0.3333) + A1, A->pointAt(0.6666) + A2, - A->finalPoint() + A3); + out->curveto(A->pointAt(0.3333) + point1, A->pointAt(0.6666) + point2, + A->finalPoint() + point3); } else { out->moveto(A->initialPoint()); - out->lineto(A->finalPoint() + A3); + out->lineto(A->finalPoint() + point3); } return out; } -Geom::Point LPERoughen::tpoint(Geom::Point A, Geom::Point B, double t) +Geom::Point LPERoughen::tPoint(Geom::Point A, Geom::Point B, double t) { using Geom::X; using Geom::Y; diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index 74331f1ef..ed9f06cf7 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -41,19 +41,19 @@ public: virtual void doBeforeEffect(SPLPEItem const * lpeitem); virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t); virtual SPCurve *jitter(const Geom::Curve *A); - virtual Geom::Point tpoint(Geom::Point A, Geom::Point B, double t = 0.5); + virtual Geom::Point tPoint(Geom::Point A, Geom::Point B, double t = 0.5); virtual Gtk::Widget *newWidget(); private: UnitParam unit; EnumParam<DivisionMethod> method; - ScalarParam maxSegmentSize; + ScalarParam max_segment_size; ScalarParam segments; - RandomParam displaceX; - RandomParam displaceY; - RandomParam globalRandomize; - BoolParam shiftNodes; - BoolParam shiftNodeHandles; + RandomParam displace_x; + RandomParam displace_y; + RandomParam global_randomize; + BoolParam shift_nodes; + BoolParam shift_node_handles; LPERoughen(const LPERoughen &); LPERoughen &operator=(const LPERoughen &); diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp index 2d8148730..2638f312e 100644 --- a/src/live_effects/lpe-show_handles.cpp +++ b/src/live_effects/lpe-show_handles.cpp @@ -24,25 +24,25 @@ LPEShowHandles::LPEShowHandles(LivePathEffectObject *lpeobject) : Effect(lpeobject), nodes(_("Show nodes"), _("Show nodes"), "nodes", &wr, this, true), handles(_("Show handles"), _("Show handles"), "handles", &wr, this, true), - originalPath(_("Show path"), _("Show path"), "originalPath", &wr, this, true), - scaleNodesAndHandles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scaleNodesAndHandles", &wr, this, 10), - rotateNodes(_("Rotate nodes"), _("Rotate nodes"), "rotateNodes", &wr, this, 0) + original_path(_("Show path"), _("Show path"), "original_path", &wr, this, true), + scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10), + rotate_nodes(_("Rotate nodes"), _("Rotate nodes"), "rotate_nodes", &wr, this, 0) { - registerParameter(dynamic_cast<Parameter *>(&nodes)); - registerParameter(dynamic_cast<Parameter *>(&handles)); - registerParameter(dynamic_cast<Parameter *>(&originalPath)); - registerParameter(dynamic_cast<Parameter *>(&scaleNodesAndHandles)); - registerParameter(dynamic_cast<Parameter *>(&rotateNodes)); - scaleNodesAndHandles.param_set_range(0, 500.); - scaleNodesAndHandles.param_set_increments(1, 1); - scaleNodesAndHandles.param_set_digits(2); - rotateNodes.param_set_range(0, 365); - rotateNodes.param_set_increments(1, 1); - rotateNodes.param_set_digits(0); - strokeWidth = 1.0; + registerParameter(&nodes); + registerParameter(&handles); + registerParameter(&original_path); + registerParameter(&scale_nodes_and_handles); + registerParameter(&rotate_nodes); + scale_nodes_and_handles.param_set_range(0, 500.); + scale_nodes_and_handles.param_set_increments(1, 1); + scale_nodes_and_handles.param_set_digits(2); + rotate_nodes.param_set_range(0, 365); + rotate_nodes.param_set_increments(1, 1); + rotate_nodes.param_set_digits(0); + stroke_width = 1.0; } -bool LPEShowHandles::alertsOff = false; +bool LPEShowHandles::alerts_off = false; /** * Sets default styles to element @@ -51,11 +51,11 @@ bool LPEShowHandles::alertsOff = false; void LPEShowHandles::doOnApply(SPLPEItem const* lpeitem) { - if(!alertsOff) { + if(!alerts_off) { char *msg = _("The \"show handles\" path effect will remove any custom style on the object you are applying it to. If this is not what you want, click Cancel."); Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true); gint response = dialog.run(); - alertsOff = true; + alerts_off = true; if(response == GTK_RESPONSE_CANCEL) { SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); item->removeCurrentPathEffect(false); @@ -76,24 +76,24 @@ void LPEShowHandles::doOnApply(SPLPEItem const* lpeitem) void LPEShowHandles::doBeforeEffect (SPLPEItem const* lpeitem) { SPItem const* item = SP_ITEM(lpeitem); - strokeWidth = item->style->stroke_width.computed; + stroke_width = item->style->stroke_width.computed; } std::vector<Geom::Path> LPEShowHandles::doEffect_path (std::vector<Geom::Path> const & path_in) { std::vector<Geom::Path> path_out; Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in); - if(originalPath) { + if(original_path) { for (unsigned int i=0; i < path_in.size(); i++) { path_out.push_back(path_in[i]); } } - if(!outlinepath.empty()) { - outlinepath.clear(); + if(!outline_path.empty()) { + outline_path.clear(); } generateHelperPath(original_pathv); - for (unsigned int i=0; i < outlinepath.size(); i++) { - path_out.push_back(outlinepath[i]); + for (unsigned int i=0; i < outline_path.size(); i++) { + path_out.push_back(outline_path[i]); } return path_out; } @@ -136,11 +136,11 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { if(handles) { - if(!are_near((*cubic)[0],(*cubic)[1])){ + if(!are_near((*cubic)[0],(*cubic)[1])) { drawHandle((*cubic)[1]); drawHandleLine((*cubic)[0],(*cubic)[1]); } - if(!are_near((*cubic)[3],(*cubic)[2])){ + if(!are_near((*cubic)[3],(*cubic)[2])) { drawHandle((*cubic)[2]); drawHandleLine((*cubic)[3],(*cubic)[2]); } @@ -150,7 +150,7 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) drawNode(curve_it1->finalPoint()); } ++curve_it1; - if(curve_it2 != curve_endit){ + if(curve_it2 != curve_endit) { ++curve_it2; } } @@ -160,30 +160,30 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) void LPEShowHandles::drawNode(Geom::Point p) { - if(strokeWidth * scaleNodesAndHandles > 0.0) { - double diameter = strokeWidth * scaleNodesAndHandles; + if(stroke_width * scale_nodes_and_handles > 0.0) { + double diameter = stroke_width * scale_nodes_and_handles; char const * svgd; svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Rotate::from_degrees(rotateNodes); + pathv *= Geom::Rotate::from_degrees(rotate_nodes); pathv *= Geom::Scale (diameter); pathv += p; - outlinepath.push_back(pathv[0]); - outlinepath.push_back(pathv[1]); + outline_path.push_back(pathv[0]); + outline_path.push_back(pathv[1]); } } void LPEShowHandles::drawHandle(Geom::Point p) { - if(strokeWidth * scaleNodesAndHandles > 0.0) { - double diameter = strokeWidth * scaleNodesAndHandles; + if(stroke_width * scale_nodes_and_handles > 0.0) { + double diameter = stroke_width * scale_nodes_and_handles; char const * svgd; svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); pathv *= Geom::Scale (diameter); pathv += p-Geom::Point(diameter * 0.35,diameter * 0.35); - outlinepath.push_back(pathv[0]); + outline_path.push_back(pathv[0]); } } @@ -192,14 +192,14 @@ void LPEShowHandles::drawHandleLine(Geom::Point p,Geom::Point p2) { Geom::Path path; - double diameter = strokeWidth * scaleNodesAndHandles; - if(diameter > 0.0 && Geom::distance(p,p2) > (diameter * 0.35)){ + double diameter = stroke_width * scale_nodes_and_handles; + if(diameter > 0.0 && Geom::distance(p,p2) > (diameter * 0.35)) { Geom::Ray ray2(p, p2); p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35)); } path.start( p ); path.appendNew<Geom::LineSegment>( p2 ); - outlinepath.push_back(path); + outline_path.push_back(path); } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-show_handles.h b/src/live_effects/lpe-show_handles.h index a405c26ee..77b28e77a 100644 --- a/src/live_effects/lpe-show_handles.h +++ b/src/live_effects/lpe-show_handles.h @@ -20,7 +20,7 @@ class LPEShowHandles : public Effect , GroupBBoxEffect { public: LPEShowHandles(LivePathEffectObject *lpeobject); - virtual ~LPEShowHandles(){} + virtual ~LPEShowHandles() {} virtual void doOnApply(SPLPEItem const* lpeitem); @@ -42,13 +42,13 @@ private: BoolParam nodes; BoolParam handles; - BoolParam originalPath; - ScalarParam scaleNodesAndHandles; - ScalarParam rotateNodes; - double strokeWidth; - static bool alertsOff; + BoolParam original_path; + ScalarParam scale_nodes_and_handles; + ScalarParam rotate_nodes; + double stroke_width; + static bool alerts_off; - Geom::PathVector outlinepath; + Geom::PathVector outline_path; LPEShowHandles(const LPEShowHandles &); LPEShowHandles &operator=(const LPEShowHandles &); diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 2b2efb1a9..7fc20ede1 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -20,40 +20,46 @@ #include <2geom/generic-rect.h> #include <2geom/interval.h> #include "ui/icon-names.h" +#include "util/units.h" namespace Inkscape { namespace LivePathEffect { LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) : Effect(lpeobject), - steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), - threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), - helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 2.), - nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false, - "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), - handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false, - "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), - simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false, - "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), - simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false, - "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")) - { - registerParameter(dynamic_cast<Parameter *>(&steps)); - registerParameter(dynamic_cast<Parameter *>(&threshold)); - registerParameter(dynamic_cast<Parameter *>(&helper_size)); - registerParameter(dynamic_cast<Parameter *>(&nodes)); - registerParameter(dynamic_cast<Parameter *>(&handles)); - registerParameter(dynamic_cast<Parameter *>(&simplifyindividualpaths)); - registerParameter(dynamic_cast<Parameter *>(&simplifyJustCoalesce)); - threshold.param_set_range(0.0001, Geom::infinity()); - threshold.param_set_increments(0.0001, 0.0001); - threshold.param_set_digits(6); - steps.param_set_range(0, 100); - steps.param_set_increments(1, 1); - steps.param_set_digits(0); - helper_size.param_set_range(0.1, 100); - helper_size.param_set_increments(1, 1); - helper_size.param_set_digits(1); + steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), + threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), + smooth_angles(_("Smooth angles:"), _("Max degree difference on handles to preform a smooth"), "smooth_angles", &wr, this, 20.), + helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 5), + simplify_individual_paths(_("Paths separately"), _("Simplifying paths (separately)"), "simplify_individual_paths", &wr, this, false, + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + simplify_just_coalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplify_just_coalesce", &wr, this, false, + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")) +{ + registerParameter(&steps); + registerParameter(&threshold); + registerParameter(&smooth_angles); + registerParameter(&helper_size); + registerParameter(&simplify_individual_paths); + registerParameter(&simplify_just_coalesce); + + threshold.param_set_range(0.0001, Geom::infinity()); + threshold.param_set_increments(0.0001, 0.0001); + threshold.param_set_digits(6); + + steps.param_set_range(0, 100); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); + + smooth_angles.param_set_range(0.0, 365.0); + smooth_angles.param_set_increments(10, 10); + smooth_angles.param_set_digits(2); + + helper_size.param_set_range(0.0, 999.0); + helper_size.param_set_increments(5, 5); + helper_size.param_set_digits(2); + + radius_helper_nodes = 6.0; } LPESimplify::~LPESimplify() {} @@ -61,14 +67,14 @@ LPESimplify::~LPESimplify() {} void LPESimplify::doBeforeEffect (SPLPEItem const* lpeitem) { - if(!hp.empty()){ + if(!hp.empty()) { hp.clear(); } bbox = SP_ITEM(lpeitem)->visualBounds(); SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); + radius_helper_nodes = helper_size; item->apply_to_clippath(item); item->apply_to_mask(item); - } Gtk::Widget * @@ -81,27 +87,12 @@ LPESimplify::newWidget() vbox->set_spacing(2); std::vector<Parameter *>::iterator it = param_vector.begin(); Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); - Gtk::HBox * buttonsTwo = Gtk::manage(new Gtk::HBox(true,0)); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter * param = *it; Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); - if (param->param_key == "simplifyindividualpaths" || - param->param_key == "simplifyJustCoalesce") - { - Glib::ustring * tip = param->param_getTooltip(); - if (widg) { - buttonsTwo->pack_start(*widg, true, true, 2); - if (tip) { - widg->set_tooltip_text(*tip); - } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); - } - } - } else if (param->param_key == "nodes" || - param->param_key == "handles") - { + if (param->param_key == "simplify_individual_paths" || + param->param_key == "simplify_just_coalesce") { Glib::ustring * tip = param->param_getTooltip(); if (widg) { buttons->pack_start(*widg, true, true, 2); @@ -112,13 +103,13 @@ LPESimplify::newWidget() widg->set_has_tooltip(false); } } - }else{ + } else { Glib::ustring * tip = param->param_getTooltip(); if (widg) { - Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg); - std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); - Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); - entryWidg->set_width_chars(8); + Gtk::HBox * horizontal_box = dynamic_cast<Gtk::HBox *>(widg); + std::vector< Gtk::Widget* > child_list = horizontal_box->get_children(); + Gtk::Entry* entry_widg = dynamic_cast<Gtk::Entry *>(child_list[1]); + entry_widg->set_width_chars(8); vbox->pack_start(*widg, true, true, 2); if (tip) { widg->set_tooltip_text(*tip); @@ -133,107 +124,143 @@ LPESimplify::newWidget() ++it; } vbox->pack_start(*buttons,true, true, 2); - vbox->pack_start(*buttonsTwo,true, true, 2); return dynamic_cast<Gtk::Widget *>(vbox); } -void -LPESimplify::doEffect(SPCurve *curve) { +void +LPESimplify::doEffect(SPCurve *curve) +{ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); gdouble size = Geom::L2(bbox->dimensions()); //size /= Geom::Affine(0,0,0,0,0,0).descrim(); Path* pathliv = Path_for_pathvector(original_pathv); - if(simplifyindividualpaths){ + if(simplify_individual_paths) { size = Geom::L2(Geom::bounds_fast(original_pathv)->dimensions()); } - for (int unsigned i = 0; i < steps; i++){ - if ( simplifyJustCoalesce ) { - pathliv->Coalesce(threshold * size); - }else{ - pathliv->ConvertEvenLines(threshold * size); - pathliv->Simplify(threshold * size); + for (int unsigned i = 0; i < steps; i++) { + if ( simplify_just_coalesce ) { + pathliv->Coalesce(threshold * size); + } else { + pathliv->ConvertEvenLines(threshold * size); + pathliv->Simplify(threshold * size); } } - Geom::PathVector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); - generateHelperPath(outres); - curve->set_pathvector(outres); + Geom::PathVector result = Geom::parse_svg_path(pathliv->svg_dump_path()); + generateHelperPathAndSmooth(result); + curve->set_pathvector(result); SPDesktop* desktop = SP_ACTIVE_DESKTOP; - if(desktop && INK_IS_NODE_TOOL(desktop->event_context)){ + if(desktop && INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context); nt->update_helperpath(); } } void -LPESimplify::generateHelperPath(Geom::PathVector result) +LPESimplify::generateHelperPathAndSmooth(Geom::PathVector &result) { - if(!handles && !nodes){ + if(steps < 1) { return; } - - if(steps < 1){ - return; - } - + Geom::PathVector tmp_path; Geom::CubicBezier const *cubic = NULL; for (Geom::PathVector::iterator path_it = result.begin(); path_it != result.end(); ++path_it) { //Si está vacÃo... - if (path_it->empty()){ - continue; + if (path_it->empty()) { + continue; } //Itreadores Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = - ++(path_it->begin()); // outgoing curve - Geom::Path::const_iterator curve_endit = - path_it->end_default(); // this determines when the loop has to stop - + Geom::Path::const_iterator curve_it2 = ++(path_it->begin());// outgoing curve + Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop + SPCurve *nCurve = new SPCurve(); if (path_it->closed()) { - // if the path is closed, maybe we have to stop a bit earlier because the - // closing line segment has zerolength. - const Geom::Curve &closingline = - path_it->back_closed(); // the closing line segment is always of type - // Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for - // *exact* zero length, which goes wrong for relative coordinates and - // rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } + // if the path is closed, maybe we have to stop a bit earlier because the + // closing line segment has zerolength. + const Geom::Curve &closingline = + path_it->back_closed(); // the closing line segment is always of type + // Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } } - if(nodes){ + if(helper_size > 0) { drawNode(curve_it1->initialPoint()); } + nCurve->moveto(curve_it1->initialPoint()); + Geom::Point start = Geom::Point(0,0); while (curve_it1 != curve_endit) { cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + Geom::Point point_at1 = curve_it1->initialPoint(); + Geom::Point point_at2 = curve_it1->finalPoint(); + Geom::Point point_at3 = curve_it1->finalPoint(); + Geom::Point point_at4 = curve_it1->finalPoint(); if (cubic) { - if(handles) { - if(!are_near((*cubic)[0],(*cubic)[1])){ + point_at1 = (*cubic)[1]; + point_at2 = (*cubic)[2]; + } + if(start == Geom::Point(0,0)) { + start = point_at1; + } + + if(path_it->closed() && curve_it2 == curve_endit) { + point_at4 = start; + } + if(curve_it2 != curve_endit) { + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2); + if (cubic) { + point_at4 = (*cubic)[1]; + } + } + Geom::Ray ray1(point_at2, point_at3); + Geom::Ray ray2(point_at3, point_at4); + double angle1 = Geom::rad_to_deg(ray1.angle()); + double angle2 = Geom::rad_to_deg(ray2.angle()); + if((smooth_angles >= angle2 - angle1) && !are_near(point_at4,point_at3) && !are_near(point_at2,point_at3)) { + double dist = Geom::distance(point_at2,point_at3); + Geom::Angle angleFixed = ray2.angle(); + angleFixed -= Geom::Angle::from_degrees(180.0); + point_at2 = Geom::Point::polar(angleFixed,dist) + point_at3; + } + nCurve->curveto(point_at1, point_at2, curve_it1->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment()); + if (cubic) { + point_at1 = (*cubic)[1]; + point_at2 = (*cubic)[2]; + if(helper_size > 0) { + if(!are_near((*cubic)[0],(*cubic)[1])) { drawHandle((*cubic)[1]); drawHandleLine((*cubic)[0],(*cubic)[1]); } - if(!are_near((*cubic)[3],(*cubic)[2])){ + if(!are_near((*cubic)[3],(*cubic)[2])) { drawHandle((*cubic)[2]); drawHandleLine((*cubic)[3],(*cubic)[2]); } } } - if(nodes) { + if(helper_size > 0) { drawNode(curve_it1->finalPoint()); } ++curve_it1; - if(curve_it2 != curve_endit){ - ++curve_it2; - } + ++curve_it2; + } + if (path_it->closed()) { + nCurve->closepath_current(); } + tmp_path.push_back(nCurve->get_pathvector()[0]); + nCurve->reset(); + delete nCurve; } + result = tmp_path; } -void +void LPESimplify::drawNode(Geom::Point p) { - double r = helper_size/0.67; + double r = radius_helper_nodes; char const * svgd; svgd = "M 0.55,0.5 A 0.05,0.05 0 0 1 0.5,0.55 0.05,0.05 0 0 1 0.45,0.5 0.05,0.05 0 0 1 0.5,0.45 0.05,0.05 0 0 1 0.55,0.5 Z M 0,0 1,0 1,1 0,1 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); @@ -246,7 +273,7 @@ LPESimplify::drawNode(Geom::Point p) void LPESimplify::drawHandle(Geom::Point p) { - double r = helper_size/0.67; + double r = radius_helper_nodes; char const * svgd; svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); @@ -261,8 +288,8 @@ LPESimplify::drawHandleLine(Geom::Point p,Geom::Point p2) { Geom::Path path; path.start( p ); - double diameter = helper_size/0.67; - if(helper_size > 0.0 && Geom::distance(p,p2) > (diameter * 0.35)){ + double diameter = radius_helper_nodes; + if(helper_size > 0 && Geom::distance(p,p2) > (diameter * 0.35)) { Geom::Ray ray2(p, p2); p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35)); } diff --git a/src/live_effects/lpe-simplify.h b/src/live_effects/lpe-simplify.h index 6acf2f2d4..294d77b35 100644 --- a/src/live_effects/lpe-simplify.h +++ b/src/live_effects/lpe-simplify.h @@ -14,43 +14,43 @@ namespace Inkscape { namespace LivePathEffect { -class LPESimplify : public Effect , GroupBBoxEffect{ +class LPESimplify : public Effect , GroupBBoxEffect { public: - LPESimplify(LivePathEffectObject *lpeobject); - virtual ~LPESimplify(); + LPESimplify(LivePathEffectObject *lpeobject); + virtual ~LPESimplify(); - virtual void doEffect(SPCurve *curve); + virtual void doEffect(SPCurve *curve); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); - virtual void generateHelperPath(Geom::PathVector result); + virtual void generateHelperPathAndSmooth(Geom::PathVector &result); - virtual Gtk::Widget * newWidget(); + virtual Gtk::Widget * newWidget(); - virtual void drawNode(Geom::Point p); - - virtual void drawHandle(Geom::Point p); + virtual void drawNode(Geom::Point p); - virtual void drawHandleLine(Geom::Point p,Geom::Point p2); + virtual void drawHandle(Geom::Point p); + + virtual void drawHandleLine(Geom::Point p,Geom::Point p2); protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); private: - ScalarParam steps; - ScalarParam threshold; - ScalarParam helper_size; - ToggleButtonParam nodes; - ToggleButtonParam handles; - ToggleButtonParam simplifyindividualpaths; - ToggleButtonParam simplifyJustCoalesce; - - Geom::PathVector hp; - Geom::OptRect bbox; - - LPESimplify(const LPESimplify &); - LPESimplify &operator=(const LPESimplify &); + ScalarParam steps; + ScalarParam threshold; + ScalarParam smooth_angles; + ScalarParam helper_size; + ToggleButtonParam simplify_individual_paths; + ToggleButtonParam simplify_just_coalesce; + + double radius_helper_nodes; + Geom::PathVector hp; + Geom::OptRect bbox; + + LPESimplify(const LPESimplify &); + LPESimplify &operator=(const LPESimplify &); }; diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index 8ad0e616f..551dbe16a 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -240,7 +240,7 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ for (unsigned i = 0; i<nbiter_approxstrokes; i++){ //Basic steps: - //- Choose a rdm seg [s0,s1], find coresponding [t0,t1], + //- Choose a rdm seg [s0,s1], find corresponding [t0,t1], //- Pick a rdm perturbation delta(s), collect 'piece(t)+delta(s(t))' over [t0,t1] into output. // pick a point where to start the stroke (s0 = dist from start). diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 7a024147c..2c74af6d6 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -19,7 +19,8 @@ #include <2geom/circle.h> #include <2geom/sbasis-to-bezier.h> -#include "pathoutlineprovider.h" +#include "helper/geom-nodetype.h" +#include "helper/geom-pathstroke.h" #include "display/curve.h" #include "sp-shape.h" #include "style.h" @@ -60,11 +61,10 @@ namespace TpS { } // TpS static const Util::EnumData<unsigned> JoinType[] = { - {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, - {LINEJOIN_ROUND, N_("Rounded"), "round"}, - {LINEJOIN_REFLECTED, N_("Reflected"), "reflected"}, - {LINEJOIN_POINTY, N_("Miter"), "miter"}, - {LINEJOIN_EXTRAPOLATED, N_("Extrapolated"), "extrapolated"} + {JOIN_BEVEL, N_("Beveled"), "bevel"}, + {JOIN_ROUND, N_("Rounded"), "round"}, + {JOIN_MITER, N_("Miter"), "miter"}, + {JOIN_EXTRAPOLATE, N_("Extrapolated"), "extrapolated"}, }; static const Util::EnumDataConverter<unsigned> JoinTypeConverter(JoinType, sizeof (JoinType)/sizeof(*JoinType)); @@ -75,7 +75,7 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : attach_start(_("Start offset:"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), attach_end(_("End offset:"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), smoothing(_("Taper smoothing:"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5), - join_type(_("Join type:"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), + join_type(_("Join type:"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, JOIN_EXTRAPOLATE), miter_limit(_("Miter limit:"), _("Limit for miter joins"), "miter_limit", &wr, this, 100.) { show_orig_path = true; @@ -102,27 +102,24 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; SPCSSAttr *css = sp_repr_css_attr_new (); - if (true) { - if (lpeitem->style->stroke.isPaintserver()) { - SPPaintServer * server = lpeitem->style->getStrokePaintServer(); - if (server) { - Glib::ustring str; - str += "url(#"; - str += server->getId(); - str += ")"; - sp_repr_css_set_property (css, "fill", str.c_str()); - } - } else if (lpeitem->style->stroke.isColor()) { - gchar c[64]; - sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); - sp_repr_css_set_property (css, "fill", c); - } else { - sp_repr_css_set_property (css, "fill", "none"); + if (lpeitem->style->stroke.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getStrokePaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "fill", str.c_str()); } + } else if (lpeitem->style->stroke.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "fill", c); } else { - sp_repr_css_unset_property (css, "fill"); + sp_repr_css_set_property (css, "fill", "none"); } + sp_repr_css_set_property(css, "fill-rule", "nonzero"); sp_repr_css_set_property(css, "stroke", "none"); sp_desktop_apply_css_recursive(item, css, true); @@ -130,7 +127,7 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) line_width.param_set_value(width); } else { - printf("WARNING: It only makes sense to apply Join Type to paths (not groups).\n"); + printf("WARNING: It only makes sense to apply Taper stroke to paths (not groups).\n"); } } @@ -142,25 +139,21 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem); SPCSSAttr *css = sp_repr_css_attr_new (); - if (true) { - if (lpeitem->style->fill.isPaintserver()) { - SPPaintServer * server = lpeitem->style->getFillPaintServer(); - if (server) { - Glib::ustring str; - str += "url(#"; - str += server->getId(); - str += ")"; - sp_repr_css_set_property (css, "stroke", str.c_str()); - } - } else if (lpeitem->style->fill.isColor()) { - gchar c[64]; - sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); - sp_repr_css_set_property (css, "stroke", c); - } else { - sp_repr_css_set_property (css, "stroke", "none"); + if (lpeitem->style->fill.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getFillPaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "stroke", str.c_str()); } + } else if (lpeitem->style->fill.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->fill.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->fill_opacity.value))); + sp_repr_css_set_property (css, "stroke", c); } else { - sp_repr_css_unset_property (css, "stroke"); + sp_repr_css_set_property (css, "stroke", "none"); } Inkscape::CSSOStringStream os; @@ -179,15 +172,22 @@ using Geom::D2; using Geom::SBasis; // leave Geom::Path -Geom::Path return_at_first_cusp(Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) { - return Geom::split_at_cusps(path_in)[0]; +static Geom::Path return_at_first_cusp(Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) +{ + Geom::Path temp; + + for (unsigned i = 0; i < path_in.size(); i++) { + temp.append(path_in[i]); + if (Geom::get_nodetype(path_in[i], path_in[i + 1]) != Geom::NODE_SMOOTH ) { + break; + } + } + + return temp; } Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path pattern, double width); -// references to pointers -void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); - // actual effect Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) @@ -285,7 +285,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) // although this seems obvious, it can probably lead to bugs. if (!metInMiddle) { // append the outside outline of the path (goes with the direction of the path) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1], -fabs(line_width), static_cast<LineJoinType>(join_type.get_value()), miter_limit); + throwaway_path = half_outline(pathv_out[1], fabs(line_width)/2., miter_limit, static_cast<LineJoinType>(join_type.get_value())); if (!zeroStart && real_path.size() >= 1 && throwaway_path.size() >= 1) { if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint())) { real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint()); @@ -317,7 +317,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) if (!metInMiddle) { // append the inside outline of the path (against direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), -fabs(line_width), static_cast<LineJoinType>(join_type.get_value()), miter_limit); + throwaway_path = half_outline(pathv_out[1].reverse(), fabs(line_width)/2., miter_limit, static_cast<LineJoinType>(join_type.get_value())); if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { real_path.appendNew<Geom::LineSegment>(throwaway_path.initialPoint()); @@ -347,85 +347,18 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) */ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & path_in) { - size_t size = path_in[0].size(); - - unsigned loc = (unsigned)attach_start; - Geom::Curve * curve_start = path_in[0] [loc].duplicate(); - - std::vector<Geom::Path> pathv_out; - Geom::Path path_out = Geom::Path(); - - Geom::Path trimmed_start = Geom::Path(); - Geom::Path trimmed_end = Geom::Path(); - - for (size_t i = 0; i < loc; ++i) { - trimmed_start.append(path_in[0] [i]); - } - - Geom::Curve * temp; - subdivideCurve(curve_start, attach_start - loc, temp, curve_start); - trimmed_start.append(*temp); - if (temp) delete temp; temp = 0; - - // special case: path is one segment long - // special case: what if the two knots occupy the same segment? - if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) { - - // If you look into it, I don't actually think there is a working way to do this - // with only point math. So we use nearest_point instead. - Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); - - // it is just a dumb segment - // we have to do some shifting here because the value changed when we reduced the length - // of the previous segment. - - subdivideCurve(curve_start, t, curve_start, temp); - trimmed_end.append(*temp); - if (temp) delete temp; temp = 0; - - for (size_t j = (size - attach_end) + 1; j < size; ++j) { - trimmed_end.append(path_in[0] [j]); - } + Geom::Coord endTime = path_in[0].size() - attach_end; - path_out.append(*curve_start); - pathv_out.push_back(trimmed_start); - pathv_out.push_back(path_out); - pathv_out.push_back(trimmed_end); - return pathv_out; - } - - pathv_out.push_back(trimmed_start); - - // append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) - path_out.append(*curve_start); - - for (size_t k = loc + 1; k < (size - unsigned(attach_end)) - 1; ++k) { - path_out.append(path_in[0] [k]); - } - - // deal with the last segment in a very similar fashion to the first - loc = size - attach_end; - - Geom::Curve * curve_end = path_in[0] [loc].duplicate(); - - Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); - - subdivideCurve(curve_end, t, curve_end, temp); - trimmed_end.append(*temp); - if (temp) delete temp; temp = 0; - - for (size_t j = (size - attach_end) + 1; j < size; ++j) { - trimmed_end.append(path_in[0] [j]); - } - - path_out.append(*curve_end); - pathv_out.push_back(path_out); - - pathv_out.push_back(trimmed_end); - - if (curve_end) delete curve_end; - if (curve_start) delete curve_start; - return pathv_out; + Geom::Path p1 = path_in[0].portion(0., attach_start); + Geom::Path p2 = path_in[0].portion(attach_start, endTime); + Geom::Path p3 = path_in[0].portion(endTime, path_in[0].size()); + + Geom::PathVector out; + out.push_back(p1); + out.push_back(p2); + out.push_back(p3); + + return out; } @@ -513,23 +446,6 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path } } -void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second) -{ - if (Geom::LineSegment* linear = dynamic_cast<Geom::LineSegment*>(curve_in)) { - // special case for line segments - std::pair<Geom::LineSegment, Geom::LineSegment> seg_pair = linear->subdivide(t); - val_first = seg_pair.first.duplicate(); - val_second = seg_pair.second.duplicate(); - } else { - // all other cases: - Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(curve_in->toSBasis()); - std::pair<Geom::CubicBezier, Geom::CubicBezier> cubic_pair = cubic.subdivide(t); - val_first = cubic_pair.first.duplicate(); - val_second = cubic_pair.second.duplicate(); - } -} - - void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index 03e3e7997..c6787aae1 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -28,6 +28,7 @@ LPEdoEffectStackTest::LPEdoEffectStackTest(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&path) ); point.set_oncanvas_looks(SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR, 0x00ff0000); + point.param_setValue(point,true); } LPEdoEffectStackTest::~LPEdoEffectStackTest() diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index f990f41c7..bd1c5b600 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -11,8 +11,6 @@ ink_common_sources += \ live_effects/parameter/random.h \ live_effects/parameter/point.cpp \ live_effects/parameter/point.h \ - live_effects/parameter/pointreseteable.cpp \ - live_effects/parameter/pointreseteable.h \ live_effects/parameter/enum.h \ live_effects/parameter/path-reference.cpp \ live_effects/parameter/path-reference.h \ diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 2ebe11b4b..e9d375b93 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -354,7 +354,7 @@ void FilletChamferPointArrayParam::set_pwd2( last_pwd2_normal = pwd2_normal_in; } -void FilletChamferPointArrayParam::set_document_unit(Glib::ustring const * value_document_unit) +void FilletChamferPointArrayParam::set_document_unit(Glib::ustring value_document_unit) { documentUnit = value_document_unit; } diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 6e5cce353..7849d5afb 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -53,7 +53,7 @@ public: virtual void set_helper_size(int hs); virtual void set_use_distance(bool use_knot_distance); virtual void set_chamfer_steps(int value_chamfer_steps); - virtual void set_document_unit(Glib::ustring const * value_document_unit); + virtual void set_document_unit(Glib::ustring value_document_unit); virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); @@ -90,7 +90,7 @@ private: int chamfer_steps; bool use_distance; const gchar *unit; - Glib::ustring const * documentUnit; + Glib::ustring documentUnit; Geom::PathVector hp; Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2; diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index 302818e55..4c4d2cd9c 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -26,7 +26,9 @@ namespace LivePathEffect { PointParam::PointParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, const gchar *htip, Geom::Point default_value) - : Geom::Point(default_value), Parameter(label, tip, key, wr, effect), defvalue(default_value) + : Parameter(label, tip, key, wr, effect), + defvalue(default_value), + knoth(NULL) { knot_shape = SP_KNOT_SHAPE_DIAMOND; knot_mode = SP_KNOT_MODE_XOR; @@ -43,7 +45,34 @@ PointParam::~PointParam() void PointParam::param_set_default() { - param_setValue(defvalue); + param_setValue(defvalue,true); +} + +Geom::Point +PointParam::param_get_default() const{ + return defvalue; +} + +void +PointParam::param_update_default(Geom::Point newpoint) +{ + defvalue = newpoint; +} + +void +PointParam::param_setValue(Geom::Point newpoint, bool write) +{ + *dynamic_cast<Geom::Point *>( this ) = newpoint; + if(write){ + Inkscape::SVGOStringStream os; + os << newpoint; + gchar * str = g_strdup(os.str().c_str()); + param_write_to_repr(str); + g_free(str); + } + if(knoth){ + knoth->update_knots(); + } } bool @@ -70,6 +99,12 @@ PointParam::param_getSVGValue() const return str; } +void +PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) +{ + param_setValue( (*this) * postmul, true); +} + Gtk::Widget * PointParam::param_newWidget() { @@ -96,29 +131,6 @@ PointParam::param_newWidget() } void -PointParam::param_setValue(Geom::Point newpoint) -{ - *dynamic_cast<Geom::Point *>( this ) = newpoint; -} - -void -PointParam::param_set_and_write_new_value (Geom::Point newpoint) -{ - Inkscape::SVGOStringStream os; - os << newpoint; - gchar * str = g_strdup(os.str().c_str()); - param_write_to_repr(str); - g_free(str); -} - -void -PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) -{ - param_set_and_write_new_value( (*this) * postmul ); -} - - -void PointParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { knot_shape = shape; @@ -129,7 +141,7 @@ PointParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint class PointParamKnotHolderEntity : public KnotHolderEntity { public: PointParamKnotHolderEntity(PointParam *p) { this->pparam = p; } - virtual ~PointParamKnotHolderEntity() {} + virtual ~PointParamKnotHolderEntity() { this->pparam->knoth = NULL;} virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); virtual Geom::Point knot_get() const; @@ -140,11 +152,25 @@ private: }; void -PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) +PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) { - Geom::Point const s = snap_knot_position(p, state); - pparam->param_setValue(s); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + Geom::Point s = snap_knot_position(p, state); + if (state & GDK_CONTROL_MASK) { + Geom::Point A(origin[Geom::X],p[Geom::Y]); + Geom::Point B(p[Geom::X],origin[Geom::Y]); + double distanceA = Geom::distance(A,p); + double distanceB = Geom::distance(B,p); + if(distanceA > distanceB){ + s = B; + } else { + s = A; + } + } + pparam->param_setValue(s, true); + SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); + if(splpeitem){ + sp_lpe_item_update_patheffect(splpeitem, false, false); + } } Geom::Point @@ -154,19 +180,27 @@ PointParamKnotHolderEntity::knot_get() const } void -PointParamKnotHolderEntity::knot_click(guint /*state*/) +PointParamKnotHolderEntity::knot_click(guint state) { - g_print ("This is the handle associated to parameter '%s'\n", pparam->param_key.c_str()); + if (state & GDK_CONTROL_MASK) { + if (state & GDK_MOD1_MASK) { + this->pparam->param_set_default(); + SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); + if(splpeitem){ + sp_lpe_item_update_patheffect(splpeitem, false, false); + } + } + } } void PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { + knoth = knotholder; PointParamKnotHolderEntity *e = new PointParamKnotHolderEntity(this); // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself??? e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); knotholder->add(e); - } } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index 319835bb3..471fbc993 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -20,6 +20,7 @@ namespace Inkscape { namespace LivePathEffect { +class PointParamKnotHolderEntity; class PointParam : public Geom::Point, public Parameter { public: @@ -37,12 +38,10 @@ public: bool param_readSVGValue(const gchar * strvalue); gchar * param_getSVGValue() const; inline const gchar *handleTip() const { return handle_tip ? handle_tip : param_tooltip.c_str(); } - - void param_setValue(Geom::Point newpoint); + void param_setValue(Geom::Point newpoint, bool write = false); void param_set_default(); - - void param_set_and_write_new_value(Geom::Point newpoint); - + Geom::Point param_get_default() const; + void param_update_default(Geom::Point newpoint); virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); @@ -50,12 +49,12 @@ public: virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + friend class PointParamKnotHolderEntity; private: PointParam(const PointParam&); PointParam& operator=(const PointParam&); - Geom::Point defvalue; - + KnotHolder *knoth; SPKnotShapeType knot_shape; SPKnotModeType knot_mode; guint32 knot_color; diff --git a/src/live_effects/parameter/pointreseteable.cpp b/src/live_effects/parameter/pointreseteable.cpp deleted file mode 100644 index c0f8858b8..000000000 --- a/src/live_effects/parameter/pointreseteable.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "ui/widget/registered-widget.h" -#include "live_effects/parameter/pointreseteable.h" -#include "live_effects/effect.h" -#include "svg/svg.h" -#include "svg/stringstream.h" -#include "ui/widget/point.h" -#include "widgets/icon.h" -#include "inkscape.h" -#include "verbs.h" -#include "knotholder.h" -#include <glibmm/i18n.h> -#include "ui/tools-switch.h" -#include "ui/tools/node-tool.h" - -// needed for on-canvas editting: -#include "desktop.h" - -namespace Inkscape { - -namespace LivePathEffect { - -PointReseteableParam::PointReseteableParam( const Glib::ustring& label, const Glib::ustring& tip, - const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, const gchar *htip, Geom::Point default_value) - : Geom::Point(default_value), Parameter(label, tip, key, wr, effect), defvalue(default_value) -{ - knot_shape = SP_KNOT_SHAPE_DIAMOND; - knot_mode = SP_KNOT_MODE_XOR; - knot_color = 0xffffff00; - handle_tip = g_strdup(htip); -} - -PointReseteableParam::~PointReseteableParam() -{ - if (handle_tip) - g_free(handle_tip); -} - -void -PointReseteableParam::param_set_default() -{ - param_setValue(defvalue); -} - -void -PointReseteableParam::param_set_and_write_default() -{ - param_set_and_write_new_value(defvalue); -} - -void -PointReseteableParam::param_update_default(Geom::Point newpoint) -{ - this->defvalue = newpoint; -} - -bool -PointReseteableParam::param_readSVGValue(const gchar * strvalue) -{ - gchar ** strarray = g_strsplit(strvalue, ",", 2); - double newx, newy; - unsigned int success = sp_svg_number_read_d(strarray[0], &newx); - success += sp_svg_number_read_d(strarray[1], &newy); - g_strfreev (strarray); - if (success == 2) { - param_setValue( Geom::Point(newx, newy) ); - return true; - } - return false; -} - -gchar * -PointReseteableParam::param_getSVGValue() const -{ - Inkscape::SVGOStringStream os; - os << *dynamic_cast<Geom::Point const *>( this ); - gchar * str = g_strdup(os.str().c_str()); - return str; -} - -Gtk::Widget * -PointReseteableParam::param_newWidget() -{ - Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage( - new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label, - param_tooltip, - param_key, - *param_wr, - param_effect->getRepr(), - param_effect->getSPDoc() ) ); - // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Geom::Affine transf = desktop->doc2dt(); - pointwdg->setTransform(transf); - pointwdg->setValue( *this ); - pointwdg->clearProgrammatically(); - pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); - - Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); - static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); - static_cast<Gtk::HBox*>(hbox)->show_all_children(); - - return dynamic_cast<Gtk::Widget *> (hbox); -} - -void -PointReseteableParam::param_setValue(Geom::Point newpoint) -{ - *dynamic_cast<Geom::Point *>( this ) = newpoint; - if(SP_ACTIVE_DESKTOP){ - SPDesktop* desktop = SP_ACTIVE_DESKTOP; - if (tools_isactive( desktop, TOOLS_NODES)) { - Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>( desktop->event_context); - nt->update_helperpath(); - } - } -} - -void -PointReseteableParam::param_set_and_write_new_value (Geom::Point newpoint) -{ - Inkscape::SVGOStringStream os; - os << newpoint; - gchar * str = g_strdup(os.str().c_str()); - param_write_to_repr(str); - g_free(str); -} - -void -PointReseteableParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) -{ - param_set_and_write_new_value( (*this) * postmul ); -} - - -void -PointReseteableParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) -{ - knot_shape = shape; - knot_mode = mode; - knot_color = color; -} - -class PointReseteableParamKnotHolderEntity : public KnotHolderEntity { -public: - PointReseteableParamKnotHolderEntity(PointReseteableParam *p) { this->pparam = p; } - virtual ~PointReseteableParamKnotHolderEntity() {} - - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; - virtual void knot_click(guint state); - -private: - PointReseteableParam *pparam; -}; - -void -PointReseteableParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) -{ - Geom::Point const s = snap_knot_position(p, state); - pparam->param_setValue(s); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); -} - -Geom::Point -PointReseteableParamKnotHolderEntity::knot_get() const -{ - return *pparam; -} - -void -PointReseteableParamKnotHolderEntity::knot_click(guint state) -{ - if (state & GDK_CONTROL_MASK) { - if (state & GDK_MOD1_MASK) { - this->pparam->param_set_default(); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); - } - } -} - -void -PointReseteableParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) -{ - PointReseteableParamKnotHolderEntity *e = new PointReseteableParamKnotHolderEntity(this); - // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself??? - e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); - knotholder->add(e); -} - -} /* 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 : diff --git a/src/live_effects/parameter/pointreseteable.h b/src/live_effects/parameter/pointreseteable.h deleted file mode 100644 index 5ae1fdf02..000000000 --- a/src/live_effects/parameter/pointreseteable.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H -#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H - -/* - * Inkscape::LivePathEffectParameters - * -* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <glib.h> -#include <2geom/point.h> - -#include "live_effects/parameter/parameter.h" - -#include "knot-holder-entity.h" - -namespace Inkscape { - -namespace LivePathEffect { - -class PointReseteableParamKnotHolderEntity; - -class PointReseteableParam : public Geom::Point, public Parameter { -public: - PointReseteableParam( const Glib::ustring& label, - const Glib::ustring& tip, - const Glib::ustring& key, - Inkscape::UI::Widget::Registry* wr, - Effect* effect, - const gchar *handle_tip = NULL, - Geom::Point default_value = Geom::Point(0,0) ); // tip for automatically associated on-canvas handle - virtual ~PointReseteableParam(); - - virtual Gtk::Widget * param_newWidget(); - - bool param_readSVGValue(const gchar * strvalue); - gchar * param_getSVGValue() const; - inline const gchar *handleTip() const { return handle_tip ? handle_tip : param_tooltip.c_str(); } - - void param_setValue(Geom::Point newpoint); - void param_set_default(); - void param_set_and_write_default(); - void param_update_default(Geom::Point newpoint); - - void param_set_and_write_new_value(Geom::Point newpoint); - - virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); - - void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); - - virtual bool providesKnotHolderEntities() const { return true; } - virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); - - friend class PointReseteableParamKnotHolderEntity; -private: - PointReseteableParam(const PointReseteableParam&); - PointReseteableParam& operator=(const PointReseteableParam&); - - Geom::Point defvalue; - - SPKnotShapeType knot_shape; - SPKnotModeType knot_mode; - guint32 knot_color; - gchar *handle_tip; -}; - - -} //namespace LivePathEffect - -} //namespace Inkscape - -#endif diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp deleted file mode 100644 index 21a0fb809..000000000 --- a/src/live_effects/pathoutlineprovider.cpp +++ /dev/null @@ -1,803 +0,0 @@ -/* Author:
- * Liam P. White <inkscapebrony@gmail.com>
- *
- * Copyright (C) 2014 Author
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#include <2geom/angle.h>
-#include <2geom/path.h>
-#include <2geom/circle.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/shape.h>
-#include <2geom/transforms.h>
-#include <2geom/path-sink.h>
-#include <cstdio>
-
-#include "pathoutlineprovider.h"
-#include "livarot/path-description.h"
-#include "helper/geom-nodetype.h"
-#include "svg/svg.h"
-
-namespace Geom {
-/**
-* Refer to: Weisstein, Eric W. "Circle-Circle Intersection."
- From MathWorld--A Wolfram Web Resource.
- http://mathworld.wolfram.com/Circle-CircleIntersection.html
-*
-* @return 0 if no intersection
-* @return 1 if one circle is contained in the other
-* @return 2 if intersections are found (they are written to p0 and p1)
-*/
-static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, Point & p0, Point & p1)
-{
- Point X0 = circle0.center();
- double r0 = circle0.ray();
- Point X1 = circle1.center();
- double r1 = circle1.ray();
-
- /* dx and dy are the vertical and horizontal distances between
- * the circle centers.
- */
- Point D = X1 - X0;
-
- /* Determine the straight-line distance between the centers. */
- double d = L2(D);
-
- /* Check for solvability. */
- if (d > (r0 + r1)) {
- /* no solution. circles do not intersect. */
- return 0;
- }
- if (d <= fabs(r0 - r1)) {
- /* no solution. one circle is contained in the other */
- return 1;
- }
-
- /* 'point 2' is the point where the line through the circle
- * intersection points crosses the line between the circle
- * centers.
- */
-
- /* Determine the distance from point 0 to point 2. */
- double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
-
- /* Determine the coordinates of point 2. */
- Point p2 = X0 + D * (a/d);
-
- /* Determine the distance from point 2 to either of the
- * intersection points.
- */
- double h = std::sqrt((r0*r0) - (a*a));
-
- /* Now determine the offsets of the intersection points from
- * point 2.
- */
- Point r = (h/d)*rot90(D);
-
- /* Determine the absolute intersection points. */
- p0 = p2 + r;
- p1 = p2 - r;
-
- return 2;
-}
-/**
-* Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t.
-* Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt).
-*/
-static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.01 )
-{
- D2<SBasis> dM=derivative(curve);
- if ( are_near(L2sq(dM(t)),0.) ) {
- dM=derivative(dM);
- }
- if ( are_near(L2sq(dM(t)),0.) ) { // try second time
- dM=derivative(dM);
- }
- Piecewise<D2<SBasis> > unitv = unitVector(dM,tol);
- Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv);
- Piecewise<SBasis> k = cross(derivative(unitv),unitv);
- k = divide(k,dMlength,tol,3);
- double curv = k(t); // note that this value is signed
-
- Geom::Point normal = unitTangentAt(curve, t).cw();
- double radius = 1/curv;
- Geom::Point center = curve(t) + radius*normal;
- return Geom::Circle(center, fabs(radius));
-}
-
-std::vector<Geom::Path> split_at_cusps(const Geom::Path& in)
-{
- PathVector out = PathVector();
- Path temp = Path();
-
- for (unsigned i = 0; i < in.size(); i++) {
- temp.append(in[i]);
- if ( get_nodetype(in[i], in[i + 1]) != Geom::NODE_SMOOTH ) {
- out.push_back(temp);
- temp = Path();
- }
- }
- if (temp.size() > 0) {
- out.push_back(temp);
- }
- return out;
-}
-
-Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2<Geom::SBasis> const & sbasis_in)
-{
- std::vector<Geom::Point> temp;
- sbasis_to_bezier(temp, sbasis_in, 4);
- return Geom::CubicBezier( temp );
-}
-
-static boost::optional<Geom::Point> intersection_point(Geom::Point const & origin_a, Geom::Point const & vector_a, Geom::Point const & origin_b, Geom::Point const & vector_b)
-{
- Geom::Coord denom = cross(vector_b, vector_a);
- if (!Geom::are_near(denom,0.)) {
- Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom;
- return origin_a + t * vector_a;
- }
- return boost::none;
-}
-
-} // namespace Geom
-
-namespace Outline {
-
-typedef Geom::D2<Geom::SBasis> D2SB;
-typedef Geom::Piecewise<D2SB> PWD2;
-
-// UTILITY
-
-unsigned bezierOrder (const Geom::Curve* curve_in)
-{
- using namespace Geom;
- if ( const BezierCurve* bz = dynamic_cast<const BezierCurve*>(curve_in) ) {
- return bz->order();
- }
- return 0;
-}
-
-/**
- * @return true if the angle formed by the curves and their handles is greater than 180 degrees clockwise, otherwise false.
- */
-bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2)
-{
- Geom::Point start_point;
- Geom::Point cross_point = cbc1.finalPoint();
- Geom::Point end_point;
-
- if (cross_point != cbc2.initialPoint()) {
- printf("WARNING: Non-contiguous path in Outline::outside_angle()");
- return false;
- }
-
- Geom::CubicBezier cubicBezier = Geom::sbasis_to_cubicbezier(cbc1.toSBasis());
- start_point = cubicBezier [2];
-
- /*
- * Because the node editor does not yet support true quadratics, paths are converted to
- * cubic beziers in the node tool with degenerate handles on one side.
- */
-
- if (are_near(start_point, cross_point, 0.0000001)) {
- start_point = cubicBezier [1];
- }
- cubicBezier = Geom::sbasis_to_cubicbezier(cbc2.toSBasis());
- end_point = cubicBezier [1];
- if (are_near(end_point, cross_point, 0.0000001)) {
- end_point = cubicBezier [2];
- }
-
- // got our three points, now let's see what their clockwise angle is
-
- // Definition of a Graham scan
-
- /********************************************************************
- # Three points are a counter-clockwise turn if ccw > 0, clockwise if
- # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that
- # gives the signed area of the triangle formed by p1, p2 and p3.
- function ccw(p1, p2, p3):
- return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x)
- *********************************************************************/
-
- double ccw = ( (cross_point.x() - start_point.x()) * (end_point.y() - start_point.y()) ) -
- ( (cross_point.y() - start_point.y()) * (end_point.x() - start_point.x()) );
- return ccw > 0;
-}
-
-// LINE JOINS
-
-typedef Geom::BezierCurveN<1u> BezierLine;
-
-/**
- * Removes the crossings on an interior join.
- * @param path_builder Contains the incoming segment; result is appended to this
- * @param outgoing The outgoing segment
- */
-void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing)
-{
- Geom::Curve const& incoming = path_builder.back();
-
- // Using Geom::crossings to find intersections between two curves
- Geom::Crossings cross = Geom::crossings(incoming, outgoing);
- if (!cross.empty()) {
- // Crossings found, create the join
- Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(incoming.toSBasis());
- cubic = cubic.subdivide(cross[0].ta).first;
- // erase the last segment, as we're going to overwrite it now
- path_builder.erase_last();
- path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS);
-
- cubic = Geom::sbasis_to_cubicbezier(outgoing.toSBasis());
- cubic = cubic.subdivide(cross[0].tb).second;
- path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS);
- } else {
- // No crossings occurred, or Geom::crossings() failed; default to bevel
- if (Geom::are_near(incoming.finalPoint(), outgoing.initialPoint())) {
- path_builder.appendNew<BezierLine>(outgoing.initialPoint());
- } else {
- path_builder.setFinal(outgoing.initialPoint());
- }
- }
-}
-
-/**
- * Try to create a miter join. Falls back to bevel if no miter can be created.
- * @param path_builder Path to append curves to; back() is the incoming curve
- * @param outgoing Outgoing curve.
- * @param miter_limit When mitering, don't exceed this length
- * @param line_width The thickness of the line.
- */
-void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
-{
- using namespace Geom;
- Curve const& incoming = path_builder.back();
- Point tang1 = unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.);
- Point tang2 = unitTangentAt(outgoing.toSBasis(), 0);
-
- boost::optional <Point> p = intersection_point (incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2);
- if (p) {
- // check size of miter
- Point point_on_path = incoming.finalPoint() - rot90(tang1) * line_width;
- Coord len = distance(*p, point_on_path);
- if (len <= miter_limit) {
- // miter OK
- path_builder.appendNew<BezierLine>(*p);
- }
- }
- path_builder.appendNew<BezierLine>(outgoing.initialPoint());
-}
-
-/**
- * Smoothly extrapolate curves along a circular route. Falls back to miter if necessary.
- * @param path_builder Path to append curves to; back() is the incoming curve
- * @param outgoing Outgoing curve.
- * @param miter_limit When mitering, don't exceed this length
- * @param line_width The thickness of the line. Used for miter fallback.
- */
-void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
-{
- Geom::Curve const& incoming = path_builder.back();
- Geom::Point endPt = outgoing.initialPoint();
-
- // The method used when extrapolating curves fails to work when either side of the join to be extrapolated
- // is a line segment. When this situation is encountered, fall back to a regular miter join.
- bool lineProblem = (dynamic_cast<const BezierLine *>(&incoming)) || (dynamic_cast<const BezierLine *>(&outgoing));
- if (lineProblem == false) {
- // Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.);
- Geom::Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0);
-
- Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
- Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
-
- Geom::Point points[2];
- int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]);
- if (solutions == 2) {
- Geom::Point sol(0,0);
- if ( dot(tang2,points[0]-endPt) > 0 ) {
- // points[0] is bad, choose points[1]
- sol = points[1];
- } else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1]
- // points[1] is bad, choose points[0]
- sol = points[0];
- } else {
- // both points are good, choose nearest
- sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? points[0] : points[1];
- }
-
- Geom::EllipticalArc *arc0 = circle1.arc(incoming.finalPoint(), 0.5*(incoming.finalPoint()+sol), sol, true);
- Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true);
- try {
- if (arc0) {
- path_builder.append (arc0->toSBasis());
- delete arc0;
- arc0 = NULL;
- } else {
- throw std::exception();
- }
-
- if (arc1) {
- path_builder.append (arc1->toSBasis());
- delete arc1;
- arc1 = NULL;
- } else {
- throw std::exception();
- }
-
- } catch (std::exception const & ex) {
- printf("WARNING: Error extrapolating line join: %s\n", ex.what());
- path_builder.appendNew<Geom::LineSegment>(endPt);
- }
- } else {
- // 1 or no solutions found, default to miter
- miter_curves(path_builder, outgoing, miter_limit, line_width);
- }
- } else {
- // Line segments exist
- miter_curves(path_builder, outgoing, miter_limit, line_width);
- }
-}
-
-/**
- * Extrapolate curves by reflecting them along the line that would be given by beveling the join.
- * @param path_builder Path to append curves to; back() is the incoming curve
- * @param outgoing Outgoing curve.
- * @param miter_limit When mitering, don't exceed this length
- * @param line_width The thickness of the line. Used for miter fallback.
- */
-void reflect_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width)
-{
- using namespace Geom;
- Curve const& incoming = path_builder.back();
- // On the outside, we'll take the incoming curve, the outgoing curve, and
- // reflect them over the line formed by taking the unit tangent vector at times
- // 0 and 1, respectively, rotated by 90 degrees.
- Crossings cross;
-
- // reflect curves along the line that would be given by beveling the join
- Point tang1 = unitTangentAt(reverse(incoming.toSBasis()), 0.);
- D2SB newcurve1 = incoming.toSBasis() * reflection(-rot90(tang1), incoming.finalPoint());
- CubicBezier bzr1 = sbasis_to_cubicbezier(reverse(newcurve1));
-
- Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0.);
- D2SB newcurve2 = outgoing.toSBasis() * reflection(-rot90(tang2), outgoing.initialPoint());
- CubicBezier bzr2 = sbasis_to_cubicbezier(reverse(newcurve2));
-
- cross = crossings(bzr1, bzr2);
- if (cross.empty()) {
- // paths don't cross, fall back to miter
- miter_curves(path_builder, outgoing, miter_limit, line_width);
- } else {
- // reflected join
- std::pair<CubicBezier, CubicBezier> sub1 = bzr1.subdivide(cross[0].ta);
- std::pair<CubicBezier, CubicBezier> sub2 = bzr2.subdivide(cross[0].tb);
-
- // TODO it seems as if a bug in 2geom sometimes doesn't catch the first
- // crossing of paths, but the second instead; but only sometimes.
- path_builder.appendNew <CubicBezier> (sub1.first[1], sub1.first[2], sub2.second[0]);
- path_builder.appendNew <CubicBezier> (sub2.second[1], sub2.second[2], outgoing.initialPoint());
- }
-}
-
-// Ideal function pointer we want to pass
-typedef void JoinFunc(Geom::Path& /*path_builder*/, Geom::Curve const& /*outgoing*/, double /*miter_limit*/, double /*line_width*/);
-
-/**
- * Helper function for repeated logic in outlineHalf.
- */
-static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, bool outside, double width, double miter, JoinFunc func)
-{
- Geom::Curve * cbc2 = path_vec->front()[0].duplicate();
-
- if (outside) {
- func(path_builder, *cbc2, miter, width);
- } else {
- joinInside(path_builder, *cbc2);
- }
-
- // store it
- Geom::Path temp_path = path_vec->front();
- if (!outside) {
- // erase the first segment since the inside join code already appended it
- temp_path.erase(temp_path.begin());
- }
-
- if (temp_path.initialPoint() != path_builder.finalPoint()) {
- temp_path.setInitial(path_builder.finalPoint());
- }
-
- path_builder.append(temp_path);
-
- delete cbc2;
-}
-
-/**
- * Offsets exactly one half of a bezier spline (path).
- * @param path_in The input path to use. (To create the other side use path_in.reverse() )
- * @param line_width the line width to use (usually you want to divide this by 2)
- * @param miter_limit the miter parameter
- * @param func Join function to apply at each join.
- */
-
-Geom::Path outlineHalf(const Geom::Path& path_in, double line_width, double miter_limit, JoinFunc func)
-{
- // NOTE: it is important to notice the distinction between a Geom::Path and a livarot ::Path here!
- // if you do not see "Geom::" there is a different function set!
-
- Geom::PathVector pv = split_at_cusps(path_in);
-
- ::Path to_outline;
- ::Path outlined_result;
-
- Geom::Path path_builder = Geom::Path(); // the path to store the result in
- Geom::PathVector* path_vec; // needed because livarot returns a pointer (TODO make this not a pointer)
-
- // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well
- const size_t k = pv.size();
- for (size_t u = 0; u < k; u += 2) {
- to_outline = Path();
- outlined_result = Path();
-
- to_outline.LoadPath(pv[u], Geom::identity(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
- // now a curve has been outside outlined and loaded into outlined_result
-
- // get the Geom::Path
- path_vec = outlined_result.MakePathVector();
-
- // on the first run through, there is no join
- if (u == 0) {
- path_builder.start(path_vec->front().initialPoint());
- path_builder.append(path_vec->front());
- } else {
- outlineHelper(path_builder, path_vec, outside_angle(pv[u-1][pv[u-1].size()-1], pv[u][0]), line_width, miter_limit, func);
- }
-
- // outline the next segment, but don't store it yet
- if (path_vec)
- delete path_vec;
- path_vec = NULL;
-
- // odd number of paths
- if (u < k - 1) {
- outlined_result = Path();
- to_outline = Path();
-
- to_outline.LoadPath(pv[u+1], Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
- outlineHelper(path_builder, path_vec, outside_angle(pv[u][pv[u].size()-1], pv[u+1][0]), line_width, miter_limit, func);
-
- if (path_vec)
- delete path_vec;
- path_vec = NULL;
- }
- }
-
- if (path_in.closed()) {
- Geom::Curve * cbc1;
- Geom::Curve * cbc2;
-
- if ( path_in[path_in.size()].isDegenerate() ) {
- // handle case for last segment curved
- outlined_result = Path();
- to_outline = Path();
-
- Geom::Path oneCurve; oneCurve.append(path_in[0]);
-
- to_outline.LoadPath(oneCurve, Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
-
- cbc1 = path_builder[path_builder.size() - 1].duplicate();
- cbc2 = path_vec->front()[0].duplicate();
-
- delete path_vec;
- } else {
- // handle case for last segment straight
- // since the path doesn't actually give us access to it, we'll do it ourselves
- outlined_result = Path();
- to_outline = Path();
-
- Geom::Path oneCurve; oneCurve.append(Geom::LineSegment(path_in.finalPoint(), path_in.initialPoint()));
-
- to_outline.LoadPath(oneCurve, Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
-
- cbc1 = path_builder[path_builder.size() - 1].duplicate();
- cbc2 = (*path_vec)[0] [0].duplicate();
-
- outlineHelper(path_builder, path_vec, outside_angle(path_in[path_in.size()-1], oneCurve[0]), line_width, miter_limit, func);
-
- delete cbc1;
- cbc1 = cbc2->duplicate();
- delete path_vec;
-
- oneCurve = Geom::Path(); oneCurve.append(path_in[0]);
-
- to_outline.LoadPath(oneCurve, Geom::Affine(), false, false);
- to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10);
-
- path_vec = outlined_result.MakePathVector();
- delete cbc2; cbc2 = (*path_vec)[0] [0].duplicate();
- delete path_vec;
- }
-
- Geom::Path temporary;
- temporary.append(*cbc1);
-
- Geom::Curve const & prev_curve = path_in[path_in.size()].isDegenerate() ? path_in[path_in.size() - 1] : path_in[path_in.size()];
- Geom::Path isStraight;
- isStraight.append(prev_curve);
- isStraight.append(path_in[0]);
- // does closing path require a join?
- if (Geom::split_at_cusps(isStraight).size() > 1) {
- bool outside = outside_angle(prev_curve, path_in[0]);
- if (outside) {
- func(temporary, *cbc2, miter_limit, line_width);
- } else {
- joinInside(temporary, *cbc2);
- path_builder.erase(path_builder.begin());
- }
-
- // extract the appended curves
- path_builder.erase_last();
- if (Geom::are_near(path_builder.finalPoint(), temporary.initialPoint())) {
- path_builder.setFinal(temporary.initialPoint());
- } else {
- path_builder.appendNew<BezierLine>(temporary.initialPoint());
- }
- path_builder.append(temporary);
- } else {
- // closing path does not require a join
- path_builder.setFinal(path_builder.initialPoint());
- }
- path_builder.close();
-
- if (cbc1) delete cbc1;
- if (cbc2) delete cbc2;
- }
-
- return path_builder;
-}
-
-Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtTypeMod butt, double miter_lim, bool extrapolate, double start_lean, double end_lean)
-{
- Geom::PathVector path_out;
-
- unsigned pv_size = path_in.size();
- for (unsigned i = 0; i < pv_size; i++) {
-
- if (path_in[i].size() > 1) {
- Geom::Path with_direction;
- Geom::Path against_direction;
-
- with_direction = Outline::outlineHalf(path_in[i], -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves);
- against_direction = Outline::outlineHalf(path_in[i].reverse(), -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves);
-
- Geom::PathBuilder pb;
-
- pb.moveTo(with_direction.initialPoint());
- pb.append(with_direction);
-
- //add in our line caps
- if (!path_in[i].closed()) {
- switch (butt) {
- case BUTT_STRAIGHT:
- pb.lineTo(against_direction.initialPoint());
- break;
- case BUTT_ROUND:
- pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() );
- break;
- case BUTT_POINTY: {
- Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.);
- double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- Geom::Point midpoint = 0.5 * (with_direction.finalPoint() + against_direction.initialPoint()) + radius*end_deriv;
- pb.lineTo(midpoint);
- pb.lineTo(against_direction.initialPoint());
- break;
- }
- case BUTT_SQUARE: {
- Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.);
- double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- pb.lineTo(with_direction.finalPoint() + radius*end_deriv);
- pb.lineTo(against_direction.initialPoint() + radius*end_deriv);
- pb.lineTo(against_direction.initialPoint());
- break;
- }
- case BUTT_LEANED: {
- Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.);
- double maxRadius = (end_lean+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- double minRadius = ((end_lean*-1)+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint());
- pb.lineTo(with_direction.finalPoint() + maxRadius*end_deriv);
- pb.lineTo(against_direction.initialPoint() + minRadius*end_deriv);
- pb.lineTo(against_direction.initialPoint());
- break;
- }
- }
- } else {
- pb.moveTo(against_direction.initialPoint());
- }
-
- pb.append(against_direction);
-
- //cap (if necessary)
- if (!path_in[i].closed()) {
- switch (butt) {
- case BUTT_STRAIGHT:
- pb.lineTo(with_direction.initialPoint());
- break;
- case BUTT_ROUND:
- pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() );
- break;
- case BUTT_POINTY: {
- Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.);
- double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- Geom::Point midpoint = 0.5 * (against_direction.finalPoint() + with_direction.initialPoint()) + radius*end_deriv;
- pb.lineTo(midpoint);
- pb.lineTo(with_direction.initialPoint());
- break;
- }
- case BUTT_SQUARE: {
- Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.);
- double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- pb.lineTo(against_direction.finalPoint() + radius*end_deriv);
- pb.lineTo(with_direction.initialPoint() + radius*end_deriv);
- pb.lineTo(with_direction.initialPoint());
- break;
- }
- case BUTT_LEANED: {
- Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.);
- double maxRadius = (start_lean+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- double minRadius = ((start_lean*-1)+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint());
- pb.lineTo(against_direction.finalPoint() + minRadius*end_deriv);
- pb.lineTo(with_direction.initialPoint() + maxRadius*end_deriv);
- pb.lineTo(with_direction.initialPoint());
- break;
- }
- }
- }
- pb.flush();
- path_out.push_back(pb.peek()[0]);
- if (path_in[i].closed()) {
- path_out.push_back(pb.peek()[1]);
- }
- } else {
- Path p = Path();
- Path outlinepath = Path();
- ButtType original_butt;
- switch (butt) {
- case BUTT_STRAIGHT:
- original_butt = butt_straight;
- break;
- case BUTT_ROUND:
- original_butt = butt_round;
- break;
- case butt_pointy: {
- original_butt = butt_pointy;
- break;
- }
- case BUTT_SQUARE: {
- original_butt = butt_square;
- break;
- }
- case BUTT_LEANED: {
- original_butt = butt_straight;
- break;
- }
- }
- p.LoadPath(path_in[i], Geom::Affine(), false, false);
- p.Outline(&outlinepath, line_width / 2, static_cast<join_typ>(join), original_butt, miter_lim);
- Geom::PathVector *pv_p = outlinepath.MakePathVector();
- //somewhat hack-ish
- path_out.push_back( (*pv_p)[0].reverse() );
- if (pv_p) delete pv_p;
- }
- }
- return path_out;
-}
-
-#define miter_lim fabs(line_width * miter_limit)
-
-Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean)
-{
- std::vector<Geom::Path> path_out = std::vector<Geom::Path>();
- if (path_in.empty()) {
- return path_out;
- }
- Path p = Path();
- Path outlinepath = Path();
- for (unsigned i = 0; i < path_in.size(); i++) {
- p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true));
- }
-
- // magic!
- ButtType original_butt;
- switch (linecap_type) {
- case BUTT_STRAIGHT:
- original_butt = butt_straight;
- break;
- case BUTT_ROUND:
- original_butt = butt_round;
- break;
- case butt_pointy: {
- original_butt = butt_pointy;
- break;
- }
- case BUTT_SQUARE: {
- original_butt = butt_square;
- break;
- }
- case BUTT_LEANED: {
- original_butt = butt_straight;
- break;
- }
- }
- if (linejoin_type <= LINEJOIN_POINTY) {
- p.Outline(&outlinepath, line_width / 2, static_cast<join_typ>(linejoin_type),
- original_butt, miter_lim);
- // fix memory leak
- std::vector<Geom::Path> *pv_p = outlinepath.MakePathVector();
- path_out = *pv_p;
- delete pv_p;
-
- } else if (linejoin_type == LINEJOIN_REFLECTED) {
- // reflected arc join
- path_out = outlinePath(path_in, line_width, static_cast<LineJoinType>(linejoin_type),
- linecap_type , miter_lim, false, start_lean, end_lean);
-
- } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) {
- // extrapolated arc join
- path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true, start_lean, end_lean);
- }
-
- return path_out;
-}
-
-Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit)
-{
-
- Geom::Path path_out;
-
- if (linejoin_type <= LINEJOIN_POINTY || path_in.size() <= 1) {
-
- Geom::PathVector * pathvec;
-
- Path path_tangent = Path();
- Path path_outline = Path();
- path_outline.LoadPath(path_in, Geom::Affine(), false, false);
- path_outline.OutsideOutline(&path_tangent, line_width / 2, static_cast<join_typ>(linejoin_type), butt_straight, miter_lim);
-
- pathvec = path_tangent.MakePathVector();
- path_out = pathvec->front();
- delete pathvec;
- return path_out;
- } else if (linejoin_type == LINEJOIN_REFLECTED) {
- path_out = outlineHalf(path_in, line_width, miter_lim, reflect_curves);
- return path_out;
- } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) {
- path_out = outlineHalf(path_in, line_width, miter_lim, extrapolate_curves);
- return path_out;
- }
- return path_out;
-}
-
-} // namespace Outline
-
-/*
- 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:encoding=utf-8 :
diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h deleted file mode 100644 index c17584be2..000000000 --- a/src/live_effects/pathoutlineprovider.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SEEN_PATH_OUTLINE_H -#define SEEN_PATH_OUTLINE_H - -/* Author: - * Liam P. White <inkscapebrony@gmail.com> - * - * Copyright (C) 2014 Author - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <livarot/Path.h> -#include <livarot/LivarotDefs.h> - -enum LineJoinType { - LINEJOIN_STRAIGHT, - LINEJOIN_ROUND, - LINEJOIN_POINTY, - LINEJOIN_REFLECTED, - LINEJOIN_EXTRAPOLATED -}; -enum ButtTypeMod { - BUTT_STRAIGHT, - BUTT_ROUND, - BUTT_SQUARE, - BUTT_POINTY, - BUTT_LEANED -}; - -namespace Geom -{ - Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2<Geom::SBasis> const & sbasis_in); - std::vector<Geom::Path> split_at_cusps(const Geom::Path& in); -} - -namespace Outline -{ - unsigned bezierOrder (const Geom::Curve* curve_in); - std::vector<Geom::Path> PathVectorOutline(std::vector<Geom::Path> const & path_in, double line_width, ButtTypeMod linecap_type, - LineJoinType linejoin_type, double miter_limit, double start_lean = 0, double end_lean = 0); - Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); -} - -#endif // SEEN_PATH_OUTLINE_H - -/* - 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:fileencoding=utf-8 : diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index 441ce6ea6..8304db684 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -233,8 +233,8 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select int n_terms = count_terms(items); gchar *objects_str = g_strdup_printf(ngettext( - "<b>%i</b> objects selected of type %s", - "<b>%i</b> objects selected of types %s", n_terms), + "<b>%1$i</b> objects selected of type %2$s", + "<b>%1$i</b> objects selected of types %2$s", n_terms), objcount, terms); g_free(terms); diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 885fedafa..932a3a1b7 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -95,6 +95,10 @@ void SPGenericEllipse::build(SPDocument *document, Inkscape::XML::Node *repr) std::cerr << "SPGenericEllipse::build() unknown defined type." << std::endl; } + // std::cout << " cx: " << cx.write() << std::endl; + // std::cout << " cy: " << cy.write() << std::endl; + // std::cout << " rx: " << rx.write() << std::endl; + // std::cout << " ry: " << ry.write() << std::endl; SPShape::build(document, repr); } @@ -103,29 +107,41 @@ void SPGenericEllipse::set(unsigned int key, gchar const *value) // There are multiple ways to set internal cx, cy, rx, and ry (via SVG attributes or Sodipodi // attributes) thus we don't want to unset them if a read fails (e.g., when we explicitly clear // an attribute by setting it to NULL). + + // We must update the SVGLengths immediately or nodes may be misplaced after they are moved. + double const w = viewport.width(); + double const h = viewport.height(); + double const d = hypot(w, h) / sqrt(2); // diagonal + double const em = style->font_size.computed; + double const ex = em * 0.5; + SVGLength t; switch (key) { case SP_ATTR_CX: case SP_ATTR_SODIPODI_CX: if( t.read(value) ) cx = t; + cx.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_CY: case SP_ATTR_SODIPODI_CY: if( t.read(value) ) cy = t; + cy.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_RX: case SP_ATTR_SODIPODI_RX: - if( t.read(value) && t.value > 0.0 ) this->rx = t; + if( t.read(value) && t.value > 0.0 ) rx = t; + rx.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_RY: case SP_ATTR_SODIPODI_RY: - if( t.read(value) && t.value > 0.0 ) this->ry = t; + if( t.read(value) && t.value > 0.0 ) ry = t; + ry.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -133,6 +149,8 @@ void SPGenericEllipse::set(unsigned int key, gchar const *value) if( t.read(value) && t.value > 0.0 ) { this->ry = this->rx = t; } + rx.update( em, ex, d ); + ry.update( em, ex, d ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -196,7 +214,7 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I // << ")" << std::endl; GenericEllipseType new_type = SP_GENERIC_ELLIPSE_UNDEFINED; - if (this->_isSlice() || hasPathEffect() ) { + if (_isSlice() || hasPathEffect() ) { new_type = SP_GENERIC_ELLIPSE_ARC; } else if ( rx.computed == ry.computed ) { new_type = SP_GENERIC_ELLIPSE_CIRCLE; @@ -246,10 +264,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I } // std::cout << " type: " << g_quark_to_string( repr->code() ) << std::endl; - // std::cout << " cx: " << cx.computed - // << " cy: " << cy.computed - // << " rx: " << rx.computed - // << " ry: " << ry.computed << std::endl; + // std::cout << " cx: " << cx.write() << " " << cx.computed + // << " cy: " << cy.write() << " " << cy.computed + // << " rx: " << rx.write() << " " << rx.computed + // << " ry: " << ry.write() << " " << ry.computed << std::endl; switch ( type ) { case SP_GENERIC_ELLIPSE_UNDEFINED: @@ -264,17 +282,17 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I if (flags & SP_OBJECT_WRITE_EXT) { repr->setAttribute("sodipodi:type", "arc"); - sp_repr_set_svg_double(repr, "sodipodi:cx", this->cx.computed); - sp_repr_set_svg_double(repr, "sodipodi:cy", this->cy.computed); - sp_repr_set_svg_double(repr, "sodipodi:rx", this->rx.computed); - sp_repr_set_svg_double(repr, "sodipodi:ry", this->ry.computed); + sp_repr_set_svg_length(repr, "sodipodi:cx", cx); + sp_repr_set_svg_length(repr, "sodipodi:cy", cy); + sp_repr_set_svg_length(repr, "sodipodi:rx", rx); + sp_repr_set_svg_length(repr, "sodipodi:ry", ry); // write start and end only if they are non-trivial; otherwise remove - if (this->_isSlice()) { - sp_repr_set_svg_double(repr, "sodipodi:start", this->start); - sp_repr_set_svg_double(repr, "sodipodi:end", this->end); + if (_isSlice()) { + sp_repr_set_svg_double(repr, "sodipodi:start", start); + sp_repr_set_svg_double(repr, "sodipodi:end", end); - repr->setAttribute("sodipodi:open", (!this->_closed) ? "true" : NULL); + repr->setAttribute("sodipodi:open", (!_closed) ? "true" : NULL); } else { repr->setAttribute("sodipodi:end", NULL); repr->setAttribute("sodipodi:start", NULL); @@ -283,13 +301,13 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I } // write d= - this->set_elliptical_path_attribute(repr); + set_elliptical_path_attribute(repr); break; case SP_GENERIC_ELLIPSE_CIRCLE: - sp_repr_set_svg_double(repr, "cx", this->cx.computed); - sp_repr_set_svg_double(repr, "cy", this->cy.computed); - sp_repr_set_svg_double(repr, "r", this->rx.computed); + sp_repr_set_svg_length(repr, "cx", cx); + sp_repr_set_svg_length(repr, "cy", cy); + sp_repr_set_svg_length(repr, "r", rx); repr->setAttribute("rx", NULL ); repr->setAttribute("ry", NULL ); repr->setAttribute("sodipodi:cx", NULL ); @@ -304,10 +322,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I break; case SP_GENERIC_ELLIPSE_ELLIPSE: - sp_repr_set_svg_double(repr, "cx", this->cx.computed); - sp_repr_set_svg_double(repr, "cy", this->cy.computed); - sp_repr_set_svg_double(repr, "rx", this->rx.computed); - sp_repr_set_svg_double(repr, "ry", this->ry.computed); + sp_repr_set_svg_length(repr, "cx", cx); + sp_repr_set_svg_length(repr, "cy", cy); + sp_repr_set_svg_length(repr, "rx", rx); + sp_repr_set_svg_length(repr, "ry", ry); repr->setAttribute("r", NULL ); repr->setAttribute("sodipodi:cx", NULL ); repr->setAttribute("sodipodi:cy", NULL ); @@ -324,11 +342,10 @@ Inkscape::XML::Node *SPGenericEllipse::write(Inkscape::XML::Document *xml_doc, I std::cerr << "SPGenericEllipse::write: unknown type." << std::endl; } - this->set_shape(); // evaluate SPCurve + set_shape(); // evaluate SPCurve SPShape::write(xml_doc, repr, flags); - // std::cout << "SPGenericEllipse::write: Exit: " << g_quark_to_string(repr->code()) << "\n" << std::endl; return repr; } @@ -339,8 +356,8 @@ const char *SPGenericEllipse::displayName() const case SP_GENERIC_ELLIPSE_UNDEFINED: case SP_GENERIC_ELLIPSE_ARC: - if (this->_isSlice()) { - if (this->_closed) { + if (_isSlice()) { + if (_closed) { return _("Segment"); } else { return _("Arc"); @@ -480,11 +497,11 @@ Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform) } if (this->rx._set) { - this->rx = this->rx.computed * sw; + this->rx.scale( sw ); } if (this->ry._set) { - this->ry = this->ry.computed * sh; + this->ry.scale( sh ); } /* Find start in item coords */ @@ -628,10 +645,10 @@ bool SPGenericEllipse::set_elliptical_path_attribute(Inkscape::XML::Node *repr) void SPGenericEllipse::position_set(gdouble x, gdouble y, gdouble rx, gdouble ry) { - this->cx.computed = x; - this->cy.computed = y; - this->rx.computed = rx; - this->ry.computed = ry; + this->cx = x; + this->cy = y; + this->rx = rx; + this->ry = ry; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); diff --git a/src/sp-factory.cpp b/src/sp-factory.cpp index 9911222e5..e48646f8d 100644 --- a/src/sp-factory.cpp +++ b/src/sp-factory.cpp @@ -36,7 +36,7 @@ #include "sp-linear-gradient.h" #include "sp-marker.h" #include "sp-mask.h" -#include "sp-mesh-gradient.h" +#include "sp-mesh.h" #include "sp-mesh-patch.h" #include "sp-mesh-row.h" #include "sp-metadata.h" @@ -168,12 +168,12 @@ SPObject *SPFactory::createObject(std::string const& id) ret = new SPMarker; else if (id == "svg:mask") ret = new SPMask; - else if (id == "svg:meshGradient") - ret = new SPMeshGradient; - else if (id == "svg:meshPatch") - ret = new SPMeshPatch; - else if (id == "svg:meshRow") - ret = new SPMeshRow; + else if (id == "svg:mesh") + ret = new SPMesh; + else if (id == "svg:meshpatch") + ret = new SPMeshpatch; + else if (id == "svg:meshrow") + ret = new SPMeshrow; else if (id == "svg:metadata") ret = new SPMetadata; else if (id == "svg:missing-glyph") diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index b3e885560..854d53dc4 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -1,6 +1,6 @@ /** \file * SPGradient, SPStop, SPLinearGradient, SPRadialGradient, - * SPMeshGradient, SPMeshRow, SPMeshPatch + * SPMesh, SPMeshRow, SPMeshPatch */ /* * Authors: @@ -44,7 +44,7 @@ #include "sp-gradient-reference.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "sp-mesh-gradient.h" +#include "sp-mesh.h" #include "sp-mesh-row.h" #include "sp-mesh-patch.h" #include "sp-stop.h" @@ -121,7 +121,7 @@ bool SPGradient::isEquivalent(SPGradient *that) else if ( (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || - (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that))) { + (SP_IS_MESH(this) && SP_IS_MESH(that))) { if(!this->isAligned(that))break; } else { break; } // this should never happen, some unhandled type of gradient @@ -206,9 +206,9 @@ bool SPGradient::isAligned(SPGradient *that) (sg->fy.computed != tg->fy.computed) ) { break; } } else if( sg->cx._set || sg->cy._set || sg->fx._set || sg->fy._set || sg->r._set ) { break; } // some mix of set and not set // none set? assume aligned and fall through - } else if (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that)) { - SPMeshGradient *sg=SP_MESHGRADIENT(this); - SPMeshGradient *tg=SP_MESHGRADIENT(that); + } else if (SP_IS_MESH(this) && SP_IS_MESH(that)) { + SPMesh *sg=SP_MESH(this); + SPMesh *tg=SP_MESH(that); if( sg->x._set != !tg->x._set) { break; } if( sg->y._set != !tg->y._set) { break; } @@ -508,9 +508,9 @@ void SPGradient::modified(guint flags) if (flags & SP_OBJECT_CHILD_MODIFIED_FLAG) { // CPPIFY // This comparison has never worked (i. e. always evaluated to false), - // the right value would have been SP_TYPE_MESHGRADIENT + // the right value would have been SP_TYPE_MESH //if( this->get_type() != SP_GRADIENT_TYPE_MESH ) { -// if (!SP_IS_MESHGRADIENT(this)) { +// if (!SP_IS_MESH(this)) { // this->invalidateVector(); // } else { // this->invalidateArray(); @@ -522,7 +522,7 @@ void SPGradient::modified(guint flags) // CPPIFY // see above //if( this->get_type() != SP_GRADIENT_TYPE_MESH ) { -// if (!SP_IS_MESHGRADIENT(this)) { +// if (!SP_IS_MESH(this)) { // this->ensureVector(); // } else { // this->ensureArray(); @@ -1014,12 +1014,12 @@ void SPGradient::rebuildArray() { // std::cout << "SPGradient::rebuildArray()" << std::endl; - if( !SP_IS_MESHGRADIENT(this) ) { + if( !SP_IS_MESH(this) ) { g_warning( "SPGradient::rebuildArray() called for non-mesh gradient" ); return; } - array.read( SP_MESHGRADIENT( this ) ); + array.read( SP_MESH( this ) ); has_patches = false; for ( SPObject *ro = firstChild() ; ro ; ro = ro->getNext() ) { @@ -1139,7 +1139,7 @@ sp_gradient_create_preview_pattern(SPGradient *gr, double width) // CPPIFY //if( gr->get_type() != SP_GRADIENT_TYPE_MESH ) { - if (!SP_IS_MESHGRADIENT(gr)) { + if (!SP_IS_MESH(gr)) { gr->ensureVector(); pat = cairo_pattern_create_linear(0, 0, width, 0); diff --git a/src/sp-gradient.h b/src/sp-gradient.h index f80d806fc..ab45d6f08 100644 --- a/src/sp-gradient.h +++ b/src/sp-gradient.h @@ -39,12 +39,6 @@ enum SPGradientType { SP_GRADIENT_TYPE_MESH }; -enum SPGradientMeshType { - SP_GRADIENT_MESH_TYPE_UNKNOWN, - SP_GRADIENT_MESH_TYPE_NORMAL, - SP_GRADIENT_MESH_TYPE_CONICAL -}; - enum SPGradientState { SP_GRADIENT_STATE_UNKNOWN, SP_GRADIENT_STATE_VECTOR, @@ -216,7 +210,7 @@ sp_gradient_pattern_common_setup(cairo_pattern_t *cp, void sp_gradient_repr_write_vector(SPGradient *gr); void sp_gradient_repr_clear_vector(SPGradient *gr); -void sp_meshgradient_repr_write(SPMeshGradient *mg); +void sp_mesh_repr_write(SPMesh *mg); cairo_pattern_t *sp_gradient_create_preview_pattern(SPGradient *gradient, double width); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index cfa142acd..9bd42665d 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -822,7 +822,7 @@ void SPGroup::update_patheffect(bool write) { LivePathEffectObject *lpeobj = (*it)->lpeobject; if (lpeobj && lpeobj->get_lpe()) { - lpeobj->get_lpe()->doBeforeEffect(this); + lpeobj->get_lpe()->doBeforeEffect_impl(this); } } diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 86beee907..767f0ed91 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -181,7 +181,9 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua if (B*B - 4*A*C < 0) { g_message("stroke scaling error : %d, %f, %f, %f, %f, %f", preserve, r0, w0, h0, w1, h1); } else { - r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); + r1 = -C/B; + if (!Geom::are_near(A*C/B/B, 0.0, Geom::EPSILON)) + r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier scale_x = (w1 - r1)/(w0 - r0); @@ -339,7 +341,9 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu if (B*B - 4*A*C < 0) { g_message("variable stroke scaling error : %d, %d, %f, %f, %f, %f, %f, %f", transform_stroke, preserve, r0w, r0h, w0, h0, w1, h1); } else { - gdouble det = (-B + sqrt(B*B - 4*A*C))/(2*A); + gdouble det = -C/B; + if (!Geom::are_near(A*C/B/B, 0.0, Geom::EPSILON)) + det = (-B + sqrt(B*B - 4*A*C))/(2*A); r1w = r0w*det; r1h = r0h*det; // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 5d181b80a..8c99e9bcf 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -75,18 +75,6 @@ static SPItemView* sp_item_view_list_remove(SPItemView *list, SPItem::SPItem() : SPObject() { - this->sensitive = 0; - this->clip_ref = NULL; - this->avoidRef = NULL; - this->_is_evaluated = false; - this->stop_paint = 0; - this->_evaluated_status = StatusUnknown; - this->bbox_valid = 0; - this->freeze_stroke_width = false; - this->transform_center_x = 0; - this->transform_center_y = 0; - this->display = NULL; - this->mask_ref = NULL; sensitive = TRUE; bbox_valid = FALSE; @@ -96,12 +84,13 @@ SPItem::SPItem() : SPObject() { transform_center_x = 0; transform_center_y = 0; + freeze_stroke_width = false; + _is_evaluated = true; _evaluated_status = StatusUnknown; transform = Geom::identity(); - doc_bbox = Geom::OptRect(); - freeze_stroke_width = false; + // doc_bbox = Geom::OptRect(); display = NULL; @@ -670,54 +659,56 @@ void SPItem::stroke_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item) } } -void SPItem::update(SPCtx* /*ctx*/, guint flags) { - SPItem *item = this; - SPItem* object = item; +void SPItem::update(SPCtx* ctx, guint flags) { -// SPObject::onUpdate(ctx, flags); + SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx); - // any of the modifications defined in sp-object.h might change bbox, + // Any of the modifications defined in sp-object.h might change bbox, // so we invalidate it unconditionally - item->bbox_valid = FALSE; + bbox_valid = FALSE; + + viewport = ictx->viewport; // Cache viewport - if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) { + if (flags & (SP_OBJECT_CHILD_MODIFIED_FLAG | + SP_OBJECT_MODIFIED_FLAG | + SP_OBJECT_STYLE_MODIFIED_FLAG) ) { if (flags & SP_OBJECT_MODIFIED_FLAG) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { - v->arenaitem->setTransform(item->transform); + for (SPItemView *v = display; v != NULL; v = v->next) { + v->arenaitem->setTransform(transform); } } - SPClipPath *clip_path = item->clip_ref ? item->clip_ref->getObject() : NULL; - SPMask *mask = item->mask_ref ? item->mask_ref->getObject() : NULL; + SPClipPath *clip_path = clip_ref ? clip_ref->getObject() : NULL; + SPMask *mask = mask_ref ? mask_ref->getObject() : NULL; if ( clip_path || mask ) { - Geom::OptRect bbox = item->geometricBounds(); + Geom::OptRect bbox = geometricBounds(); if (clip_path) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { + for (SPItemView *v = display; v != NULL; v = v->next) { clip_path->setBBox(v->arenaitem->key(), bbox); } } if (mask) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { + for (SPItemView *v = display; v != NULL; v = v->next) { mask->sp_mask_set_bbox(v->arenaitem->key(), bbox); } } } if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - for (SPItemView *v = item->display; v != NULL; v = v->next) { - v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(object->style->opacity.value)); - v->arenaitem->setAntialiasing(object->style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES); - v->arenaitem->setIsolation( object->style->isolation.value ); - v->arenaitem->setBlendMode( object->style->mix_blend_mode.value ); - v->arenaitem->setVisible(!item->isHidden()); + for (SPItemView *v = display; v != NULL; v = v->next) { + v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(style->opacity.value)); + v->arenaitem->setAntialiasing(style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES); + v->arenaitem->setIsolation( style->isolation.value ); + v->arenaitem->setBlendMode( style->mix_blend_mode.value ); + v->arenaitem->setVisible(!isHidden()); } } } /* Update bounding box in user space, used for filter and objectBoundingBox units */ - if (item->style->filter.set && item->display) { - Geom::OptRect item_bbox = item->geometricBounds(); - SPItemView *itemview = item->display; + if (style->filter.set && display) { + Geom::OptRect item_bbox = geometricBounds(); + SPItemView *itemview = display; do { if (itemview->arenaitem) itemview->arenaitem->setItemBounds(item_bbox); @@ -725,8 +716,8 @@ void SPItem::update(SPCtx* /*ctx*/, guint flags) { } // Update libavoid with item geometry (for connector routing). - if (item->avoidRef) - item->avoidRef->handleSettingChange(); + if (avoidRef) + avoidRef->handleSettingChange(); } void SPItem::modified(unsigned int /*flags*/) diff --git a/src/sp-item.h b/src/sp-item.h index b9d71c551..bdc6a0ad9 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -145,6 +145,7 @@ public: Geom::Affine transform; mutable Geom::OptRect doc_bbox; + Geom::Rect viewport; // Cache viewport information SPClipPathReference *clip_ref; SPMaskReference *mask_ref; diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 6228f3692..9befd2a2b 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -263,7 +263,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve) { } if (!SP_IS_GROUP(this)) { lpe->doAfterEffect(this); - } + } } } } diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp index e2d654f2f..445c9a8f6 100644 --- a/src/sp-mesh-array.cpp +++ b/src/sp-mesh-array.cpp @@ -46,8 +46,8 @@ #include "document.h" #include "sp-root.h" +#include "sp-mesh.h" #include "sp-mesh-array.h" -#include "sp-mesh-gradient.h" #include "sp-mesh-row.h" #include "sp-mesh-patch.h" #include "sp-stop.h" @@ -289,7 +289,7 @@ bool SPMeshPatchI::tensorIsSet() { /** Return if tensor control point for "corner" i is set. */ -bool SPMeshPatchI::tensorIsSet( guint i ) { +bool SPMeshPatchI::tensorIsSet( unsigned int i ) { assert( i < 4 ); @@ -574,7 +574,7 @@ void SPMeshPatchI::setOpacity( guint i, gdouble opacity ) { }; -SPMeshNodeArray::SPMeshNodeArray( SPMeshGradient *mg ) { +SPMeshNodeArray::SPMeshNodeArray( SPMesh *mg ) { read( mg ); @@ -621,7 +621,7 @@ SPMeshNodeArray& SPMeshNodeArray::operator=( const SPMeshNodeArray& rhs ) { }; -void SPMeshNodeArray::read( SPMeshGradient *mg_in ) { +void SPMeshNodeArray::read( SPMesh *mg_in ) { mg = mg_in; @@ -641,7 +641,7 @@ void SPMeshNodeArray::read( SPMeshGradient *mg_in ) { if (SP_IS_MESHPATCH(po)) { - SPMeshPatch *patch = SP_MESHPATCH(po); + SPMeshpatch *patch = SP_MESHPATCH(po); // std::cout << "SPMeshNodeArray::read: row size: " << nodes.size() << std::endl; SPMeshPatchI new_patch( &nodes, irow, icolumn ); // Adds new nodes. @@ -838,7 +838,7 @@ void SPMeshNodeArray::read( SPMeshGradient *mg_in ) { /** Write repr using our array. */ -void SPMeshNodeArray::write( SPMeshGradient *mg ) { +void SPMeshNodeArray::write( SPMesh *mg ) { // std::cout << "SPMeshNodeArray::write: entrance:" << std::endl; // print(); @@ -889,14 +889,14 @@ void SPMeshNodeArray::write( SPMeshGradient *mg ) { for( guint i = 0; i < rows; ++i ) { // Write row - Inkscape::XML::Node *row = xml_doc->createElement("svg:meshRow"); + Inkscape::XML::Node *row = xml_doc->createElement("svg:meshrow"); mesh->appendChild( row ); // No attributes guint columns = array->patch_columns(); for( guint j = 0; j < columns; ++j ) { // Write patch - Inkscape::XML::Node *patch = xml_doc->createElement("svg:meshPatch"); + Inkscape::XML::Node *patch = xml_doc->createElement("svg:meshpatch"); SPMeshPatchI patchi( &(array->nodes), i, j ); @@ -967,10 +967,10 @@ void SPMeshNodeArray::write( SPMeshGradient *mg ) { break; case 'z': case 'Z': - std::cout << "sp_meshgradient_repr_write: bad path type" << path_type << std::endl; + std::cout << "sp_mesh_repr_write: bad path type" << path_type << std::endl; break; default: - std::cout << "sp_meshgradient_repr_write: unhandled path type" << path_type << std::endl; + std::cout << "sp_mesh_repr_write: unhandled path type" << path_type << std::endl; } stop->setAttribute("path", is.str().c_str()); // std::cout << "SPMeshNodeArray::write: path: " << is.str().c_str() << std::endl; @@ -1039,7 +1039,7 @@ static SPColor default_color( SPItem *item ) { /** Create a default mesh. */ -void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox ) { +void SPMeshNodeArray::create( SPMesh *mg, SPItem *item, Geom::OptRect bbox ) { // std::cout << "SPMeshNodeArray::create: Entrance" << std::endl; @@ -1077,10 +1077,10 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb guint prows = prefs->getInt("/tools/mesh/mesh_rows", 1); guint pcols = prefs->getInt("/tools/mesh/mesh_cols", 1); - SPGradientMeshType mesh_type = - (SPGradientMeshType) prefs->getInt("/tools/mesh/mesh_type", SP_GRADIENT_MESH_TYPE_NORMAL); + SPMeshGeometry mesh_type = + (SPMeshGeometry) prefs->getInt("/tools/mesh/mesh_geometry", SP_MESH_GEOMETRY_NORMAL); - if( mesh_type == SP_GRADIENT_MESH_TYPE_CONICAL ) { + if( mesh_type == SP_MESH_GEOMETRY_CONICAL ) { // Conical gradient.. for any shape/path using geometric bounding box. @@ -1424,133 +1424,7 @@ void SPMeshNodeArray::print() { -// Find the slopes at start and end for Hermite interpolation. -// Smooth using Hermite interpolation. -// Inputs are: -// pb: color value before patch -// p0: color value start of patch -// p1: color value end of patch -// pa: color value after patch -// lb0: distance between points b and 0 -// l01: distance between points 0 and 1 -// l1a: distance between points 1 and a -// is_first: If first patch in row/column -// is_last: If last patch in row/column -// type: Type of smoothing -// Output: -// m0: slope of Hermite function at start. -// m1: slope of Hermite function at end. -void find_slopes( const double &pb, const double &p0, const double &p1, const double &pa, - const double &lb0, const double &l01, const double &l1a, - const bool &is_first, const bool &is_last, const SPMeshSmooth type, - double &m0, double &m1 ) { - - // We use Hermite interpolation. We have end points, we need tangents. - - // Try various ways of finding tangents m0, m1 - - // Default to Catmul-Rom (assumes pb and pa already calculatedd) - m0 = (p1 - pb)/2.0; - m1 = (pa - p0)/2.0; - - // Finite differences - if( lb0 > 0 && l01 > 0 ) - m0 = 0.5 * ((p0 - pb )/lb0 + (p1 - p0)/l01) * l01; - if( l01 > 0 && l1a > 0 ) - m1 = 0.5 * ((p1 - p0 )/l01 + (pa - p1)/l1a) * l01; - - bool parabolic = false; // Require end patches to be parabolic - switch (type) { - case SP_MESH_SMOOTH_SMOOTH1: - // Flat - m0 = 0.0; - m1 = 0.0; - break; - case SP_MESH_SMOOTH_SMOOTH2: - // Catmul-Rom, standard end treatment. Double first/last point. - if( is_first ) { - m0 = (p1-p0)/2.0; - } - if( is_last ) { - m1 = (p1-p0)/2.0; - } - break; - case SP_MESH_SMOOTH_SMOOTH3: - // Catmul-Rom, standard end treatment. Reflect first/last point. - if( is_first ) { - m0 = (p1-p0); - } - if( is_last ) { - m1 = (p1-p0); - } - break; - case SP_MESH_SMOOTH_SMOOTH4: - // Catmul-Rom, Parabolic ends - parabolic = true; - break; - case SP_MESH_SMOOTH_SMOOTH5: - // Catmul-Rom, Parabolic ends, no color min/max in middle of patch. - parabolic = true; - - if( (pb > p0 && p1 > p0) || - (pb < p0 && p1 < p0) ) { - // tangents flat at min/max - m0 = 0; - } else { - // https://en.wikipedia.org/wiki/Monotone_cubic_interpolation - // ensure we don't overshoot - if( fabs(m0) > fabs(3*(p1-p0)) ) { - m0 = 3*(p1-p0); - } - if( fabs(m0) > fabs(3*(p0-pb)) * l01 / lb0 ) { - m0 = 3*(p0-pb) * l01 / lb0; - } - } - if( (p0 > p1 && pa > p1) || - (p0 < p1 && pa < p1) ) { - // tangents flat at min/max - m1 = 0; - } else { - // ensure we don't overshoot - if( fabs(m1) > fabs(3*(pa-p1) * l01 / l1a) ) { - m1 = 3*(pa-p1) * l01 / l1a; - } - if( fabs(m1) > fabs(3*(p1-p0)) ) { - m1 = 3*(p1-p0); - } - } - break; - case SP_MESH_SMOOTH_NONE: - default: - std::cerr << "find_slopes() Invalid smoothing type." << std::endl; - break; - } - - // Force end patches to be parabolic - if( parabolic ) { - if( is_first ) { - // Constraint for parabola - m0 = 2.0*(p1-p0) - m1; - if ( ((p1-p0) < 0 && m0 > 0) || ((p1-p0) > 0 && m0 < 0 ) ) { - m0 = 0; // Prevent overshooting start value; - } - } else if( is_last ) { - // Constraint for parabola - m1 = 2.0*(p1-p0) - m0; - if ( ((p1-p0) < 0 && m1 > 0) || ((p1-p0) > 0 && m1 < 0 ) ) { - m1 = 0; // Prevent overshooting end value; - } - } - } - - // std::cout << " pb: " << pb - // << " p0: " << p0 - // << " p1: " << p1 - // << " pa: " << pa - // << " m0: " << m0 - // << " m1: " << m1 << std::endl; -} - +/* double hermite( const double p0, const double p1, const double m0, const double m1, const double t ) { double t2 = t*t; double t3 = t2*t; @@ -1562,178 +1436,7 @@ double hermite( const double p0, const double p1, const double m0, const double return result; } - - -/** - Fill 'smooth' with a smoothed version of the array by subdividing each patch into smaller patches. */ -void SPMeshNodeArray::smooth( SPMeshNodeArray* smooth, SPMeshSmooth type ) { - - *smooth = *this; // Deep copy via copy assignment constructor, smooth cleared before copy - // std::cout << "SPMeshNodeArray::smooth(): " << this->patch_rows() << " " << smooth->patch_rows() << std::endl; - // std::cout << " " << smooth << " " << this << std::endl; - // Next split each patch into 8x8 smaller patches. - - // Do rows first. - - // Split each row into eight rows. - // Must do it from end so inserted rows don't mess up indexing - for( int i = smooth->patch_rows() - 1; i >= 0; --i ) { - smooth->split_row( i, unsigned(8) ); - } - - // Update color values (every third node is a corner) - for( unsigned i = 0; i < this->patch_rows(); ++i ) { // i is orignal patch index - - bool is_first_row = (i == 0); - bool is_last_row = (i == this->patch_rows() - 1 ); - //std::cout << " last row: " << smooth->patch_rows()/8 - 1 << " " << is_last_row << std::endl; - for( unsigned j = 0; j < smooth->patch_columns()+1; ++j ) { // j is smooth patch index - - // Can't use guint32 since delta can be negative - float pb[3]; // Point before patch - float p0[3]; // Point at start of patch - float p1[3]; // Point at end of patch - float pa[3]; // Point after patch - float result[3][8]; - sp_color_get_rgb_floatv( &this->nodes[ i *3 ][ j*3 ]->color, p0 ); - sp_color_get_rgb_floatv( &this->nodes[ (i+1)*3 ][ j*3 ]->color, p1 ); - - // Use linear distance to avoid calculation overhead of calculating true path length - Geom::Point *ptb = NULL; - Geom::Point *pt0 = &this->nodes[ i *3 ][ j*3 ]->p; - Geom::Point *pt1 = &this->nodes[ (i+1)*3 ][ j*3 ]->p; - Geom::Point *pta = NULL; - - double lb0 = 0.0; - double l01 = Geom::distance( *pt0, *pt1 ); - double l1a = 0.0; - - if( !is_first_row ) { - sp_color_get_rgb_floatv( &this->nodes[ (i-1)*3 ][ j*3 ]->color, pb ); - ptb = &this->nodes[ (i-1)*3 ][ j*3 ]->p; - lb0 = Geom::distance( *ptb, *pt0 ); - } else { - pb[0] = 2.0*p0[0] - p1[0]; - pb[1] = 2.0*p0[1] - p1[1]; - pb[2] = 2.0*p0[2] - p1[2]; - } - if( !is_last_row ) { - sp_color_get_rgb_floatv( &this->nodes[ (i+2)*3 ][ j*3 ]->color, pa ); - pta = &this->nodes[ (i+2)*3 ][ j*3 ]->p; - l1a = Geom::distance( *pt1, *pta ); - } else { - pa[0] = 2.0*p1[0] - p0[0]; - pa[1] = 2.0*p1[1] - p0[1]; - pa[2] = 2.0*p1[2] - p0[2]; - } - - for( unsigned n = 0; n < 3; ++n ) { // Loop over colors - - // We use Hermite interpolation. We have end points, we need tangents. - double m0 = 0; - double m1 = 0; - find_slopes( pb[n], p0[n], p1[n], pa[n], - lb0, l01, l1a, - is_first_row, is_last_row, type, m0, m1 ); - - for( unsigned k = 1; k < 8; ++k ) { - double t = k/8.0; - // Cubic Hermite (four constraints) - result[n][k] = hermite( p0[n], p1[n], m0, m1, t ); - // Clamp to allowed values - if( result[n][k] > 1.0 ) - result[n][k] = 1.0; - if( result[n][k] < 0.0 ) - result[n][k] = 0.0; - } - } - - for( unsigned k = 1; k < 8; ++k ) { - smooth->nodes[ (i*8+k)*3 ][ j*3 ]->color.set( result[0][k], result[1][k], result[2][k] ); - } - } - } - - // Split each column into eight columns. - // Must do it from end so inserted columns don't mess up indexing - for( int i = smooth->patch_columns() - 1; i >= 0; --i ) { - smooth->split_column( i, (unsigned)8 ); - } - - // Update color values (every third node is a corner) - for( unsigned i = 0; i < this->patch_columns(); ++i ) { // i is orignal patch index - - bool is_first_column = (i == 0); - bool is_last_column = (i == this->patch_columns() - 1 ); - //std::cout << " last column: " << smooth->patch_columns()/8 - 1 << " " << is_last_column << std::endl; - for( unsigned j = 0; j < smooth->patch_rows()+1; ++j ) { // j is smooth patch index - - // Can't use guint32 since delta can be negative - float pb[3]; // Point before patch - float p0[3]; // Point at start of patch - float p1[3]; // Point at end of patch - float pa[3]; // Point after patch - float result[3][8]; - sp_color_get_rgb_floatv( &smooth->nodes[ j*3 ][ i *3*8 ]->color, p0 ); - sp_color_get_rgb_floatv( &smooth->nodes[ j*3 ][ (i+1)*3*8 ]->color, p1 ); - - // Use linear distance to avoid calculation overhead of calculating true path length - Geom::Point *ptb = NULL; - Geom::Point *pt0 = &smooth->nodes[ j*3 ][ i *3*8 ]->p; - Geom::Point *pt1 = &smooth->nodes[ j*3 ][ (i+1)*3*8 ]->p; - Geom::Point *pta = NULL; - - double lb0 = 0.0; - double l01 = Geom::distance( *pt0, *pt1 ); - double l1a = 0.0; - - if( !is_first_column ) { - sp_color_get_rgb_floatv( &smooth->nodes[ j*3 ][ (i-1)*3*8 ]->color, pb ); - ptb = &smooth->nodes[ j*3 ][ (i-1)*3*8 ]->p; - lb0 = Geom::distance( *ptb, *pt0 ); - } else { - pb[0] = 2.0*p0[0] - p1[0]; - pb[1] = 2.0*p0[1] - p1[1]; - pb[2] = 2.0*p0[2] - p1[2]; - } - if( !is_last_column ) { - sp_color_get_rgb_floatv( &smooth->nodes[ j*3 ][ (i+2)*3*8 ]->color, pa ); - pta = &smooth->nodes[ j*3 ][ (i+2)*3*8 ]->p; - l1a = Geom::distance( *pt1, *pta ); - } else { - pa[0] = 2.0*p1[0] - p0[0]; - pa[1] = 2.0*p1[1] - p0[1]; - pa[2] = 2.0*p1[2] - p0[2]; - } - - for( unsigned n = 0; n < 3; ++n ) { // Loop over colors - - // We use Hermite interpolation. We have end points, we need tangents. - double m0 = 0; - double m1 = 0; - find_slopes( pb[n], p0[n], p1[n], pa[n], - lb0, l01, l1a, - is_first_column, is_last_column, type, m0, m1 ); - - for( unsigned k = 1; k < 8; ++k ) { - double t = k/8.0; - // Cubic Hermite (four constraints) - result[n][k] = hermite( p0[n], p1[n], m0, m1, t ); - // Clamp to allowed values - if( result[n][k] > 1.0 ) - result[n][k] = 1.0; - if( result[n][k] < 0.0 ) - result[n][k] = 0.0; - } - } - - for( unsigned k = 1; k < 8; ++k ) { - smooth->nodes[ j*3 ][ (i*8+k)*3 ]->color.set( result[0][k], result[1][k], result[2][k] ); - } - } - } -} class SPMeshSmoothCorner { @@ -1792,6 +1495,7 @@ double find_slope1( const double &p0, const double &p1, const double &p2, }; +/* // Find slope at point 0 given values at previous and next points // TO DO: TAKE DISTANCE BETWEEN POINTS INTO ACCOUNT double find_slope2( double pmm, double ppm, double pmp, double ppp, double p0 ) { @@ -1819,6 +1523,7 @@ double find_slope2( double pmm, double ppm, double pmp, double ppp, double p0 ) } return slope; } +*/ // https://en.wikipedia.org/wiki/Bicubic_interpolation void invert( const double v[16], double alpha[16] ) { @@ -1883,7 +1588,7 @@ double sum( const double alpha[16], const double& x, const double& y ) { /** Fill 'smooth' with a smoothed version of the array by subdividing each patch into smaller patches. */ -void SPMeshNodeArray::smooth2( SPMeshNodeArray* smooth, SPMeshSmooth type ) { +void SPMeshNodeArray::bicubic( SPMeshNodeArray* smooth, SPMeshType type ) { *smooth = *this; // Deep copy via copy assignment constructor, smooth cleared before copy @@ -1911,40 +1616,29 @@ void SPMeshNodeArray::smooth2( SPMeshNodeArray* smooth, SPMeshSmooth type ) { for( unsigned i = 0; i < d.size(); ++i ) { for( unsigned j = 0; j < d[i].size(); ++j ) { for( unsigned k = 0; k < 3; ++k ) { // Loop over colors - if( type == SP_MESH_SMOOTH_SMOOTH7 || type == SP_MESH_SMOOTH_SMOOTH ) { - // dx - if( i != 0 && i != d.size()-1 ) { - double lm = Geom::distance( d[i-1][j].p, d[i][j].p ); - double lp = Geom::distance( d[i+1][j].p, d[i][j].p ); - d[i][j].g[k][1] = find_slope1( d[i-1][j].g[k][0], d[i][j].g[k][0], d[i+1][j].g[k][0], lm, lp ); - } + // dx - // dy - if( j != 0 && j != d[i].size()-1 ) { - double lm = Geom::distance( d[i][j-1].p, d[i][j].p ); - double lp = Geom::distance( d[i][j+1].p, d[i][j].p ); - d[i][j].g[k][2] = find_slope1( d[i][j-1].g[k][0], d[i][j].g[k][0], d[i][j+1].g[k][0], lm, lp ); - } - - // dxdy if needed, need to take lengths into account - // if( i != 0 && i != d.size()-1 && j != 0 && j != d[i].size()-1 ) { - // d[i][j].g[k][3] = find_slope2( d[i-1][j-1].g[k][0], d[i+1][j-1].g[k][0], - // d[i-1][j+1].g[k][0], d[i-1][j-1].g[k][0], - // d[i][j].g[k][0] ); - // } + if( i != 0 && i != d.size()-1 ) { + double lm = Geom::distance( d[i-1][j].p, d[i][j].p ); + double lp = Geom::distance( d[i+1][j].p, d[i][j].p ); + d[i][j].g[k][1] = find_slope1( d[i-1][j].g[k][0], d[i][j].g[k][0], d[i+1][j].g[k][0], lm, lp ); + } - } else { - // Catmul-Rom - if( i != 0 && i != d.size()-1 ) { - double d2 = Geom::distance( d[i-1][j].p, d[i+1][j].p ); - d[i][j].g[k][1] = (d[i+1][j].g[k][0] - d[i-1][j].g[k][0])/d2; - } - if( j != 0 && j != d[i].size()-1 ) { - double d2 = Geom::distance( d[i][j-1].p, d[i][j+1].p ); - d[i][j].g[k][2] = (d[i][j+1].g[k][0] - d[i][j-1].g[k][0])/d2; - } + // dy + if( j != 0 && j != d[i].size()-1 ) { + double lm = Geom::distance( d[i][j-1].p, d[i][j].p ); + double lp = Geom::distance( d[i][j+1].p, d[i][j].p ); + d[i][j].g[k][2] = find_slope1( d[i][j-1].g[k][0], d[i][j].g[k][0], d[i][j+1].g[k][0], lm, lp ); } + + // dxdy if needed, need to take lengths into account + // if( i != 0 && i != d.size()-1 && j != 0 && j != d[i].size()-1 ) { + // d[i][j].g[k][3] = find_slope2( d[i-1][j-1].g[k][0], d[i+1][j-1].g[k][0], + // d[i-1][j+1].g[k][0], d[i-1][j-1].g[k][0], + // d[i][j].g[k][0] ); + // } + } } } @@ -1954,80 +1648,42 @@ void SPMeshNodeArray::smooth2( SPMeshNodeArray* smooth, SPMeshSmooth type ) { // have the non-exterior derivative calculated for finding the parabola. for( unsigned j = 0; j< d[0].size(); ++j ) { for( unsigned k = 0; k < 3; ++k ) { // Loop over colors - unsigned z = d.size()-1; - if( type == SP_MESH_SMOOTH_SMOOTH7 || type == SP_MESH_SMOOTH_SMOOTH ) { - - // Parabolic - double d0 = Geom::distance( d[1][j].p, d[0 ][j].p ); - if( d0 > 0 ) { - d[0][j].g[k][1] = 2.0*(d[1][j].g[k][0] - d[0 ][j].g[k][0])/d0 - d[1][j].g[k][1]; - } else { - d[0][j].g[k][1] = 0; - } - - double dz = Geom::distance( d[z][j].p, d[z-1][j].p ); - if( dz > 0 ) { - d[z][j].g[k][1] = 2.0*(d[z][j].g[k][0] - d[z-1][j].g[k][0])/dz - d[z-1][j].g[k][1]; - } else { - d[z][j].g[k][1] = 0; - } + // Parabolic + double d0 = Geom::distance( d[1][j].p, d[0 ][j].p ); + if( d0 > 0 ) { + d[0][j].g[k][1] = 2.0*(d[1][j].g[k][0] - d[0 ][j].g[k][0])/d0 - d[1][j].g[k][1]; } else { + d[0][j].g[k][1] = 0; + } - // Catmul-Rom - double d0 = Geom::distance( d[1][j].p, d[0 ][j].p ); - if( d0 > 0 ) { - d[0][j].g[k][1] = (d[1][j].g[k][0] - d[0 ][j].g[k][0])/d0; - } else { - d[0][j].g[k][1] = 0; - } - - double dz = Geom::distance( d[z][j].p, d[z-1][j].p ); - if( dz > 0 ) { - d[z][j].g[k][1] = (d[z][j].g[k][0] - d[z-1][j].g[k][0])/dz; - } else { - d[z][j].g[k][1] = 0; - } + unsigned z = d.size()-1; + double dz = Geom::distance( d[z][j].p, d[z-1][j].p ); + if( dz > 0 ) { + d[z][j].g[k][1] = 2.0*(d[z][j].g[k][0] - d[z-1][j].g[k][0])/dz - d[z-1][j].g[k][1]; + } else { + d[z][j].g[k][1] = 0; } } } for( unsigned i = 0; i< d.size(); ++i ) { for( unsigned k = 0; k < 3; ++k ) { // Loop over colors - unsigned z = d[0].size()-1; - if( type == SP_MESH_SMOOTH_SMOOTH7 || type == SP_MESH_SMOOTH_SMOOTH ) { - - // Parabolic - double d0 = Geom::distance( d[i][1].p, d[i][0 ].p ); - if( d0 > 0 ) { - d[i][0].g[k][2] = 2.0*(d[i][1].g[k][0] - d[i][0 ].g[k][0])/d0 - d[i][1].g[k][2]; - } else { - d[i][0].g[k][2] = 0; - } - double dz = Geom::distance( d[i][z].p, d[i][z-1].p ); - if( dz > 0 ) { - d[i][z].g[k][2] = 2.0*(d[i][z].g[k][0] - d[i][z-1].g[k][0])/dz - d[i][z-1].g[k][2]; - } else { - d[i][z].g[k][2] = 0; - } - + // Parabolic + double d0 = Geom::distance( d[i][1].p, d[i][0 ].p ); + if( d0 > 0 ) { + d[i][0].g[k][2] = 2.0*(d[i][1].g[k][0] - d[i][0 ].g[k][0])/d0 - d[i][1].g[k][2]; } else { + d[i][0].g[k][2] = 0; + } - // Catmul-Rom - double d0 = Geom::distance( d[i][1].p, d[i][0 ].p ); - if( d0 > 0 ) { - d[i][0].g[k][2] = (d[i][1].g[k][0] - d[i][0 ].g[k][0])/d0; - } else { - d[i][0].g[k][2] = 0; - } - - double dz = Geom::distance( d[i][z].p, d[i][z-1].p ); - if( dz > 0 ) { - d[i][z].g[k][2] = (d[i][z].g[k][0] - d[i][z-1].g[k][0])/dz; - } else { - d[i][z].g[k][2] = 0; - } + unsigned z = d[0].size()-1; + double dz = Geom::distance( d[i][z].p, d[i][z-1].p ); + if( dz > 0 ) { + d[i][z].g[k][2] = 2.0*(d[i][z].g[k][0] - d[i][z-1].g[k][0])/dz - d[i][z-1].g[k][2]; + } else { + d[i][z].g[k][2] = 0; } } } @@ -2964,7 +2620,7 @@ guint32 average_color(guint32 c1, guint32 c2, gdouble p); /** Split a row into n equal parts. */ -void SPMeshNodeArray::split_row( guint row, guint n ) { +void SPMeshNodeArray::split_row( unsigned int row, unsigned int n ) { double nn = n; if( n > 1 ) split_row( row, (nn-1)/nn ); @@ -2974,7 +2630,7 @@ void SPMeshNodeArray::split_row( guint row, guint n ) { /** Split a column into n equal parts. */ -void SPMeshNodeArray::split_column( guint col, guint n ) { +void SPMeshNodeArray::split_column( unsigned int col, unsigned int n ) { double nn = n; if( n > 1 ) split_column( col, (nn-1)/nn ); @@ -2984,7 +2640,7 @@ void SPMeshNodeArray::split_column( guint col, guint n ) { /** Split a row into two rows at coord (fraction of row height). */ -void SPMeshNodeArray::split_row( guint row, double coord ) { +void SPMeshNodeArray::split_row( unsigned int row, double coord ) { // std::cout << "Splitting row: " << row << " at " << coord << std::endl; // print(); @@ -3107,7 +2763,7 @@ void SPMeshNodeArray::split_row( guint row, double coord ) { /** Split a column into two columns at coord (fraction of column width). */ -void SPMeshNodeArray::split_column( guint col, double coord ) { +void SPMeshNodeArray::split_column( unsigned int col, double coord ) { // std::cout << "Splitting column: " << col << " at " << coord << std::endl; // print(); diff --git a/src/sp-mesh-array.h b/src/sp-mesh-array.h index 19f8634f8..b078b221e 100644 --- a/src/sp-mesh-array.h +++ b/src/sp-mesh-array.h @@ -45,16 +45,14 @@ // For color picking #include "sp-item.h" -enum SPMeshSmooth { - SP_MESH_SMOOTH_NONE, - SP_MESH_SMOOTH_SMOOTH, - SP_MESH_SMOOTH_SMOOTH1, - SP_MESH_SMOOTH_SMOOTH2, - SP_MESH_SMOOTH_SMOOTH3, - SP_MESH_SMOOTH_SMOOTH4, - SP_MESH_SMOOTH_SMOOTH5, - SP_MESH_SMOOTH_SMOOTH6, - SP_MESH_SMOOTH_SMOOTH7 +enum SPMeshType { + SP_MESH_TYPE_COONS, + SP_MESH_TYPE_BICUBIC +}; + +enum SPMeshGeometry { + SP_MESH_GEOMETRY_NORMAL, + SP_MESH_GEOMETRY_CONICAL }; enum NodeType { @@ -137,14 +135,14 @@ public: void setOpacity( unsigned int i, double o ); }; -class SPMeshGradient; +class SPMesh; // An array of mesh nodes. class SPMeshNodeArray { // Should be private public: - SPMeshGradient *mg; + SPMesh *mg; std::vector< std::vector< SPMeshNode* > > nodes; public: @@ -159,22 +157,21 @@ public: friend class SPMeshPatchI; SPMeshNodeArray() { built = false; mg = NULL; drag_valid = false; }; - SPMeshNodeArray( SPMeshGradient *mg ); + SPMeshNodeArray( SPMesh *mg ); SPMeshNodeArray( const SPMeshNodeArray& rhs ); SPMeshNodeArray& operator=(const SPMeshNodeArray& rhs); ~SPMeshNodeArray() { clear(); }; bool built; - void read( SPMeshGradient *mg ); - void write( SPMeshGradient *mg ); - void create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bbox ); + void read( SPMesh *mg ); + void write( SPMesh *mg ); + void create( SPMesh *mg, SPItem *item, Geom::OptRect bbox ); void clear(); void print(); // Fill 'smooth' with a smoothed version by subdividing each patch. - void smooth( SPMeshNodeArray* smooth, SPMeshSmooth type); - void smooth2( SPMeshNodeArray* smooth, SPMeshSmooth type); + void bicubic( SPMeshNodeArray* smooth, SPMeshType type); // Get size of patch unsigned int patch_rows(); diff --git a/src/sp-mesh-gradient.cpp b/src/sp-mesh-gradient.cpp deleted file mode 100644 index 3301d257c..000000000 --- a/src/sp-mesh-gradient.cpp +++ /dev/null @@ -1,299 +0,0 @@ -#include <glibmm.h> - -#include "attributes.h" -#include "display/cairo-utils.h" -#include "xml/repr.h" - -#include "sp-mesh-gradient.h" - -/* - * Mesh Gradient - */ -//#define MESH_DEBUG -SPMeshGradient::SPMeshGradient() : SPGradient(), smooth(SP_MESH_SMOOTH_NONE), smooth_set(false) { - // Start coordinate of mesh - this->x.unset(SVGLength::NONE, 0.0, 0.0); - this->y.unset(SVGLength::NONE, 0.0, 0.0); -} - -SPMeshGradient::~SPMeshGradient() { -} - -void SPMeshGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { - SPGradient::build(document, repr); - - // Start coordinate of mesh - this->readAttr( "x" ); - this->readAttr( "y" ); - - this->readAttr( "smooth" ); -} - - -void SPMeshGradient::set(unsigned key, gchar const *value) { - switch (key) { - case SP_ATTR_X: - if (!this->x.read(value)) { - this->x.unset(SVGLength::NONE, 0.0, 0.0); - } - - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_Y: - if (!this->y.read(value)) { - this->y.unset(SVGLength::NONE, 0.0, 0.0); - } - - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_SMOOTH: - if (value) { - if (!strcmp(value, "none")) { - this->smooth = SP_MESH_SMOOTH_NONE; - } else if (!strcmp(value, "smooth")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH; - } else if (!strcmp(value, "smooth1")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH1; - } else if (!strcmp(value, "smooth2")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH2; - } else if (!strcmp(value, "smooth3")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH3; - } else if (!strcmp(value, "smooth4")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH4; - } else if (!strcmp(value, "smooth5")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH5; - } else if (!strcmp(value, "smooth6")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH6; - } else if (!strcmp(value, "smooth7")) { - this->smooth = SP_MESH_SMOOTH_SMOOTH7; - } else { - std::cout << "SPMeshGradient::set(): invalid value " << value << std::endl; - } - this->smooth_set = TRUE; - } else { - // std::cout << "SPMeshGradient::set() No value " << std::endl; - this->smooth = SP_MESH_SMOOTH_NONE; - this->smooth_set = FALSE; - } - - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - default: - SPGradient::set(key, value); - break; - } -} - -/** - * Write mesh gradient attributes to associated repr. - */ -Inkscape::XML::Node* SPMeshGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { -#ifdef MESH_DEBUG - std::cout << "sp_meshgradient_write() ***************************" << std::endl; -#endif - - if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:meshGradient"); - } - - if ((flags & SP_OBJECT_WRITE_ALL) || this->x._set) { - sp_repr_set_svg_double(repr, "x", this->x.computed); - } - - if ((flags & SP_OBJECT_WRITE_ALL) || this->y._set) { - sp_repr_set_svg_double(repr, "y", this->y.computed); - } - - if ((flags & SP_OBJECT_WRITE_ALL) || this->smooth_set) { - switch (this->smooth) { - case SP_MESH_SMOOTH_SMOOTH: - repr->setAttribute("smooth", "smooth"); - break; - case SP_MESH_SMOOTH_SMOOTH1: - repr->setAttribute("smooth", "smooth1"); - break; - case SP_MESH_SMOOTH_SMOOTH2: - repr->setAttribute("smooth", "smooth2"); - break; - case SP_MESH_SMOOTH_SMOOTH3: - repr->setAttribute("smooth", "smooth3"); - break; - case SP_MESH_SMOOTH_SMOOTH4: - repr->setAttribute("smooth", "smooth4"); - break; - case SP_MESH_SMOOTH_SMOOTH5: - repr->setAttribute("smooth", "smooth5"); - break; - case SP_MESH_SMOOTH_SMOOTH6: - repr->setAttribute("smooth", "smooth6"); - break; - case SP_MESH_SMOOTH_SMOOTH7: - repr->setAttribute("smooth", "smooth7"); - break; - case SP_MESH_SMOOTH_NONE: - repr->setAttribute("smooth", "none"); - break; - default: - // Do nothing - break; - } - } - - SPGradient::write(xml_doc, repr, flags); - - return repr; -} - -void -sp_meshgradient_repr_write(SPMeshGradient *mg) -{ - mg->array.write( mg ); -} - - -cairo_pattern_t* SPMeshGradient::pattern_new(cairo_t * /*ct*/, -#if defined(MESH_DEBUG) || (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4)) - Geom::OptRect const &bbox, - double opacity -#else - Geom::OptRect const & /*bbox*/, - double /*opacity*/ -#endif - ) -{ - using Geom::X; - using Geom::Y; - -#ifdef MESH_DEBUG - std::cout << "sp_meshgradient_create_pattern: (" << bbox->x0 << "," << bbox->y0 << ") (" << bbox->x1 << "," << bbox->y1 << ") " << opacity << std::endl; -#endif - - this->ensureArray(); - - cairo_pattern_t *cp = NULL; - -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4) - SPMeshNodeArray* my_array = &array; - - if( smooth_set ) { - switch (smooth) { - case SP_MESH_SMOOTH_NONE: - // std::cout << "SPMeshGradient::pattern_new: no smoothing" << std::endl; - break; - case SP_MESH_SMOOTH_SMOOTH1: - case SP_MESH_SMOOTH_SMOOTH2: - case SP_MESH_SMOOTH_SMOOTH3: - case SP_MESH_SMOOTH_SMOOTH4: - case SP_MESH_SMOOTH_SMOOTH5: - // std::cout << "SPMeshGradient::pattern_new: calling array.smooth" << std::endl; - array.smooth( &array_smoothed, smooth ); - my_array = &array_smoothed; - break; - case SP_MESH_SMOOTH_SMOOTH: - case SP_MESH_SMOOTH_SMOOTH6: - case SP_MESH_SMOOTH_SMOOTH7: - // std::cout << "SPMeshGradient::pattern_new: calling array.smooth2" << std::endl; - array.smooth2( &array_smoothed, smooth ); - my_array = &array_smoothed; - break; - } - } - - cp = cairo_pattern_create_mesh(); - - for( unsigned int i = 0; i < my_array->patch_rows(); ++i ) { - for( unsigned int j = 0; j < my_array->patch_columns(); ++j ) { - - SPMeshPatchI patch( &(my_array->nodes), i, j ); - - cairo_mesh_pattern_begin_patch( cp ); - cairo_mesh_pattern_move_to( cp, patch.getPoint( 0, 0 )[X], patch.getPoint( 0, 0 )[Y] ); - - for( unsigned int k = 0; k < 4; ++k ) { -#ifdef DEBUG_MESH - std::cout << i << " " << j << " " - << patch.getPathType( k ) << " ("; - for( int p = 0; p < 4; ++p ) { - std::cout << patch.getPoint( k, p ); - } - std::cout << ") " - << patch.getColor( k ).toString() << std::endl; -#endif - - switch ( patch.getPathType( k ) ) { - case 'l': - case 'L': - case 'z': - case 'Z': - cairo_mesh_pattern_line_to( cp, - patch.getPoint( k, 3 )[X], - patch.getPoint( k, 3 )[Y] ); - break; - case 'c': - case 'C': - { - std::vector< Geom::Point > pts = patch.getPointsForSide( k ); - cairo_mesh_pattern_curve_to( cp, - pts[1][X], pts[1][Y], - pts[2][X], pts[2][Y], - pts[3][X], pts[3][Y] ); - break; - } - default: - // Shouldn't happen - std::cout << "sp_meshgradient_create_pattern: path error" << std::endl; - } - - if( patch.tensorIsSet(k) ) { - // Tensor point defined relative to corner. - Geom::Point t = patch.getTensorPoint(k); - cairo_mesh_pattern_set_control_point( cp, k, t[X], t[Y] ); - //std::cout << " sp_meshgradient_create_pattern: tensor " << k - // << " set to " << t << "." << std::endl; - } else { - // Geom::Point t = patch.coonsTensorPoint(k); - //std::cout << " sp_meshgradient_create_pattern: tensor " << k - // << " calculated as " << t << "." <<std::endl; - } - - cairo_mesh_pattern_set_corner_color_rgba( - cp, k, - patch.getColor( k ).v.c[0], - patch.getColor( k ).v.c[1], - patch.getColor( k ).v.c[2], - patch.getOpacity( k ) * opacity ); - } - - cairo_mesh_pattern_end_patch( cp ); - } - } - - // set pattern matrix - Geom::Affine gs2user = this->gradientTransform; - if (this->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); - gs2user *= bbox2user; - } - ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); - -#else - static bool shown = false; - if( !shown ) { - std::cout << "sp_meshgradient_create_pattern: needs cairo >= 1.11.4, using " - << cairo_version_string() << std::endl; - shown = true; - } -#endif - -/* - cairo_pattern_t *cp = cairo_pattern_create_radial( - rg->fx.computed, rg->fy.computed, 0, - rg->cx.computed, rg->cy.computed, rg->r.computed); - sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); -*/ - - return cp; -} diff --git a/src/sp-mesh-patch.cpp b/src/sp-mesh-patch.cpp index e7c7c837d..834c09935 100644 --- a/src/sp-mesh-patch.cpp +++ b/src/sp-mesh-patch.cpp @@ -20,9 +20,9 @@ #include "attributes.h" #include "xml/repr.h" -SPMeshPatch* SPMeshPatch::getNextMeshPatch() +SPMeshpatch* SPMeshpatch::getNextMeshpatch() { - SPMeshPatch *result = 0; + SPMeshpatch *result = 0; for (SPObject* obj = getNext(); obj && !result; obj = obj->getNext()) { if (SP_IS_MESHPATCH(obj)) { @@ -33,19 +33,19 @@ SPMeshPatch* SPMeshPatch::getNextMeshPatch() return result; } -SPMeshPatch* SPMeshPatch::getPrevMeshPatch() +SPMeshpatch* SPMeshpatch::getPrevMeshpatch() { - SPMeshPatch *result = 0; + SPMeshpatch *result = 0; for (SPObject* obj = getPrev(); obj; obj = obj->getPrev()) { - // The closest previous SPObject that is an SPMeshPatch *should* be ourself. + // The closest previous SPObject that is an SPMeshpatch *should* be ourself. if (SP_IS_MESHPATCH(obj)) { - SPMeshPatch* meshpatch = SP_MESHPATCH(obj); + SPMeshpatch* meshpatch = SP_MESHPATCH(obj); // Sanity check to ensure we have a proper sibling structure. - if (meshpatch->getNextMeshPatch() == this) { + if (meshpatch->getNextMeshpatch() == this) { result = meshpatch; } else { - g_warning("SPMeshPatch previous/next relationship broken"); + g_warning("SPMeshpatch previous/next relationship broken"); } break; } @@ -59,14 +59,14 @@ SPMeshPatch* SPMeshPatch::getPrevMeshPatch() * Mesh Patch */ -SPMeshPatch::SPMeshPatch() : SPObject() { +SPMeshpatch::SPMeshpatch() : SPObject() { this->tensor_string = NULL; } -SPMeshPatch::~SPMeshPatch() { +SPMeshpatch::~SPMeshpatch() { } -void SPMeshPatch::build(SPDocument* doc, Inkscape::XML::Node* repr) { +void SPMeshpatch::build(SPDocument* doc, Inkscape::XML::Node* repr) { SPObject::build(doc, repr); this->readAttr( "tensor" ); @@ -76,7 +76,7 @@ void SPMeshPatch::build(SPDocument* doc, Inkscape::XML::Node* repr) { * Virtual build: set meshpatch attributes from its associated XML node. */ -void SPMeshPatch::set(unsigned int key, const gchar* value) { +void SPMeshpatch::set(unsigned int key, const gchar* value) { switch (key) { case SP_ATTR_TENSOR: { if (value) { @@ -95,9 +95,9 @@ void SPMeshPatch::set(unsigned int key, const gchar* value) { * Virtual set: set attribute to value. */ -Inkscape::XML::Node* SPMeshPatch::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { +Inkscape::XML::Node* SPMeshpatch::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:meshPatch"); + repr = xml_doc->createElement("svg:meshpatch"); } SPObject::write(xml_doc, repr, flags); diff --git a/src/sp-mesh-patch.h b/src/sp-mesh-patch.h index e57ad1699..88d6325c3 100644 --- a/src/sp-mesh-patch.h +++ b/src/sp-mesh-patch.h @@ -2,7 +2,7 @@ #define SEEN_SP_MESHPATCH_H /** \file - * SPMeshPatch: SVG <meshpatch> implementation. + * SPMeshpatch: SVG <meshpatch> implementation. */ /* * Authors: Tavmjong Bah @@ -15,17 +15,17 @@ #include <glibmm/ustring.h> #include "sp-object.h" -#define SP_MESHPATCH(obj) (dynamic_cast<SPMeshPatch*>((SPObject*)obj)) -#define SP_IS_MESHPATCH(obj) (dynamic_cast<const SPMeshPatch*>((SPObject*)obj) != NULL) +#define SP_MESHPATCH(obj) (dynamic_cast<SPMeshpatch*>((SPObject*)obj)) +#define SP_IS_MESHPATCH(obj) (dynamic_cast<const SPMeshpatch*>((SPObject*)obj) != NULL) -/** Gradient MeshPatch. */ -class SPMeshPatch : public SPObject { +/** Gradient Meshpatch. */ +class SPMeshpatch : public SPObject { public: - SPMeshPatch(); - virtual ~SPMeshPatch(); + SPMeshpatch(); + virtual ~SPMeshpatch(); - SPMeshPatch* getNextMeshPatch(); - SPMeshPatch* getPrevMeshPatch(); + SPMeshpatch* getNextMeshpatch(); + SPMeshpatch* getPrevMeshpatch(); Glib::ustring * tensor_string; //SVGLength tx[4]; // Tensor points //SVGLength ty[4]; // Tensor points diff --git a/src/sp-mesh-row.cpp b/src/sp-mesh-row.cpp index f95909b63..dd7948bdf 100644 --- a/src/sp-mesh-row.cpp +++ b/src/sp-mesh-row.cpp @@ -1,5 +1,5 @@ /** @file - * @gradient meshpatch class. + * @gradient meshrow class. */ /* Authors: * Lauris Kaplinski <lauris@kaplinski.com> @@ -19,9 +19,9 @@ #include "xml/repr.h" -SPMeshRow* SPMeshRow::getNextMeshRow() +SPMeshrow* SPMeshrow::getNextMeshrow() { - SPMeshRow *result = 0; + SPMeshrow *result = 0; for (SPObject* obj = getNext(); obj && !result; obj = obj->getNext()) { if (SP_IS_MESHROW(obj)) { @@ -32,19 +32,19 @@ SPMeshRow* SPMeshRow::getNextMeshRow() return result; } -SPMeshRow* SPMeshRow::getPrevMeshRow() +SPMeshrow* SPMeshrow::getPrevMeshrow() { - SPMeshRow *result = 0; + SPMeshrow *result = 0; for (SPObject* obj = getPrev(); obj; obj = obj->getPrev()) { - // The closest previous SPObject that is an SPMeshRow *should* be ourself. + // The closest previous SPObject that is an SPMeshrow *should* be ourself. if (SP_IS_MESHROW(obj)) { - SPMeshRow* meshrow = SP_MESHROW(obj); + SPMeshrow* meshrow = SP_MESHROW(obj); // Sanity check to ensure we have a proper sibling structure. - if (meshrow->getNextMeshRow() == this) { + if (meshrow->getNextMeshrow() == this) { result = meshrow; } else { - g_warning("SPMeshRow previous/next relationship broken"); + g_warning("SPMeshrow previous/next relationship broken"); } break; } @@ -57,13 +57,13 @@ SPMeshRow* SPMeshRow::getPrevMeshRow() /* * Mesh Row */ -SPMeshRow::SPMeshRow() : SPObject() { +SPMeshrow::SPMeshrow() : SPObject() { } -SPMeshRow::~SPMeshRow() { +SPMeshrow::~SPMeshrow() { } -void SPMeshRow::build(SPDocument* doc, Inkscape::XML::Node* repr) { +void SPMeshrow::build(SPDocument* doc, Inkscape::XML::Node* repr) { SPObject::build(doc, repr); } @@ -71,16 +71,16 @@ void SPMeshRow::build(SPDocument* doc, Inkscape::XML::Node* repr) { * Virtual build: set meshrow attributes from its associated XML node. */ -void SPMeshRow::set(unsigned int /*key*/, const gchar* /*value*/) { +void SPMeshrow::set(unsigned int /*key*/, const gchar* /*value*/) { } /** * Virtual set: set attribute to value. */ -Inkscape::XML::Node* SPMeshRow::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { +Inkscape::XML::Node* SPMeshrow::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - repr = xml_doc->createElement("svg:meshRow"); + repr = xml_doc->createElement("svg:meshrow"); } SPObject::write(xml_doc, repr, flags); diff --git a/src/sp-mesh-row.h b/src/sp-mesh-row.h index 793b5a645..ffb3efa6b 100644 --- a/src/sp-mesh-row.h +++ b/src/sp-mesh-row.h @@ -2,7 +2,7 @@ #define SEEN_SP_MESHROW_H /** \file - * SPMeshRow: SVG <meshRow> implementation. + * SPMeshrow: SVG <meshrow> implementation. */ /* * Authors: Tavmjong Bah @@ -13,17 +13,17 @@ #include "sp-object.h" -#define SP_MESHROW(obj) (dynamic_cast<SPMeshRow*>((SPObject*)obj)) -#define SP_IS_MESHROW(obj) (dynamic_cast<const SPMeshRow*>((SPObject*)obj) != NULL) +#define SP_MESHROW(obj) (dynamic_cast<SPMeshrow*>((SPObject*)obj)) +#define SP_IS_MESHROW(obj) (dynamic_cast<const SPMeshrow*>((SPObject*)obj) != NULL) -/** Gradient MeshRow. */ -class SPMeshRow : public SPObject { +/** Gradient Meshrow. */ +class SPMeshrow : public SPObject { public: - SPMeshRow(); - virtual ~SPMeshRow(); + SPMeshrow(); + virtual ~SPMeshrow(); - SPMeshRow* getNextMeshRow(); - SPMeshRow* getPrevMeshRow(); + SPMeshrow* getNextMeshrow(); + SPMeshrow* getPrevMeshrow(); protected: virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); diff --git a/src/sp-mesh.cpp b/src/sp-mesh.cpp new file mode 100644 index 000000000..e04c29e8e --- /dev/null +++ b/src/sp-mesh.cpp @@ -0,0 +1,252 @@ +#include <glibmm.h> + +#include "attributes.h" +#include "display/cairo-utils.h" +#include "xml/repr.h" + +#include "sp-mesh.h" + +/* + * Mesh Gradient + */ +//#define MESH_DEBUG +SPMesh::SPMesh() : SPGradient(), type( SP_MESH_TYPE_COONS ), type_set(false) { + // Start coordinate of mesh + this->x.unset(SVGLength::NONE, 0.0, 0.0); + this->y.unset(SVGLength::NONE, 0.0, 0.0); +} + +SPMesh::~SPMesh() { +} + +void SPMesh::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPGradient::build(document, repr); + + // Start coordinate of mesh + this->readAttr( "x" ); + this->readAttr( "y" ); + + this->readAttr( "type" ); +} + + +void SPMesh::set(unsigned key, gchar const *value) { + switch (key) { + case SP_ATTR_X: + if (!this->x.read(value)) { + this->x.unset(SVGLength::NONE, 0.0, 0.0); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_Y: + if (!this->y.read(value)) { + this->y.unset(SVGLength::NONE, 0.0, 0.0); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_TYPE: + if (value) { + if (!strcmp(value, "coons")) { + this->type = SP_MESH_TYPE_COONS; + } else if (!strcmp(value, "bicubic")) { + this->type = SP_MESH_TYPE_BICUBIC; + } else { + std::cerr << "SPMesh::set(): invalid value " << value << std::endl; + } + this->type_set = TRUE; + } else { + // std::cout << "SPMesh::set() No value " << std::endl; + this->type = SP_MESH_TYPE_COONS; + this->type_set = FALSE; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + default: + SPGradient::set(key, value); + break; + } +} + +/** + * Write mesh gradient attributes to associated repr. + */ +Inkscape::XML::Node* SPMesh::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { +#ifdef MESH_DEBUG + std::cout << "sp_mesh_write() ***************************" << std::endl; +#endif + + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:mesh"); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->x._set) { + sp_repr_set_svg_double(repr, "x", this->x.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->y._set) { + sp_repr_set_svg_double(repr, "y", this->y.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->type_set) { + switch (this->type) { + case SP_MESH_TYPE_COONS: + repr->setAttribute("type", "coons"); + break; + case SP_MESH_TYPE_BICUBIC: + repr->setAttribute("type", "bicubic"); + break; + default: + // Do nothing + break; + } + } + + SPGradient::write(xml_doc, repr, flags); + + return repr; +} + +void +sp_mesh_repr_write(SPMesh *mg) +{ + mg->array.write( mg ); +} + + +cairo_pattern_t* SPMesh::pattern_new(cairo_t * /*ct*/, +#if defined(MESH_DEBUG) || (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4)) + Geom::OptRect const &bbox, + double opacity +#else + Geom::OptRect const & /*bbox*/, + double /*opacity*/ +#endif + ) +{ + using Geom::X; + using Geom::Y; + +#ifdef MESH_DEBUG + std::cout << "sp_mesh_create_pattern: (" << bbox->x0 << "," << bbox->y0 << ") (" << bbox->x1 << "," << bbox->y1 << ") " << opacity << std::endl; +#endif + + this->ensureArray(); + + cairo_pattern_t *cp = NULL; + +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 4) + SPMeshNodeArray* my_array = &array; + + if( type_set ) { + switch (type) { + case SP_MESH_TYPE_COONS: + // std::cout << "SPMesh::pattern_new: Coons" << std::endl; + break; + case SP_MESH_TYPE_BICUBIC: + array.bicubic( &array_smoothed, type ); + my_array = &array_smoothed; + break; + } + } + + cp = cairo_pattern_create_mesh(); + + for( unsigned int i = 0; i < my_array->patch_rows(); ++i ) { + for( unsigned int j = 0; j < my_array->patch_columns(); ++j ) { + + SPMeshPatchI patch( &(my_array->nodes), i, j ); + + cairo_mesh_pattern_begin_patch( cp ); + cairo_mesh_pattern_move_to( cp, patch.getPoint( 0, 0 )[X], patch.getPoint( 0, 0 )[Y] ); + + for( unsigned int k = 0; k < 4; ++k ) { +#ifdef DEBUG_MESH + std::cout << i << " " << j << " " + << patch.getPathType( k ) << " ("; + for( int p = 0; p < 4; ++p ) { + std::cout << patch.getPoint( k, p ); + } + std::cout << ") " + << patch.getColor( k ).toString() << std::endl; +#endif + + switch ( patch.getPathType( k ) ) { + case 'l': + case 'L': + case 'z': + case 'Z': + cairo_mesh_pattern_line_to( cp, + patch.getPoint( k, 3 )[X], + patch.getPoint( k, 3 )[Y] ); + break; + case 'c': + case 'C': + { + std::vector< Geom::Point > pts = patch.getPointsForSide( k ); + cairo_mesh_pattern_curve_to( cp, + pts[1][X], pts[1][Y], + pts[2][X], pts[2][Y], + pts[3][X], pts[3][Y] ); + break; + } + default: + // Shouldn't happen + std::cout << "sp_mesh_create_pattern: path error" << std::endl; + } + + if( patch.tensorIsSet(k) ) { + // Tensor point defined relative to corner. + Geom::Point t = patch.getTensorPoint(k); + cairo_mesh_pattern_set_control_point( cp, k, t[X], t[Y] ); + //std::cout << " sp_mesh_create_pattern: tensor " << k + // << " set to " << t << "." << std::endl; + } else { + // Geom::Point t = patch.coonsTensorPoint(k); + //std::cout << " sp_mesh_create_pattern: tensor " << k + // << " calculated as " << t << "." <<std::endl; + } + + cairo_mesh_pattern_set_corner_color_rgba( + cp, k, + patch.getColor( k ).v.c[0], + patch.getColor( k ).v.c[1], + patch.getColor( k ).v.c[2], + patch.getOpacity( k ) * opacity ); + } + + cairo_mesh_pattern_end_patch( cp ); + } + } + + // set pattern matrix + Geom::Affine gs2user = this->gradientTransform; + if (this->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { + Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); + gs2user *= bbox2user; + } + ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); + +#else + static bool shown = false; + if( !shown ) { + std::cout << "sp_mesh_create_pattern: needs cairo >= 1.11.4, using " + << cairo_version_string() << std::endl; + shown = true; + } +#endif + + /* + cairo_pattern_t *cp = cairo_pattern_create_radial( + rg->fx.computed, rg->fy.computed, 0, + rg->cx.computed, rg->cy.computed, rg->r.computed); + sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); + */ + + return cp; +} diff --git a/src/sp-mesh-gradient.h b/src/sp-mesh.h index 343cae840..6f992d034 100644 --- a/src/sp-mesh-gradient.h +++ b/src/sp-mesh.h @@ -1,26 +1,26 @@ -#ifndef SP_MESH_GRADIENT_H -#define SP_MESH_GRADIENT_H +#ifndef SP_MESH_H +#define SP_MESH_H /** \file - * SPMeshGradient: SVG <meshgradient> implementation. + * SPMesh: SVG <mesh> implementation. */ #include "svg/svg-length.h" #include "sp-gradient.h" -#define SP_MESHGRADIENT(obj) (dynamic_cast<SPMeshGradient*>((SPObject*)obj)) -#define SP_IS_MESHGRADIENT(obj) (dynamic_cast<const SPMeshGradient*>((SPObject*)obj) != NULL) +#define SP_MESH(obj) (dynamic_cast<SPMesh*>((SPObject*)obj)) +#define SP_IS_MESH(obj) (dynamic_cast<const SPMesh*>((SPObject*)obj) != NULL) /** Mesh gradient. */ -class SPMeshGradient : public SPGradient { +class SPMesh : public SPGradient { public: - SPMeshGradient(); - virtual ~SPMeshGradient(); + SPMesh(); + virtual ~SPMesh(); SVGLength x; // Upper left corner of mesh SVGLength y; // Upper right corner of mesh - SPMeshSmooth smooth; - bool smooth_set; + SPMeshType type; + bool type_set; virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); protected: @@ -29,7 +29,7 @@ protected: virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); }; -#endif /* !SP_MESH_GRADIENT_H */ +#endif /* !SP_MESH_H */ /* Local Variables: diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index c26eff39f..3154c9e7b 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -261,6 +261,8 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { Geom::Rect viewbox = document->getRoot()->viewBox; double factor = svgwidth.value(unit_table.primary(Inkscape::Util::UNIT_TYPE_LINEAR)) / viewbox.width(); svg_units = unit_table.findUnit(factor, Inkscape::Util::UNIT_TYPE_LINEAR); + } else { // force the document units to be px + repr->setAttribute("inkscape:document-units", "px"); } } @@ -551,7 +553,7 @@ void SPNamedView::set(unsigned int key, const gchar* value) { static Inkscape::Util::Unit const *px = unit_table.getUnit("px"); Inkscape::Util::Unit const *new_unit = px; - if (value) { + if (value && document->getRoot()->viewBox_set) { Inkscape::Util::Unit const *const req_unit = unit_table.getUnit(value); if ( !unit_table.hasUnit(value) ) { g_warning("Unrecognized unit `%s'", value); diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 51cc8d6dc..42883588b 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -130,10 +130,29 @@ void SPPath::build(SPDocument *document, Inkscape::XML::Node *repr) { SPShape::build(document, repr); - // this->readAttr( "inkscape:original-d" ); // lp1299948 + // this->readAttr( "inkscape:original-d" ); // bug #1299948 + // Why we take the long way of doing this probably needs some explaining: + // + // Normally upon being built, reading the inkscape:original-d attribute + // will cause the path to actually _write to its repr_ in response to this. + // This is bad, bad news if the attached effect refers to a path which + // hasn't been constructed yet. + // + // What will happen is the effect parameter will cause the effect to + // recalculate with a completely different value due to the parameter being + // "empty" -- even worse, an undo event might be created with the bad value, + // and undoing the current action could cause it to revert to the "bad" + // state. (After that, the referred object will be constructed and the + // reference will trigger the path effect to update and commit the right + // value to "d".) + // + // This mild nastiness here (don't recalculate effects on build) prevents a + // plethora of issues with effects with linked parameters doing wild and + // stupid things on new documents upon a mere undo. + if (gchar const* s = this->getRepr()->attribute("inkscape:original-d")) { - // write it to XML, and to my curve, but don't update patheffects + // Write the value to _curve_before_lpe, do not recalculate effects Geom::PathVector pv = sp_svg_read_pathv(s); SPCurve *curve = new SPCurve(pv); @@ -148,10 +167,17 @@ void SPPath::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr( "d" ); /* d is a required attribute */ - gchar const *d = this->getAttribute("d", NULL); + char const *d = this->getAttribute("d", NULL); if (d == NULL) { - this->setKeyValue( sp_attribute_lookup("d"), ""); + // First see if calculating the path effect will generate "d": + this->update_patheffect(true); + d = this->getAttribute("d", NULL); + + // I guess that didn't work, now we have nothing useful to write ("") + if (d == NULL) { + this->setKeyValue( sp_attribute_lookup("d"), ""); + } } } diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index 361d3c8c0..e17d7373c 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -52,22 +52,30 @@ void SPRect::build(SPDocument* doc, Inkscape::XML::Node* repr) { void SPRect::set(unsigned key, gchar const *value) { /* fixme: We need real error processing some time */ + // We must update the SVGLengths immediately or nodes may be misplaced after they are moved. + double const w = viewport.width(); + double const h = viewport.height(); + double const em = style->font_size.computed; + double const ex = em * 0.5; + switch (key) { case SP_ATTR_X: - this->x.readOrUnset(value); - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->x.readOrUnset(value); + this->x.update( ex, em, w ); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_Y: - this->y.readOrUnset(value); - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->y.readOrUnset(value); + this->y.update( ex, em, h ); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_WIDTH: if (!this->width.read(value) || this->width.value < 0.0) { this->width.unset(); } - + this->width.update( ex, em, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -75,7 +83,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->height.read(value) || this->height.value < 0.0) { this->height.unset(); } - + this->height.update( ex, em, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -83,7 +91,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->rx.read(value) || this->rx.value <= 0.0) { this->rx.unset(); } - + this->rx.update( ex, em, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -91,7 +99,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->ry.read(value) || this->ry.value <= 0.0) { this->ry.unset(); } - + this->ry.update( ex, em, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -129,19 +137,19 @@ Inkscape::XML::Node * SPRect::write(Inkscape::XML::Document *xml_doc, Inkscape:: repr = xml_doc->createElement("svg:rect"); } - sp_repr_set_svg_double(repr, "width", this->width.computed); - sp_repr_set_svg_double(repr, "height", this->height.computed); + sp_repr_set_svg_length(repr, "width", this->width); + sp_repr_set_svg_length(repr, "height", this->height); if (this->rx._set) { - sp_repr_set_svg_double(repr, "rx", this->rx.computed); + sp_repr_set_svg_length(repr, "rx", this->rx); } if (this->ry._set) { - sp_repr_set_svg_double(repr, "ry", this->ry.computed); + sp_repr_set_svg_length(repr, "ry", this->ry); } - sp_repr_set_svg_double(repr, "x", this->x.computed); - sp_repr_set_svg_double(repr, "y", this->y.computed); + sp_repr_set_svg_length(repr, "x", this->x); + sp_repr_set_svg_length(repr, "y", this->y); this->set_shape(); // evaluate SPCurve SPShape::write(xml_doc, repr, flags); @@ -235,29 +243,29 @@ void SPRect::set_shape() { /* fixme: Think (Lauris) */ void SPRect::setPosition(gdouble x, gdouble y, gdouble width, gdouble height) { - this->x.computed = x; - this->y.computed = y; - this->width.computed = width; - this->height.computed = height; + this->x = x; + this->y = y; + this->width = width; + this->height = height; this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } void SPRect::setRx(bool set, gdouble value) { - this->rx._set = set; + this->rx._set = set; if (set) { - this->rx.computed = value; + this->rx = value; } this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } void SPRect::setRy(bool set, gdouble value) { - this->ry._set = set; + this->ry._set = set; if (set) { - this->ry.computed = value; + this->ry = value; } this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -289,16 +297,16 @@ Geom::Affine SPRect::set_transform(Geom::Affine const& xform) { ret[3] = 1.0; } - /* fixme: Would be nice to preserve units here */ - this->width = this->width.computed * sw; - this->height = this->height.computed * sh; + /* Preserve units */ + this->width.scale( sw ); + this->height.scale( sh ); if (this->rx._set) { - this->rx = this->rx.computed * sw; + this->rx.scale( sw ); } if (this->ry._set) { - this->ry = this->ry.computed * sh; + this->ry.scale( sh ); } /* Find start in item coords */ @@ -336,15 +344,12 @@ gdouble SPRect::vectorStretch(Geom::Point p0, Geom::Point p1, Geom::Affine xform void SPRect::setVisibleRx(gdouble rx) { if (rx == 0) { - this->rx.computed = 0; - this->rx._set = false; + this->rx.unset(); } else { - this->rx.computed = rx / SPRect::vectorStretch( + this->rx = rx / SPRect::vectorStretch( Geom::Point(this->x.computed + 1, this->y.computed), Geom::Point(this->x.computed, this->y.computed), - this->transform); - - this->rx._set = true; + this->i2doc_affine()); } this->updateRepr(); @@ -352,15 +357,12 @@ void SPRect::setVisibleRx(gdouble rx) { void SPRect::setVisibleRy(gdouble ry) { if (ry == 0) { - this->ry.computed = 0; - this->ry._set = false; + this->ry.unset(); } else { - this->ry.computed = ry / SPRect::vectorStretch( + this->ry = ry / SPRect::vectorStretch( Geom::Point(this->x.computed, this->y.computed + 1), Geom::Point(this->x.computed, this->y.computed), - this->transform); - - this->ry._set = true; + this->i2doc_affine()); } this->updateRepr(); @@ -374,7 +376,7 @@ gdouble SPRect::getVisibleRx() const { return this->rx.computed * SPRect::vectorStretch( Geom::Point(this->x.computed + 1, this->y.computed), Geom::Point(this->x.computed, this->y.computed), - this->transform); + this->i2doc_affine()); } gdouble SPRect::getVisibleRy() const { @@ -385,7 +387,7 @@ gdouble SPRect::getVisibleRy() const { return this->ry.computed * SPRect::vectorStretch( Geom::Point(this->x.computed, this->y.computed + 1), Geom::Point(this->x.computed, this->y.computed), - this->transform); + this->i2doc_affine()); } Geom::Rect SPRect::getRect() const { @@ -418,37 +420,33 @@ void SPRect::compensateRxRy(Geom::Affine xform) { // This is needed because if we just set them the same length in SVG, they might end up unequal because of transform if ((this->rx._set && !this->ry._set) || (this->ry._set && !this->rx._set)) { gdouble r = MAX(this->rx.computed, this->ry.computed); - this->rx.computed = r / eX; - this->ry.computed = r / eY; + this->rx = r / eX; + this->ry = r / eY; } else { - this->rx.computed = this->rx.computed / eX; - this->ry.computed = this->ry.computed / eY; + this->rx = this->rx.computed / eX; + this->ry = this->ry.computed / eY; } // Note that a radius may end up larger than half-side if the rect is scaled down; // that's ok because this preserves the intended radii in case the rect is enlarged again, // and set_shape will take care of trimming too large radii when generating d= - - this->rx._set = this->ry._set = true; } void SPRect::setVisibleWidth(gdouble width) { - this->width.computed = width / SPRect::vectorStretch( + this->width = width / SPRect::vectorStretch( Geom::Point(this->x.computed + 1, this->y.computed), Geom::Point(this->x.computed, this->y.computed), - this->transform); + this->i2doc_affine()); - this->width._set = true; - this->updateRepr(); + this->updateRepr(); } void SPRect::setVisibleHeight(gdouble height) { - this->height.computed = height / SPRect::vectorStretch( + this->height = height / SPRect::vectorStretch( Geom::Point(this->x.computed, this->y.computed + 1), Geom::Point(this->x.computed, this->y.computed), - this->transform); + this->i2doc_affine()); - this->height._set = true; this->updateRepr(); } @@ -460,7 +458,7 @@ gdouble SPRect::getVisibleWidth() const { return this->width.computed * SPRect::vectorStretch( Geom::Point(this->x.computed + 1, this->y.computed), Geom::Point(this->x.computed, this->y.computed), - this->transform); + this->i2doc_affine()); } gdouble SPRect::getVisibleHeight() const { @@ -471,7 +469,7 @@ gdouble SPRect::getVisibleHeight() const { return this->height.computed * SPRect::vectorStretch( Geom::Point(this->x.computed, this->y.computed + 1), Geom::Point(this->x.computed, this->y.computed), - this->transform); + this->i2doc_affine()); } void SPRect::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) const { diff --git a/src/splivarot.cpp b/src/splivarot.cpp index c668199c0..a04dedda9 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -1717,7 +1717,9 @@ void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool if ( !updating ) { // delete original, apply the transform to the offset + const char *n_id = item->getRepr()->attribute("id"); item->deleteObject(false); + repr->setAttribute("id", n_id); nitem->doWriteTransform(repr, transform); } diff --git a/src/svg-profile.h b/src/svg-profile.h index 9d221fc76..8945ee313 100644 --- a/src/svg-profile.h +++ b/src/svg-profile.h @@ -74,7 +74,7 @@ public: SVG_PRINT_1_1, /**< */ - PROFILE_UNIQUE_CNT, /**< A marker to seperate between the entires + PROFILE_UNIQUE_CNT, /**< A marker to separate between the entires that are unique, and those which are aggregates of them. */ diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index ea235b2e4..edbc59c36 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -14,6 +14,7 @@ #include <cstring> #include <string> #include <glib.h> +#include <iostream> #include "svg.h" #include "stringstream.h" @@ -462,6 +463,51 @@ unsigned int sp_svg_length_read_ldd(gchar const *str, SVGLength::Unit *unit, dou return r; } +std::string const SVGLength::write() +{ + return sp_svg_length_write_with_units(*this); +} + +void SVGLength::set(SVGLength::Unit u, float v) +{ + _set = true; + unit = u; + Glib::ustring hack("px"); + switch( unit ) { + case NONE: + case PX: + case EM: + case EX: + case PERCENT: + break; + case PT: + hack = "pt"; + break; + case PC: + hack = "pc"; + break; + case MM: + hack = "pt"; + break; + case CM: + hack = "pt"; + break; + case INCH: + hack = "pt"; + break; + case FOOT: + hack = "pt"; + break; + case MITRE: + hack = "m"; + break; + default: + break; + } + value = v; + computed = Inkscape::Util::Quantity::convert(v, hack, "px"); +} + void SVGLength::set(SVGLength::Unit u, float v, float c) { _set = true; @@ -478,6 +524,12 @@ void SVGLength::unset(SVGLength::Unit u, float v, float c) computed = c; } +void SVGLength::scale(double scale) +{ + value *= scale; + computed *= scale; +} + void SVGLength::update(double em, double ex, double scale) { if (unit == EM) { diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h index 1e6b4c96c..84056dd5f 100644 --- a/src/svg/svg-length.h +++ b/src/svg/svg-length.h @@ -57,9 +57,13 @@ public: bool read(char const *str); void readOrUnset(char const *str, Unit u = NONE, float v = 0, float c = 0); bool readAbsolute(char const *str); - void set(Unit u, float v, float c); + std::string const write(); + // To set 'v' use '=' + void set(Unit u, float v); // Sets computed value based on u and v. + void set(Unit u, float v, float c); // Sets all three values. void unset(Unit u = NONE, float v = 0, float c = 0); - void update(double em, double ex, double scale); + void scale(double scale); // Scales length (value, computed), leaving unit alone. + void update(double em, double ex, double scale); // Updates computed value }; #endif // SEEN_SP_SVG_LENGTH_H diff --git a/src/trace/potrace/auxiliary.h b/src/trace/potrace/auxiliary.h index b7480bbb8..dbf124d7c 100644 --- a/src/trace/potrace/auxiliary.h +++ b/src/trace/potrace/auxiliary.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -8,6 +8,8 @@ #ifndef AUXILIARY_H #define AUXILIARY_H +#include <stdlib.h> + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -75,31 +77,4 @@ static inline int floordiv(int a, int n) { #define sq(a) ((a)*(a)) #define cu(a) ((a)*(a)*(a)) -/* ---------------------------------------------------------------------- */ -/* deterministically and efficiently hash (x,y) into a pseudo-random bit */ -static inline int detrand(int x, int y) { - unsigned int z; - static const unsigned char t[256] = { - /* non-linear sequence: constant term of inverse in GF(8), - mod x^8+x^4+x^3+x+1 */ - 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, - 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - }; - - /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible - 5-bit sequence */ - z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93; - z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff]; - return z; -} - #endif /* AUXILIARY_H */ diff --git a/src/trace/potrace/bitmap.h b/src/trace/potrace/bitmap.h index 2df04b46f..086bbb046 100644 --- a/src/trace/potrace/bitmap.h +++ b/src/trace/potrace/bitmap.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -7,6 +7,7 @@ #include <string.h> #include <stdlib.h> +#include <errno.h> /* The bitmap type is defined in potracelib.h */ #include "potracelib.h" @@ -27,7 +28,7 @@ /* macros for accessing pixel at index (x,y). U* macros omit the bounds check. */ -#define bm_scanline(bm, y) ((bm)->map + (y)*(bm)->dy) +#define bm_scanline(bm, y) ((bm)->map + (ssize_t)(y)*(ssize_t)(bm)->dy) #define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS]) #define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1))) #define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a)) @@ -51,10 +52,18 @@ static inline void bm_free(potrace_bitmap_t *bm) { free(bm); } -/* return new un-initialized bitmap. NULL with errno on error */ +/* return new un-initialized bitmap. NULL with errno on error. + Assumes w, h >= 0. */ static inline potrace_bitmap_t *bm_new(int w, int h) { potrace_bitmap_t *bm; - int dy = (w + BM_WORDBITS - 1) / BM_WORDBITS; + int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1; + ssize_t size = (ssize_t)dy * (ssize_t)h * (ssize_t)BM_WORDSIZE; + + /* check for overflow error */ + if (size < 0 || size / h / dy != BM_WORDSIZE) { + errno = ENOMEM; + return NULL; + } bm = (potrace_bitmap_t *) malloc(sizeof(potrace_bitmap_t)); if (!bm) { @@ -63,7 +72,7 @@ static inline potrace_bitmap_t *bm_new(int w, int h) { bm->w = w; bm->h = h; bm->dy = dy; - bm->map = (potrace_word *) malloc(dy * h * BM_WORDSIZE); + bm->map = (potrace_word *) malloc(size); if (!bm->map) { free(bm); return NULL; @@ -73,23 +82,29 @@ static inline potrace_bitmap_t *bm_new(int w, int h) { /* clear the given bitmap. Set all bits to c. */ static inline void bm_clear(potrace_bitmap_t *bm, int c) { - memset(bm->map, c ? -1 : 0, bm->dy * bm->h * BM_WORDSIZE); + /* Note: if the bitmap was created with bm_new, then it is + guaranteed that size will fit into the ssize_t type. */ + ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE; + memset(bm->map, c ? -1 : 0, size); } /* duplicate the given bitmap. Return NULL on error with errno set. */ static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) { potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h); + ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE; if (!bm1) { return NULL; } - memcpy(bm1->map, bm->map, bm->dy * bm->h * BM_WORDSIZE); + memcpy(bm1->map, bm->map, size); return bm1; } /* invert the given bitmap. */ static inline void bm_invert(potrace_bitmap_t *bm) { - int i; - for (i = 0; i < bm->dy * bm->h; i++) { + ssize_t i; + ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h; + + for (i = 0; i < size; i++) { bm->map[i] ^= BM_ALLBITS; } } diff --git a/src/trace/potrace/bitops.h b/src/trace/potrace/bitops.h new file mode 100644 index 000000000..cff734a46 --- /dev/null +++ b/src/trace/potrace/bitops.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2001-2015 Peter Selinger. + This file is part of Potrace. It is free software and it is covered + by the GNU General Public License. See the file COPYING for details. */ + + +/* bits.h: this file defines some macros for bit manipulations. We + provide a generic implementation, as well as machine- and + compiler-specific fast implementations */ + +/* lobit: return the position of the rightmost "1" bit of an int, or + 32 if none. hibit: return 1 + the position of the leftmost "1" bit + of an int, or 0 if none. Note: these functions work on 32-bit + integers. */ + +#ifndef BITOPS_H +#define BITOPS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* ---------------------------------------------------------------------- */ +/* machine specific macros */ + +#if defined(HAVE_I386) + +static inline unsigned int lobit(unsigned int x) { + unsigned int res; + asm ("bsf %1,%0\n\t" + "jnz 0f\n\t" + "movl $32,%0\n" + "0:" + : "=r" (res) + : "r" (x) + : "cc"); + return res; +} + +static inline unsigned int hibit(unsigned int x) { + unsigned int res; + + asm ("bsr %1,%0\n\t" + "jnz 0f\n\t" + "movl $-1,%0\n" + "0:" + : "=r" (res) + : "r" (x) + : "cc"); + return res+1; +} + +/* ---------------------------------------------------------------------- */ +#else /* generic macros */ + +static inline unsigned int lobit(unsigned int x) { + unsigned int res = 32; + while (x & 0xffffff) { + x <<= 8; + res -= 8; + } + while (x) { + x <<= 1; + res -= 1; + } + return res; +} + +static inline unsigned int hibit(unsigned int x) { + unsigned int res = 0; + while (x > 0xff) { + x >>= 8; + res += 8; + } + while (x) { + x >>= 1; + res += 1; + } + return res; +} + +#endif + +#endif /* BITOPS_H */ diff --git a/src/trace/potrace/curve.cpp b/src/trace/potrace/curve.cpp index d2e32aa7b..e6a9a4721 100644 --- a/src/trace/potrace/curve.cpp +++ b/src/trace/potrace/curve.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -12,8 +12,8 @@ #include "lists.h" #include "curve.h" -#define SAFE_MALLOC(var, n, typ) \ - if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error +#define SAFE_CALLOC(var, n, typ) \ + if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error /* ---------------------------------------------------------------------- */ /* allocate and free path objects */ @@ -22,14 +22,14 @@ path_t *path_new(void) { path_t *p = NULL; privpath_t *priv = NULL; - SAFE_MALLOC(p, 1, path_t); + SAFE_CALLOC(p, 1, path_t); memset(p, 0, sizeof(path_t)); - SAFE_MALLOC(priv, 1, privpath_t); + SAFE_CALLOC(priv, 1, privpath_t); memset(priv, 0, sizeof(privpath_t)); p->priv = priv; return p; - malloc_error: + calloc_error: free(p); free(priv); return NULL; @@ -81,15 +81,15 @@ typedef dpoint_t dpoint3_t[3]; int privcurve_init(privcurve_t *curve, int n) { memset(curve, 0, sizeof(privcurve_t)); curve->n = n; - SAFE_MALLOC(curve->tag, n, int); - SAFE_MALLOC(curve->c, n, dpoint3_t); - SAFE_MALLOC(curve->vertex, n, dpoint_t); - SAFE_MALLOC(curve->alpha, n, double); - SAFE_MALLOC(curve->alpha0, n, double); - SAFE_MALLOC(curve->beta, n, double); + SAFE_CALLOC(curve->tag, n, int); + SAFE_CALLOC(curve->c, n, dpoint3_t); + SAFE_CALLOC(curve->vertex, n, dpoint_t); + SAFE_CALLOC(curve->alpha, n, double); + SAFE_CALLOC(curve->alpha0, n, double); + SAFE_CALLOC(curve->beta, n, double); return 0; - malloc_error: + calloc_error: free(curve->tag); free(curve->c); free(curve->vertex); diff --git a/src/trace/potrace/curve.h b/src/trace/potrace/curve.h index 6ceae0c3a..feb95b39b 100644 --- a/src/trace/potrace/curve.h +++ b/src/trace/potrace/curve.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/decompose.cpp b/src/trace/potrace/decompose.cpp index 6c27a7ebf..7628b202d 100644 --- a/src/trace/potrace/decompose.cpp +++ b/src/trace/potrace/decompose.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -15,6 +15,33 @@ #include "decompose.h" #include "progress.h" +/* ---------------------------------------------------------------------- */ +/* deterministically and efficiently hash (x,y) into a pseudo-random bit */ + +static inline int detrand(int x, int y) { + unsigned int z; + static const unsigned char t[256] = { + /* non-linear sequence: constant term of inverse in GF(8), + mod x^8+x^4+x^3+x+1 */ + 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, + 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, + 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, + 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + }; + + /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible + 5-bit sequence */ + z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93; + z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff]; + return z; +} /* ---------------------------------------------------------------------- */ /* auxiliary bitmap manipulations */ diff --git a/src/trace/potrace/decompose.h b/src/trace/potrace/decompose.h index 89b01e504..8ae89b8ad 100644 --- a/src/trace/potrace/decompose.h +++ b/src/trace/potrace/decompose.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/greymap.cpp b/src/trace/potrace/greymap.cpp index e116021c1..4ef2ec8df 100644 --- a/src/trace/potrace/greymap.cpp +++ b/src/trace/potrace/greymap.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -9,8 +9,10 @@ #include <stdlib.h> #include <string.h> #include <math.h> +#include <errno.h> #include "greymap.h" +#include "bitops.h" #define INTBITS (8*sizeof(int)) @@ -22,10 +24,17 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp); /* ---------------------------------------------------------------------- */ /* basic greymap routines */ -/* return new un-initialized greymap. NULL with errno on error */ - +/* return new un-initialized greymap. NULL with errno on error. + Assumes w, h >= 0. */ greymap_t *gm_new(int w, int h) { greymap_t *gm; + ssize_t size = (ssize_t)w * (ssize_t)h * (ssize_t)sizeof(signed short int); + + /* check for overflow error */ + if (size < 0 || size / w / h != sizeof(signed short int)) { + errno = ENOMEM; + return NULL; + } gm = (greymap_t *) malloc(sizeof(greymap_t)); if (!gm) { @@ -33,7 +42,7 @@ greymap_t *gm_new(int w, int h) { } gm->w = w; gm->h = h; - gm->map = (signed short int *) malloc(w*h*sizeof(signed short int)); + gm->map = (signed short int *) malloc(size); if (!gm->map) { free(gm); return NULL; @@ -405,6 +414,10 @@ struct bmp_info_s { unsigned int YpixelsPerM; unsigned int ncolors; /* number of colors in palette */ unsigned int ColorsImportant; + unsigned int RedMask; + unsigned int GreenMask; + unsigned int BlueMask; + unsigned int AlphaMask; unsigned int ctbits; /* sample size for color table */ int topdown; /* top-down mode? */ }; @@ -495,6 +508,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) { int col[2]; unsigned int bitbuf; unsigned int n; + unsigned int redshift, greenshift, blueshift; gm_read_error = NULL; gm = NULL; @@ -523,12 +537,24 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) { TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM)); TRY(bmp_readint(f, 4, &bmpinfo.ncolors)); TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant)); - if ((signed int)bmpinfo.h < 0) { - bmpinfo.h = -bmpinfo.h; + if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */ + TRY(bmp_readint(f, 4, &bmpinfo.RedMask)); + TRY(bmp_readint(f, 4, &bmpinfo.GreenMask)); + TRY(bmp_readint(f, 4, &bmpinfo.BlueMask)); + TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask)); + } + if (bmpinfo.w > 0x7fffffff) { + goto format_error; + } + if (bmpinfo.h > 0x7fffffff) { + bmpinfo.h = (-bmpinfo.h) & 0xffffffff; bmpinfo.topdown = 1; } else { bmpinfo.topdown = 0; } + if (bmpinfo.h > 0x7fffffff) { + goto format_error; + } } else if (bmpinfo.InfoSize == 12) { /* old OS/2 format */ bmpinfo.ctbits = 24; /* sample size in color table */ @@ -543,6 +569,11 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) { goto format_error; } + if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) { + /* bitfield feature is only understood with V4 and V5 format */ + goto format_error; + } + /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */ TRY(bmp_forward(f, 14+bmpinfo.InfoSize)); @@ -557,7 +588,7 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) { /* color table, present only if bmpinfo.bits <= 8. */ if (bmpinfo.bits <= 8) { - coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int)); + coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int)); if (!coltable) { goto std_error; } @@ -651,6 +682,22 @@ static int gm_readbody_bmp(FILE *f, greymap_t **gmp) { } break; + case 0x320: /* 32-bit encoding with bitfields */ + redshift = lobit(bmpinfo.RedMask); + greenshift = lobit(bmpinfo.GreenMask); + blueshift = lobit(bmpinfo.BlueMask); + + for (y=0; y<bmpinfo.h; y++) { + bmp_pad_reset(); + for (x=0; x<bmpinfo.w; x++) { + TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c)); + c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift); + GM_UPUT(gm, x, ycorr(y), c/3); + } + TRY(bmp_pad(f)); + } + break; + case 0x204: /* 4-bit runlength compressed encoding (RLE4) */ x = 0; y = 0; diff --git a/src/trace/potrace/greymap.h b/src/trace/potrace/greymap.h index 1fb5426c1..8c9db9bbf 100644 --- a/src/trace/potrace/greymap.h +++ b/src/trace/potrace/greymap.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -7,6 +7,7 @@ #define GREYMAP_H #include <stdio.h> +#include <stdlib.h> /* internal format for greymaps. Note: in this format, rows are ordered from bottom to top. The pixels in each row are given from @@ -22,7 +23,7 @@ typedef struct greymap_s greymap_t; /* macros for accessing pixel at index (x,y). Note that the origin is in the *lower* left corner. U* macros omit the bounds check. */ -#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(gm)->w]) +#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(ssize_t)(gm)->w]) #define gm_safe(gm, x, y) ((int)(x)>=0 && (int)(x)<(gm)->w && (int)(y)>=0 && (int)(y)<(gm)->h) #define gm_bound(x, m) ((x)<0 ? 0 : (x)>=(m) ? (m)-1 : (x)) #define GM_UGET(gm, x, y) (*gm_index(gm, x, y)) diff --git a/src/trace/potrace/lists.h b/src/trace/potrace/lists.h index 078129afc..394262c23 100644 --- a/src/trace/potrace/lists.h +++ b/src/trace/potrace/lists.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/potracelib.cpp b/src/trace/potrace/potracelib.cpp index 0fb835593..b5463d676 100644 --- a/src/trace/potrace/potracelib.cpp +++ b/src/trace/potrace/potracelib.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/potracelib.h b/src/trace/potrace/potracelib.h index cd142a6e1..0a6ddbf1f 100644 --- a/src/trace/potrace/potracelib.h +++ b/src/trace/potrace/potracelib.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/progress.h b/src/trace/potrace/progress.h index 3e1dfb34e..ecc2ba217 100644 --- a/src/trace/potrace/progress.h +++ b/src/trace/potrace/progress.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/render.cpp b/src/trace/potrace/render.cpp index 3c8f79c05..4f44ae6a6 100644 --- a/src/trace/potrace/render.cpp +++ b/src/trace/potrace/render.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -52,7 +52,7 @@ render_t *render_new(greymap_t *gm) { } memset(rm, 0, sizeof(render_t)); rm->gm = gm; - rm->incrow_buf = (int *) malloc(gm->h * sizeof(int)); + rm->incrow_buf = (int *) calloc(gm->h, sizeof(int)); if (!rm->incrow_buf) { free(rm); return NULL; diff --git a/src/trace/potrace/render.h b/src/trace/potrace/render.h index ad600156a..0caaedff6 100644 --- a/src/trace/potrace/render.h +++ b/src/trace/potrace/render.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/trace/potrace/trace.cpp b/src/trace/potrace/trace.cpp index f1e88a908..469262b67 100644 --- a/src/trace/potrace/trace.cpp +++ b/src/trace/potrace/trace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ @@ -21,8 +21,8 @@ #define COS179 -0.999847695156 /* the cosine of 179 degrees */ /* ---------------------------------------------------------------------- */ -#define SAFE_MALLOC(var, n, typ) \ - if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error +#define SAFE_CALLOC(var, n, typ) \ + if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error /* ---------------------------------------------------------------------- */ /* auxiliary functions */ @@ -265,7 +265,7 @@ static int calc_sums(privpath_t *pp) { int i, x, y; int n = pp->len; - SAFE_MALLOC(pp->sums, pp->len+1, sums_t); + SAFE_CALLOC(pp->sums, pp->len+1, sums_t); /* origin */ pp->x0 = pp->pt[0].x; @@ -284,7 +284,7 @@ static int calc_sums(privpath_t *pp) { } return 0; - malloc_error: + calloc_error: return 1; } @@ -331,8 +331,8 @@ static int calc_lon(privpath_t *pp) { point_t dk; /* direction of k-k1 */ int a, b, c, d; - SAFE_MALLOC(pivk, n, int); - SAFE_MALLOC(nc, n, int); + SAFE_CALLOC(pivk, n, int); + SAFE_CALLOC(nc, n, int); /* initialize the nc data structure. Point from each point to the furthest future point to which it is connected by a vertical or @@ -349,7 +349,7 @@ static int calc_lon(privpath_t *pp) { nc[i] = k; } - SAFE_MALLOC(pp->lon, n, int); + SAFE_CALLOC(pp->lon, n, int); /* determine pivot points: for each i, let pivk[i] be the furthest k such that all j with i<j<k lie on a line connecting i,k. */ @@ -458,7 +458,7 @@ static int calc_lon(privpath_t *pp) { free(nc); return 0; - malloc_error: + calloc_error: free(pivk); free(nc); return 1; @@ -537,12 +537,12 @@ static int bestpolygon(privpath_t *pp) double best; int c; - SAFE_MALLOC(pen, n+1, double); - SAFE_MALLOC(prev, n+1, int); - SAFE_MALLOC(clip0, n, int); - SAFE_MALLOC(clip1, n+1, int); - SAFE_MALLOC(seg0, n+1, int); - SAFE_MALLOC(seg1, n+1, int); + SAFE_CALLOC(pen, n+1, double); + SAFE_CALLOC(prev, n+1, int); + SAFE_CALLOC(clip0, n, int); + SAFE_CALLOC(clip1, n+1, int); + SAFE_CALLOC(seg0, n+1, int); + SAFE_CALLOC(seg1, n+1, int); /* calculate clipped paths */ for (i=0; i<n; i++) { @@ -604,7 +604,7 @@ static int bestpolygon(privpath_t *pp) } pp->m = m; - SAFE_MALLOC(pp->po, m, int); + SAFE_CALLOC(pp->po, m, int); /* read off shortest path */ for (i=n, j=m-1; i>0; j--) { @@ -620,7 +620,7 @@ static int bestpolygon(privpath_t *pp) free(seg1); return 0; - malloc_error: + calloc_error: free(pen); free(prev); free(clip0); @@ -655,13 +655,13 @@ static int adjust_vertices(privpath_t *pp) { dpoint_t s; int r; - SAFE_MALLOC(ctr, m, dpoint_t); - SAFE_MALLOC(dir, m, dpoint_t); - SAFE_MALLOC(q, m, quadform_t); + SAFE_CALLOC(ctr, m, dpoint_t); + SAFE_CALLOC(dir, m, dpoint_t); + SAFE_CALLOC(q, m, quadform_t); r = privcurve_init(&pp->curve, m); if (r) { - goto malloc_error; + goto calloc_error; } /* calculate "optimal" point-slope representation for each line @@ -827,7 +827,7 @@ static int adjust_vertices(privpath_t *pp) { free(q); return 0; - malloc_error: + calloc_error: free(ctr); free(dir); free(q); @@ -875,7 +875,7 @@ static void smooth(privcurve_t *curve, double alphamax) { } curve->alpha0[j] = alpha; /* remember "original" value of alpha */ - if (alpha > alphamax) { /* pointed corner */ + if (alpha >= alphamax) { /* pointed corner */ curve->tag[j] = POTRACE_CORNER; curve->c[j][1] = curve->vertex[j]; curve->c[j][2] = p4; @@ -1075,12 +1075,12 @@ static int opticurve(privpath_t *pp, double opttolerance) { int *convc = NULL; /* conv[m]: pre-computed convexities */ double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */ - SAFE_MALLOC(pt, m+1, int); - SAFE_MALLOC(pen, m+1, double); - SAFE_MALLOC(len, m+1, int); - SAFE_MALLOC(opt, m+1, opti_t); - SAFE_MALLOC(convc, m, int); - SAFE_MALLOC(areac, m+1, double); + SAFE_CALLOC(pt, m+1, int); + SAFE_CALLOC(pen, m+1, double); + SAFE_CALLOC(len, m+1, int); + SAFE_CALLOC(opt, m+1, opti_t); + SAFE_CALLOC(convc, m, int); + SAFE_CALLOC(areac, m+1, double); /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */ for (i=0; i<m; i++) { @@ -1134,10 +1134,10 @@ static int opticurve(privpath_t *pp, double opttolerance) { om = len[m]; r = privcurve_init(&pp->ocurve, om); if (r) { - goto malloc_error; + goto calloc_error; } - SAFE_MALLOC(s, om, double); - SAFE_MALLOC(t, om, double); + SAFE_CALLOC(s, om, double); + SAFE_CALLOC(t, om, double); j = m; for (i=om-1; i>=0; i--) { @@ -1182,7 +1182,7 @@ static int opticurve(privpath_t *pp, double opttolerance) { free(areac); return 0; - malloc_error: + calloc_error: free(pt); free(pen); free(len); diff --git a/src/trace/potrace/trace.h b/src/trace/potrace/trace.h index dc2b9247a..c53cdd10f 100644 --- a/src/trace/potrace/trace.h +++ b/src/trace/potrace/trace.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2011 Peter Selinger. +/* Copyright (C) 2001-2015 Peter Selinger. This file is part of Potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. */ diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 674254686..991d11feb 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,11 +1,10 @@ - set(ui_SRC clipboard.cpp control-manager.cpp dialog-events.cpp draw-anchor.cpp - interface.cpp - object-edit.cpp + interface.cpp + object-edit.cpp previewholder.cpp shape-editor.cpp tool-factory.cpp @@ -56,8 +55,8 @@ set(ui_SRC dialog/aboutbox.cpp dialog/align-and-distribute.cpp dialog/calligraphic-profile-rename.cpp - dialog/color-item.cpp dialog/clonetiler.cpp + dialog/color-item.cpp dialog/debug.cpp dialog/desktop-tracker.cpp dialog/dialog-manager.cpp @@ -86,31 +85,36 @@ set(ui_SRC dialog/livepatheffect-add.cpp dialog/livepatheffect-editor.cpp dialog/lpe-fillet-chamfer-properties.cpp + dialog/lpe-powerstroke-properties.cpp dialog/memory.cpp dialog/messages.cpp dialog/new-from-template.cpp dialog/object-attributes.cpp dialog/object-properties.cpp + dialog/objects.cpp dialog/ocaldialogs.cpp + dialog/pixelartdialog.cpp dialog/polar-arrange-tab.cpp dialog/print-colors-preview-dialog.cpp dialog/print.cpp - dialog/symbols.cpp - dialog/xml-tree.cpp dialog/spellcheck.cpp dialog/svg-fonts-dialog.cpp dialog/swatches.cpp + dialog/symbols.cpp + dialog/tags.cpp dialog/template-load-tab.cpp dialog/template-widget.cpp dialog/text-edit.cpp dialog/tile.cpp dialog/tracedialog.cpp - dialog/pixelartdialog.cpp dialog/transformation.cpp dialog/undo-history.cpp + dialog/xml-tree.cpp + widget/addtoicon.cpp widget/anchor-selector.cpp widget/button.cpp + widget/clipmaskicon.cpp widget/color-picker.cpp widget/color-preview.cpp widget/dock-item.cpp @@ -121,10 +125,13 @@ set(ui_SRC widget/frame.cpp widget/gimpcolorwheel.c widget/gimpspinscale.c + widget/highlight-picker.cpp widget/imageicon.cpp widget/imagetoggler.cpp + widget/insertordericon.cpp widget/labelled.cpp widget/layer-selector.cpp + widget/layertypeicon.cpp widget/licensor.cpp widget/notebook-page.cpp widget/object-composite-settings.cpp @@ -179,8 +186,8 @@ set(ui_SRC dialog/arrange-tab.h dialog/behavior.h dialog/calligraphic-profile-rename.h - dialog/color-item.h dialog/clonetiler.h + dialog/color-item.h dialog/debug.h dialog/desktop-tracker.h dialog/dialog-manager.h @@ -200,8 +207,8 @@ set(ui_SRC dialog/floating-behavior.h dialog/font-substitution.h dialog/glyphs.h - dialog/guides.h dialog/grid-arrange-tab.h + dialog/guides.h dialog/icon-preview.h dialog/inkscape-preferences.h dialog/input.h @@ -215,13 +222,13 @@ set(ui_SRC dialog/new-from-template.h dialog/object-attributes.h dialog/object-properties.h + dialog/objects.h dialog/ocaldialogs.h dialog/panel-dialog.h - dialog/polar-arrange-tab.h dialog/pixelartdialog.h + dialog/polar-arrange-tab.h dialog/print-colors-preview-dialog.h dialog/print.h - dialog/spellcheck.h dialog/svg-fonts-dialog.h dialog/swatches.h diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index f324f285d..c381ed755 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -1473,6 +1473,7 @@ void DocumentProperties::update() } _page_sizer.setDim(Inkscape::Util::Quantity(doc_w, doc_w_unit), Inkscape::Util::Quantity(doc_h, doc_h_unit)); _page_sizer.updateFitMarginsUI(nv->getRepr()); + _page_sizer.updateScaleUI(); //-----------------------------------------------------------guide page @@ -1655,6 +1656,8 @@ void DocumentProperties::onRemoveGrid() } /** Callback for document unit change. */ +/* This should not effect anything in the SVG tree (other than "inkscape:document-units"). + This should only effect values displayed in the GUI. */ void DocumentProperties::onDocUnitChange() { SPDocument *doc = SP_ACTIVE_DOCUMENT; @@ -1680,6 +1683,8 @@ void DocumentProperties::onDocUnitChange() os << doc_unit->abbr; repr->setAttribute("inkscape:document-units", os.str().c_str()); + _page_sizer.updateScaleUI(); + // Disable changing of SVG Units. The intent here is to change the units in the UI, not the units in SVG. // This code should be moved (and fixed) once we have an "SVG Units" setting that sets what units are used in SVG data. #if 0 diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index 34339dab2..cafc3be4f 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -44,6 +44,7 @@ #include "filedialog.h" #include "sp-root.h" +#include "preferences.h" #include <zlib.h> #include <cairomm/win32_surface.h> @@ -272,6 +273,9 @@ void FileOpenDialogImplWin32::createFilterMenu() } if (dialogType != EXE_TYPES) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + _show_preview = prefs->getBool("/dialogs/open/enable_preview", true); + // Compose the filter string Inkscape::Extension::DB::InputList extension_list; Inkscape::Extension::db.get_input_list(extension_list); @@ -842,6 +846,10 @@ LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, void FileOpenDialogImplWin32::enable_preview(bool enable) { + if (_show_preview != enable) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/dialogs/open/enable_preview", enable); + } _show_preview = enable; // Relayout the dialog diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index cb2771503..f81519ed1 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -211,7 +211,7 @@ private: ComboBoxEnum<T>* combo; }; -// Contains an arbitrary number of spin buttons that use seperate attributes +// Contains an arbitrary number of spin buttons that use separate attributes class MultiSpinButton : public Gtk::HBox { public: diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 9f86158aa..3b0731953 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -529,14 +529,14 @@ void InkscapePreferences::initPageUI() _("English/Canada (en_CA)"), _("English/Great Britain (en_GB)"), _("Pig Latin (en_US@piglatin)"), _("Esperanto (eo)"), _("Estonian (et)"), _("Farsi (fa)"), _("Finnish (fi)"), _("French (fr)"), _("Irish (ga)"), _("Galician (gl)"), _("Hebrew (he)"), _("Hungarian (hu)"), - _("Indonesian (id)"), _("Italian (it)"), _("Japanese (ja)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Korean (ko)"), _("Lithuanian (lt)"), _("Latvian (lv)"), _("Macedonian (mk)"), + _("Indonesian (id)"), _("Icelandic (is)"), _("Italian (it)"), _("Japanese (ja)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Korean (ko)"), _("Lithuanian (lt)"), _("Latvian (lv)"), _("Macedonian (mk)"), _("Mongolian (mn)"), _("Nepali (ne)"), _("Norwegian BokmÃ¥l (nb)"), _("Norwegian Nynorsk (nn)"), _("Panjabi (pa)"), _("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"), _("Romanian (ro)"), _("Russian (ru)"), _("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"), _("Swedish (sv)"),_("Telugu (te)"), _("Thai (th)"), _("Turkish (tr)"), _("Ukrainian (uk)"), _("Vietnamese (vi)")}; Glib::ustring langValues[] = {"", "sq", "am", "ar", "hy", "az", "eu", "be", "bg", "bn", "bn_BD", "br", "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs", "da", "nl", "dz", "de", "el", "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et", "fa", "fi", "fr", "ga", - "gl", "he", "hu", "id", "it", "ja", "km", "rw", "ko", "lt", "lv", "mk", "mn", "ne", "nb", "nn", "pa", + "gl", "he", "hu", "id", "is", "it", "ja", "km", "rw", "ko", "lt", "lv", "mk", "mn", "ne", "nb", "nn", "pa", "pl", "pt", "pt_BR", "ro", "ru", "sr", "sr@latin", "sk", "sl", "es", "es_MX", "sv", "te", "th", "tr", "uk", "vi" }; { diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp index b318933a7..7e5c17133 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -129,7 +129,7 @@ void FilletChamferPropertiesDialog::showDialog( const gchar *unit, bool use_distance, bool aprox_radius, - Glib::ustring const * documentUnit) + Glib::ustring documentUnit) { FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog(); @@ -172,7 +172,7 @@ void FilletChamferPropertiesDialog::_apply() } d_pos = _index + (d_pos / 100); } else { - d_pos = Inkscape::Util::Quantity::convert(d_pos, unit, *document_unit); + d_pos = Inkscape::Util::Quantity::convert(d_pos, unit, document_unit); d_pos = d_pos * -1; } _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width)); @@ -226,7 +226,7 @@ void FilletChamferPropertiesDialog::_set_knot_point(Geom::Point knotpoint) _fillet_chamfer_position_label.set_label(_(posConcat.c_str())); position = knotpoint[Geom::X] * -1; - position = Inkscape::Util::Quantity::convert(position, *document_unit, unit); + position = Inkscape::Util::Quantity::convert(position, document_unit, unit); } _fillet_chamfer_position_numeric.set_value(position); if (knotpoint.y() == 1) { @@ -256,7 +256,7 @@ void FilletChamferPropertiesDialog::_set_unit(const gchar *abbr) unit = abbr; } -void FilletChamferPropertiesDialog::_set_document_unit(Glib::ustring const *abbr) +void FilletChamferPropertiesDialog::_set_document_unit(Glib::ustring abbr) { document_unit = abbr; } diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h index 3807e98c8..870a1734f 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.h +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h @@ -33,7 +33,7 @@ public: const gchar *unit, bool use_distance, bool aprox_radius, - Glib::ustring const * documentUnit); + Glib::ustring documentUnit); protected: @@ -69,14 +69,14 @@ protected: void _set_pt(const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt); void _set_unit(const gchar *abbr); - void _set_document_unit(Glib::ustring const * abbr); + void _set_document_unit(Glib::ustring abbr); void _set_use_distance(bool use_knot_distance); void _set_aprox(bool aprox_radius); void _apply(); void _close(); bool _flexible; const gchar *unit; - Glib::ustring const * document_unit; + Glib::ustring document_unit; bool use_distance; bool aprox; void _set_knot_point(Geom::Point knotpoint); diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp index 351971294..c44d645a5 100644 --- a/src/ui/dialog/print.cpp +++ b/src/ui/dialog/print.cpp @@ -126,30 +126,13 @@ static void draw_page( cairo_surface_t *surface = cairo_get_target(cr); cairo_matrix_t ctm; cairo_get_matrix(cr, &ctm); -#ifdef WIN32 - //Gtk+ does not take the non printable area into account - //http://bugzilla.gnome.org/show_bug.cgi?id=381371 - // - // This workaround translates the origin from the top left of the - // printable area to the top left of the page. - GtkPrintSettings *settings = gtk_print_operation_get_print_settings(operation); - const gchar *printerName = gtk_print_settings_get_printer(settings); - HDC hdc = CreateDC("WINSPOOL", printerName, NULL, NULL); - if (hdc) { - cairo_matrix_t mat; - int x_off = GetDeviceCaps (hdc, PHYSICALOFFSETX); - int y_off = GetDeviceCaps (hdc, PHYSICALOFFSETY); - cairo_matrix_init_translate(&mat, -x_off, -y_off); - cairo_matrix_multiply (&ctm, &ctm, &mat); - DeleteDC(hdc); - } -#endif + bool ret = ctx->setSurfaceTarget (surface, true, &ctm); if (ret) { ret = renderer.setupDocument (ctx, junk->_doc, TRUE, 0., NULL); if (ret) { renderer.renderItem(ctx, junk->_base); - ret = ctx->finish(); + ctx->finish(); } else { g_warning("%s", _("Could not set up Document")); diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp index c3bc2d52c..0a6c792dc 100644 --- a/src/ui/object-edit.cpp +++ b/src/ui/object-edit.cpp @@ -154,12 +154,9 @@ RectKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*orig if (state & GDK_CONTROL_MASK) { gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0; - rect->rx.computed = rect->ry.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, temp); - rect->rx._set = rect->ry._set = true; - + rect->rx = rect->ry = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, temp); } else { - rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0); - rect->rx._set = true; + rect->rx = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0); } update_knot(); @@ -207,20 +204,17 @@ RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*orig if (state & GDK_CONTROL_MASK) { // When holding control then rx will be kept equal to ry, // resulting in a perfect circle (and not an ellipse) gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0; - rect->rx.computed = rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp); - rect->ry._set = rect->rx._set = true; + rect->rx = rect->ry = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp); } else { if (!rect->rx._set || rect->rx.computed == 0) { - rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, - 0.0, - MIN(rect->height.computed / 2.0, rect->width.computed / 2.0)); + rect->ry = CLAMP(s[Geom::Y] - rect->y.computed, + 0.0, + MIN(rect->height.computed / 2.0, rect->width.computed / 2.0)); } else { - rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, - 0.0, - rect->height.computed / 2.0); + rect->ry = CLAMP(s[Geom::Y] - rect->y.computed, + 0.0, + rect->height.computed / 2.0); } - - rect->ry._set = true; } update_knot(); @@ -250,12 +244,10 @@ static void sp_rect_clamp_radii(SPRect *rect) { // clamp rounding radii so that they do not exceed width/height if (2 * rect->rx.computed > rect->width.computed) { - rect->rx.computed = 0.5 * rect->width.computed; - rect->rx._set = true; + rect->rx = 0.5 * rect->width.computed; } if (2 * rect->ry.computed > rect->height.computed) { - rect->ry.computed = 0.5 * rect->height.computed; - rect->ry._set = true; + rect->ry = 0.5 * rect->height.computed; } } @@ -298,16 +290,16 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->height.computed = MAX(h_orig + minx / ratio, 0); + rect->height = MAX(h_orig + minx / ratio, 0); } else { // closer to the horizontal, change only width, height is h_orig s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-1, 0)), state); minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->height.computed = MAX(h_orig, 0); + rect->height = MAX(h_orig, 0); } - rect->width.computed = MAX(w_orig + minx, 0); + rect->width = MAX(w_orig + minx, 0); } else { // snap to vertical or diagonal @@ -317,27 +309,24 @@ RectKnotHolderEntityWH::set_internal(Geom::Point const &p, Geom::Point const &or // Dead assignment: Value stored to 'minx' is never read //minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->width.computed = MAX(w_orig + miny * ratio, 0); + rect->width = MAX(w_orig + miny * ratio, 0); } else { // closer to the vertical, change only height, width is w_orig s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(0, -1)), state); // Dead assignment: Value stored to 'minx' is never read //minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->width.computed = MAX(w_orig, 0); + rect->width = MAX(w_orig, 0); } - rect->height.computed = MAX(h_orig + miny, 0); + rect->height = MAX(h_orig + miny, 0); } - rect->width._set = rect->height._set = true; - } else { // move freely s = snap_knot_position(p, state); - rect->width.computed = MAX(s[Geom::X] - rect->x.computed, 0); - rect->height.computed = MAX(s[Geom::Y] - rect->y.computed, 0); - rect->width._set = rect->height._set = true; + rect->width = MAX(s[Geom::X] - rect->x.computed, 0); + rect->height = MAX(s[Geom::Y] - rect->y.computed, 0); } sp_rect_clamp_radii(rect); @@ -394,19 +383,19 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->y.computed = MIN(origin[Geom::Y] + minx / ratio, opposite_y); - rect->height.computed = MAX(h_orig - minx / ratio, 0); + rect->y = MIN(origin[Geom::Y] + minx / ratio, opposite_y); + rect->height = MAX(h_orig - minx / ratio, 0); } else { // closer to the horizontal, change only width, height is h_orig s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(-1, 0)), state); minx = s[Geom::X] - origin[Geom::X]; // Dead assignment: Value stored to 'miny' is never read //miny = s[Geom::Y] - origin[Geom::Y]; - rect->y.computed = MIN(origin[Geom::Y], opposite_y); - rect->height.computed = MAX(h_orig, 0); + rect->y = MIN(origin[Geom::Y], opposite_y); + rect->height = MAX(h_orig, 0); } - rect->x.computed = MIN(s[Geom::X], opposite_x); - rect->width.computed = MAX(w_orig - minx, 0); + rect->x = MIN(s[Geom::X], opposite_x); + rect->width = MAX(w_orig - minx, 0); } else { // snap to vertical or diagonal if (miny != 0 && fabs(minx/miny) > 0.5 *ratio && (SGN(minx) == SGN(miny))) { @@ -415,34 +404,31 @@ RectKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &origin // Dead assignment: Value stored to 'minx' is never read //minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->x.computed = MIN(origin[Geom::X] + miny * ratio, opposite_x); - rect->width.computed = MAX(w_orig - miny * ratio, 0); + rect->x = MIN(origin[Geom::X] + miny * ratio, opposite_x); + rect->width = MAX(w_orig - miny * ratio, 0); } else { // closer to the vertical, change only height, width is w_orig s = snap_knot_position_constrained(p, Inkscape::Snapper::SnapConstraint(p_handle, Geom::Point(0, -1)), state); // Dead assignment: Value stored to 'minx' is never read //minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->x.computed = MIN(origin[Geom::X], opposite_x); - rect->width.computed = MAX(w_orig, 0); + rect->x = MIN(origin[Geom::X], opposite_x); + rect->width = MAX(w_orig, 0); } - rect->y.computed = MIN(s[Geom::Y], opposite_y); - rect->height.computed = MAX(h_orig - miny, 0); + rect->y = MIN(s[Geom::Y], opposite_y); + rect->height = MAX(h_orig - miny, 0); } - rect->width._set = rect->height._set = rect->x._set = rect->y._set = true; - } else { // move freely s = snap_knot_position(p, state); minx = s[Geom::X] - origin[Geom::X]; miny = s[Geom::Y] - origin[Geom::Y]; - rect->x.computed = MIN(s[Geom::X], opposite_x); - rect->width.computed = MAX(w_orig - minx, 0); - rect->y.computed = MIN(s[Geom::Y], opposite_y); - rect->height.computed = MAX(h_orig - miny, 0); - rect->width._set = rect->height._set = rect->x._set = rect->y._set = true; + rect->x = MIN(s[Geom::X], opposite_x); + rect->y = MIN(s[Geom::Y], opposite_y); + rect->width = MAX(w_orig - minx, 0); + rect->height = MAX(h_orig - miny, 0); } sp_rect_clamp_radii(rect); @@ -917,10 +903,10 @@ ArcKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*origi Geom::Point const s = snap_knot_position(p, state); - ge->rx.computed = fabs( ge->cx.computed - s[Geom::X] ); + ge->rx = fabs( ge->cx.computed - s[Geom::X] ); if ( state & GDK_CONTROL_MASK ) { - ge->ry.computed = ge->rx.computed; + ge->ry = ge->rx.computed; } item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -942,7 +928,7 @@ ArcKnotHolderEntityRX::knot_click(unsigned int state) g_assert(ge != NULL); if (state & GDK_CONTROL_MASK) { - ge->ry.computed = ge->rx.computed; + ge->ry = ge->rx.computed; ge->updateRepr(); } } @@ -955,10 +941,10 @@ ArcKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*origi Geom::Point const s = snap_knot_position(p, state); - ge->ry.computed = fabs( ge->cy.computed - s[Geom::Y] ); + ge->ry = fabs( ge->cy.computed - s[Geom::Y] ); if ( state & GDK_CONTROL_MASK ) { - ge->rx.computed = ge->ry.computed; + ge->rx = ge->ry.computed; } item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -980,7 +966,7 @@ ArcKnotHolderEntityRY::knot_click(unsigned int state) g_assert(ge != NULL); if (state & GDK_CONTROL_MASK) { - ge->rx.computed = ge->ry.computed; + ge->rx = ge->ry.computed; ge->updateRepr(); } } diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp index 49c949107..23640456e 100644 --- a/src/ui/tool/curve-drag-point.cpp +++ b/src/ui/tool/curve-drag-point.cpp @@ -54,7 +54,7 @@ bool CurveDragPoint::grabbed(GdkEventMotion */*event*/) // delta is a vector equal 1/3 of distance from first to second Geom::Point delta = (second->position() - first->position()) / 3.0; // only update the nodes if the mode is bspline - if(!_pm.isBSpline(false)){ + if(!_pm._isBSpline()){ first->front()->move(first->front()->position() + delta); second->back()->move(second->back()->position() - delta); } @@ -91,7 +91,7 @@ void CurveDragPoint::dragged(Geom::Point &new_pos, GdkEventMotion *event) Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta; //modified so that, if the trace is bspline, it only acts if the SHIFT key is pressed - if(!_pm.isBSpline(false)){ + if(!_pm._isBSpline()){ first->front()->move(first->front()->position() + offset0); second->back()->move(second->back()->position() + offset1); }else if(weight>=0.8){ diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index cdbf34e9d..1bbcdd7ec 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -39,7 +39,7 @@ public: virtual bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *event); bool empty() { return _mmap.empty(); } - unsigned size() { return _mmap.empty(); } + unsigned size() { return _mmap.size(); } void setItems(std::set<ShapeRecord> const &); void clear() { _mmap.clear(); } void cleanup(); diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index eeea47e4d..aa5365265 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -175,9 +175,9 @@ void Handle::move(Geom::Point const &new_pos) setPosition(new_pos); //move the handler and its oposite the same proportion - if(_pm().isBSpline()){ - setPosition(_pm().BSplineHandleReposition(this,this)); - this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this)); + if(_pm()._isBSpline()){ + setPosition(_pm()._bsplineHandleReposition(this,this)); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this)); } return; } @@ -192,9 +192,9 @@ void Handle::move(Geom::Point const &new_pos) setRelativePos(new_delta); //move the handler and its oposite the same proportion - if(_pm().isBSpline()){ - setPosition(_pm().BSplineHandleReposition(this,this)); - this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this)); + if(_pm()._isBSpline()){ + setPosition(_pm()._bsplineHandleReposition(this,this)); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this)); } return; @@ -218,11 +218,10 @@ void Handle::move(Geom::Point const &new_pos) setPosition(new_pos); // moves the handler and its oposite the same proportion - if(_pm().isBSpline()){ - setPosition(_pm().BSplineHandleReposition(this,this)); - this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),this)); + if(_pm()._isBSpline()){ + setPosition(_pm()._bsplineHandleReposition(this,this)); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this)); } - } void Handle::setPosition(Geom::Point const &p) @@ -313,9 +312,9 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven //this function moves the handler and its oposite to the default proportion of defaultStartPower void Handle::handle_2button_press(){ - if(_pm().isBSpline()){ - setPosition(_pm().BSplineHandleReposition(this,defaultStartPower)); - this->other()->setPosition(_pm().BSplineHandleReposition(this->other(),defaultStartPower)); + if(_pm()._isBSpline()){ + setPosition(_pm()._bsplineHandleReposition(this,defaultStartPower)); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),defaultStartPower)); _pm().update(); } } @@ -373,16 +372,16 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) new_pos = result; // moves the handler and its oposite in X fixed positions depending on parameter "steps with control" // by default in live BSpline - if(_pm().isBSpline()){ + if(_pm()._isBSpline()){ setPosition(new_pos); - int steps = _pm().BSplineGetSteps(); - new_pos=_pm().BSplineHandleReposition(this,ceilf(_pm().BSplineHandlePosition(this,this)*steps)/steps); + int steps = _pm()._bsplineGetSteps(); + new_pos=_pm()._bsplineHandleReposition(this,ceilf(_pm()._bsplineHandlePosition(this,this)*steps)/steps); } } std::vector<Inkscape::SnapCandidatePoint> unselected; //if the snap adjustment is activated and it is not bspline - if (snap && !_pm().isBSpline(false)) { + if (snap && !_pm()._isBSpline()) { ControlPointSelection::Set &nodes = _parent->_selection.allPoints(); for (ControlPointSelection::Set::iterator i = nodes.begin(); i != nodes.end(); ++i) { Node *n = static_cast<Node*>(*i); @@ -423,7 +422,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) } } //if it is bspline but SHIFT or CONTROL are not pressed it fixes it in the original position - if(_pm().isBSpline() && !held_shift(*event) && !held_control(*event)){ + if(_pm()._isBSpline() && !held_shift(*event) && !held_control(*event)){ new_pos=_last_drag_origin(); } move(new_pos); // needed for correct update, even though it's redundant @@ -486,8 +485,8 @@ Glib::ustring Handle::_getTip(unsigned state) const char const *more; // a trick to mark as bspline if the node has no strength, we are going to use it later // to show the appropiate messages. We cannot do it in any different way becasue the function is constant - - bool isBSpline = _pm().isBSpline(); + Handle *h = const_cast<Handle *>(this); + bool isBSpline = _pm()._isBSpline(); bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate(); if (can_shift_rotate && !isBSpline) { more = C_("Path handle tip", "more: Shift, Ctrl, Alt"); @@ -550,7 +549,7 @@ Glib::ustring Handle::_getTip(unsigned state) const "<b>Auto node handle</b>: drag to convert to smooth node (%s)"), more); }else{ return format_tip(C_("Path handle tip", - "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s)"), more); + "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s). %g power"),more,_pm()._bsplineHandlePosition(h,NULL)); } } } @@ -634,15 +633,15 @@ void Node::move(Geom::Point const &new_pos) Node *n = this; Node * nextNode = n->nodeToward(n->front()); Node * prevNode = n->nodeToward(n->back()); - nodeWeight = fmax(_pm().BSplineHandlePosition(n->front()),_pm().BSplineHandlePosition(n->back())); + nodeWeight = fmax(_pm()._bsplineHandlePosition(n->front()),_pm()._bsplineHandlePosition(n->back())); if(prevNode){ if(prevNode->isEndNode()){ - prevNodeWeight = _pm().BSplineHandlePosition(prevNode->front(),prevNode->front()); + prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front(),prevNode->front()); } } if(nextNode){ if(nextNode->isEndNode()){ - nextNodeWeight = _pm().BSplineHandlePosition(nextNode->back(),nextNode->back()); + nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back(),nextNode->back()); } } @@ -656,21 +655,21 @@ void Node::move(Geom::Point const &new_pos) _fixNeighbors(old_pos, new_pos); // move the affected handlers. First the node ones, later the adjoining ones. - if(_pm().isBSpline()){ - _front.setPosition(_pm().BSplineHandleReposition(this->front(),nodeWeight)); - _back.setPosition(_pm().BSplineHandleReposition(this->back(),nodeWeight)); + if(_pm()._isBSpline()){ + _front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight)); + _back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight)); if(prevNode){ if(prevNode->isEndNode()){ - prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNodeWeight)); + prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNodeWeight)); }else{ - prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNode->back())); + prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNode->back())); } } if(nextNode){ if(nextNode->isEndNode()){ - nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNodeWeight)); + nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNodeWeight)); }else{ - nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNode->front())); + nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNode->front())); } } } @@ -688,15 +687,15 @@ void Node::transform(Geom::Affine const &m) Node *n = this; Node * nextNode = n->nodeToward(n->front()); Node * prevNode = n->nodeToward(n->back()); - nodeWeight = _pm().BSplineHandlePosition(n->front()); + nodeWeight = _pm()._bsplineHandlePosition(n->front()); if(prevNode){ if(prevNode->isEndNode()){ - prevNodeWeight = _pm().BSplineHandlePosition(prevNode->front(),prevNode->front()); + prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front(),prevNode->front()); } } if(nextNode){ if(nextNode->isEndNode()){ - nextNodeWeight = _pm().BSplineHandlePosition(nextNode->back(),nextNode->back()); + nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back(),nextNode->back()); } } @@ -709,21 +708,21 @@ void Node::transform(Geom::Affine const &m) _fixNeighbors(old_pos, position()); // move the involved handlers, first the node ones, later the adjoining ones - if(_pm().isBSpline()){ - _front.setPosition(_pm().BSplineHandleReposition(this->front(),nodeWeight)); - _back.setPosition(_pm().BSplineHandleReposition(this->back(),nodeWeight)); + if(_pm()._isBSpline()){ + _front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight)); + _back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight)); if(prevNode){ if(prevNode->isEndNode()){ - prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNodeWeight)); + prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNodeWeight)); }else{ - prevNode->front()->setPosition(_pm().BSplineHandleReposition(prevNode->front(),prevNode->back())); + prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNode->back())); } } if(nextNode){ if(nextNode->isEndNode()){ - nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNodeWeight)); + nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNodeWeight)); }else{ - nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNode->front())); + nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNode->front())); } } } @@ -916,13 +915,13 @@ void Node::setType(NodeType type, bool update_handles) } /* in node type changes, about bspline traces, we can mantain them with noPower power in border mode, or we give them the default power in curve mode */ - if(_pm().isBSpline()){ + if(_pm()._isBSpline()){ double weight = noPower; - if(_pm().BSplineHandlePosition(this->front()) != noPower ){ + if(_pm()._bsplineHandlePosition(this->front()) != noPower ){ weight = defaultStartPower; } - _front.setPosition(_pm().BSplineHandleReposition(this->front(),weight)); - _back.setPosition(_pm().BSplineHandleReposition(this->back(),weight)); + _front.setPosition(_pm()._bsplineHandleReposition(this->front(),weight)); + _back.setPosition(_pm()._bsplineHandleReposition(this->back(),weight)); } } _type = type; @@ -1172,9 +1171,9 @@ void Node::_setState(State state) mgr.setActive(_canvas_item, true); mgr.setPrelight(_canvas_item, false); //this shows the handlers when selecting the nodes - if(_pm().isBSpline()){ - this->front()->setPosition(_pm().BSplineHandleReposition(this->front())); - this->back()->setPosition(_pm().BSplineHandleReposition(this->back())); + if(_pm()._isBSpline()){ + this->front()->setPosition(_pm()._bsplineHandleReposition(this->front())); + this->back()->setPosition(_pm()._bsplineHandleReposition(this->back())); } break; } @@ -1434,7 +1433,9 @@ Node *Node::nodeAwayFrom(Handle *h) Glib::ustring Node::_getTip(unsigned state) const { - bool isBSpline = _pm().isBSpline(); + bool isBSpline = _pm()._isBSpline(); + Handle *h = const_cast<Handle *>(&_front); + Handle *h2 = const_cast<Handle *>(&_back); if (state_held_shift(state)) { bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate()); if (can_drag_out) { @@ -1469,7 +1470,7 @@ Glib::ustring Node::_getTip(unsigned state) const "<b>%s</b>: drag to shape the path (more: Shift, Ctrl, Alt)"), nodetype); }else if(_selection.size() == 1){ return format_tip(C_("Path node tip", - "<b>BSpline node</b>: %g weight, drag to shape the path (more: Shift, Ctrl, Alt)"),noPower/*this->bsplineWeight*/); + "<b>BSpline node</b>: drag to shape the path (more: Shift, Ctrl, Alt). %g power"),_pm()._bsplineHandlePosition(h,h2)); } return format_tip(C_("Path node tip", "<b>%s</b>: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"), nodetype); @@ -1479,7 +1480,7 @@ Glib::ustring Node::_getTip(unsigned state) const "<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype); }else{ return format_tip(C_("Path node tip", - "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)")); + "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"),_pm()._bsplineHandlePosition(h,h2)); } } diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index c8b986824..6b0c95f68 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -11,6 +11,7 @@ */ #include "live_effects/lpe-powerstroke.h" +#include "live_effects/lpe-bspline.h" #include "live_effects/lpe-fillet-chamfer.h" #include <string> #include <sstream> @@ -43,7 +44,6 @@ #include "ui/tool/multi-path-manipulator.h" #include "xml/node.h" #include "xml/node-observer.h" -#include "live_effects/lpe-bspline.h" namespace Inkscape { namespace UI { @@ -56,8 +56,8 @@ enum PathChange { }; } // anonymous namespace -const double handleCubicGap = 0.01; -const double noPower = 0.0; +const double HANDLE_CUBIC_GAP = 0.01; +const double NO_POWER = 0.0; const double defaultStartPower = 0.3334; @@ -124,6 +124,7 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path, , _show_path_direction(false) , _live_outline(true) , _live_objects(true) + , _is_bspline(false) , _lpe_key(lpe_key) { if (_lpe_key.empty()) { @@ -151,7 +152,7 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path, _createControlPointsFromGeometry(); //Define if the path is BSpline on construction - isBSpline(true); + _recalculateIsBSpline(); } PathManipulator::~PathManipulator() @@ -670,12 +671,12 @@ unsigned PathManipulator::_deleteStretch(NodeList::iterator start, NodeList::ite start = next; } // if we are removing, we readjust the handlers - if(isBSpline()){ + if(_isBSpline()){ if(start.prev()){ - start.prev()->front()->setPosition(BSplineHandleReposition(start.prev()->front(),start.prev()->back())); + start.prev()->front()->setPosition(_bsplineHandleReposition(start.prev()->front(),start.prev()->back())); } if(end){ - end->back()->setPosition(BSplineHandleReposition(end->back(),end->front())); + end->back()->setPosition(_bsplineHandleReposition(end->back(),end->front())); } } @@ -999,30 +1000,30 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d // set new handle positions Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]); - if(!isBSpline()){ + if(!_isBSpline()){ n->back()->setPosition(seg1[2]); n->front()->setPosition(seg2[1]); n->setType(NODE_SMOOTH, false); } else { - Geom::D2< Geom::SBasis > SBasisInsideNodes; - SPCurve *lineInsideNodes = new SPCurve(); + Geom::D2< Geom::SBasis > sbasis_inside_nodes; + SPCurve *line_inside_nodes = new SPCurve(); if(second->back()->isDegenerate()){ - lineInsideNodes->moveto(n->position()); - lineInsideNodes->lineto(second->position()); - SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis(); - Geom::Point next = SBasisInsideNodes.valueAt(defaultStartPower); - next = Geom::Point(next[Geom::X] + handleCubicGap,next[Geom::Y] + handleCubicGap); - lineInsideNodes->reset(); + line_inside_nodes->moveto(n->position()); + line_inside_nodes->lineto(second->position()); + sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis(); + Geom::Point next = sbasis_inside_nodes.valueAt(defaultStartPower); + next = Geom::Point(next[Geom::X] + HANDLE_CUBIC_GAP,next[Geom::Y] + HANDLE_CUBIC_GAP); + line_inside_nodes->reset(); n->front()->setPosition(next); }else{ n->front()->setPosition(seg2[1]); } if(first->front()->isDegenerate()){ - lineInsideNodes->moveto(n->position()); - lineInsideNodes->lineto(first->position()); - SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis(); - Geom::Point previous = SBasisInsideNodes.valueAt(defaultStartPower); - previous = Geom::Point(previous[Geom::X] + handleCubicGap,previous[Geom::Y] + handleCubicGap); + line_inside_nodes->moveto(n->position()); + line_inside_nodes->lineto(first->position()); + sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis(); + Geom::Point previous = sbasis_inside_nodes.valueAt(defaultStartPower); + previous = Geom::Point(previous[Geom::X] + HANDLE_CUBIC_GAP,previous[Geom::Y] + HANDLE_CUBIC_GAP); n->back()->setPosition(previous); }else{ n->back()->setPosition(seg1[2]); @@ -1217,14 +1218,17 @@ void PathManipulator::_createControlPointsFromGeometry() } //determines if the trace has a bspline effect and the number of steps that it takes -int PathManipulator::BSplineGetSteps() const { +int PathManipulator::_bsplineGetSteps() const { LivePathEffect::LPEBSpline const *lpe_bsp = NULL; - if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){ - Inkscape::LivePathEffect::Effect const *thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE); - if(thisEffect){ - lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline const*>(thisEffect->getLPEObj()->get_lpe()); + SPLPEItem * path = dynamic_cast<SPLPEItem *>(_path); + if (path){ + if(path->hasPathEffect()){ + Inkscape::LivePathEffect::Effect const *this_effect = path->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE); + if(this_effect){ + lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline const*>(this_effect->getLPEObj()->get_lpe()); + } } } int steps = 0; @@ -1235,66 +1239,72 @@ int PathManipulator::BSplineGetSteps() const { } // determines if the trace has bspline effect -bool PathManipulator::isBSpline(bool recalculate){ - if(recalculate){ - _is_bspline = this->BSplineGetSteps() > 0; +void PathManipulator::_recalculateIsBSpline(){ + if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) { + Inkscape::LivePathEffect::Effect const *this_effect = _path->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE); + if(this_effect){ + _is_bspline = true; + return; + } } - return _is_bspline; + _is_bspline = false; } -bool PathManipulator::isBSpline() const { - return BSplineGetSteps() > 0; +bool PathManipulator::_isBSpline() const { + return _is_bspline; } // returns the corresponding strength to the position of the handlers -double PathManipulator::BSplineHandlePosition(Handle *h, Handle *h2){ +double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2) +{ using Geom::X; using Geom::Y; if(h2){ h = h2; } - double pos = noPower; + double pos = NO_POWER; Node *n = h->parent(); - Node * nextNode = NULL; - nextNode = n->nodeToward(h); - if(nextNode){ - SPCurve *lineInsideNodes = new SPCurve(); - lineInsideNodes->moveto(n->position()); - lineInsideNodes->lineto(nextNode->position()); + Node * next_node = NULL; + next_node = n->nodeToward(h); + if(next_node){ + SPCurve *line_inside_nodes = new SPCurve(); + line_inside_nodes->moveto(n->position()); + line_inside_nodes->lineto(next_node->position()); if(!are_near(h->position(), n->position())){ - pos = Geom::nearest_point(Geom::Point(h->position()[X] - handleCubicGap, h->position()[Y] - handleCubicGap), *lineInsideNodes->first_segment()); + pos = Geom::nearest_point(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment()); } } - if (pos == noPower && !h2){ - return BSplineHandlePosition(h, h->other()); + if (pos == NO_POWER && !h2){ + return _bsplineHandlePosition(h, h->other()); } return pos; } // give the location for the handler in the corresponding position -Geom::Point PathManipulator::BSplineHandleReposition(Handle *h, Handle *h2){ - double pos = this->BSplineHandlePosition(h, h2); - return BSplineHandleReposition(h,pos); +Geom::Point PathManipulator::_bsplineHandleReposition(Handle *h, Handle *h2) +{ + double pos = this->_bsplineHandlePosition(h, h2); + return _bsplineHandleReposition(h,pos); } // give the location for the handler to the specified position -Geom::Point PathManipulator::BSplineHandleReposition(Handle *h,double pos){ +Geom::Point PathManipulator::_bsplineHandleReposition(Handle *h,double pos){ using Geom::X; using Geom::Y; Geom::Point ret = h->position(); Node *n = h->parent(); - Geom::D2< Geom::SBasis > SBasisInsideNodes; - SPCurve *lineInsideNodes = new SPCurve(); - Node * nextNode = NULL; - nextNode = n->nodeToward(h); - if(nextNode && pos != noPower){ - lineInsideNodes->moveto(n->position()); - lineInsideNodes->lineto(nextNode->position()); - SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis(); - ret = SBasisInsideNodes.valueAt(pos); - ret = Geom::Point(ret[X] + handleCubicGap,ret[Y] + handleCubicGap); + Geom::D2< Geom::SBasis > sbasis_inside_nodes; + SPCurve *line_inside_nodes = new SPCurve(); + Node * next_node = NULL; + next_node = n->nodeToward(h); + if(next_node && pos != NO_POWER){ + line_inside_nodes->moveto(n->position()); + line_inside_nodes->lineto(next_node->position()); + sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis(); + ret = sbasis_inside_nodes.valueAt(pos); + ret = Geom::Point(ret[X] + HANDLE_CUBIC_GAP, ret[Y] + HANDLE_CUBIC_GAP); }else{ - if(pos == noPower){ + if(pos == NO_POWER){ ret = n->position(); } } @@ -1309,7 +1319,7 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) { Geom::PathBuilder builder; //Refresh if is bspline some times -think on path change selection, this value get lost - isBSpline(true); + _recalculateIsBSpline(); for (std::list<SubpathPtr>::iterator spi = _subpaths.begin(); spi != _subpaths.end(); ) { SubpathPtr subpath = *spi; if (subpath->empty()) { @@ -1338,17 +1348,17 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) _spcurve->set_pathvector(pathv); if (alert_LPE) { /// \todo note that _path can be an Inkscape::LivePathEffect::Effect* too, kind of confusing, rework member naming? - if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){ - Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE); - if(thisEffect){ - LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe()); + if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) { + Inkscape::LivePathEffect::Effect* this_effect = _path->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE); + if(this_effect){ + LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(this_effect->getLPEObj()->get_lpe()); if (lpe_pwr) { lpe_pwr->adjustForNewPath(pathv); } } - thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER); - if(thisEffect){ - LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe()); + this_effect = _path->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER); + if(this_effect){ + LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(this_effect->getLPEObj()->get_lpe()); if (lpe_fll) { lpe_fll->adjustForNewPath(pathv); } diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 4d2bf4300..2219af849 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -96,7 +96,7 @@ public: NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected, bool search_unselected, bool closest); - int BSplineGetSteps() const; + int _bsplineGetSteps() const; // this is necessary for Tab-selection in MultiPathManipulator SubpathList &subpathList() { return _subpaths; } @@ -107,11 +107,11 @@ private: void _createControlPointsFromGeometry(); - bool isBSpline(bool recalculate = false); - bool isBSpline() const; - double BSplineHandlePosition(Handle *h, Handle *h2 = NULL); - Geom::Point BSplineHandleReposition(Handle *h, Handle *h2 = NULL); - Geom::Point BSplineHandleReposition(Handle *h, double pos); + void _recalculateIsBSpline(); + bool _isBSpline() const; + double _bsplineHandlePosition(Handle *h, Handle *h2 = NULL); + Geom::Point _bsplineHandleReposition(Handle *h, Handle *h2 = NULL); + Geom::Point _bsplineHandleReposition(Handle *h, double pos); void _createGeometryFromControlPoints(bool alert_LPE = false); unsigned _deleteStretch(NodeList::iterator first, NodeList::iterator last, bool keep_shape); std::string _createTypeString(); diff --git a/src/ui/tools/box3d-tool.h b/src/ui/tools/box3d-tool.h index 1dd6bb5f8..33ae6d8e7 100644 --- a/src/ui/tools/box3d-tool.h +++ b/src/ui/tools/box3d-tool.h @@ -80,7 +80,7 @@ private: Proj::Pt3 drag_ptC_proj; bool ctrl_dragged; /* whether we are ctrl-dragging */ - bool extruded; /* whether shift-dragging already occured (i.e. the box is already extruded) */ + bool extruded; /* whether shift-dragging already occurred (i.e. the box is already extruded) */ sigc::connection sel_changed_connection; diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index 19094e3f7..0a36877ff 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -49,7 +49,7 @@ * Much of the way connectors work for user-defined points has been * changed so that it no longer defines special attributes to record * the points. Instead it uses single node paths to define points - * who are then seperate objects that can be fixed on the canvas, + * who are then separate objects that can be fixed on the canvas, * grouped into objects and take full advantage of all transform, snap * and align functionality of all other objects. * diff --git a/src/ui/tools/dynamic-base.h b/src/ui/tools/dynamic-base.h index c948fa286..095af8f88 100644 --- a/src/ui/tools/dynamic-base.h +++ b/src/ui/tools/dynamic-base.h @@ -47,7 +47,7 @@ protected: /** accumulated shape which ultimately goes in svg:path */ SPCurve *accumulated; - /** canvas items for "comitted" segments */ + /** canvas items for "committed" segments */ GSList *segments; /** canvas item for red "leading" segment */ diff --git a/src/ui/tools/flood-tool.cpp b/src/ui/tools/flood-tool.cpp index bb8782dfa..ffd41d97d 100644 --- a/src/ui/tools/flood-tool.cpp +++ b/src/ui/tools/flood-tool.cpp @@ -84,6 +84,28 @@ const std::string& FloodTool::getPrefsPath() { const std::string FloodTool::prefsPath = "/tools/paintbucket"; +// TODO: Replace by C++11 initialization +// Must match PaintBucketChannels enum +Glib::ustring ch_init[8] = { + _("Visible Colors"), + _("Red"), + _("Green"), + _("Blue"), + _("Hue"), + _("Saturation"), + _("Lightness"), + _("Alpha"), +}; +const std::vector<Glib::ustring> FloodTool::channel_list( ch_init, ch_init+8 ); + +Glib::ustring gap_init[4] = { + C_("Flood autogap", "None"), + C_("Flood autogap", "Small"), + C_("Flood autogap", "Medium"), + C_("Flood autogap", "Large") +}; +const std::vector<Glib::ustring> FloodTool::gap_list( gap_init, gap_init+4 ); + FloodTool::FloodTool() : ToolBase(cursor_paintbucket_xpm, 11, 30) , item(NULL) @@ -174,38 +196,6 @@ inline unsigned char * get_trace_pixel(guchar *trace_px, int x, int y, int width } /** - * Generate the list of trace channel selection entries. - */ -GList * flood_channels_dropdown_items_list() { - GList *glist = NULL; - - glist = g_list_append (glist, _("Visible Colors")); - glist = g_list_append (glist, _("Red")); - glist = g_list_append (glist, _("Green")); - glist = g_list_append (glist, _("Blue")); - glist = g_list_append (glist, _("Hue")); - glist = g_list_append (glist, _("Saturation")); - glist = g_list_append (glist, _("Lightness")); - glist = g_list_append (glist, _("Alpha")); - - return glist; -} - -/** - * Generate the list of autogap selection entries. - */ -GList * flood_autogap_dropdown_items_list() { - GList *glist = NULL; - - glist = g_list_append (glist, (void*) C_("Flood autogap", "None")); - glist = g_list_append (glist, (void*) C_("Flood autogap", "Small")); - glist = g_list_append (glist, (void*) C_("Flood autogap", "Medium")); - glist = g_list_append (glist, (void*) C_("Flood autogap", "Large")); - - return glist; -} - -/** * Compare a pixel in a pixel buffer with another pixel to determine if a point should be included in the fill operation. * @param check The pixel in the pixel buffer to check. * @param orig The original selected pixel to use as the fill target color. diff --git a/src/ui/tools/flood-tool.h b/src/ui/tools/flood-tool.h index 5104a42e9..100875f22 100644 --- a/src/ui/tools/flood-tool.h +++ b/src/ui/tools/flood-tool.h @@ -13,6 +13,7 @@ #include <sigc++/connection.h> #include "ui/tools/tool-base.h" +#include <vector> #define SP_FLOOD_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::FloodTool*>((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_FLOOD_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::FloodTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -39,15 +40,14 @@ public: virtual const std::string& getPrefsPath(); static void set_channels(gint channels); + static const std::vector<Glib::ustring> channel_list; + static const std::vector<Glib::ustring> gap_list; private: void selection_changed(Inkscape::Selection* selection); void finishItem(); }; -GList* flood_channels_dropdown_items_list (void); -GList* flood_autogap_dropdown_items_list (void); - enum PaintBucketChannels { FLOOD_CHANNELS_RGB, FLOOD_CHANNELS_R, diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 0f14d7534..e8cbfcdbf 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -92,7 +92,7 @@ FreehandBase::FreehandBase(gchar const *const *cursor_shape, gint hot_x, gint ho , white_item(NULL) , white_curves(NULL) , white_anchors(NULL) - , overwriteCurve(NULL) + , overwrite_curve(NULL) , sa(NULL) , ea(NULL) , waiting_LPE_type(Inkscape::LivePathEffect::INVALID_LPE) @@ -149,7 +149,7 @@ void FreehandBase::setup() { this->green_closed = FALSE; // Create start anchor alternative curve - this->overwriteCurve = new SPCurve(); + this->overwrite_curve = new SPCurve(); this->attach = TRUE; spdc_attach_selection(this, this->selection); @@ -575,12 +575,12 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed) } if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 || prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){ - dc->overwriteCurve->append_continuous(c, 0.0625); + dc->overwrite_curve->append_continuous(c, 0.0625); c->unref(); - dc->overwriteCurve->closepath_current(); + dc->overwrite_curve->closepath_current(); if(dc->sa){ dc->white_curves = g_slist_remove(dc->white_curves, dc->sa->curve); - dc->white_curves = g_slist_append(dc->white_curves, dc->overwriteCurve); + dc->white_curves = g_slist_append(dc->white_curves, dc->overwrite_curve); } }else{ dc->sa->curve->append_continuous(c, 0.0625); @@ -597,7 +597,7 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed) dc->white_curves = g_slist_remove(dc->white_curves, s); if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 || prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){ - s = dc->overwriteCurve; + s = dc->overwrite_curve; } if (dc->sa->start) { s = reverse_then_unref(s); diff --git a/src/ui/tools/freehand-base.h b/src/ui/tools/freehand-base.h index 6b4265215..a3e7b42f9 100644 --- a/src/ui/tools/freehand-base.h +++ b/src/ui/tools/freehand-base.h @@ -78,7 +78,7 @@ public: //ALternative curve to use on continuing exisiting curve in case of bspline or spirolive //because usigh anchor curves give memory and random bugs, - and obscure code- in some plataform reported by su_v in mac - SPCurve *overwriteCurve; + SPCurve *overwrite_curve; // Start anchor SPDrawAnchor *sa; diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index cae525bfb..bf38b5ca5 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -321,7 +321,7 @@ sp_gradient_context_add_stops_between_selected_stops (GradientTool *rc) if (d->point_type == POINT_RG_FOCUS) { /* * There are 2 draggables at the center (start) of a radial gradient - * To avoid creating 2 seperate stops, ignore this draggable point type + * To avoid creating 2 separate stops, ignore this draggable point type */ continue; } diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index af341a9aa..0e68af601 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -48,7 +48,7 @@ // Mesh specific #include "ui/tools/mesh-tool.h" -#include "sp-mesh-gradient.h" +#include "sp-mesh.h" #include "display/sp-ctrlcurve.h" using Inkscape::DocumentUndo; @@ -162,9 +162,9 @@ void MeshTool::selection_changed(Inkscape::Selection* /*sel*/) { // if (style && (style->fill.isPaintserver())) { // SPPaintServer *server = item->style->getFillPaintServer(); - // if ( SP_IS_MESHGRADIENT(server) ) { + // if ( SP_IS_MESH(server) ) { - // SPMeshGradient *mg = SP_MESHGRADIENT(server); + // SPMesh *mg = SP_MESH(server); // guint rows = 0;//mg->array.patches.size(); // for ( guint i = 0; i < rows; ++i ) { @@ -327,8 +327,8 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) SPDocument *doc = NULL; GrDrag *drag = rc->_grdrag; - std::map<SPMeshGradient*, std::vector<guint> > points; - std::map<SPMeshGradient*, SPItem*> items; + std::map<SPMesh*, std::vector<guint> > points; + std::map<SPMesh*, SPItem*> items; // Get list of selected draggers for each mesh. // For all selected draggers @@ -342,7 +342,7 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) if( d->point_type != POINT_MG_CORNER ) continue; // Find the gradient - SPMeshGradient *gradient = SP_MESHGRADIENT( getGradient (d->item, d->fill_or_stroke) ); + SPMesh *gradient = SP_MESH( getGradient (d->item, d->fill_or_stroke) ); // Collect points together for same gradient points[gradient].push_back( d->point_i ); @@ -351,8 +351,8 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) } // Loop over meshes. - for( std::map<SPMeshGradient*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) { - SPMeshGradient *mg = SP_MESHGRADIENT( iter->first ); + for( std::map<SPMesh*, std::vector<guint> >::const_iterator iter = points.begin(); iter != points.end(); ++iter) { + SPMesh *mg = SP_MESH( iter->first ); if( iter->second.size() > 0 ) { guint noperation = 0; switch (operation) { diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 40d54af6e..ef00eaa40 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -75,7 +75,7 @@ * - ControlPointSelection: keeps track of node selection and a set of nodes that can potentially * be selected. There can be more than one selection. Performs actions that require no * knowledge about the path, only about the nodes, like dragging and transforms. It is not - * specific to nodes and can accomodate any control point derived from SelectableControlPoint. + * specific to nodes and can accommodate any control point derived from SelectableControlPoint. * Transforms nodes in response to transform handle events. * - TransformHandleSet: displays nodeset transform handles and emits transform events. The aim * is to eventually use a common class for object and control point transforms. diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index d28b7c27a..daffc7032 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -85,7 +85,7 @@ namespace Tools { static Geom::Point pen_drag_origin_w(0, 0); static bool pen_within_tolerance = false; static int pen_last_paraxial_dir = 0; // last used direction in horizontal/vertical mode; 0 = horizontal, 1 = vertical -const double handleCubicGap = 0.01; +const double HANDLE_CUBIC_GAP = 0.01; const std::string& PenTool::getPrefsPath() { return PenTool::prefsPath; @@ -165,17 +165,17 @@ void PenTool::setPolylineMode() { this->polylines_paraxial = (mode == 4); //we call the function which defines the Spiro modes and the BSpline //todo: merge to one function only - this->_pen_context_set_mode(mode); + this->_penContextSetMode(mode); } /* *.Set the mode of draw spiro, and bsplines */ -void PenTool::_pen_context_set_mode(guint mode) { +void PenTool::_penContextSetMode(guint mode) { // define the nodes this->spiro = (mode == 1); this->bspline = (mode == 2); - this->_bspline_spiro_color(); + this->_bsplineSpiroColor(); } /** @@ -429,7 +429,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) { // This is allowed, if we just canceled curve case PenTool::POINT: if (this->npoints == 0) { - this->_bspline_spiro_color(); + this->_bsplineSpiroColor(); Geom::Point p; if ((bevent.state & GDK_CONTROL_MASK) && (this->polylines_only || this->polylines_paraxial)) { p = event_dt; @@ -451,7 +451,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) { this->sa = anchor; if(anchor){ - this->_bspline_spiro_start_anchor(bevent.state & GDK_SHIFT_MASK); + this->_bsplineSpiroStartAnchor(bevent.state & GDK_SHIFT_MASK); } if (anchor && (!this->hasWaitingLPE()|| this->bspline || this->spiro)) { // Adjust point to anchor if needed; if we have a waiting LPE, we need @@ -700,10 +700,10 @@ bool PenTool::_handleMotionNotify(GdkEventMotion const &mevent) { } // calls the function "bspline_spiro_motion" when the mouse starts or stops moving if(this->bspline){ - this->_bspline_spiro_motion(mevent.state & GDK_SHIFT_MASK); + this->_bsplineSpiroMotion(mevent.state & GDK_SHIFT_MASK); }else{ if ( Geom::LInfty( event_w - pen_drag_origin_w ) > (tolerance/2) || mevent.time == 0) { - this->_bspline_spiro_motion(mevent.state & GDK_SHIFT_MASK); + this->_bsplineSpiroMotion(mevent.state & GDK_SHIFT_MASK); pen_drag_origin_w = event_w; } } @@ -742,7 +742,7 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) { case PenTool::POINT: if ( this->npoints == 0 ) { // Start new thread only with button release - this->_bspline_spiro_color(); + this->_bsplineSpiroColor(); if (anchor) { p = anchor->dp; } @@ -750,7 +750,7 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) { // continue the existing curve if (anchor) { if(this->bspline || this->spiro){ - this->_bspline_spiro_start_anchor(revent.state & GDK_SHIFT_MASK);; + this->_bsplineSpiroStartAnchor(revent.state & GDK_SHIFT_MASK);; } } this->_setInitialPoint(p); @@ -879,11 +879,11 @@ void PenTool::_redrawAll() { this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data); } // one canvas bpath for all of green_curve - SPCanvasItem *cshape = sp_canvas_bpath_new(this->desktop->getSketch(), this->green_curve); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cshape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cshape), 0, SP_WIND_RULE_NONZERO); + SPCanvasItem *canvas_shape = sp_canvas_bpath_new(this->desktop->getSketch(), this->green_curve); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvas_shape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvas_shape), 0, SP_WIND_RULE_NONZERO); - this->green_bpaths = g_slist_prepend(this->green_bpaths, cshape); + this->green_bpaths = g_slist_prepend(this->green_bpaths, canvas_shape); } if (this->green_anchor) SP_CTRL(this->green_anchor->ctrl)->moveto(this->green_anchor->dp); @@ -925,7 +925,7 @@ void PenTool::_redrawAll() { // simply redraw the spiro. because its a redrawing, we don't call the global function, // but we call the redrawing at the ending. - this->_bspline_spiro_build(); + this->_bsplineSpiroBuild(); } void PenTool::_lastpointMove(gdouble x, gdouble y) { @@ -1001,7 +1001,7 @@ void PenTool::_lastpointToCurve() { } //if the last node is an union with another curve if (this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()) { - this->_bspline_spiro_start_anchor(false); + this->_bsplineSpiroStartAnchor(false); } } @@ -1048,7 +1048,7 @@ void PenTool::_lastpointToLine() { } // if the last node is an union with another curve if(this->green_curve->is_empty() && this->sa && !this->sa->curve->is_empty()){ - this->_bspline_spiro_start_anchor(true); + this->_bsplineSpiroStartAnchor(true); } } @@ -1312,7 +1312,7 @@ void PenTool::_setAngleDistanceStatusMessage(Geom::Point const p, int pc_point_t } // this function changes the colors red, green and blue making them transparent or not, depending on if spiro is being used. -void PenTool::_bspline_spiro_color() +void PenTool::_bsplineSpiroColor() { static Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if(this->spiro){ @@ -1346,25 +1346,25 @@ void PenTool::_bspline_spiro_color() this->green_bpaths = g_slist_remove(this->green_bpaths, this->green_bpaths->data); } // one canvas bpath for all of green_curve - SPCanvasItem *cshape = sp_canvas_bpath_new(this->desktop->getSketch(), this->green_curve); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cshape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cshape), 0, SP_WIND_RULE_NONZERO); - this->green_bpaths = g_slist_prepend(this->green_bpaths, cshape); + SPCanvasItem *canvas_shape = sp_canvas_bpath_new(this->desktop->getSketch(), this->green_curve); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvas_shape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvas_shape), 0, SP_WIND_RULE_NONZERO); + this->green_bpaths = g_slist_prepend(this->green_bpaths, canvas_shape); } sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->red_bpath), this->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); } -void PenTool::_bspline_spiro(bool shift) +void PenTool::_bsplineSpiro(bool shift) { if(!this->spiro && !this->bspline) return; - shift?this->_bspline_spiro_off():this->_bspline_spiro_on(); - this->_bspline_spiro_build(); + shift?this->_bsplineSpiroOff():this->_bsplineSpiroOn(); + this->_bsplineSpiroBuild(); } -void PenTool::_bspline_spiro_on() +void PenTool::_bsplineSpiroOn() { if(!this->red_curve->is_empty()){ using Geom::X; @@ -1373,11 +1373,11 @@ void PenTool::_bspline_spiro_on() this->p[0] = this->red_curve->first_segment()->initialPoint(); this->p[3] = this->red_curve->first_segment()->finalPoint(); this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]); - this->p[2] = Geom::Point(this->p[2][X] + handleCubicGap,this->p[2][Y] + handleCubicGap); + this->p[2] = Geom::Point(this->p[2][X] + HANDLE_CUBIC_GAP,this->p[2][Y] + HANDLE_CUBIC_GAP); } } -void PenTool::_bspline_spiro_off() +void PenTool::_bsplineSpiroOff() { if(!this->red_curve->is_empty()){ this->npoints = 5; @@ -1387,7 +1387,7 @@ void PenTool::_bspline_spiro_off() } } -void PenTool::_bspline_spiro_start_anchor(bool shift) +void PenTool::_bsplineSpiroStartAnchor(bool shift) { if(this->sa->curve->is_empty()){ return; @@ -1423,73 +1423,73 @@ void PenTool::_bspline_spiro_start_anchor(bool shift) return; if(shift) - this->_bspline_spiro_start_anchor_off(); + this->_bsplineSpiroStartAnchorOff(); else - this->_bspline_spiro_start_anchor_on(); + this->_bsplineSpiroStartAnchorOn(); } -void PenTool::_bspline_spiro_start_anchor_on() +void PenTool::_bsplineSpiroStartAnchorOn() { using Geom::X; using Geom::Y; - SPCurve *tmpCurve = new SPCurve(); - tmpCurve = this->sa->curve->copy(); + SPCurve *tmp_curve = new SPCurve(); + tmp_curve = this->sa->curve->copy(); if(this->sa->start) - tmpCurve = tmpCurve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - SPCurve *lastSeg = new SPCurve(); - Geom::Point A = tmpCurve->last_segment()->initialPoint(); - Geom::Point D = tmpCurve->last_segment()->finalPoint(); - Geom::Point C = D + (1./3)*(A - D); - C = Geom::Point(C[X] + handleCubicGap,C[Y] + handleCubicGap); + tmp_curve = tmp_curve ->create_reverse(); + Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmp_curve ->last_segment()); + SPCurve *last_segment = new SPCurve(); + Geom::Point point_a = tmp_curve ->last_segment()->initialPoint(); + Geom::Point point_d = tmp_curve ->last_segment()->finalPoint(); + Geom::Point point_c = point_d + (1./3)*(point_a - point_d); + point_c = Geom::Point(point_c[X] + HANDLE_CUBIC_GAP, point_c[Y] + HANDLE_CUBIC_GAP); if(cubic){ - lastSeg->moveto(A); - lastSeg->curveto((*cubic)[1],C,D); + last_segment->moveto(point_a); + last_segment->curveto((*cubic)[1],point_c,point_d); }else{ - lastSeg->moveto(A); - lastSeg->curveto(A,C,D); + last_segment->moveto(point_a); + last_segment->curveto(point_a,point_c,point_d); } - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; + if( tmp_curve ->get_segment_count() == 1){ + tmp_curve = last_segment; }else{ //we eliminate the last segment - tmpCurve->backspace(); + tmp_curve ->backspace(); //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); + tmp_curve ->append_continuous(last_segment, 0.0625); } if (this->sa->start) { - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); } - this->overwriteCurve = tmpCurve; + this->overwrite_curve = tmp_curve ; } -void PenTool::_bspline_spiro_start_anchor_off() +void PenTool::_bsplineSpiroStartAnchorOff() { - SPCurve *tmpCurve = new SPCurve(); - tmpCurve = this->sa->curve->copy(); + SPCurve *tmp_curve = new SPCurve(); + tmp_curve = this->sa->curve->copy(); if(this->sa->start) - tmpCurve = tmpCurve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); + tmp_curve = tmp_curve ->create_reverse(); + Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmp_curve ->last_segment()); if(cubic){ - SPCurve *lastSeg = new SPCurve(); - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; + SPCurve *last_segment = new SPCurve(); + last_segment->moveto((*cubic)[0]); + last_segment->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); + if( tmp_curve ->get_segment_count() == 1){ + tmp_curve = last_segment; }else{ //we eliminate the last segment - tmpCurve->backspace(); + tmp_curve ->backspace(); //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); + tmp_curve ->append_continuous(last_segment, 0.0625); } } if (this->sa->start) { - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); } - this->overwriteCurve = tmpCurve; + this->overwrite_curve = tmp_curve ; } -void PenTool::_bspline_spiro_motion(bool shift){ +void PenTool::_bsplineSpiroMotion(bool shift){ if(!this->spiro && !this->bspline) return; @@ -1497,40 +1497,40 @@ void PenTool::_bspline_spiro_motion(bool shift){ using Geom::Y; if(this->red_curve->is_empty()) return; this->npoints = 5; - SPCurve *tmpCurve = new SPCurve(); + SPCurve *tmp_curve = new SPCurve(); this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]); - this->p[2] = Geom::Point(this->p[2][X] + handleCubicGap,this->p[2][Y] + handleCubicGap); + this->p[2] = Geom::Point(this->p[2][X] + HANDLE_CUBIC_GAP,this->p[2][Y] + HANDLE_CUBIC_GAP); if(this->green_curve->is_empty() && !this->sa){ this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]); - this->p[1] = Geom::Point(this->p[1][X] + handleCubicGap,this->p[1][Y] + handleCubicGap); + this->p[1] = Geom::Point(this->p[1][X] + HANDLE_CUBIC_GAP,this->p[1][Y] + HANDLE_CUBIC_GAP); if(shift){ this->p[2] = this->p[3]; } }else if(!this->green_curve->is_empty()){ - tmpCurve = this->green_curve->copy(); + tmp_curve = this->green_curve->copy(); }else{ - tmpCurve = this->overwriteCurve->copy(); + tmp_curve = this->overwrite_curve->copy(); if(this->sa->start) - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); } - if(!tmpCurve->is_empty()){ - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); + if(!tmp_curve ->is_empty()){ + Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmp_curve ->last_segment()); if(cubic){ if(this->bspline){ - SPCurve * WPower = new SPCurve(); - Geom::D2< Geom::SBasis > SBasisWPower; - WPower->moveto(tmpCurve->last_segment()->finalPoint()); - WPower->lineto(tmpCurve->last_segment()->initialPoint()); - float WP = Geom::nearest_point((*cubic)[2],*WPower->first_segment()); - WPower->reset(); - WPower->moveto(this->red_curve->last_segment()->initialPoint()); - WPower->lineto(this->red_curve->last_segment()->finalPoint()); - SBasisWPower = WPower->first_segment()->toSBasis(); - WPower->reset(); - this->p[1] = SBasisWPower.valueAt(WP); + SPCurve * weight_power = new SPCurve(); + Geom::D2< Geom::SBasis > SBasisweight_power; + weight_power->moveto(tmp_curve ->last_segment()->finalPoint()); + weight_power->lineto(tmp_curve ->last_segment()->initialPoint()); + float WP = Geom::nearest_point((*cubic)[2],*weight_power->first_segment()); + weight_power->reset(); + weight_power->moveto(this->red_curve->last_segment()->initialPoint()); + weight_power->lineto(this->red_curve->last_segment()->finalPoint()); + SBasisweight_power = weight_power->first_segment()->toSBasis(); + weight_power->reset(); + this->p[1] = SBasisweight_power.valueAt(WP); if(!Geom::are_near(this->p[1],this->p[0])){ - this->p[1] = Geom::Point(this->p[1][X] + handleCubicGap,this->p[1][Y] + handleCubicGap); + this->p[1] = Geom::Point(this->p[1][X] + HANDLE_CUBIC_GAP,this->p[1][Y] + HANDLE_CUBIC_GAP); } else { this->p[1] = this->p[0]; } @@ -1548,129 +1548,129 @@ void PenTool::_bspline_spiro_motion(bool shift){ if(this->anchor_statusbar && !this->red_curve->is_empty()){ if(shift){ - this->_bspline_spiro_end_anchor_off(); + this->_bsplineSpiroEndAnchorOff(); }else{ - this->_bspline_spiro_end_anchor_on(); + this->_bsplineSpiroEndAnchorOn(); } } - this->_bspline_spiro_build(); + this->_bsplineSpiroBuild(); } -void PenTool::_bspline_spiro_end_anchor_on() +void PenTool::_bsplineSpiroEndAnchorOn() { using Geom::X; using Geom::Y; this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]); - this->p[2] = Geom::Point(this->p[2][X] + handleCubicGap,this->p[2][Y] + handleCubicGap); - SPCurve *tmpCurve = new SPCurve(); - SPCurve *lastSeg = new SPCurve(); - Geom::Point C(0,0); + this->p[2] = Geom::Point(this->p[2][X] + HANDLE_CUBIC_GAP,this->p[2][Y] + HANDLE_CUBIC_GAP); + SPCurve *tmp_curve = new SPCurve(); + SPCurve *last_segment = new SPCurve(); + Geom::Point point_c(0,0); bool reverse = false; if( this->green_anchor && this->green_anchor->active ){ - tmpCurve = this->green_curve->create_reverse(); + tmp_curve = this->green_curve->create_reverse(); if(this->green_curve->get_segment_count()==0){ return; } reverse = true; } else if(this->sa){ - tmpCurve = this->overwriteCurve->copy(); + tmp_curve = this->overwrite_curve->copy(); if(!this->sa->start){ - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); reverse = true; } }else{ return; } - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); + Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmp_curve ->last_segment()); if(this->bspline){ - C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint()); - C = Geom::Point(C[X] + handleCubicGap,C[Y] + handleCubicGap); + point_c = tmp_curve ->last_segment()->finalPoint() + (1./3)*(tmp_curve ->last_segment()->initialPoint() - tmp_curve ->last_segment()->finalPoint()); + point_c = Geom::Point(point_c[X] + HANDLE_CUBIC_GAP, point_c[Y] + HANDLE_CUBIC_GAP); }else{ - C = this->p[3] + this->p[3] - this->p[2]; + point_c = this->p[3] + this->p[3] - this->p[2]; } if(cubic){ - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],C,(*cubic)[3]); + last_segment->moveto((*cubic)[0]); + last_segment->curveto((*cubic)[1],point_c,(*cubic)[3]); }else{ - lastSeg->moveto(tmpCurve->last_segment()->initialPoint()); - lastSeg->lineto(tmpCurve->last_segment()->finalPoint()); + last_segment->moveto(tmp_curve ->last_segment()->initialPoint()); + last_segment->lineto(tmp_curve ->last_segment()->finalPoint()); } - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; + if( tmp_curve ->get_segment_count() == 1){ + tmp_curve = last_segment; }else{ //we eliminate the last segment - tmpCurve->backspace(); + tmp_curve ->backspace(); //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); + tmp_curve ->append_continuous(last_segment, 0.0625); } if (reverse) { - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); } if( this->green_anchor && this->green_anchor->active ) { this->green_curve->reset(); - this->green_curve = tmpCurve; + this->green_curve = tmp_curve ; }else{ - this->overwriteCurve->reset(); - this->overwriteCurve = tmpCurve; + this->overwrite_curve->reset(); + this->overwrite_curve = tmp_curve ; } } -void PenTool::_bspline_spiro_end_anchor_off() +void PenTool::_bsplineSpiroEndAnchorOff() { - SPCurve *tmpCurve = new SPCurve(); - SPCurve *lastSeg = new SPCurve(); + SPCurve *tmp_curve = new SPCurve(); + SPCurve *last_segment = new SPCurve(); bool reverse = false; this->p[2] = this->p[3]; if( this->green_anchor && this->green_anchor->active ){ - tmpCurve = this->green_curve->create_reverse(); + tmp_curve = this->green_curve->create_reverse(); if(this->green_curve->get_segment_count()==0){ return; } reverse = true; } else if(this->sa){ - tmpCurve = this->overwriteCurve->copy(); + tmp_curve = this->overwrite_curve->copy(); if(!this->sa->start){ - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); reverse = true; } }else{ return; } - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); + Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmp_curve ->last_segment()); if(cubic){ - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); + last_segment->moveto((*cubic)[0]); + last_segment->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); }else{ - lastSeg->moveto(tmpCurve->last_segment()->initialPoint()); - lastSeg->lineto(tmpCurve->last_segment()->finalPoint()); + last_segment->moveto(tmp_curve ->last_segment()->initialPoint()); + last_segment->lineto(tmp_curve ->last_segment()->finalPoint()); } - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; + if( tmp_curve ->get_segment_count() == 1){ + tmp_curve = last_segment; }else{ //we eliminate the last segment - tmpCurve->backspace(); + tmp_curve ->backspace(); //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); + tmp_curve ->append_continuous(last_segment, 0.0625); } if (reverse) { - tmpCurve = tmpCurve->create_reverse(); + tmp_curve = tmp_curve ->create_reverse(); } if( this->green_anchor && this->green_anchor->active ) { this->green_curve->reset(); - this->green_curve = tmpCurve; + this->green_curve = tmp_curve ; }else{ - this->overwriteCurve->reset(); - this->overwriteCurve = tmpCurve; + this->overwrite_curve->reset(); + this->overwrite_curve = tmp_curve ; } } //prepares the curves for its transformation into BSpline curve. -void PenTool::_bspline_spiro_build() +void PenTool::_bsplineSpiroBuild() { if(!this->spiro && !this->bspline){ return; @@ -1680,7 +1680,7 @@ void PenTool::_bspline_spiro_build() SPCurve *curve = new SPCurve(); //If we continuate the existing curve we add it at the start if(this->sa && !this->sa->curve->is_empty()){ - curve = this->overwriteCurve->copy(); + curve = this->overwrite_curve->copy(); if (this->sa->start) { curve = curve->create_reverse(); } @@ -1715,9 +1715,9 @@ void PenTool::_bspline_spiro_build() //Effect *spr = static_cast<Effect*> ( new LPEbspline(lpeobj) ); //spr->doEffect(curve); if(this->bspline){ - this->_bspline_doEffect(curve); + this->_bsplineDoEffect(curve); }else{ - this->_spiro_doEffect(curve); + this->_spiroDoEffect(curve); } sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->blue_bpath), curve); @@ -1741,66 +1741,73 @@ void PenTool::_bspline_spiro_build() } } -void PenTool::_bspline_doEffect(SPCurve * curve) +//from LPE BSPLINE: +void PenTool::_bsplineDoEffect(SPCurve * curve) { - // commenting the function doEffect in src/live_effects/lpe-bspline.cpp - if (curve->get_segment_count() < 1){ + const double NO_POWER = 0.0; + const double DEFAULT_START_POWER = 0.3334; + const double DEFAULT_END_POWER = 0.6667; + if (curve->get_segment_count() < 1) { return; } // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - //Si está vacÃo... - if (path_it->empty()) + if (path_it->empty()) { continue; - //Itreadores - + } Geom::Path::const_iterator curve_it1 = path_it->begin(); Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - SPCurve *nCurve = new SPCurve(); + Geom::Path::const_iterator curve_endit = path_it->end_default(); + SPCurve *curve_n = new SPCurve(); Geom::Point previousNode(0, 0); Geom::Point node(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::D2<Geom::SBasis> SBasisIn; - Geom::D2<Geom::SBasis> SBasisOut; - Geom::D2<Geom::SBasis> SBasisHelper; + Geom::Point point_at1(0, 0); + Geom::Point point_at2(0, 0); + Geom::Point next_point_at1(0, 0); + Geom::D2<Geom::SBasis> sbasis_in; + Geom::D2<Geom::SBasis> sbasis_out; + Geom::D2<Geom::SBasis> sbasis_helper; Geom::CubicBezier const *cubic = NULL; if (path_it->closed()) { + // if the path is closed, maybe we have to stop a bit earlier because the + // closing line segment has zerolength. const Geom::Curve &closingline = path_it->back_closed(); // the closing line segment is always of type + // Geom::LineSegment. if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! curve_endit = path_it->end_open(); } } - nCurve->moveto(curve_it1->initialPoint()); + curve_n->moveto(curve_it1->initialPoint()); while (curve_it1 != curve_endit) { SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - SBasisIn = in->first_segment()->toSBasis(); + sbasis_in = in->first_segment()->toSBasis(); if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { - pointAt1 = SBasisIn.valueAt(0.3334); + point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); + point_at1 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); } if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) { - pointAt2 = SBasisIn.valueAt(0.6667); + point_at2 = sbasis_in.valueAt(DEFAULT_END_POWER); } else { - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); + point_at2 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); } } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); + point_at1 = in->first_segment()->initialPoint(); + point_at2 = in->first_segment()->finalPoint(); } in->reset(); delete in; @@ -1810,31 +1817,30 @@ void PenTool::_bspline_doEffect(SPCurve * curve) out->lineto(curve_it2->finalPoint()); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2); if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); + sbasis_out = out->first_segment()->toSBasis(); if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { - nextPointAt1 = SBasisIn.valueAt(0.3334); + next_point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + next_point_at1 = sbasis_out.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); } } else { - nextPointAt1 = out->first_segment()->initialPoint(); + next_point_at1 = out->first_segment()->initialPoint(); } out->reset(); delete out; } - Geom::Point startNode = path_it->begin()->initialPoint(); if (path_it->closed() && curve_it2 == curve_endit) { SPCurve *start = new SPCurve(); start->moveto(path_it->begin()->initialPoint()); start->lineto(path_it->begin()->finalPoint()); - Geom::D2<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis(); - SPCurve *lineHelper = new SPCurve(); + Geom::D2<Geom::SBasis> sbasis_start = start->first_segment()->toSBasis(); + SPCurve *line_helper = new SPCurve(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*path_it->begin()); if (cubic) { - lineHelper->moveto(SBasisStart.valueAt( + line_helper->moveto(sbasis_start.valueAt( Geom::nearest_point((*cubic)[1], *start->first_segment()))); } else { - lineHelper->moveto(start->first_segment()->initialPoint()); + line_helper->moveto(start->first_segment()->initialPoint()); } start->reset(); delete start; @@ -1842,55 +1848,56 @@ void PenTool::_bspline_doEffect(SPCurve * curve) SPCurve *end = new SPCurve(); end->moveto(curve_it1->initialPoint()); end->lineto(curve_it1->finalPoint()); - Geom::D2<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis(); + Geom::D2<Geom::SBasis> sbasis_end = end->first_segment()->toSBasis(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - lineHelper->lineto(SBasisEnd.valueAt( + line_helper->lineto(sbasis_end.valueAt( Geom::nearest_point((*cubic)[2], *end->first_segment()))); } else { - lineHelper->lineto(end->first_segment()->finalPoint()); + line_helper->lineto(end->first_segment()->finalPoint()); } end->reset(); delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - startNode = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, startNode); - nCurve->move_endpoints(startNode, startNode); + sbasis_helper = line_helper->first_segment()->toSBasis(); + line_helper->reset(); + delete line_helper; + node = sbasis_helper.valueAt(0.5); + curve_n->curveto(point_at1, point_at2, node); + curve_n->move_endpoints(node, node); } else if ( curve_it2 == curve_endit) { - nCurve->curveto(pointAt1, pointAt2, curve_it1->finalPoint()); - nCurve->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint()); + curve_n->curveto(point_at1, point_at2, curve_it1->finalPoint()); + curve_n->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint()); } else { - SPCurve *lineHelper = new SPCurve(); - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; + SPCurve *line_helper = new SPCurve(); + line_helper->moveto(point_at2); + line_helper->lineto(next_point_at1); + sbasis_helper = line_helper->first_segment()->toSBasis(); + line_helper->reset(); + delete line_helper; previousNode = node; - node = SBasisHelper.valueAt(0.5); + node = sbasis_helper.valueAt(0.5); Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) { node = curve_it1->finalPoint(); } - nCurve->curveto(pointAt1, pointAt2, node); + curve_n->curveto(point_at1, point_at2, node); } ++curve_it1; ++curve_it2; } + //y cerramos la curva if (path_it->closed()) { - nCurve->closepath_current(); + curve_n->closepath_current(); } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; + curve->append(curve_n, false); + curve_n->reset(); + delete curve_n; } } //Spiro function cloned from lpe-spiro.cpp // commenting the function "doEffect" from src/live_effects/lpe-spiro.cpp -void PenTool::_spiro_doEffect(SPCurve * curve) +void PenTool::_spiroDoEffect(SPCurve * curve) { using Geom::X; using Geom::Y; @@ -2087,16 +2094,16 @@ void PenTool::_finishSegment(Geom::Point const p, guint const state) { if (!this->red_curve->is_empty()) { - this->_bspline_spiro(state & GDK_SHIFT_MASK); + this->_bsplineSpiro(state & GDK_SHIFT_MASK); this->green_curve->append_continuous(this->red_curve, 0.0625); SPCurve *curve = this->red_curve->copy(); /// \todo fixme: - SPCanvasItem *cshape = sp_canvas_bpath_new(this->desktop->getSketch(), curve); + SPCanvasItem *canvas_shape = sp_canvas_bpath_new(this->desktop->getSketch(), curve); curve->unref(); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cshape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvas_shape), this->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - this->green_bpaths = g_slist_prepend(this->green_bpaths, cshape); + this->green_bpaths = g_slist_prepend(this->green_bpaths, canvas_shape); this->p[0] = this->p[3]; this->p[1] = this->p[4]; @@ -2143,7 +2150,7 @@ bool PenTool::_undoLastPoint() { this->p[1] = this->p[0]; } - // asign the value in a third of the distance of the last segment. + // assign the value in a third of the distance of the last segment. if (this->bspline){ this->p[1] = this->p[0] + (1./3)*(this->p[3] - this->p[0]); } @@ -2165,7 +2172,7 @@ bool PenTool::_undoLastPoint() { this->green_curve->backspace(); } - // assign the value of this->p[1] to the oposite of the green line last segment + // assign the value of this->p[1] to the opposite of the green line last segment if (this->spiro){ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(this->green_curve->last_segment()); if ( cubic ) { @@ -2185,7 +2192,7 @@ bool PenTool::_undoLastPoint() { pen_last_paraxial_dir = !pen_last_paraxial_dir; //redraw - this->_bspline_spiro_build(); + this->_bsplineSpiroBuild(); ret = true; } @@ -2210,7 +2217,7 @@ void PenTool::_finish(gboolean const closed) { // cancelate line without a created segment this->red_curve->reset(); spdc_concat_colors_and_flush(this, closed); - this->overwriteCurve = NULL; + this->overwrite_curve = NULL; this->sa = NULL; this->ea = NULL; diff --git a/src/ui/tools/pen-tool.h b/src/ui/tools/pen-tool.h index 2208005c5..0ae16caf0 100644 --- a/src/ui/tools/pen-tool.h +++ b/src/ui/tools/pen-tool.h @@ -89,33 +89,33 @@ private: bool _handle2ButtonPress(GdkEventButton const &bevent); bool _handleKeyPress(GdkEvent *event); //adds spiro & bspline modes - void _pen_context_set_mode(guint mode); + void _penContextSetMode(guint mode); //this function changes the colors red, green and blue making them transparent or not depending on if the function uses spiro - void _bspline_spiro_color(); + void _bsplineSpiroColor(); //creates a node in bspline or spiro modes - void _bspline_spiro(bool shift); + void _bsplineSpiro(bool shift); //creates a node in bspline or spiro modes - void _bspline_spiro_on(); + void _bsplineSpiroOn(); //creates a CUSP node - void _bspline_spiro_off(); + void _bsplineSpiroOff(); //continues the existing curve in bspline or spiro mode - void _bspline_spiro_start_anchor(bool shift); + void _bsplineSpiroStartAnchor(bool shift); //continues the existing curve with the union node in bspline or spiro modes - void _bspline_spiro_start_anchor_on(); + void _bsplineSpiroStartAnchorOn(); //continues an existing curve with the union node in CUSP mode - void _bspline_spiro_start_anchor_off(); + void _bsplineSpiroStartAnchorOff(); //modifies the "red_curve" when it detects movement - void _bspline_spiro_motion(bool shift); + void _bsplineSpiroMotion(bool shift); //closes the curve with the last node in bspline or spiro mode - void _bspline_spiro_end_anchor_on(); + void _bsplineSpiroEndAnchorOn(); //closes the curve with the last node in CUSP mode - void _bspline_spiro_end_anchor_off(); + void _bsplineSpiroEndAnchorOff(); //CHECK: join all the curves "in game" and we call doEffect function - void _bspline_spiro_build(); + void _bsplineSpiroBuild(); //function bspline cloned from lpe-bspline.cpp - void _bspline_doEffect(SPCurve * curve); + void _bsplineDoEffect(SPCurve * curve); //function spiro cloned from lpe-spiro.cpp - void _spiro_doEffect(SPCurve * curve); + void _spiroDoEffect(SPCurve * curve); void _setInitialPoint(Geom::Point const p); void _setSubsequentPoint(Geom::Point const p, bool statusbar, guint status = 0); diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index db24c7432..008804162 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -191,7 +191,7 @@ bool PencilTool::_handleButtonPress(GdkEventButton const &bevent) { } if (anchor) { p = anchor->dp; - this->overwriteCurve = anchor->curve; + this->overwrite_curve = anchor->curve; desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Continuing selected path")); } else { m.setup(desktop); @@ -663,11 +663,11 @@ void PencilTool::_interpolate() { for (int c = 0; c < n_segs; c++) { // if we are in BSpline we modify the trace to create adhoc nodes if(mode == 2){ - Geom::Point BP = b[4*c+0] + (1./3)*(b[4*c+3] - b[4*c+0]); - BP = Geom::Point(BP[X] + 0.0001,BP[Y] + 0.0001); - Geom::Point CP = b[4*c+3] + (1./3)*(b[4*c+0] - b[4*c+3]); - CP = Geom::Point(CP[X] + 0.0001,CP[Y] + 0.0001); - this->green_curve->curveto(BP,CP,b[4*c+3]); + Geom::Point point_at1 = b[4*c+0] + (1./3)*(b[4*c+3] - b[4*c+0]); + point_at1 = Geom::Point(point_at1[X] + 0.0001,point_at1[Y] + 0.0001); + Geom::Point point_at2 = b[4*c+3] + (1./3)*(b[4*c+0] - b[4*c+3]); + point_at2 = Geom::Point(point_at2[X] + 0.0001,point_at2[Y] + 0.0001); + this->green_curve->curveto(point_at1,point_at2,b[4*c+3]); }else{ this->green_curve->curveto(b[4 * c + 1], b[4 * c + 2], b[4 * c + 3]); } @@ -810,11 +810,11 @@ void PencilTool::_fitAndSplit() { // if we are in BSpline we modify the trace to create adhoc nodes guint mode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0); if(mode == 2){ - Geom::Point B = b[0] + (1./3)*(b[3] - b[0]); - B = Geom::Point(B[X] + 0.0001,B[Y] + 0.0001); - Geom::Point C = b[3] + (1./3)*(b[0] - b[3]); - C = Geom::Point(C[X] + 0.0001,C[Y] + 0.0001); - this->red_curve->curveto(B,C,b[3]); + Geom::Point point_at1 = b[0] + (1./3)*(b[3] - b[0]); + point_at1 = Geom::Point(point_at1[X] + 0.0001,point_at1[Y] + 0.0001); + Geom::Point point_at2 = b[3] + (1./3)*(b[0] - b[3]); + point_at2 = Geom::Point(point_at2[X] + 0.0001,point_at2[Y] + 0.0001); + this->red_curve->curveto(point_at1,point_at2,b[3]); }else{ this->red_curve->curveto(b[1], b[2], b[3]); } diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index 39321ff21..26d74733a 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -406,7 +406,7 @@ static bool sp_spray_recursive(SPDesktop *desktop, parent->appendChild(copy); SPObject *new_obj = doc->getObjectByRepr(copy); - item_copied = dynamic_cast<SPItem *>(new_obj); // Convertion object->item + item_copied = dynamic_cast<SPItem *>(new_obj); // Conversion object->item Geom::Point center=item->getCenter(); sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale)); sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale)); @@ -437,39 +437,41 @@ static bool sp_spray_recursive(SPDesktop *desktop, } i++; } - SPDocument *doc = parent_item->document; - Inkscape::XML::Document* xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *old_repr = parent_item->getRepr(); - Inkscape::XML::Node *parent = old_repr->parent(); - - Geom::OptRect a = parent_item->documentVisualBounds(); - if (a) { - if (_fid <= population) { // Rules the population of objects sprayed - // Duplicates the parent item - Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); - parent->appendChild(copy); - SPObject *new_obj = doc->getObjectByRepr(copy); - item_copied = dynamic_cast<SPItem *>(new_obj); - - // Move around the cursor - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); - - Geom::Point center = parent_item->getCenter(); - sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); - sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); - sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); - sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); - - // Union and duplication - selection->clear(); - selection->add(item_copied); - if (unionResult) { // No need to add the very first item (initialized with NULL). - selection->add(unionResult); + if (parent_item) { + SPDocument *doc = parent_item->document; + Inkscape::XML::Document* xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *old_repr = parent_item->getRepr(); + Inkscape::XML::Node *parent = old_repr->parent(); + + Geom::OptRect a = parent_item->documentVisualBounds(); + if (a) { + if (_fid <= population) { // Rules the population of objects sprayed + // Duplicates the parent item + Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + parent->appendChild(copy); + SPObject *new_obj = doc->getObjectByRepr(copy); + item_copied = dynamic_cast<SPItem *>(new_obj); + + // Move around the cursor + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + + Geom::Point center = parent_item->getCenter(); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); + sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); + sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); + + // Union and duplication + selection->clear(); + selection->add(item_copied); + if (unionResult) { // No need to add the very first item (initialized with NULL). + selection->add(unionResult); + } + sp_selected_path_union_skip_undo(selection, selection->desktop()); + selection->add(parent_item); + Inkscape::GC::release(copy); + did = true; } - sp_selected_path_union_skip_undo(selection, selection->desktop()); - selection->add(parent_item); - Inkscape::GC::release(copy); - did = true; } } #endif diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp index 8c3b44bf5..0a5697661 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -26,6 +26,7 @@ #include <cmath> #include <string> #include <string.h> +#include <sstream> #include <vector> #include <glibmm/i18n.h> @@ -240,6 +241,14 @@ PageSizer::PageSizer(Registry & _wr) _marginRight( _("Ri_ght:"), _("Right margin"), "fit-margin-right", _wr), _marginBottom( _("Botto_m:"), _("Bottom margin"), "fit-margin-bottom", _wr), _lockMarginUpdate(false), + _scaleX(_("Scale _x:"), _("Scale X"), "scale-x", _wr), + _scaleY(_("Scale _y:"), _("Scale Y"), "scale-y", _wr), + _lockScaleUpdate(false), + _viewboxX(_("X:"), _("X"), "viewbox-x", _wr), + _viewboxY(_("Y:"), _("Y"), "viewbox-y", _wr), + _viewboxW(_("Width:"), _("Width"), "viewbox-width", _wr), + _viewboxH(_("Height:"), _("Height"), "viewbox-height", _wr), + _lockViewboxUpdate(false), _widgetRegistry(&_wr) { // set precision of scalar entry boxes @@ -250,6 +259,22 @@ PageSizer::PageSizer(Registry & _wr) _marginLeft.setDigits(5); _marginRight.setDigits(5); _marginBottom.setDigits(5); + _scaleX.setDigits(5); + _scaleY.setDigits(5); + _viewboxX.setDigits(2); + _viewboxY.setDigits(2); + _viewboxW.setDigits(2); + _viewboxH.setDigits(2); + + _scaleX.setRange( 0.00001, 100000 ); + _scaleY.setRange( 0.00001, 100000 ); + _viewboxX.setRange( -100000, 100000 ); + _viewboxY.setRange( -100000, 100000 ); + _viewboxW.setRange( 0, 200000 ); + _viewboxH.setRange( 0, 200000 ); + + _scaleY.set_sensitive (false); // We only want to display Y scale. + _wr.setUpdating (false); //# Set up the Paper Size combo box @@ -318,6 +343,7 @@ PageSizer::PageSizer(Registry & _wr) } _wr.setUpdating (false); + //## Set up custom size frame _customFrame.set_label(_("Custom size")); pack_start (_customFrame, false, false, 0); @@ -419,6 +445,75 @@ PageSizer::PageSizer(Registry & _wr) _fitPageButton.set_label(_("_Resize page to drawing or selection")); _fitPageButton.set_tooltip_text(_("Resize the page to fit the current selection, or the entire drawing if there is no selection")); + _scaleFrame.set_label(_("Scale")); + pack_start (_scaleFrame, false, false, 0); + _scaleFrame.add(_scaleTable); + + _scaleTable.set_border_width(4); + +#if WITH_GTKMM_3_0 + _scaleTable.set_row_spacing(4); + _scaleTable.set_column_spacing(4); + + _scaleTable.attach(_scaleX, 0, 0, 1, 1); + _scaleTable.attach(_scaleY, 1, 0, 1, 1); + + _scaleTable.attach(_scaleLabel, 2, 0, 1, 1); + _scaleTable.attach(_scaleWarning, 0, 1, 2, 1); + _viewboxExpander.set_hexpand(); + _viewboxExpander.set_vexpand(); + _scaleTable.attach(_viewboxExpander, 0, 2, 2, 1); +#else + _scaleTable.resize(3, 2); + _scaleTable.set_row_spacings(4); + _scaleTable.set_col_spacings(4); + _scaleTable.attach(_scaleX, 0,1, 0,1); + _scaleTable.attach(_scaleY, 1,2, 0,1); + _scaleTable.attach(_scaleLabel, 2,3, 0,1); + _scaleTable.attach(_scaleWarning, 0,3, 1,2, Gtk::FILL); + _scaleTable.attach(_viewboxExpander, 0,3, 2,3); +#endif + + _scaleWarning.set_label(_("While SVG allows non-uniform scaling it is recommended to use only uniform scaling in Inkscape. To set a non-uniform scaling, set the 'viewBox' directly.")); + _scaleWarning.set_line_wrap( true ); + + _viewboxExpander.set_use_underline(); + _viewboxExpander.set_label(_("_Viewbox...")); + _viewboxExpander.add(_viewboxTable); + +#if WITH_GTKMM_3_0 + _viewboxTable.set_row_spacing(2); + _viewboxTable.set_column_spacing(2); + + _viewboxX.set_hexpand(); + _viewboxX.set_vexpand(); + _viewboxTable.attach(_viewboxX, 0, 0, 1, 1); + + _viewboxY.set_hexpand(); + _viewboxY.set_vexpand(); + _viewboxTable.attach(_viewboxY, 1, 0, 1, 1); + + _viewboxW.set_hexpand(); + _viewboxW.set_vexpand(); + _viewboxTable.attach(_viewboxW, 0, 1, 1, 1); + + _viewboxH.set_hexpand(); + _viewboxH.set_vexpand(); + _viewboxTable.attach(_viewboxH, 1, 1, 1, 1); + +#else + _viewboxTable.set_border_width(4); + _viewboxTable.set_row_spacings(2); + _viewboxTable.set_col_spacings(2); + _viewboxTable.attach(_viewboxX, 0,1, 0,1); + _viewboxTable.attach(_viewboxY, 1,2, 0,1); + _viewboxTable.attach(_viewboxW, 0,1, 1,2); + _viewboxTable.attach(_viewboxH, 1,2, 1,2); +#endif + + _wr.setUpdating (true); + updateScaleUI(); + _wr.setUpdating (false); } @@ -444,7 +539,11 @@ PageSizer::init () _changedh_connection = _dimensionHeight.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed)); _changedu_connection = _dimensionUnits.getUnitMenu()->signal_changed().connect (sigc::mem_fun (*this, &PageSizer::on_units_changed)); _fitPageButton.signal_clicked().connect(sigc::mem_fun(*this, &PageSizer::fire_fit_canvas_to_selection_or_drawing)); - + _changeds_connection = _scaleX.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_scale_changed)); + _changedvx_connection = _viewboxX.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed)); + _changedvy_connection = _viewboxY.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed)); + _changedvw_connection = _viewboxW.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed)); + _changedvh_connection = _viewboxH.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_viewbox_changed)); show_all_children(); } @@ -512,6 +611,7 @@ PageSizer::setDim (Inkscape::Util::Quantity w, Inkscape::Util::Quantity h, bool _dimensionHeight.setUnit(h.unit->abbr); _dimensionHeight.setValue (h.quantity); + _paper_size_list_connection.unblock(); _landscape_connection.unblock(); _portrait_connection.unblock(); @@ -701,6 +801,88 @@ PageSizer::on_landscape() } } + +/** + * Update scale widgets + */ +void +PageSizer::updateScaleUI() +{ + + static bool _called = false; + if (_called) { + return; + } + + _called = true; + + _changeds_connection.block(); + _changedvx_connection.block(); + _changedvy_connection.block(); + _changedvw_connection.block(); + _changedvh_connection.block(); + + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt) { + SPDocument *doc = dt->getDocument(); + + // Update scale + Geom::Scale scale = doc->getDocumentScale(); + SPNamedView *nv = dt->getNamedView(); + + std::stringstream ss; + ss << _("User units per ") << nv->display_units->abbr << "." ; + _scaleLabel.set_text( ss.str() ); + + if( !_lockScaleUpdate ) { + + double scaleX_inv = + Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units ); + if( scaleX_inv > 0 ) { + _scaleX.setValue(1.0/scaleX_inv); + } else { + // Should never happen + std::cerr << "PageSizer::updateScaleUI(): Invalid scale value: " << scaleX_inv << std::endl; + _scaleX.setValue(1.0); + } + } + + { // Don't need to lock as scaleY widget not linked to callback. + double scaleY_inv = + Inkscape::Util::Quantity::convert( scale[Geom::Y], "px", nv->display_units ); + if( scaleY_inv > 0 ) { + _scaleY.setValue(1.0/scaleY_inv); + } else { + // Should never happen + std::cerr << "PageSizer::updateScaleUI(): Invalid scale value: " << scaleY_inv << std::endl; + _scaleY.setValue(1.0); + } + } + + if( !_lockViewboxUpdate ) { + Geom::Rect viewBox = doc->getViewBox(); + _viewboxX.setValue( viewBox.min()[Geom::X] ); + _viewboxY.setValue( viewBox.min()[Geom::Y] ); + _viewboxW.setValue( viewBox.width() ); + _viewboxH.setValue( viewBox.height() ); + } + + } else { + // Should never happen + std::cerr << "PageSizer::updateScaleUI(): No active desktop." << std::endl; + _scaleLabel.set_text( "Unknown scale" ); + } + + _changeds_connection.unblock(); + _changedvx_connection.unblock(); + _changedvy_connection.unblock(); + _changedvw_connection.unblock(); + _changedvh_connection.unblock(); + + _called = false; +} + + /** * Callback for the dimension widgets */ @@ -712,6 +894,7 @@ PageSizer::on_value_changed() setDim (Inkscape::Util::Quantity(_dimensionWidth.getValue(""), _dimensionUnits.getUnit()), Inkscape::Util::Quantity(_dimensionHeight.getValue(""), _dimensionUnits.getUnit())); } + void PageSizer::on_units_changed() { @@ -722,6 +905,63 @@ PageSizer::on_units_changed() true, false); } +/** + * Callback for scale widgets + */ +void +PageSizer::on_scale_changed() +{ + if (_widgetRegistry->isUpdating()) return; + + double value = _scaleX.getValue(); + if( value > 0 ) { + + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt) { + SPDocument *doc = dt->getDocument(); + SPNamedView *nv = dt->getNamedView(); + + double scaleX_inv = Inkscape::Util::Quantity(1.0/value, nv->display_units ).value("px"); + + _lockScaleUpdate = true; + doc->setDocumentScale( 1.0/scaleX_inv ); + updateScaleUI(); + _lockScaleUpdate = false; + DocumentUndo::done(doc, SP_VERB_NONE, _("Set page scale")); + } + } +} + +/** + * Callback for viewbox widgets + */ +void +PageSizer::on_viewbox_changed() +{ + if (_widgetRegistry->isUpdating()) return; + + double viewboxX = _viewboxX.getValue(); + double viewboxY = _viewboxY.getValue(); + double viewboxW = _viewboxW.getValue(); + double viewboxH = _viewboxH.getValue(); + + if( viewboxW > 0 && viewboxH > 0) { + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt) { + SPDocument *doc = dt->getDocument(); + _lockViewboxUpdate = true; + doc->setViewBox( Geom::Rect::from_xywh( viewboxX, viewboxY, viewboxW, viewboxH ) ); + updateScaleUI(); + _lockViewboxUpdate = false; + DocumentUndo::done(doc, SP_VERB_NONE, _("Set 'viewBox'")); + } + } else { + std::cerr + << "PageSizer::on_viewbox_changed(): width and height must both be greater than zero." + << std::endl; + } +} + } // namespace Widget } // namespace UI } // namespace Inkscape diff --git a/src/ui/widget/page-sizer.h b/src/ui/widget/page-sizer.h index bed117e5a..0eea28e61 100644 --- a/src/ui/widget/page-sizer.h +++ b/src/ui/widget/page-sizer.h @@ -169,6 +169,11 @@ public: */ void updateFitMarginsUI(Inkscape::XML::Node *nv_repr); + /** + * Updates the scale widgets. (Just changes the values of the ui widgets.) + */ + void updateScaleUI(); + protected: /** @@ -250,12 +255,47 @@ protected: Gtk::Button _fitPageButton; bool _lockMarginUpdate; + // Document scale + Gtk::Frame _scaleFrame; +#if WITH_GTKMM_3_0 + Gtk::Grid _scaleTable; +#else + Gtk::Table _scaleTable; +#endif + + Gtk::Label _scaleLabel; + Gtk::Label _scaleWarning; + RegisteredScalar _scaleX; + RegisteredScalar _scaleY; + bool _lockScaleUpdate; + + // Viewbox + Gtk::Expander _viewboxExpander; +#if WITH_GTKMM_3_0 + Gtk::Grid _viewboxTable; +#else + Gtk::Table _viewboxTable; +#endif + + RegisteredScalar _viewboxX; + RegisteredScalar _viewboxY; + RegisteredScalar _viewboxW; + RegisteredScalar _viewboxH; + bool _lockViewboxUpdate; + //callback void on_value_changed(); void on_units_changed(); + void on_scale_changed(); + void on_viewbox_changed(); sigc::connection _changedw_connection; sigc::connection _changedh_connection; sigc::connection _changedu_connection; + sigc::connection _changeds_connection; + sigc::connection _changedvx_connection; + sigc::connection _changedvy_connection; + sigc::connection _changedvw_connection; + sigc::connection _changedvh_connection; Registry *_widgetRegistry; diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp index 1fc67dcef..9e283fc64 100644 --- a/src/ui/widget/selected-style.cpp +++ b/src/ui/widget/selected-style.cpp @@ -25,8 +25,8 @@ #include "desktop-style.h" #include "sp-namedview.h" #include "sp-linear-gradient.h" -#include "sp-mesh-gradient.h" #include "sp-radial-gradient.h" +#include "sp-mesh.h" #include "sp-pattern.h" #include "ui/dialog/dialog-manager.h" #include "ui/dialog/fill-and-stroke.h" @@ -1045,7 +1045,7 @@ SelectedStyle::update() place->set_tooltip_text(__rgradient[i]); _mode[i] = SS_RGRADIENT; #ifdef WITH_MESH - } else if (SP_IS_MESHGRADIENT(server)) { + } else if (SP_IS_MESH(server)) { SPGradient *vector = SP_GRADIENT(server)->getVector(); sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(_gradient_preview_m[i]), vector); place->add(_gradient_box_m[i]); diff --git a/src/uri-references.cpp b/src/uri-references.cpp index b23bed74a..2518c173e 100644 --- a/src/uri-references.cpp +++ b/src/uri-references.cpp @@ -65,7 +65,7 @@ void URIReference::attach(const URI &uri) throw(BadURIException) skip = true; } - // The path contains references to seperate document files to load. + // The path contains references to separate document files to load. if(document && uri.getPath() && !skip ) { std::string base = document->getBase() ? document->getBase() : ""; std::string path = uri.getFullPath(base); diff --git a/src/widgets/box3d-toolbar.cpp b/src/widgets/box3d-toolbar.cpp index 26e914070..31b897ced 100644 --- a/src/widgets/box3d-toolbar.cpp +++ b/src/widgets/box3d-toolbar.cpp @@ -193,15 +193,15 @@ static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObj Inkscape::GC::anchor(persp_repr); sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl); sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl); - } - SP_ACTIVE_DOCUMENT->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); + SP_ACTIVE_DOCUMENT->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); - box3d_resync_toolbar(persp_repr, tbl); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); + box3d_resync_toolbar(persp_repr, tbl); + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); + } } } diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp index 49fc7b67c..1af55d9cd 100644 --- a/src/widgets/mesh-toolbar.cpp +++ b/src/widgets/mesh-toolbar.cpp @@ -44,7 +44,7 @@ #include "ui/tools/gradient-tool.h" #include "ui/tools/mesh-tool.h" #include "gradient-drag.h" -#include "sp-mesh-gradient.h" +#include "sp-mesh.h" #include "gradient-chemistry.h" #include "gradient-selector.h" #include "selection.h" @@ -77,15 +77,15 @@ static bool blocked = false; * Get the current selection and dragger status from the desktop */ void ms_read_selection( Inkscape::Selection *selection, - SPMeshGradient *&ms_selected, + SPMesh *&ms_selected, bool &ms_selected_multi, - SPMeshSmooth &ms_smooth, - bool &ms_smooth_multi ) + SPMeshType &ms_type, + bool &ms_type_multi ) { // Read desktop selection bool first = true; - ms_smooth = SP_MESH_SMOOTH_NONE; + ms_type = SP_MESH_TYPE_COONS; std::vector<SPItem*> itemlist=selection->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ @@ -94,10 +94,10 @@ void ms_read_selection( Inkscape::Selection *selection, if (style && (style->fill.isPaintserver())) { SPPaintServer *server = item->style->getFillPaintServer(); - if ( SP_IS_MESHGRADIENT(server) ) { + if ( SP_IS_MESH(server) ) { - SPMeshGradient *gradient = SP_MESHGRADIENT(server); // ->getVector(); - SPMeshSmooth smooth = gradient->smooth; + SPMesh *gradient = SP_MESH(server); // ->getVector(); + SPMeshType type = gradient->type; if (gradient != ms_selected) { if (ms_selected) { @@ -106,11 +106,11 @@ void ms_read_selection( Inkscape::Selection *selection, ms_selected = gradient; } } - if( smooth != ms_smooth ) { - if (ms_smooth != SP_MESH_SMOOTH_NONE && !first) { - ms_smooth_multi = true; + if( type != ms_type ) { + if (ms_type != SP_MESH_TYPE_COONS && !first) { + ms_type_multi = true; } else { - ms_smooth = smooth; + ms_type = type; } } first = false; @@ -119,10 +119,10 @@ void ms_read_selection( Inkscape::Selection *selection, if (style && (style->stroke.isPaintserver())) { SPPaintServer *server = item->style->getStrokePaintServer(); - if ( SP_IS_MESHGRADIENT(server) ) { + if ( SP_IS_MESH(server) ) { - SPMeshGradient *gradient = SP_MESHGRADIENT(server); // ->getVector(); - SPMeshSmooth smooth = gradient->smooth; + SPMesh *gradient = SP_MESH(server); // ->getVector(); + SPMeshType type = gradient->type; if (gradient != ms_selected) { if (ms_selected) { @@ -131,11 +131,11 @@ void ms_read_selection( Inkscape::Selection *selection, ms_selected = gradient; } } - if( smooth != ms_smooth ) { - if (ms_smooth != SP_MESH_SMOOTH_NONE && !first) { - ms_smooth_multi = true; + if( type != ms_type ) { + if (ms_type != SP_MESH_TYPE_COONS && !first) { + ms_type_multi = true; } else { - ms_smooth = smooth; + ms_type = type; } } first = false; @@ -171,18 +171,18 @@ static void ms_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe // // Hide/show handles? // } - SPMeshGradient *ms_selected = 0; - SPMeshSmooth ms_smooth = SP_MESH_SMOOTH_NONE; + SPMesh *ms_selected = 0; + SPMeshType ms_type = SP_MESH_TYPE_COONS; bool ms_selected_multi = false; - bool ms_smooth_multi = false; - ms_read_selection( selection, ms_selected, ms_selected_multi, ms_smooth, ms_smooth_multi ); - // std::cout << " smooth: " << ms_smooth << std::endl; + bool ms_type_multi = false; + ms_read_selection( selection, ms_selected, ms_selected_multi, ms_type, ms_type_multi ); + // std::cout << " type: " << ms_type << std::endl; - EgeSelectOneAction* smooth = (EgeSelectOneAction *) g_object_get_data(G_OBJECT(widget), "mesh_select_smooth_action"); - gtk_action_set_sensitive( GTK_ACTION(smooth), (ms_selected && !ms_selected_multi) ); + EgeSelectOneAction* type = (EgeSelectOneAction *) g_object_get_data(G_OBJECT(widget), "mesh_select_type_action"); + gtk_action_set_sensitive( GTK_ACTION(type), (ms_selected && !ms_selected_multi) ); if (ms_selected) { blocked = TRUE; - ege_select_one_action_set_active( smooth, ms_smooth ); + ege_select_one_action_set_active( type, ms_type ); blocked = FALSE; } } @@ -210,9 +210,9 @@ static void ms_defs_modified(SPObject * /*defs*/, guint /*flags*/, GObject *widg ms_tb_selection_changed(NULL, widget); } -void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient *&ms_selected) +void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMesh *&ms_selected) { - SPMeshGradient *gradient = 0; + SPMesh *gradient = 0; std::vector<SPItem*> itemlist=selection->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ @@ -227,8 +227,8 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient server = item->style->getStrokePaintServer(); } - if ( SP_IS_MESHGRADIENT(server) ) { - gradient = SP_MESHGRADIENT(server); + if ( SP_IS_MESH(server) ) { + gradient = SP_MESH(server); } } @@ -242,11 +242,11 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient * Callback functions for user actions */ -static void ms_new_type_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) +static void ms_new_geometry_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint typemode = ege_select_one_action_get_active( act ) == 0 ? SP_GRADIENT_MESH_TYPE_NORMAL : SP_GRADIENT_MESH_TYPE_CONICAL; - prefs->setInt("/tools/mesh/mesh_type", typemode); + gint geometrymode = ege_select_one_action_get_active( act ) == 0 ? SP_MESH_GEOMETRY_NORMAL : SP_MESH_GEOMETRY_CONICAL; + prefs->setInt("/tools/mesh/mesh_geometry", geometrymode); } static void ms_new_fillstroke_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) @@ -290,27 +290,27 @@ static void ms_col_changed(GtkAdjustment *adj, GObject * /*tbl*/ ) blocked = FALSE; } -static void ms_smooth_changed(EgeSelectOneAction *act, GtkWidget *widget) +static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget) { - // std::cout << "ms_smooth_changed" << std::endl; + // std::cout << "ms_type_changed" << std::endl; if (blocked) { return; } SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(widget), "desktop")); Inkscape::Selection *selection = desktop->getSelection(); - SPMeshGradient *gradient = 0; + SPMesh *gradient = 0; ms_get_dt_selected_gradient(selection, gradient); if (gradient) { - SPMeshSmooth smooth = (SPMeshSmooth) ege_select_one_action_get_active(act); - // std::cout << " smooth: " << smooth << std::endl; - gradient->smooth = smooth; - gradient->smooth_set = true; + SPMeshType type = (SPMeshType) ege_select_one_action_get_active(act); + // std::cout << " type: " << type << std::endl; + gradient->type = type; + gradient->type_set = true; gradient->updateRepr(); DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_GRADIENT, - _("Set mesh smoothing")); + _("Set mesh type")); } } @@ -351,9 +351,9 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj ege_select_one_action_set_tooltip_column( act, 1 ); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint mode = prefs->getInt("/tools/mesh/mesh_type", SP_GRADIENT_MESH_TYPE_NORMAL) != SP_GRADIENT_MESH_TYPE_NORMAL; + gint mode = prefs->getInt("/tools/mesh/mesh_geometry", SP_MESH_GEOMETRY_NORMAL) != SP_MESH_GEOMETRY_NORMAL; ege_select_one_action_set_active( act, mode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(ms_new_type_changed), holder ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(ms_new_geometry_changed), holder ); } /* New gradient on fill or stroke*/ @@ -462,51 +462,30 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj /* Warning */ { GtkAction* act = gtk_action_new( "MeshWarningAction", - _("WARNING: Mesh SVG Syntax Subject to Change, Smoothing Experimental"), NULL, NULL ); + _("WARNING: Mesh SVG Syntax Subject to Change"), NULL, NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); } - /* Smoothing method */ + /* Typeing method */ { GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); GtkTreeIter iter; gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, C_("Smoothing", "None"), 1, SP_MESH_SMOOTH_NONE, -1 ); + gtk_list_store_set( model, &iter, 0, C_("Type", "Coons"), 1, SP_MESH_TYPE_COONS, -1 ); gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Default"), 1, SP_MESH_SMOOTH_SMOOTH, -1 ); + gtk_list_store_set( model, &iter, 0, _("Bicubic"), 1, SP_MESH_TYPE_BICUBIC, -1 ); - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth1"), 1, SP_MESH_SMOOTH_SMOOTH1, -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth2"), 1, SP_MESH_SMOOTH_SMOOTH2, -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth3"), 1, SP_MESH_SMOOTH_SMOOTH3, -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth4"), 1, SP_MESH_SMOOTH_SMOOTH4, -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth5"), 1, SP_MESH_SMOOTH_SMOOTH5, -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth6"), 1, SP_MESH_SMOOTH_SMOOTH6, -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Smooth7"), 1, SP_MESH_SMOOTH_SMOOTH7, -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "MeshSmoothAction", _("None"), - _("If the mesh should be smoothed across patch boundaries."), + EgeSelectOneAction* act = ege_select_one_action_new( "MeshSmoothAction", _("Coons"), + _("Coons: no smoothing. Bicubic: smoothing across patch boundaries."), NULL, GTK_TREE_MODEL(model) ); g_object_set( act, "short_label", _("Smoothing:"), NULL ); ege_select_one_action_set_appearance( act, "compact" ); gtk_action_set_sensitive( GTK_ACTION(act), FALSE ); - g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(ms_smooth_changed), holder ); + g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(ms_type_changed), holder ); gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "mesh_select_smooth_action", act ); + g_object_set_data( holder, "mesh_select_type_action", act ); } } diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 6ef910f61..948c80db3 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -37,8 +37,8 @@ #include "sp-color-notebook.h" #include "sp-linear-gradient.h" -#include "sp-mesh-gradient.h" #include "sp-radial-gradient.h" +#include "sp-mesh.h" /* fixme: Move it from dialogs to here */ #include "gradient-selector.h" #include <inkscape.h> @@ -777,7 +777,7 @@ static void sp_paint_selector_set_mode_gradient(SPPaintSelector *psel, SPPaintSe } #ifdef WITH_MESH else { - SP_GRADIENT_SELECTOR(gsel)->setMode(SPGradientSelector::MODE_RADIAL); + SP_GRADIENT_SELECTOR(gsel)->setMode(SPGradientSelector::MODE_MESH); gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Mesh gradient</b>")); } #endif @@ -1244,7 +1244,7 @@ SPPaintSelector::Mode SPPaintSelector::getModeForStyle(SPStyle const & style, Fi } else if (SP_IS_RADIALGRADIENT(server)) { mode = MODE_GRADIENT_RADIAL; #ifdef WITH_MESH - } else if (SP_IS_MESHGRADIENT(server)) { + } else if (SP_IS_MESH(server)) { mode = MODE_GRADIENT_MESH; #endif } else if (SP_IS_PATTERN(server)) { diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp index d8edeb9f6..eb55287c4 100644 --- a/src/widgets/paintbucket-toolbar.cpp +++ b/src/widgets/paintbucket-toolbar.cpp @@ -121,17 +121,16 @@ void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions { GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - GList* items = 0; gint count = 0; - for ( items = Inkscape::UI::Tools::flood_channels_dropdown_items_list(); items ; items = g_list_next(items) ) - { + const std::vector<Glib::ustring>& channel_list = Inkscape::UI::Tools::FloodTool::channel_list; + for (std::vector<Glib::ustring>::const_iterator iterator = channel_list.begin(); + iterator != channel_list.end(); ++iterator ) { GtkTreeIter iter; gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); + gtk_list_store_set( model, &iter, 0, (*iterator).c_str(), 1, count, -1 ); count++; } - g_list_free( items ); - items = 0; + EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) ); g_object_set( act1, "short_label", _("Fill by:"), NULL ); ege_select_one_action_set_appearance( act1, "compact" ); @@ -188,17 +187,15 @@ void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions { GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - GList* items = 0; gint count = 0; - for ( items = Inkscape::UI::Tools::flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) ) - { + const std::vector<Glib::ustring>& gap_list = Inkscape::UI::Tools::FloodTool::gap_list; + for (std::vector<Glib::ustring>::const_iterator iterator = gap_list.begin(); + iterator != gap_list.end(); ++iterator ) { GtkTreeIter iter; gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); + gtk_list_store_set( model, &iter, 0, (*iterator).c_str(), 1, count, -1 ); count++; } - g_list_free( items ); - items = 0; EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) ); g_object_set( act2, "short_label", _("Close gaps:"), NULL ); ege_select_one_action_set_appearance( act2, "compact" ); diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 018ebbcdf..29a10a534 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -110,7 +110,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { - (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, desktop->getNamedView()->svg_units)); + (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } else { (*i)->getRepr()->setAttribute(value_name, NULL); } @@ -182,7 +182,6 @@ static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar con UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); Unit const *unit = tracker->getActiveUnit(); - Unit const *svg_unit = SP_ACTIVE_DESKTOP->getNamedView()->svg_units; g_return_if_fail(unit != NULL); gpointer item = g_object_get_data( tbl, "item" ); @@ -191,28 +190,28 @@ static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar con GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) ); gdouble rx = SP_RECT(item)->getVisibleRx(); - gtk_adjustment_set_value(adj, Quantity::convert(rx, svg_unit, unit)); + gtk_adjustment_set_value(adj, Quantity::convert(rx, "px", unit)); } { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) ); gdouble ry = SP_RECT(item)->getVisibleRy(); - gtk_adjustment_set_value(adj, Quantity::convert(ry, svg_unit, unit)); + gtk_adjustment_set_value(adj, Quantity::convert(ry, "px", unit)); } { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) ); gdouble width = SP_RECT(item)->getVisibleWidth(); - gtk_adjustment_set_value(adj, Quantity::convert(width, svg_unit, unit)); + gtk_adjustment_set_value(adj, Quantity::convert(width, "px", unit)); } { GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) ); gdouble height = SP_RECT(item)->getVisibleHeight(); - gtk_adjustment_set_value(adj, Quantity::convert(height, svg_unit, unit)); + gtk_adjustment_set_value(adj, Quantity::convert(height, "px", unit)); } } diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 447f2ff40..3858f08a7 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -32,6 +32,7 @@ #include <2geom/point.h> #include "svg/stringstream.h" #include "svg/css-ostringstream.h" +#include "svg/svg-length.h" #include "xml/repr.h" #include "xml/repr-sorting.h" @@ -502,6 +503,20 @@ unsigned int sp_repr_set_svg_double(Inkscape::XML::Node *repr, gchar const *key, return true; } +/** + * For attributes where an exponent is allowed. + * + * Not suitable for property attributes. + */ +unsigned int sp_repr_set_svg_length(Inkscape::XML::Node *repr, gchar const *key, SVGLength &val) +{ + g_return_val_if_fail(repr != NULL, FALSE); + g_return_val_if_fail(key != NULL, FALSE); + + repr->setAttribute(key, val.write()); + return true; +} + unsigned sp_repr_set_point(Inkscape::XML::Node *repr, gchar const *key, Geom::Point const & val) { g_return_val_if_fail(repr != NULL, FALSE); diff --git a/src/xml/repr.h b/src/xml/repr.h index c96560a98..fbe25ec12 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -30,6 +30,7 @@ #define SP_DC_NS_URI "http://purl.org/dc/elements/1.1/" class SPCSSAttr; +class SVGLength; namespace Inkscape { namespace IO { @@ -115,6 +116,7 @@ unsigned sp_repr_set_boolean(Inkscape::XML::Node *repr, char const *key, unsigne unsigned sp_repr_set_int(Inkscape::XML::Node *repr, char const *key, int val); unsigned sp_repr_set_css_double(Inkscape::XML::Node *repr, char const *key, double val); unsigned sp_repr_set_svg_double(Inkscape::XML::Node *repr, char const *key, double val); +unsigned sp_repr_set_svg_length(Inkscape::XML::Node *repr, char const *key, SVGLength &val); unsigned sp_repr_set_point(Inkscape::XML::Node *repr, char const *key, Geom::Point const & val); unsigned sp_repr_get_point(Inkscape::XML::Node *repr, char const *key, Geom::Point *val); |
