summaryrefslogtreecommitdiffstats
path: root/src/ui/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/tools')
-rw-r--r--src/ui/tools/freehand-base.cpp65
-rw-r--r--src/ui/tools/pencil-tool.cpp215
-rw-r--r--src/ui/tools/pencil-tool.h8
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);