summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: e9c20a4)
raw | patch | inline | side by side (parent: e9c20a4)
author | johanengelen <johanengelen@users.sourceforge.net> | |
Sat, 13 Dec 2008 17:31:18 +0000 (17:31 +0000) | ||
committer | johanengelen <johanengelen@users.sourceforge.net> | |
Sat, 13 Dec 2008 17:31:18 +0000 (17:31 +0000) |
diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp
index a80f565faf4725ea5059647b311ae59ccc705cbd..1b13445d6dbd5eed8911a6850f7aaaeddd9a689b 100644 (file)
--- a/src/pencil-context.cpp
+++ b/src/pencil-context.cpp
#include "preferences.h"
#include "snap.h"
#include "pixmaps/cursor-pencil.xpm"
-#include "display/bezier-utils.h"
+#include <2geom/bezier-utils.h>
#include "display/canvas-bpath.h"
#include <glibmm/i18n.h>
#include "libnr/in-svg-plane.h"
static gint pencil_handle_motion_notify(SPPencilContext *const pc, GdkEventMotion const &mevent);
static gint pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &revent);
static gint pencil_handle_key_press(SPPencilContext *const pc, guint const keyval, guint const state);
+static gint pencil_handle_key_release(SPPencilContext *const pc, guint const keyval, guint const state);
static void spdc_set_startpoint(SPPencilContext *pc, Geom::Point const p);
static void spdc_set_endpoint(SPPencilContext *pc, Geom::Point const p);
static void spdc_add_freehand_point(SPPencilContext *pc, Geom::Point p, guint state);
static void fit_and_split(SPPencilContext *pc);
static void interpolate(SPPencilContext *pc);
+static void sketch_interpolate(SPPencilContext *pc);
static SPDrawContextClass *pencil_parent_class;
static Geom::Point pencil_drag_origin_w(0, 0);
pc->npoints = 0;
pc->state = SP_PENCIL_CONTEXT_IDLE;
pc->req_tangent = Geom::Point(0, 0);
+
+ // since SPPencilContext is not properly constructed...
+ pc->sketch_interpolation = Geom::Path();
+ pc->sketch_n = 0;
}
/**
ret = pencil_handle_key_press(pc, get_group0_keyval (&event->key), event->key.state);
break;
+ case GDK_KEY_RELEASE:
+ ret = pencil_handle_key_release(pc, get_group0_keyval (&event->key), event->key.state);
+ break;
+
default:
break;
}
@@ -442,26 +452,41 @@ pencil_handle_button_release(SPPencilContext *const pc, GdkEventButton const &re
ret = TRUE;
break;
case SP_PENCIL_CONTEXT_FREEHAND:
- /* Finish segment now */
- /// \todo fixme: Clean up what follows (Lauris)
- if (anchor) {
- p = anchor->dp;
- }
- pc->ea = anchor;
- /* Write curves to object */
+ if (revent.state & GDK_MOD1_MASK) {
+ /* sketch mode: interpolate the sketched path and improve the current output path with the new interpolation. don't finish sketch */
+ if (anchor) {
+ p = anchor->dp;
+ }
+ pc->ea = anchor;
- dt->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand"));
+ dt->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Sketching: release <b>Alt</b> to finalize current curve"));
- interpolate(pc);
- spdc_concat_colors_and_flush(pc, FALSE);
- pc->sa = NULL;
- pc->ea = NULL;
- if (pc->green_anchor) {
- pc->green_anchor = sp_draw_anchor_destroy(pc->green_anchor);
+ sketch_interpolate(pc);
+
+ pc->state = SP_PENCIL_CONTEXT_SKETCH;
+ } else {
+ /* Finish segment now */
+ /// \todo fixme: Clean up what follows (Lauris)
+ if (anchor) {
+ p = anchor->dp;
+ }
+ pc->ea = anchor;
+ /* Write curves to object */
+
+ dt->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand"));
+
+ interpolate(pc);
+ spdc_concat_colors_and_flush(pc, FALSE);
+ pc->sa = NULL;
+ pc->ea = NULL;
+ if (pc->green_anchor) {
+ pc->green_anchor = sp_draw_anchor_destroy(pc->green_anchor);
+ }
+ pc->state = SP_PENCIL_CONTEXT_IDLE;
}
- pc->state = SP_PENCIL_CONTEXT_IDLE;
ret = TRUE;
break;
+ case SP_PENCIL_CONTEXT_SKETCH:
default:
break;
}
@@ -553,6 +578,34 @@ pencil_handle_key_press(SPPencilContext *const pc, guint const keyval, guint con
return ret;
}
+static gint
+pencil_handle_key_release(SPPencilContext *const pc, guint const keyval, guint const /*state*/)
+{
+ gint ret = FALSE;
+ switch (keyval) {
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ case GDK_Meta_L:
+ case GDK_Meta_R:
+ if (pc->state == SP_PENCIL_CONTEXT_SKETCH) {
+ spdc_concat_colors_and_flush(pc, FALSE);
+ pc->sketch_interpolation = Geom::Path();
+ pc->sketch_n = 0;
+ pc->sa = NULL;
+ pc->ea = NULL;
+ if (pc->green_anchor) {
+ pc->green_anchor = sp_draw_anchor_destroy(pc->green_anchor);
+ }
+ pc->state = SP_PENCIL_CONTEXT_IDLE;
+ ret = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
/**
* Reset points and set new starting point.
*/
// worst case gives us a segment per point
int max_segs = 4*n_points;
- int const n_segs = sp_bezier_fit_cubic_r(b, points, n_points,
+ int const n_segs = Geom::bezier_fit_cubic_r(b, points, n_points,
tolerance_sq, max_segs);
if ( n_segs > 0)
}
+/* interpolates the sketched curve and tweaks the current sketch interpolation*/
+static void
+sketch_interpolate(SPPencilContext *pc)
+{
+ g_assert( pc->ps.size() > 1 );
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ double const tol = 100.0 * 0.4; //prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
+ double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() *
+ tol) * exp(0.2*tol - 2);
+
+ bool average_all_sketches = prefs->getBool("/tools/freehand/pencil/average_all_sketches", true);
+
+ g_assert(is_zero(pc->req_tangent)
+ || is_unit_vector(pc->req_tangent));
+ Geom::Point const tHatEnd(0, 0);
+
+ guint n_points = pc->ps.size();
+ pc->red_curve->reset();
+ pc->red_curve_is_valid = false;
+
+ Geom::Point * b = g_new(Geom::Point, 4*n_points);
+ Geom::Point * points = g_new(Geom::Point, 4*n_points);
+ for (unsigned i = 0; i < pc->ps.size(); i++) {
+ points[i] = pc->ps[i];
+ }
+
+ // worst case gives us a segment per point
+ int max_segs = 4*n_points;
+
+ int const n_segs = Geom::bezier_fit_cubic_r(b, points, n_points,
+ tolerance_sq, max_segs);
+
+ if ( n_segs > 0)
+ {
+ // only take first cubic and average its coefficients with the old ones
+
+ Geom::Point coeffs[4];
+ if ( pc->sketch_n > 0 ) {
+ Geom::CubicBezier const * oldcubic = dynamic_cast<Geom::CubicBezier const *>( &pc->sketch_interpolation.front() );
+ g_assert(oldcubic);
+ for (unsigned i = 0; i < 4; i++){
+ if (average_all_sketches) {
+ // Average = (sum of all) / n
+ // = (sum of all + new one) / n+1
+ // = ((old average)*n + new one) / n+1
+ coeffs[i] = ((*oldcubic)[i] * pc->sketch_n + b[i]) / (pc->sketch_n + 1);
+ } else {
+ coeffs[i] = 0.5 * (b[i] + (*oldcubic)[i]);
+ }
+ }
+ } else {
+ for (unsigned i = 0; i < 4; i++){
+ coeffs[i] = b[i];
+ }
+ }
+ pc->sketch_n++;
+
+ pc->sketch_interpolation.start(coeffs[0]);
+ pc->sketch_interpolation.appendNew<Geom::CubicBezier>(coeffs[1], coeffs[2], coeffs[3]);
+
+ Geom::PathVector temp;
+ temp.push_back(pc->sketch_interpolation);
+
+ pc->green_curve->reset();
+ pc->green_curve->set_pathvector(temp);
+ sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->red_bpath), pc->green_curve);
+
+ /* Fit and draw and copy last point */
+ g_assert(!pc->green_curve->is_empty());
+
+ /* Set up direction of next curve. */
+ {
+ Geom::CubicBezier const * last_seg = dynamic_cast<Geom::CubicBezier const *>(pc->green_curve->last_segment());
+ g_assert( last_seg ); // Relevance: validity of (*last_seg)[2]
+ pc->p[0] = last_seg->finalPoint();
+ pc->npoints = 1;
+ Geom::Point const req_vec( pc->p[0] - (*last_seg)[2] );
+ pc->req_tangent = ( ( Geom::is_zero(req_vec) || !in_svg_plane(req_vec) )
+ ? Geom::Point(0, 0)
+ : Geom::unit_vector(req_vec) );
+ }
+ }
+ g_free(b);
+ g_free(points);
+ pc->ps.clear();
+}
+
static void
fit_and_split(SPPencilContext *pc)
{
g_assert(is_zero(pc->req_tangent)
|| is_unit_vector(pc->req_tangent));
Geom::Point const tHatEnd(0, 0);
- int const n_segs = sp_bezier_fit_cubic_full(b, NULL, pc->p, pc->npoints,
+ int const n_segs = Geom::bezier_fit_cubic_full(b, NULL, pc->p, pc->npoints,
pc->req_tangent, tHatEnd,
tolerance_sq, 1);
if ( n_segs > 0
diff --git a/src/pencil-context.h b/src/pencil-context.h
index 0845c82ba9234b7e0e6b2e06383fbce3583d1bff..dd59c0466f3a1b98fc0c91710732b262921fe8e5 100644 (file)
--- a/src/pencil-context.h
+++ b/src/pencil-context.h
enum PencilState {
SP_PENCIL_CONTEXT_IDLE,
SP_PENCIL_CONTEXT_ADDLINE,
- SP_PENCIL_CONTEXT_FREEHAND
+ SP_PENCIL_CONTEXT_FREEHAND,
+ SP_PENCIL_CONTEXT_SKETCH
};
/**
bool is_drawing;
bool prev_snap_was_succesful;
-
+
std::vector<Geom::Point> ps;
+
+ Geom::Path sketch_interpolation; // the current proposal from the sketched paths
+ unsigned sketch_n; // number of sketches done
};
/// The SPPencilContext vtable (empty).
index 68df4e730965f2a939b0143c28551ab9503bf71f..dd6a9a92f3fed86906358694430b8f176a424c0d 100644 (file)
" </group>\n"
" <group id=\"freehand\"\n"
" style=\"fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-linejoin:miter;stroke-linecap:butt;\">\n"
-" <eventcontext id=\"pencil\" tolerance=\"4.0\" selcue=\"1\" style=\"stroke-width:1px;\" usecurrent=\"0\"/>\n"
+" <eventcontext id=\"pencil\" tolerance=\"4.0\" selcue=\"1\" style=\"stroke-width:1px;\" usecurrent=\"0\" average_all_sketches=\"1\"/>\n"
" <eventcontext id=\"pen\" mode=\"drag\" selcue=\"1\" style=\"stroke-width:1px;\" usecurrent=\"0\"/>\n"
" </group>\n"
" <eventcontext id=\"calligraphic\" style=\"fill:black;fill-opacity:1;fill-rule:nonzero;stroke:none;\"\n"
index b1a14e7817c373c43067684832a56e22c7cd862b..d656e2a537b970be878be298df81ada73e3933f5 100644 (file)
_page_tools.add_line( true, "", _t_cvg_convert_whole_groups, "",
_("Treat groups as a single object during conversion to guides rather than converting each child separately."));
+ _pencil_average_all_sketches.init ( _("Average all sketches"), "/tools/freehand/pencil/average_all_sketches", false);
_calligrapy_use_abs_size.init ( _("Width is in absolute units"), "/tools/calligraphic/abs_width", false);
_calligrapy_keep_selected.init ( _("Select new path"), "/tools/calligraphic/keep_selected", true);
_connector_ignore_text.init( _("Don't attach connectors to text objects"), "/tools/connector/ignoretext", true);
this->AddSelcueCheckbox(_page_pencil, "/tools/freehand/pencil", true);
this->AddNewObjectsStyle(_page_pencil, "/tools/freehand/pencil");
this->AddDotSizeSpinbutton(_page_pencil, "/tools/freehand/pencil", 3.0);
+ _page_pencil.add_group_header( _("Sketch mode"));
+ _page_pencil.add_line( true, "", _pencil_average_all_sketches, "",
+ _("If on, the sketch result will be the normal average of all sketches made, instead of averaging the old result with the new sketch."));
//Pen
this->AddPage(_page_pen, _("Pen"), iter_tools, PREFS_PAGE_TOOLS_PEN);
index b439f25dd26ad1b7e425045d4dc2248d8305110f..1c5a3a85f667c0bb09217e0864c2977beea6794e 100644 (file)
PrefSpinButton _win_trans_blur; /**< The dialog transparency setting for when the dialog is out of focus. */
PrefSpinButton _win_trans_time; /**< How much time to go from one transparency setting to another */
+ PrefCheckButton _pencil_average_all_sketches;
+
PrefCheckButton _calligrapy_use_abs_size;
PrefCheckButton _calligrapy_keep_selected;