diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2013-03-05 08:43:18 +0000 |
|---|---|---|
| committer | Jabiertxo Arraiza Zenotz <jtx@jtx.marker.es> | 2013-03-05 08:43:18 +0000 |
| commit | a33dbbc4fbad29c187611660d3651bbe57243903 (patch) | |
| tree | 1260bfa9c376aa441bb26087283ed0014f5986ec /src/pen-context.cpp | |
| parent | Fix sintax (diff) | |
| parent | merge from branch (diff) | |
| download | inkscape-a33dbbc4fbad29c187611660d3651bbe57243903.tar.gz inkscape-a33dbbc4fbad29c187611660d3651bbe57243903.zip | |
refactor bsplineSpirolive
(bzr r11950.1.44)
Diffstat (limited to 'src/pen-context.cpp')
| -rw-r--r-- | src/pen-context.cpp | 821 |
1 files changed, 251 insertions, 570 deletions
diff --git a/src/pen-context.cpp b/src/pen-context.cpp index e781a048f..26f800328 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -94,35 +94,22 @@ static void spdc_pen_set_initial_point(SPPenContext *pc, Geom::Point const p); */ static void sp_pen_context_set_mode(SPPenContext *const pc, guint mode); //Esta función cambia los colores rojo,verde y azul haciendolos transparentes o no en función de si se usa spiro -static void spiro_color(SPPenContext *const pc); -//Guarda el valor si se ha pulsado la tecla SHIFT al continuar una curva -static void spiro(SPPenContext *const pc,bool shift); -static void spiroOn(SPPenContext *const pc); -static void spiroOff(SPPenContext *const pc); -static void spiroStartAnchor(SPPenContext *const pc,bool shift); -static void spiroStartAnchorOn(SPPenContext *const pc); -static void spiroStartAnchorOff(SPPenContext *const pc); -static void spiroMotion(SPPenContext *const pc,bool shift); -static void spiroEndAnchorOn(SPPenContext *const pc); -static void spiroEndAnchorOff(SPPenContext *const pc); +static void bspline_spiro_color(SPPenContext *const pc); +static void bspline_spiro(SPPenContext *const pc,bool shift); +static void bspline_spiro_on(SPPenContext *const pc); +static void bspline_spiro_off(SPPenContext *const pc); +static void bspline_spiro_start_anchor(SPPenContext *const pc,bool shift); +static void bspline_spiro_start_anchor_on(SPPenContext *const pc); +static void bspline_spiro_start_anchor_off(SPPenContext *const pc); +static void bspline_spiro_motion(SPPenContext *const pc,bool shift); +static void bspline_spiro_end_anchor_on(SPPenContext *const pc); +static void bspline_spiro_end_anchor_off(SPPenContext *const pc); //Unimos todas las curvas en juego y llamamos a la función doEffect. -static void spiro_build(SPPenContext *const pc); -//function spiro cloned from lpe-spiro.cpp -static void spiro_doEffect(SPCurve * curve); -//Preparamos la curva roja para que se muestre según esté pulsada la tecla SHIFT -static void bspline(SPPenContext *const pc,bool shift); -static void bsplineOn(SPPenContext *const pc); -static void bsplineOff(SPPenContext *const pc); -static void bsplineStartAnchor(SPPenContext *const pc,bool shift); -static void bsplineStartAnchorOn(SPPenContext *const pc); -static void bsplineStartAnchorOff(SPPenContext *const pc); -static void bsplineMotion(SPPenContext *const pc,bool shift); -static void bsplineEndAnchorOn(SPPenContext *const pc); -static void bsplineEndAnchorOff(SPPenContext *const pc); -//Unimos todas las curvas en juego y llamamos a la función doEffect. -static void bspline_build(SPPenContext *const pc); +static void bspline_spiro_build(SPPenContext *const pc); //function bspline cloned from lpe-bspline.cpp static void bspline_doEffect(SPCurve * curve); +//function spiro cloned from lpe-spiro.cpp +static void spiro_doEffect(SPCurve * curve); //BSpline end @@ -472,9 +459,7 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const Geom::Point event_dt(desktop->w2d(event_w)); SPEventContext *event_context = SP_EVENT_CONTEXT(pc); //Test whether we hit any anchor. - //Anchor changed from Const because need to update pc->ea for BSpline. - SPDrawAnchor * anchor = spdc_test_inside(pc, event_w); - //BSpline + SPDrawAnchor * const anchor = spdc_test_inside(pc, event_w); //with this we avoid creating a new point over the existing one if((pc->spiro || pc->bspline) && pc->npoints > 0 && pc->p[0] == pc->p[3]){ return FALSE; @@ -545,12 +530,8 @@ static gint pen_handle_button_press(SPPenContext *const pc, GdkEventButton const pc->sa = anchor; //BSpline if(anchor){ - if(pc->spiro){ - spiroStartAnchor(pc,(bevent.state & GDK_SHIFT_MASK)); - } - if(pc->bspline){ - bsplineStartAnchor(pc,(bevent.state & GDK_SHIFT_MASK)); - } + if(pc->bspline || pc->spiro) + bspline_spiro_start_anchor(pc,(bevent.state & GDK_SHIFT_MASK)); } //BSpline End if (anchor && !sp_pen_context_has_waiting_LPE(pc)) { @@ -674,7 +655,7 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gint const tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); //"spiro_color" lo ejecutamos siempre sea o no spiro - spiro_color(pc); + bspline_spiro_color(pc); if (pen_within_tolerance) { if ( Geom::LInfty( event_w - pen_drag_origin_w ) < tolerance) { return FALSE; // Do not drag if we're within tolerance from origin. @@ -798,12 +779,7 @@ static gint pen_handle_motion_notify(SPPenContext *const pc, GdkEventMotion cons } //BSpline if ( Geom::LInfty( event_w - pen_drag_origin_w ) > tolerance || mevent.time == 0) { - if(pc->spiro){ - spiroMotion(pc,(mevent.state & GDK_SHIFT_MASK)); - } - if(pc->bspline){ - bsplineMotion(pc,(mevent.state & GDK_SHIFT_MASK)); - } + bspline_spiro_motion(pc,(mevent.state & GDK_SHIFT_MASK)); pen_drag_origin_w = event_w; } //BSpline End @@ -852,11 +828,8 @@ static gint pen_handle_button_release(SPPenContext *const pc, GdkEventButton con pc->sa = anchor; //BSpline if (anchor) { - if(pc->spiro){ - spiroStartAnchor(pc,(revent.state & GDK_SHIFT_MASK)); - } - if(pc->bspline){ - bsplineStartAnchor(pc,(revent.state & GDK_SHIFT_MASK)); + if(pc->bspline || pc->spiro){ + bspline_spiro_start_anchor(pc,(revent.state & GDK_SHIFT_MASK)); } } //BSpline End @@ -1042,14 +1015,9 @@ static void pen_redraw_all (SPPenContext *const pc) //Simplemente redibujamos la spiro teniendo en cuenta si el nodo es cusp o symm. //como es un redibujo simplemente no llamamos a la función global //sino al final de esta - if(pc->spiro){ - //we redraw spiro - spiro_build(pc); - } - if(pc->bspline){ - //we redraw bspline - bspline_build(pc); - } + + //BSpline + bspline_spiro_build(pc); //BSpline End } @@ -1432,7 +1400,7 @@ static gint pen_handle_key_press(SPPenContext *const pc, GdkEvent *event) spdc_pen_set_subsequent_point(pc, pt, true); pen_last_paraxial_dir = !pen_last_paraxial_dir; //BSpline - if(pc->spiro || pc->bspline) bspline_build(pc); + bspline_spiro_build(pc); //BSpline End ret = TRUE; } @@ -1506,7 +1474,7 @@ static void spdc_pen_set_angle_distance_status_message(SPPenContext *const pc, G //Esta función cambia los colores rojo,verde y azul haciendolos transparentes o no en función de si se usa spiro -static void spiro_color(SPPenContext *const pc) +static void bspline_spiro_color(SPPenContext *const pc) { bool remake_green_bpaths = false; if(pc->spiro){ @@ -1550,435 +1518,19 @@ static void spiro_color(SPPenContext *const pc) sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(pc->red_bpath), pc->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); } - -//Unimos todas las curvas en juego y llamamos a la función doEffect. - -static void spiro(SPPenContext *const pc, bool shift) -{ - if(!pc->anchor_statusbar) - shift?spiroOff(pc):spiroOn(pc); - - spiro_build(pc); -} - -static void spiroOn(SPPenContext *const pc){ - if(!pc->red_curve->is_empty()){ - using Geom::X; - using Geom::Y; - pc->npoints = 5; - pc->p[0] = pc->red_curve->first_segment()->initialPoint(); - pc->p[3] = pc->red_curve->first_segment()->finalPoint(); - pc->p[2] = pc->p[3] + (1./3)*(pc->p[0] - pc->p[3]); - pc->p[2] = Geom::Point(pc->p[2][X] + 0.0625,pc->p[2][Y] + 0.0625); - } -} - -static void spiroOff(SPPenContext *const pc) -{ - if(!pc->red_curve->is_empty()){ - pc->npoints = 5; - pc->p[0] = pc->red_curve->first_segment()->initialPoint(); - pc->p[3] = pc->red_curve->first_segment()->finalPoint(); - pc->p[2] = pc->p[3]; - } -} - -static void spiroStartAnchor(SPPenContext *const pc, bool shift) +static void bspline_spiro(SPPenContext *const pc, bool shift) { - if(pc->sa->curve->is_empty()) + if(!pc->spiro && !pc->bspline) return; - if(shift) - bsplineStartAnchorOff(pc); - else - bsplineStartAnchorOn(pc); -} - -static void spiroStartAnchorOn(SPPenContext *const pc) -{ - using Geom::X; - using Geom::Y; - SPCurve *tmpCurve = new SPCurve(); - tmpCurve = pc->sa->curve->copy(); - if(pc->sa->start) - tmpCurve = tmpCurve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - SPCurve *lastSeg = new SPCurve(); - Geom::Point A = tmpCurve->last_segment()->initialPoint(); - Geom::Point D = tmpCurve->last_segment()->finalPoint(); - Geom::Point C = D + (1./3)*(A - D); - C = Geom::Point(C[X] + 0.0625,C[Y] + 0.0625); - if(cubic){ - lastSeg->moveto(A); - lastSeg->curveto((*cubic)[1],C,D); - }else{ - lastSeg->moveto(A); - lastSeg->curveto(A,C,D); - } - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; - }else{ - //we eliminate the last segment - tmpCurve->backspace(); - //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); - } - if (pc->sa->start) { - tmpCurve = tmpCurve->create_reverse(); - } - pc->sa->curve->reset(); - pc->sa->curve = tmpCurve; -} - -static void spiroStartAnchorOff(SPPenContext *const pc) -{ - SPCurve *tmpCurve = new SPCurve(); - tmpCurve = pc->sa->curve->copy(); - if(pc->sa->start) - tmpCurve = tmpCurve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - if(cubic){ - SPCurve *lastSeg = new SPCurve(); - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; - }else{ - //we eliminate the last segment - tmpCurve->backspace(); - //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); - } - if (pc->sa->start) { - tmpCurve = tmpCurve->create_reverse(); - } - pc->sa->curve->reset(); - pc->sa->curve = tmpCurve; - } - -} - -static void spiroMotion(SPPenContext *const pc, bool shift){ - using Geom::X; - using Geom::Y; - SPCurve *tmpCurve = new SPCurve(); - if(shift) - pc->p[2] = pc->p[3]; - else - pc->p[2] = pc->p[3] + (1./3)*(pc->p[0] - pc->p[3]); - pc->p[2] = Geom::Point(pc->p[2][X] + 0.0625,pc->p[2][Y] + 0.0625); - - if(pc->green_curve->is_empty() && !pc->sa){ - pc->p[1] = pc->p[0] + (1./3)*(pc->p[3] - pc->p[0]); - }else if(!pc->green_curve->is_empty()){ - tmpCurve = pc->green_curve->copy(); - }else{ - tmpCurve = pc->sa->curve->copy(); - if(pc->sa->start) - tmpCurve = tmpCurve->create_reverse(); - } - if(!tmpCurve->is_empty() && !pc->red_curve->is_empty()){ - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - if(cubic){ - pc->p[1] = (*cubic)[3] + (Geom::Point)((*cubic)[3] - (*cubic)[2] ); - }else{ - pc->p[1] = pc->p[0]; - } - } - - if(pc->anchor_statusbar && !pc->red_curve->is_empty()){ - if(shift) - bsplineEndAnchorOff(pc); - else - bsplineEndAnchorOn(pc); - } - - spiro_build(pc); -} - -static void spiroEndAnchorOn(SPPenContext *const pc) -{ - using Geom::X; - using Geom::Y; - pc->p[2] = pc->p[3] + (1./3)*(pc->p[0] - pc->p[3]); - pc->p[2] = Geom::Point(pc->p[2][X] + 0.0625,pc->p[2][Y] + 0.0625); - SPCurve *tmpCurve = new SPCurve(); - SPCurve *lastSeg = new SPCurve(); - Geom::Point C(0,0); - if(!pc->sa || pc->sa->curve->is_empty()){ - tmpCurve = pc->green_curve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - C = tmpCurve->last_segment()->finalPoint() + (Geom::Point)(tmpCurve->last_segment()->finalPoint() - pc->p[2]); - if(cubic){ - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],C,(*cubic)[3]); - }else{ - lastSeg->moveto(tmpCurve->last_segment()->initialPoint()); - lastSeg->curveto(tmpCurve->last_segment()->initialPoint(),C,tmpCurve->last_segment()->finalPoint()); - } - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; - }else{ - //we eliminate the last segment - tmpCurve->backspace(); - //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); - } - tmpCurve = tmpCurve->create_reverse(); - pc->green_curve->reset(); - pc->green_curve = tmpCurve; - }else{ - tmpCurve = pc->sa->curve->copy(); - if(!pc->sa->start) - tmpCurve = tmpCurve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - C = tmpCurve->last_segment()->finalPoint() + (Geom::Point)(tmpCurve->last_segment()->finalPoint() - pc->p[2]); - if(cubic){ - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],C,(*cubic)[3]); - }else{ - lastSeg->moveto(tmpCurve->last_segment()->initialPoint()); - lastSeg->curveto(tmpCurve->last_segment()->initialPoint(),C,tmpCurve->last_segment()->finalPoint()); - } - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; - }else{ - //we eliminate the last segment - tmpCurve->backspace(); - //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); - } - if (!pc->sa->start) { - tmpCurve = tmpCurve->create_reverse(); - } - pc->sa->curve->reset(); - pc->sa->curve = tmpCurve; - } -} - -static void spiroEndAnchorOff(SPPenContext *const pc) -{ - pc->p[2] = pc->p[3]; - SPCurve *tmpCurve = new SPCurve(); - SPCurve *lastSeg = new SPCurve(); - if(!pc->sa || pc->sa->curve->is_empty()){ - tmpCurve = pc->green_curve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - if(cubic){ - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; - }else{ - //we eliminate the last segment - tmpCurve->backspace(); - //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); - } - tmpCurve = tmpCurve->create_reverse(); - pc->green_curve->reset(); - pc->green_curve = tmpCurve; - } - }else{ - tmpCurve = pc->sa->curve->copy(); - if(!pc->sa->start) - tmpCurve = tmpCurve->create_reverse(); - Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - if(cubic){ - lastSeg->moveto((*cubic)[0]); - lastSeg->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]); - if( tmpCurve->get_segment_count() == 1){ - tmpCurve = lastSeg; - }else{ - //we eliminate the last segment - tmpCurve->backspace(); - //and we add it again with the recreation - tmpCurve->append_continuous(lastSeg, 0.0625); - } - if (!pc->sa->start) { - tmpCurve = tmpCurve->create_reverse(); - } - pc->sa->curve->reset(); - pc->sa->curve = tmpCurve; - } - } -} - -//Unimos todas las curvas en juego y llamamos a la función doEffect. -static void spiro_build(SPPenContext *const pc) -{ - //We create the base curve - SPCurve *curve = new SPCurve(); - //If we continuate the existing curve we add it at the start - if(pc->sa && !pc->sa->curve->is_empty()){ - curve = pc->sa->curve->copy(); - if (pc->sa->start) { - curve = curve->create_reverse(); - } - } - //We add also the green curve - if (!pc->green_curve->is_empty()) - curve->append_continuous(pc->green_curve, 0.0625); - - //and the red one - if (!pc->red_curve->is_empty()){ - pc->red_curve->reset(); - pc->red_curve->moveto(pc->p[0]); - pc->red_curve->curveto(pc->p[1],pc->p[2],pc->p[3]); - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->red_bpath), pc->red_curve); - curve->append_continuous(pc->red_curve, 0.0625); - } - - if(!curve->is_empty()){ - //cerramos la curva si estan cerca los puntos finales de la curva spiro - if(Geom::are_near(curve->first_path()->initialPoint(), curve->last_path()->finalPoint())){ - curve->closepath_current(); - } - //TODO: CALL TO CLONED FUNCTION SPIRO::doEffect IN lpe-spiro.cpp - //For example - //using namespace Inkscape::LivePathEffect; - //LivePathEffectObject *lpeobj = static_cast<LivePathEffectObject*> (curve); - //Effect *spr = static_cast<Effect*> ( new LPEspiro(lpeobj) ); - //spr->doEffect(curve); - spiro_doEffect(curve); - sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->blue_bpath), curve); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(pc->blue_bpath), pc->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_item_show(pc->blue_bpath); - curve->unref(); - sp_canvas_item_show(pc->c1); - pc->blue_curve->reset(); - SP_CTRL(pc->c1)->moveto(pc->p[0]); - //We hide the holders that doesn't contribute anything - sp_canvas_item_hide(pc->cl1); - sp_canvas_item_hide(pc->c0); - sp_canvas_item_hide(pc->cl0); - }else{ - //if the curve is empty - sp_canvas_item_hide(pc->blue_bpath); - } -} -//Spiro function cloned from lpe-spiro.cpp -static void spiro_doEffect(SPCurve * curve) -{ - using Geom::X; - using Geom::Y; - - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - guint len = curve->get_segment_count() + 2; - - curve->reset(); - Spiro::spiro_cp *path = g_new (Spiro::spiro_cp, len); - int ip = 0; - - for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - if (path_it->empty()) - continue; - - // start of path - { - Geom::Point p = path_it->front().pointAt(0); - path[ip].x = p[X]; - path[ip].y = p[Y]; - path[ip].ty = '{' ; // for closed paths, this is overwritten - ip++; - } - - // midpoints - Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve - - Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop - if (path_it->closed()) { - // if the path is closed, maybe we have to stop a bit earlier because the closing line segment has zerolength. - const Geom::Curve &closingline = path_it->back_closed(); // the closing line segment is always of type Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for *exact* zero length, which goes wrong for relative coordinates and rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } - } - - while ( curve_it2 != curve_endit ) - { - /* This deals with the node between curve_it1 and curve_it2. - * Loop to end_default (so without last segment), loop ends when curve_it2 hits the end - * and then curve_it1 points to end or closing segment */ - Geom::Point p = curve_it1->finalPoint(); - path[ip].x = p[X]; - path[ip].y = p[Y]; - - // Determine type of spiro node this is, determined by the tangents (angles) of the curves - // TODO: see if this can be simplified by using /helpers/geom-nodetype.cpp:get_nodetype - bool this_is_line = is_straight_curve(*curve_it1); - bool next_is_line = is_straight_curve(*curve_it2); - - Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2); - - if ( nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM ) - { - if (this_is_line && !next_is_line) { - path[ip].ty = ']'; - } else if (next_is_line && !this_is_line) { - path[ip].ty = '['; - } else { - path[ip].ty = 'c'; - } - } else { - path[ip].ty = 'v'; - } - - ++curve_it1; - ++curve_it2; - ip++; - } - - // add last point to the spiropath - Geom::Point p = curve_it1->finalPoint(); - path[ip].x = p[X]; - path[ip].y = p[Y]; - if (path_it->closed()) { - // curve_it1 points to the (visually) closing segment. determine the match between first and this last segment (the closing node) - Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, path_it->front()); - switch (nodetype) { - case Geom::NODE_NONE: // can't happen! but if it does, it means the path isn't closed :-) - path[ip].ty = '}'; - ip++; - break; - case Geom::NODE_CUSP: - path[0].ty = path[ip].ty = 'v'; - break; - case Geom::NODE_SMOOTH: - case Geom::NODE_SYMM: - path[0].ty = path[ip].ty = 'c'; - break; - } - } else { - // set type to path closer - path[ip].ty = '}'; - ip++; - } - - // run subpath through spiro - int sp_len = ip; - Spiro::spiro_run(path, sp_len, *curve); - ip = 0; - } - - g_free (path); -} - -//Unimos todas las curvas en juego y llamamos a la función doEffect. - -static void bspline(SPPenContext *const pc, bool shift) -{ if(!pc->anchor_statusbar) - shift?bsplineOff(pc):bsplineOn(pc); + shift?bspline_spiro_off(pc):bspline_spiro_on(pc); - bspline_build(pc); + bspline_spiro_build(pc); } -static void bsplineOn(SPPenContext *const pc){ +static void bspline_spiro_on(SPPenContext *const pc) +{ if(!pc->red_curve->is_empty()){ using Geom::X; using Geom::Y; @@ -1990,7 +1542,7 @@ static void bsplineOn(SPPenContext *const pc){ } } -static void bsplineOff(SPPenContext *const pc) +static void bspline_spiro_off(SPPenContext *const pc) { if(!pc->red_curve->is_empty()){ pc->npoints = 5; @@ -2000,18 +1552,21 @@ static void bsplineOff(SPPenContext *const pc) } } -static void bsplineStartAnchor(SPPenContext *const pc, bool shift) +static void bspline_spiro_start_anchor(SPPenContext *const pc, bool shift) { + if(!pc->spiro && !pc->bspline) + return; + if(pc->sa->curve->is_empty()) return; if(shift) - bsplineStartAnchorOff(pc); + bspline_spiro_start_anchor_off(pc); else - bsplineStartAnchorOn(pc); + bspline_spiro_start_anchor_on(pc); } -static void bsplineStartAnchorOn(SPPenContext *const pc) +static void bspline_spiro_start_anchor_on(SPPenContext *const pc) { using Geom::X; using Geom::Y; @@ -2047,7 +1602,7 @@ static void bsplineStartAnchorOn(SPPenContext *const pc) pc->sa->curve = tmpCurve; } -static void bsplineStartAnchorOff(SPPenContext *const pc) +static void bspline_spiro_start_anchor_off(SPPenContext *const pc) { SPCurve *tmpCurve = new SPCurve(); tmpCurve = pc->sa->curve->copy(); @@ -2075,7 +1630,10 @@ static void bsplineStartAnchorOff(SPPenContext *const pc) } -static void bsplineMotion(SPPenContext *const pc, bool shift){ +static void bspline_spiro_motion(SPPenContext *const pc, bool shift){ + if(!pc->spiro && !pc->bspline) + return; + using Geom::X; using Geom::Y; SPCurve *tmpCurve = new SPCurve(); @@ -2097,18 +1655,22 @@ static void bsplineMotion(SPPenContext *const pc, bool shift){ if(!tmpCurve->is_empty() && !pc->red_curve->is_empty()){ Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); if(cubic){ - SPCurve * WPower = new SPCurve(); - Geom::D2< Geom::SBasis > SBasisWPower; - WPower->moveto(tmpCurve->last_segment()->finalPoint()); - WPower->lineto(tmpCurve->last_segment()->initialPoint()); - float WP = Geom::nearest_point((*cubic)[2],*WPower->first_segment()); - WPower->reset(); - WPower->moveto(pc->red_curve->last_segment()->initialPoint()); - WPower->lineto(pc->red_curve->last_segment()->finalPoint()); - SBasisWPower = WPower->first_segment()->toSBasis(); - WPower->reset(); - pc->p[1] = SBasisWPower.valueAt(WP); - pc->p[1] = Geom::Point(pc->p[1][X] + 0.0625,pc->p[1][Y] + 0.0625); + if(pc->bspline){ + SPCurve * WPower = new SPCurve(); + Geom::D2< Geom::SBasis > SBasisWPower; + WPower->moveto(tmpCurve->last_segment()->finalPoint()); + WPower->lineto(tmpCurve->last_segment()->initialPoint()); + float WP = Geom::nearest_point((*cubic)[2],*WPower->first_segment()); + WPower->reset(); + WPower->moveto(pc->red_curve->last_segment()->initialPoint()); + WPower->lineto(pc->red_curve->last_segment()->finalPoint()); + SBasisWPower = WPower->first_segment()->toSBasis(); + WPower->reset(); + pc->p[1] = SBasisWPower.valueAt(WP); + pc->p[1] = Geom::Point(pc->p[1][X] + 0.0625,pc->p[1][Y] + 0.0625); + }else{ + pc->p[1] = (*cubic)[3] + (Geom::Point)((*cubic)[3] - (*cubic)[2] ); + } }else{ pc->p[1] = pc->p[0]; } @@ -2116,16 +1678,17 @@ static void bsplineMotion(SPPenContext *const pc, bool shift){ if(pc->anchor_statusbar && !pc->red_curve->is_empty()){ if(shift) - bsplineEndAnchorOff(pc); + bspline_spiro_end_anchor_off(pc); else - bsplineEndAnchorOn(pc); + bspline_spiro_end_anchor_on(pc); } - bspline_build(pc); + bspline_spiro_build(pc); } -static void bsplineEndAnchorOn(SPPenContext *const pc) +static void bspline_spiro_end_anchor_on(SPPenContext *const pc) { + using Geom::X; using Geom::Y; pc->p[2] = pc->p[3] + (1./3)*(pc->p[0] - pc->p[3]); @@ -2136,8 +1699,12 @@ static void bsplineEndAnchorOn(SPPenContext *const pc) if(!pc->sa || pc->sa->curve->is_empty()){ tmpCurve = pc->green_curve->create_reverse(); Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint()); - C = Geom::Point(C[X] + 0.0625,C[Y] + 0.0625); + if(pc->bspline){ + C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint()); + C = Geom::Point(C[X] + 0.0625,C[Y] + 0.0625); + }else{ + C = pc->p[3] + (Geom::Point)(pc->p[3] - pc->p[2] ); + } if(cubic){ lastSeg->moveto((*cubic)[0]); lastSeg->curveto((*cubic)[1],C,(*cubic)[3]); @@ -2161,8 +1728,12 @@ static void bsplineEndAnchorOn(SPPenContext *const pc) if(!pc->sa->start) tmpCurve = tmpCurve->create_reverse(); Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const*>(&*tmpCurve->last_segment()); - C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint()); - C = Geom::Point(C[X] + 0.0625,C[Y] + 0.0625); + if(pc->bspline){ + C = tmpCurve->last_segment()->finalPoint() + (1./3)*(tmpCurve->last_segment()->initialPoint() - tmpCurve->last_segment()->finalPoint()); + C = Geom::Point(C[X] + 0.0625,C[Y] + 0.0625); + }else{ + C = pc->p[3] + (Geom::Point)(pc->p[3] - pc->p[2] ); + } if(cubic){ lastSeg->moveto((*cubic)[0]); lastSeg->curveto((*cubic)[1],C,(*cubic)[3]); @@ -2186,8 +1757,9 @@ static void bsplineEndAnchorOn(SPPenContext *const pc) } } -static void bsplineEndAnchorOff(SPPenContext *const pc) +static void bspline_spiro_end_anchor_off(SPPenContext *const pc) { + pc->p[2] = pc->p[3]; SPCurve *tmpCurve = new SPCurve(); SPCurve *lastSeg = new SPCurve(); @@ -2236,8 +1808,11 @@ static void bsplineEndAnchorOff(SPPenContext *const pc) //preparates the curves for its trasformation into BSline curves. -static void bspline_build(SPPenContext *const pc) +static void bspline_spiro_build(SPPenContext *const pc) { + if(!pc->spiro && !pc->bspline) + return; + //We create the base curve SPCurve *curve = new SPCurve(); //If we continuate the existing curve we add it at the start @@ -2271,7 +1846,10 @@ static void bspline_build(SPPenContext *const pc) //LivePathEffectObject *lpeobj = static_cast<LivePathEffectObject*> (curve); //Effect *spr = static_cast<Effect*> ( new LPEbspline(lpeobj) ); //spr->doEffect(curve); - bspline_doEffect(curve); + if(pc->bspline) + bspline_doEffect(curve); + else + spiro_doEffect(curve); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(pc->blue_bpath), curve); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(pc->blue_bpath), pc->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); sp_canvas_item_show(pc->blue_bpath); @@ -2311,7 +1889,6 @@ static void bspline_doEffect(SPCurve * curve) //Esto hace que la curva BSpline no pierda su condición aunque se trasladen //dichos manejadores SPCurve *nCurve = new SPCurve(); - Geom::Point startNode(0,0); Geom::Point previousNode(0,0); Geom::Point node(0,0); Geom::Point pointAt1(0,0); @@ -2323,63 +1900,19 @@ static void bspline_doEffect(SPCurve * curve) Geom::D2< Geom::SBasis > SBasisOut; Geom::D2< Geom::SBasis > SBasisHelper; Geom::CubicBezier const *cubic = NULL; - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo BSPline - if (path_it->closed()) { - //Calculamos el nodo de inicio BSpline - const Geom::Curve &closingline = path_it->back_closed(); + // if the path is closed, maybe we have to stop a bit earlier because the closing line segment has zerolength. + const Geom::Curve &closingline = path_it->back_closed(); // the closing line segment is always of type Geom::LineSegment. if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for *exact* zero length, which goes wrong for relative coordinates and rounding errors... + // the closing line segment has zero-length. So stop before that one! curve_endit = path_it->end_open(); } - - SPCurve * in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - SBasisIn = in->first_segment()->toSBasis(); - - SPCurve *lineHelper = new SPCurve(); - cubic = dynamic_cast<Geom::CubicBezier const*>(&*curve_it1); - if(cubic){ - lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment()))); - }else{ - lineHelper->moveto(in->first_segment()->initialPoint()); - } - in->reset(); - delete in; - - SPCurve * end = new SPCurve(); - end->moveto(curve_endit->initialPoint()); - end->lineto(curve_endit->finalPoint()); - Geom::D2< Geom::SBasis > SBasisEnd = end->first_segment()->toSBasis(); - //Geom::BezierCurve const *bezier = dynamic_cast<Geom::BezierCurve const*>(&*curve_endit); - cubic = dynamic_cast<Geom::CubicBezier const*>(&*curve_endit); - if(cubic){ - lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubic)[2],*end->first_segment()))); - }else{ - lineHelper->lineto(end->first_segment()->finalPoint()); - } - end->reset(); - delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - //Guardamos el principio de la curva - startNode = SBasisHelper.valueAt(0.5); - //Definimos el punto de inicio original de la curva resultante - node = startNode; - }else{ - //Guardamos el principio de la curva - SPCurve * in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - startNode = in->first_segment()->initialPoint(); - in->reset(); - delete in; - //Definimos el punto de inicio original de la curva resultante - node = startNode; } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo BSPline + //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { @@ -2448,13 +1981,54 @@ static void bspline_doEffect(SPCurve * curve) curveHelper->moveto(node); //Si está cerrada la curva, la cerramos sobre el valor guardado previamente //Si no finalizamos en el punto final + Geom::Point startNode(0,0); if (path_it->closed()) { + SPCurve * start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + Geom::D2< Geom::SBasis > SBasisStart = start->first_segment()->toSBasis(); + SPCurve *lineHelper = new SPCurve(); + cubic = dynamic_cast<Geom::CubicBezier const*>(&*path_it->begin()); + if(cubic){ + lineHelper->moveto(SBasisStart.valueAt(Geom::nearest_point((*cubic)[1],*start->first_segment()))); + }else{ + lineHelper->moveto(start->first_segment()->initialPoint()); + } + start->reset(); + delete start; + + SPCurve * end = new SPCurve(); + end->moveto(curve_it1->initialPoint()); + end->lineto(curve_it1->finalPoint()); + Geom::D2< Geom::SBasis > SBasisEnd = end->first_segment()->toSBasis(); + //Geom::BezierCurve const *bezier = dynamic_cast<Geom::BezierCurve const*>(&*curve_endit); + cubic = dynamic_cast<Geom::CubicBezier const*>(&*curve_it1); + if(cubic){ + lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubic)[2],*end->first_segment()))); + }else{ + lineHelper->lineto(end->first_segment()->finalPoint()); + } + end->reset(); + delete end; + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + //Guardamos el principio de la curva + startNode = SBasisHelper.valueAt(0.5); curveHelper->curveto(nextPointAt1, nextPointAt2, startNode); + nCurve->append_continuous(curveHelper, 0.0625); + nCurve->move_endpoints(startNode,startNode); }else{ + SPCurve * start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + startNode = start->first_segment()->initialPoint(); + start->reset(); + delete start; curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->append_continuous(curveHelper, 0.0625); + nCurve->move_endpoints(startNode,nextPointAt3); } - //añadimos este último segmento - nCurve->append_continuous(curveHelper, 0.0625); curveHelper->reset(); delete curveHelper; //y cerramos la curva @@ -2466,6 +2040,118 @@ static void bspline_doEffect(SPCurve * curve) delete nCurve; } } + +//Spiro function cloned from lpe-spiro.cpp +static void spiro_doEffect(SPCurve * curve) +{ + using Geom::X; + using Geom::Y; + + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + guint len = curve->get_segment_count() + 2; + + curve->reset(); + Spiro::spiro_cp *path = g_new (Spiro::spiro_cp, len); + int ip = 0; + + for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + if (path_it->empty()) + continue; + + // start of path + { + Geom::Point p = path_it->front().pointAt(0); + path[ip].x = p[X]; + path[ip].y = p[Y]; + path[ip].ty = '{' ; // for closed paths, this is overwritten + ip++; + } + + // midpoints + Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve + + Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop + if (path_it->closed()) { + // if the path is closed, maybe we have to stop a bit earlier because the closing line segment has zerolength. + const Geom::Curve &closingline = path_it->back_closed(); // the closing line segment is always of type Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for *exact* zero length, which goes wrong for relative coordinates and rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } + } + + while ( curve_it2 != curve_endit ) + { + /* This deals with the node between curve_it1 and curve_it2. + * Loop to end_default (so without last segment), loop ends when curve_it2 hits the end + * and then curve_it1 points to end or closing segment */ + Geom::Point p = curve_it1->finalPoint(); + path[ip].x = p[X]; + path[ip].y = p[Y]; + + // Determine type of spiro node this is, determined by the tangents (angles) of the curves + // TODO: see if this can be simplified by using /helpers/geom-nodetype.cpp:get_nodetype + bool this_is_line = is_straight_curve(*curve_it1); + bool next_is_line = is_straight_curve(*curve_it2); + + Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2); + + if ( nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM ) + { + if (this_is_line && !next_is_line) { + path[ip].ty = ']'; + } else if (next_is_line && !this_is_line) { + path[ip].ty = '['; + } else { + path[ip].ty = 'c'; + } + } else { + path[ip].ty = 'v'; + } + + ++curve_it1; + ++curve_it2; + ip++; + } + + // add last point to the spiropath + Geom::Point p = curve_it1->finalPoint(); + path[ip].x = p[X]; + path[ip].y = p[Y]; + if (path_it->closed()) { + // curve_it1 points to the (visually) closing segment. determine the match between first and this last segment (the closing node) + Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, path_it->front()); + switch (nodetype) { + case Geom::NODE_NONE: // can't happen! but if it does, it means the path isn't closed :-) + path[ip].ty = '}'; + ip++; + break; + case Geom::NODE_CUSP: + path[0].ty = path[ip].ty = 'v'; + break; + case Geom::NODE_SMOOTH: + case Geom::NODE_SYMM: + path[0].ty = path[ip].ty = 'c'; + break; + } + } else { + // set type to path closer + path[ip].ty = '}'; + ip++; + } + + // run subpath through spiro + int sp_len = ip; + Spiro::spiro_run(path, sp_len, *curve); + ip = 0; + } + + g_free (path); +} + //BSpline end static void spdc_pen_set_subsequent_point(SPPenContext *const pc, Geom::Point const p, bool statusbar, guint status) @@ -2569,12 +2255,7 @@ static void spdc_pen_finish_segment(SPPenContext *const pc, Geom::Point const p, ++pc->num_clicks; if (!pc->red_curve->is_empty()) { - if(pc->spiro){ - spiro(pc,(state & GDK_SHIFT_MASK)); - } - if(pc->bspline){ - bspline(pc,(state & GDK_SHIFT_MASK)); - } + bspline_spiro(pc,(state & GDK_SHIFT_MASK)); pc->green_curve->append_continuous(pc->red_curve, 0.0625); SPCurve *curve = pc->red_curve->copy(); /// \todo fixme: |
