diff options
Diffstat (limited to 'src/ui/tools')
| -rw-r--r-- | src/ui/tools/freehand-base.cpp | 65 | ||||
| -rw-r--r-- | src/ui/tools/pencil-tool.cpp | 215 | ||||
| -rw-r--r-- | src/ui/tools/pencil-tool.h | 8 |
3 files changed, 215 insertions, 73 deletions
diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 05afd8058..fba3c8397 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -237,40 +237,36 @@ static void spdc_apply_powerstroke_shape(std::vector<Geom::Point> points, Freeha Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 3) { SPShape *sp_shape = dynamic_cast<SPShape *>(item); - Geom::PathVector pathvector; if (sp_shape) { - pathvector = sp_shape->getCurve()->get_pathvector(); - size_t counter = 0; + SPCurve * c = sp_shape->getCurve(); + if (!c) { + return; + } auto wps = pt->wps.begin(); - double previous_pos = 0.0; for (auto pps = pt->pps.begin(); pps != pt->pps.end(); ++pps,++wps) { - counter++; - Geom::Affine transformCoordinate = item->i2dt_affine(); - Geom::Point position = *pps; - position *= transformCoordinate.inverse(); - double pos = Geom::nearest_time(position, paths_to_pw(pathvector)); - double width = *wps; - if(pos > 1e6) { - pos = 0;; - } - if(pos > pathvector[0].size() ) { - pos = pathvector[0].size(); - } - if ((pos - previous_pos) < pt->min_distance || - (counter == pt->wps.size() || (pos - previous_pos) < 0.1) ) - { - continue; - } - previous_pos = pos; - if (!Geom::are_near(width, 0.0, 0.1) ) { - points.push_back(Geom::Point(pos,width)); - } + pt->addPowerStrokePoint(c, *pps, *wps); + } + } + if(pt->points.empty()){ + //if use mouse give a line + double zoom = SP_EVENT_CONTEXT(dc)->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; } + Geom::Affine transformCoordinate = SP_ITEM(SP_ACTIVE_DESKTOP->currentLayer())->i2dt_affine(); + Geom::Coord scale = transformCoordinate.expansionX(); + double pressure_shirnked = (1.0 * (max - min)) + min; + double pressure_computed = (pressure_shirnked * 8.0 * scale) / zoom; + pt->points.push_back(Geom::Point(0,pressure_computed)); } Effect::createAndApply(POWERSTROKE, dc->desktop->doc(), item); Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE(); - static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points); + static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(pt->points); + pt->points.clear(); return; } } @@ -389,13 +385,7 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, if (sp_shape) { curve = sp_shape->getCurve(); } - if (SP_IS_PENCIL_CONTEXT(dc)) { - if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 3) { - std::vector<Geom::Point> points; - spdc_apply_powerstroke_shape(points, dc, item); - shape = NONE; - } - } + bool shape_applied = false; SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS); const char *cstroke = sp_repr_css_property(css_item, "stroke", "none"); @@ -407,6 +397,15 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, if (!swidth) { swidth = swidth/2; } + if (SP_IS_PENCIL_CONTEXT(dc)) { + if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 3) { + std::vector<Geom::Point> points; + spdc_apply_powerstroke_shape(points, dc, item); + shape = NONE; + //To allow retain color + shape_applied = true; + } + } #define SHAPE_LENGTH 10 #define SHAPE_HEIGHT 10 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(); } diff --git a/src/ui/tools/pencil-tool.h b/src/ui/tools/pencil-tool.h index b6e9680d2..607d10c4a 100644 --- a/src/ui/tools/pencil-tool.h +++ b/src/ui/tools/pencil-tool.h @@ -46,13 +46,15 @@ public: std::vector<Geom::Point> ps; std::vector<Geom::Point> pps; + std::vector<Geom::Point> points; std::vector<double> wps; double previous_pressure; + Geom::Point previous_point; + bool start; double gap_pressure; - double min_distance; double start_clamp; double end_clamp; - + void addPowerStrokePoint(SPCurve * c, Geom::Point p, double pressure_data); Geom::Piecewise<Geom::D2<Geom::SBasis> > sketch_interpolation; // the current proposal from the sketched paths unsigned sketch_n; // number of sketches done @@ -71,8 +73,8 @@ private: bool _handleButtonRelease(GdkEventButton const &revent); bool _handleKeyPress(GdkEventKey const &event); bool _handleKeyRelease(GdkEventKey const &event); - void _setStartpoint(Geom::Point const &p); + void _setEndpoint(Geom::Point const &p); void _finishEndpoint(); void _addFreehandPoint(Geom::Point const &p, guint state); |
