~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/pencil-context.cpp

  • Committer: Ted Gould
  • Date: 2008-11-21 05:24:08 UTC
  • Revision ID: ted@canonical.com-20081121052408-tilucis2pjrrpzxx
MergeĀ fromĀ fe-moved

Show diffs side-by-side

added added

removed removed

Lines of Context:
58
58
static void spdc_finish_endpoint(SPPencilContext *pc);
59
59
static void spdc_add_freehand_point(SPPencilContext *pc, Geom::Point p, guint state);
60
60
static void fit_and_split(SPPencilContext *pc);
61
 
 
 
61
static void interpolate(SPPencilContext *pc);
62
62
 
63
63
static SPDrawContextClass *pencil_parent_class;
64
64
static Geom::Point pencil_drag_origin_w(0, 0);
263
263
                        Inkscape::SnappedPoint const s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, p);
264
264
                        if (s.getSnapped()) {
265
265
                                s.getPoint(p);
266
 
                                pc->pencil_has_snapped_before = true;
 
266
                                pc->prev_snap_was_succesful = true;
267
267
                        } else {
268
 
                                pc->pencil_has_snapped_before = false;
 
268
                                pc->prev_snap_was_succesful = false;
269
269
                        }
270
270
                    } else if (selection->singleItem() && SP_IS_PATH(selection->singleItem())) {
271
271
                        desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Appending to selected path"));
362
362
                    Inkscape::SnappedPoint const s = m.freeSnap(Inkscape::SnapPreferences::SNAPPOINT_NODE, p);
363
363
                    if (s.getSnapped()) {
364
364
                        s.getPoint(p);
365
 
                        pc->pencil_has_snapped_before = true;
 
365
                        pc->prev_snap_was_succesful = true;
 
366
                    } else {
 
367
                        pc->prev_snap_was_succesful = false;
366
368
                    }
367
369
                }
368
370
                if ( pc->npoints != 0) { // buttonpress may have happened before we entered draw context!
369
 
                        if (!(pc->pencil_has_snapped_before && m.snapprefs.getSnapPostponedGlobally())) {
 
371
                        if (!(pc->prev_snap_was_succesful && m.snapprefs.getSnapPostponedGlobally())) {
370
372
                            // When snapping is enabled but temporarily on hold because the mouse is moving 
371
373
                                // fast, then we don't want to add nodes off-grid
372
374
                                spdc_add_freehand_point(pc, from_2geom(p), mevent.state);
450
452
 
451
453
                dt->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Finishing freehand"));
452
454
 
 
455
                interpolate(pc);
453
456
                spdc_concat_colors_and_flush(pc, FALSE);
454
457
                pc->sa = NULL;
455
458
                pc->ea = NULL;
624
627
    }
625
628
}
626
629
 
 
630
 
627
631
static void
628
632
spdc_add_freehand_point(SPPencilContext *pc, Geom::Point p, guint /*state*/)
629
633
{
633
637
    if ( ( p != pc->p[ pc->npoints - 1 ] )
634
638
         && in_svg_plane(p) )
635
639
    {
 
640
        pc->ps.push_back(p);
636
641
        pc->p[pc->npoints++] = p;
637
642
        fit_and_split(pc);
638
643
    }
645
650
}
646
651
 
647
652
static void
 
653
interpolate(SPPencilContext *pc)
 
654
{
 
655
 
 
656
    g_assert( pc->ps.size() > 1 );
 
657
 
 
658
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
659
    double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
 
660
    double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() * 
 
661
                                               tol) * exp(0.2*tol - 2);
 
662
 
 
663
    g_assert(is_zero(pc->req_tangent)
 
664
             || is_unit_vector(pc->req_tangent));
 
665
    Geom::Point const tHatEnd(0, 0);
 
666
 
 
667
    guint n_points  = pc->ps.size();
 
668
    pc->green_curve->reset();
 
669
    pc->red_curve->reset();
 
670
 
 
671
    Geom::Point * b = g_new(Geom::Point, 4*n_points);
 
672
    Geom::Point * points = g_new(Geom::Point, 4*n_points);
 
673
    for (int i = 0; i < pc->ps.size(); i++) { 
 
674
        points[i] = pc->ps[i];
 
675
    }
 
676
 
 
677
    // worst case gives us a segment per point
 
678
    int max_segs = 4*n_points;
 
679
 
 
680
    int const n_segs = sp_bezier_fit_cubic_r(b, points, n_points,
 
681
                                             tolerance_sq, max_segs);
 
682
 
 
683
    if ( n_segs > 0)
 
684
    {
 
685
        /* Fit and draw and reset state */
 
686
        pc->red_curve->reset();
 
687
        pc->red_curve->moveto(b[0]);
 
688
        for (int c = 0; c < n_segs; c++) { 
 
689
            pc->red_curve->curveto(b[4*c+1], b[4*c+2], b[4*c+3]);
 
690
        }
 
691
        sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->red_bpath), pc->red_curve);
 
692
        pc->red_curve_is_valid = true;
 
693
 
 
694
        /* Fit and draw and copy last point */
 
695
        g_assert(!pc->red_curve->is_empty());
 
696
 
 
697
        /* Set up direction of next curve. */
 
698
        {
 
699
            Geom::CubicBezier const * last_seg = dynamic_cast<Geom::CubicBezier const *>(pc->red_curve->last_segment());
 
700
            g_assert( last_seg );      // Relevance: validity of (*last_seg)[2]
 
701
            pc->p[0] = last_seg->finalPoint();
 
702
            pc->npoints = 1;
 
703
            Geom::Point const req_vec( pc->p[0] - (*last_seg)[2] );
 
704
            pc->req_tangent = ( ( Geom::is_zero(req_vec) || !in_svg_plane(req_vec) )
 
705
                                ? Geom::Point(0, 0)
 
706
                                : Geom::unit_vector(req_vec) );
 
707
        }
 
708
 
 
709
        pc->green_curve->append_continuous(pc->red_curve, 0.0625);
 
710
        SPCurve *curve = pc->red_curve->copy();
 
711
 
 
712
        /// \todo fixme:
 
713
        SPCanvasItem *cshape = sp_canvas_bpath_new(sp_desktop_sketch(pc->desktop), curve);
 
714
        curve->unref();
 
715
        sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cshape), pc->green_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
 
716
 
 
717
        pc->green_bpaths = g_slist_prepend(pc->green_bpaths, cshape);
 
718
 
 
719
        pc->red_curve_is_valid = false;
 
720
    }
 
721
    g_free(b);
 
722
    g_free(points);
 
723
    pc->ps.clear();
 
724
}
 
725
 
 
726
 
 
727
static void
648
728
fit_and_split(SPPencilContext *pc)
649
729
{
650
730
    g_assert( pc->npoints > 1 );
651
731
 
652
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
653
 
    double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0);
654
 
    double const tolerance_sq = 0.02 * square( pc->desktop->w2d().descrim() * tol) 
655
 
        * exp(0.2*tol - 2);
 
732
    double const tolerance_sq = 0;
656
733
 
657
734
    Geom::Point b[4];
658
735
    g_assert(is_zero(pc->req_tangent)
659
736
             || is_unit_vector(pc->req_tangent));
660
737
    Geom::Point const tHatEnd(0, 0);
661
738
    int const n_segs = sp_bezier_fit_cubic_full(b, NULL, pc->p, pc->npoints,
662
 
                                                pc->req_tangent, tHatEnd, tolerance_sq, 1);
 
739
                                                pc->req_tangent, tHatEnd, 
 
740
                                                tolerance_sq, 1);
663
741
    if ( n_segs > 0
664
742
         && unsigned(pc->npoints) < G_N_ELEMENTS(pc->p) )
665
743
    {