diff options
Diffstat (limited to 'src/ui/tools/pencil-tool.cpp')
| -rw-r--r-- | src/ui/tools/pencil-tool.cpp | 215 |
1 files changed, 178 insertions, 37 deletions
diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index 23a442b11..9b411297f 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -20,6 +20,7 @@ #include "ui/tools/pencil-tool.h" #include "desktop.h" +#include "inkscape.h" #include "selection.h" #include "selection-chemistry.h" @@ -35,9 +36,14 @@ #include <glibmm/i18n.h> #include "context-fns.h" #include "sp-namedview.h" +#include "xml/node.h" +#include "xml/sp-css-attr.h" +#include "svg/svg.h" +#include "display/curve.h" #include "desktop-style.h" #include "display/sp-canvas.h" #include "display/curve.h" +#include "live_effects/lpe-powerstroke.h" #include "ui/tool/event-utils.h" namespace Inkscape { @@ -64,8 +70,9 @@ PencilTool::PencilTool() , req_tangent(0, 0) , is_drawing(false) , previous_pressure(0.0) + , previous_point(Geom::Point(0,0)) + , start(false) , gap_pressure(1.0) - , min_distance(0.2) , start_clamp(DDC_MIN_PRESSURE) , end_clamp(DDC_MAX_PRESSURE) , sketch_n(0) @@ -315,9 +322,6 @@ bool PencilTool::_handleMotionNotify(GdkEventMotion const &mevent) { // - We cannot do this in the button press handler because at that point we don't know yet // wheter we're going into freehand mode or not this->ps.push_back(this->p[0]); - this->pps.push_back(this->p[0]); - double pressure_computed = pow(this->pressure,3); - this->wps.push_back(pressure_computed); } this->_addFreehandPoint(p, mevent.state); ret = true; @@ -421,12 +425,16 @@ bool PencilTool::_handleButtonRelease(GdkEventButton const &revent) { desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand")); this->_interpolate(); + //Remove here because points are recalculated once finish. This is because we want live preview. + this->points.clear(); spdc_concat_colors_and_flush(this, FALSE); this->sa = NULL; this->ea = NULL; this->ps.clear(); this->wps.clear(); this->pps.clear(); + previous_pressure = 0.0; + previous_point = Geom::Point(0,0); if (this->green_anchor) { this->green_anchor = sp_draw_anchor_destroy(this->green_anchor); } @@ -628,52 +636,184 @@ void PencilTool::_finishEndpoint() { } } -void PencilTool::_addFreehandPoint(Geom::Point const &p, guint /*state*/) { - g_assert( this->npoints > 0 ); - g_return_if_fail(unsigned(this->npoints) < G_N_ELEMENTS(this->p)); +void +sp_powerstroke_preview(SPObject *elemref, Geom::PathVector pathvector, const char * item_id, std::vector<Geom::Point> points) +{ + using namespace Inkscape::LivePathEffect; + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + Geom::Affine transformCoordinate = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->i2dt_affine(); + Geom::Coord scale = transformCoordinate.expansionX(); + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + Inkscape::XML::Node *preview = NULL; + if (elemref) { + Effect* lpe = SP_LPE_ITEM(elemref)->getCurrentLPE(); + if (points.size() != static_cast<LPEPowerStroke*>(lpe)->offset_points.data().size()) { + static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points); + } + gchar * pvector_str = sp_svg_write_path(pathvector); + elemref->setAttribute("inkscape:original-d" , pvector_str); + g_free(pvector_str); + } else { + preview = xml_doc->createElement("svg:path"); + preview->setAttribute("id", item_id); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property (css, "fill","none"); + sp_repr_css_set_property (css, "stroke","#DEDEDE"); + sp_repr_css_set_property (css, "opacity","0.9"); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + preview->setAttribute("style", css_str.c_str()); + gchar * pvector_str = sp_svg_write_path(pathvector); + preview->setAttribute("d" , pvector_str); + g_free(pvector_str); + elemref = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->appendChildRepr(preview); + Inkscape::GC::release(preview); + Effect::createAndApply(POWERSTROKE, SP_ACTIVE_DESKTOP->doc(), SP_ITEM(elemref)); + Effect* lpe = SP_LPE_ITEM(elemref)->getCurrentLPE(); + static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points); + } +} - if ( ( p != this->p[ this->npoints - 1 ] ) - && in_svg_plane(p) ) - { - - this->p[this->npoints++] = p; - this->_fitAndSplit(); - SPCurve *c; +void +PencilTool::addPowerStrokePoint(SPCurve * c, Geom::Point p, double pressure_data) +{ + bool live = false; + SPCurve * curve; + if(!c) { + SPCurve * previous_red = red_curve->copy(); + SPCurve * previous_green = green_curve->copy(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + //Simplify a bit the base curve to avoid artifacts + //double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0); + //prefs->setDouble("/tools/freehand/pencil/tolerance", 30.0); + _interpolate(); + //prefs->setDouble("/tools/freehand/pencil/tolerance", tol); + live = true; if (sa) { - c = sa->curve; + curve = sa->curve; if (!green_curve->is_empty()) { - c->append_continuous( green_curve, 0.0625); + curve->append_continuous( green_curve, 0.0625); + if (!red_curve->is_empty()) { + curve->append_continuous( red_curve, 0.0625); + } } } else { if (!green_curve->is_empty()) { - c = green_curve; + curve = green_curve->copy(); + if (!red_curve->is_empty()) { + curve->append_continuous( red_curve, 0.0625); + } } else { - c = new SPCurve(); + curve = NULL; } } - if (red_curve_is_valid && !red_curve->is_empty()) { - c->append_continuous(red_curve, 0.0625); + red_curve = previous_red->copy(); + green_curve = previous_green->copy(); + previous_red->unref(); + previous_green->unref(); + } else { + curve = c->copy(); + } + SPObject *elemref = NULL; + SPDocument * document = SP_ACTIVE_DOCUMENT; + if (!document) { + return; + } + const char * item_id = "___pencil_preview_powerstroke___"; + if ((elemref = document->getObjectById(item_id))) { + if (!live && 2==3) { + LivePathEffectObject * lpeobj = SP_LPE_ITEM(elemref)->getCurrentLPE()->getLPEObj(); + SP_OBJECT(lpeobj)->deleteObject(); + lpeobj = NULL; + elemref->deleteObject(); + elemref = NULL; } - Geom::PathVector pathvector = c->get_pathvector(); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double pressure = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3 ? this->pressure :1; - this->ps.push_back(p); - double pressure_computed = pow(this->pressure, 3) * 25; -// std::cout << previous_pressure <<"previous_pressure\n"; -// std::cout << pressure_computed <<"pressure_computed\n"; -// std::cout << std::abs(previous_pressure - pressure_computed) <<"std::abs(previous_pressure - pressure_computed)\n"; -// std::cout << gap_pressure <<"gap_pressure\n"; -// std::cout << Geom::distance(this->pps[this->pps.size()-1], p) << "distance\n"; - - if (previous_pressure == 0.0 || - std::abs(previous_pressure - pressure_computed) > gap_pressure ) - { - previous_pressure = pressure_computed; - this->pps.push_back(p); - this->wps.push_back(pressure_computed); + } + if (!curve) { + return; + } + Geom::Affine transformCoordinate = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->i2dt_affine(); + Geom::Coord scale = transformCoordinate.expansionX(); + double zoom = SP_EVENT_CONTEXT(this)->desktop->current_zoom() * 5.0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double min = prefs->getIntLimited("/tools/freehand/pencil/minpressure", 0, 1, 100) / 100.0; + double max = prefs->getIntLimited("/tools/freehand/pencil/maxpressure", 100, 1, 100) / 100.0; + if (min > max){ + min = max; + } + //Maybe the 12 POW can be moved to a preferences 12 give a good results of sensibility on my tablet + //But maybe is a tweakable value. less number = less sensibility + //8 give an aceptable max witht to powerstoke + double pressure_base = pow(pressure_data, 12); + double pressure_shirnked = (pressure_base * (max - min)) + min; + double pressure_factor = pressure_base/pressure_shirnked; + double pressure_computed = (pressure_shirnked * 8.0 * scale) / zoom; + bool force = false; + bool buttonrelease = false; + if (pressure_computed < 0.05 && previous_pressure != 0.0 ) { + pressure_computed = previous_pressure; + force = true; + buttonrelease = true; +// } else if (std::abs(previous_pressure - pressure_computed) > 4 && previous_pressure != 0.0) { +// pressure_computed = previous_pressure; +// force = true; + } + if (previous_pressure == 0.0 && pressure_computed != 0.0) { + start = true; + } + double tol = 135.0 / zoom; + Geom::PathVector pathvector = curve->get_pathvector(); + pathvector *= transformCoordinate.inverse(); + if (start || force || std::abs(previous_pressure - pressure_computed) > gap_pressure / (zoom * pressure_factor)) { + previous_pressure = pressure_computed; + double pos = pathvector[0].size(); + if (live) { + p = pathvector[0].finalPoint(); + } else { + pos = Geom::nearest_time(p, paths_to_pw(pathvector)); + } + //This magic number get an acurate result maybe is better move to preferences and optionaly add GUI + + //Force star and end in start and end path position + if(pos > 1e6 || start) { + pos = 0.0; + } else if (buttonrelease) { + pos = pathvector[0].size(); + } else if (pos > 0.0 && Geom::distance(p, previous_point) < tol ) { + sp_powerstroke_preview(elemref, pathvector, item_id, points); + return; + } + start = false; + previous_point = p; + this->points.push_back(Geom::Point(pos, pressure_computed)); + if (live) { + pps.push_back(p); + wps.push_back(pressure_data); } + } + if (live) { + sp_powerstroke_preview(elemref, pathvector, item_id, points); + } +} + +void PencilTool::_addFreehandPoint(Geom::Point const &p, guint /*state*/) { + g_assert( this->npoints > 0 ); + g_return_if_fail(unsigned(this->npoints) < G_N_ELEMENTS(this->p)); + + if ( ( p != this->p[ this->npoints - 1 ] ) + && in_svg_plane(p) ) + { + this->p[this->npoints++] = p; this->_fitAndSplit(); + this->ps.push_back(p); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getInt("/tools/freehand/pencil/freehand-mode", 0) == 3) { + this->addPowerStrokePoint(NULL, p, this->pressure); + } } } @@ -849,6 +989,7 @@ void PencilTool::_sketchInterpolate() { this->ps.clear(); this->pps.clear(); + this->points.clear(); this->wps.clear(); } |
