~inkscape.dev/inkscape/eraser_improvements

« back to all changes in this revision

Viewing changes to src/helper/geom-pathstroke.cpp

  • Committer: jabiertxof
  • Date: 2016-03-01 01:42:13 UTC
  • mfrom: (14648.1.28 inkscape)
  • Revision ID: info@marker.es-20160301014213-ewfxjn3ohelo104c
update to trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis
16
16
#include <2geom/path-intersection.h>
17
17
#include <2geom/circle.h>
 
18
#include <math.h>
18
19
 
19
20
#include "helper/geom-pathstroke.h"
20
21
 
55
56
    return Geom::Circle(center, fabs(radius));
56
57
}
57
58
 
 
59
 
 
60
// Area of triangle given three corner points
 
61
static double area( Geom::Point a, Geom::Point b, Geom::Point c ) {
 
62
 
 
63
    using Geom::X;
 
64
    using Geom::Y;
 
65
    return( 0.5 * fabs( ( a[X]*(b[Y]-c[Y]) + b[X]*(c[Y]-a[Y]) + c[X]*(a[Y]-b[Y]) ) ) );
 
66
}
 
67
 
 
68
// Alternative touching circle routine directly using Beziers. Works only at end points.
 
69
static Circle touching_circle( CubicBezier const &curve, bool start ) {
 
70
 
 
71
    double k = 0;
 
72
    Geom::Point p;
 
73
    Geom::Point normal;
 
74
    if ( start ) {
 
75
        double distance = Geom::distance( curve[1], curve[0] );
 
76
        k = 4.0/3.0 * area( curve[0], curve[1], curve[2] ) /
 
77
            (distance * distance * distance);
 
78
        if( Geom::cross(curve[0]-curve[1], curve[1]-curve[2]) < 0 ) {
 
79
            k = -k;
 
80
        }
 
81
        p = curve[0];
 
82
        normal = Geom::Point(curve[1] - curve[0]).cw();
 
83
        normal.normalize();
 
84
        // std::cout << "Start k: " << k << " d: " << distance << " normal: " << normal << std::endl;
 
85
    } else {
 
86
        double distance = Geom::distance( curve[3], curve[2] );
 
87
        k = 4.0/3.0 * area( curve[1], curve[2], curve[3] ) /
 
88
            (distance * distance * distance);
 
89
        if( Geom::cross(curve[1]-curve[2], curve[2]-curve[3]) < 0 ) {
 
90
            k = -k;
 
91
        }
 
92
        p = curve[3];
 
93
        normal = Geom::Point(curve[3] - curve[2]).cw();
 
94
        normal.normalize();
 
95
        // std::cout << "End   k: " << k << " d: " << distance << " normal: " << normal << std::endl;
 
96
    }
 
97
    if( k == 0 ) {
 
98
        return Geom::Circle( Geom::Point(0,std::numeric_limits<float>::infinity()),
 
99
                             std::numeric_limits<float>::infinity());
 
100
    } else {
 
101
        double radius = 1/k;
 
102
        Geom::Point center = p + normal * radius;
 
103
        return Geom::Circle( center, fabs(radius) );
 
104
    }
 
105
}
58
106
}
59
107
 
60
108
namespace {
77
125
 
78
126
    // line parameters
79
127
    double miter;
80
 
    double width;
 
128
    double width; // half stroke width
81
129
};
82
130
 
83
131
// Join functions must append the outgoing path
115
163
    if (p.isFinite()) {
116
164
        // check size of miter
117
165
        Point point_on_path = incoming.finalPoint() + rot90(tang1)*width;
118
 
        satisfied = distance(p, point_on_path) <= miter * 2.0 * width;
 
166
        // SVG defines miter length as distance between inner intersection and outer intersection,
 
167
        // which is twice the distance from p to point_on_path but width is half stroke width.
 
168
        satisfied = distance(p, point_on_path) <= miter * width; 
119
169
        if (satisfied) {
120
170
            // miter OK, check to see if we can do a relocation
121
171
            if (inc_ls) {
124
174
                res.appendNew<LineSegment>(p);
125
175
            }
126
176
        } else if (clip) {
 
177
            // std::cout << "  Clipping ------------ " << std::endl;
127
178
            // miter needs clipping, find two points
128
179
            Point bisector_versor = Line(point_on_path, p).versor();
129
 
            Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor;
130
 
 
 
180
            Point point_limit = point_on_path + miter * width * bisector_versor;
 
181
            // std::cout << "     bisector_versor: " << bisector_versor << std::endl;
 
182
            // std::cout << "     point_limit: " << point_limit << std::endl;
131
183
            Point p1 = intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw());
132
184
            Point p2 = intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw());
133
 
 
 
185
            // std::cout << "     p1: " << p1 << std::endl;
 
186
            // std::cout << "     p2: " << p2 << std::endl;
134
187
            if (inc_ls) {
135
188
                res.setFinal(p1);
136
189
            } else {
176
229
    return sol;
177
230
}
178
231
 
179
 
void extrapolate_join(join_data jd)
 
232
// Arcs line join. If two circles don't intersect, expand inner circle.
 
233
Geom::Point expand_circle( Geom::Circle &inner_circle, Geom::Circle const &outer_circle, Geom::Point const &start_pt, Geom::Point const &start_tangent ) {
 
234
    // std::cout << "expand_circle:" << std::endl;
 
235
    // std::cout << "  outer_circle: radius: " << outer_circle.radius() << "  center: " << outer_circle.center() << std::endl;
 
236
    // std::cout << "  start: point: " << start_pt << "  tangent: " << start_tangent << std::endl;
 
237
 
 
238
    if( !(outer_circle.contains(start_pt) ) ) {
 
239
        // std::cout << "  WARNING: Outer circle does not contain starting point!" << std::endl;
 
240
        return Geom::Point(0,0);
 
241
    }
 
242
 
 
243
    Geom::Line secant1(start_pt, start_pt + start_tangent);
 
244
    std::vector<Geom::ShapeIntersection> chord1_pts = outer_circle.intersect(secant1);
 
245
    // std::cout << "  chord1: " << chord1_pts[0].point() << ", " << chord1_pts[1].point() << std::endl;
 
246
    Geom::LineSegment chord1(chord1_pts[0].point(), chord1_pts[1].point());
 
247
 
 
248
    Geom::Line bisector = make_bisector_line( chord1 );
 
249
    std::vector<Geom::ShapeIntersection> chord2_pts = outer_circle.intersect(bisector);
 
250
    // std::cout << "  chord2: " << chord2_pts[0].point() << ", " << chord2_pts[1].point() << std::endl;
 
251
    Geom::LineSegment chord2(chord2_pts[0].point(), chord2_pts[1].point());
 
252
 
 
253
    // Find D, point on chord2 and on circle closest to start point
 
254
    Geom::Coord d0 = Geom::distance(chord2_pts[0].point(),start_pt);
 
255
    Geom::Coord d1 = Geom::distance(chord2_pts[1].point(),start_pt);
 
256
    // std::cout << "  d0: " << d0 << " d1: " << d1 << std::endl;
 
257
    Geom::Point d = (d0 < d1) ? chord2_pts[0].point() : chord2_pts[1].point();
 
258
    Geom::Line da(d,start_pt);
 
259
 
 
260
    // Chord through start point and point D
 
261
    std::vector<Geom::ShapeIntersection> chord3_pts =  outer_circle.intersect(da);
 
262
    // std::cout << "  chord3: " << chord3_pts[0].point() << ", " << chord3_pts[1].point() << std::endl;
 
263
 
 
264
    // Find farthest point on chord3 and on circle (could be more robust)
 
265
    Geom::Coord d2 = Geom::distance(chord3_pts[0].point(),d);
 
266
    Geom::Coord d3 = Geom::distance(chord3_pts[1].point(),d);
 
267
    // std::cout << "  d2: " << d2 << " d3: " << d3 << std::endl;
 
268
 
 
269
    // Find point P, the intersection of outer circle and new inner circle
 
270
    Geom::Point p = (d2 > d3) ? chord3_pts[0].point() : chord3_pts[1].point();
 
271
 
 
272
    // Find center of new circle: it is at the intersection of the bisector
 
273
    // of the chord defined by the start point and point P and a line through
 
274
    // the start point and parallel to the first bisector.
 
275
    Geom::LineSegment chord4(start_pt,p);
 
276
    Geom::Line bisector2 = make_bisector_line( chord4 );
 
277
    Geom::Line diameter = make_parallel_line( start_pt, bisector );
 
278
    std::vector<Geom::ShapeIntersection> center_new = bisector2.intersect( diameter );
 
279
    // std::cout << "  center_new: " << center_new[0].point() << std::endl;
 
280
    Geom::Coord r_new = Geom::distance( center_new[0].point(), start_pt );
 
281
    // std::cout << "  r_new: " << r_new << std::endl;
 
282
 
 
283
    inner_circle.setCenter( center_new[0].point() );
 
284
    inner_circle.setRadius( r_new );
 
285
    return p;
 
286
}
 
287
 
 
288
// Arcs line join. If two circles don't intersect, adjust both circles so they just touch.
 
289
// Increase (decrease) the radius of circle 1 and decrease (increase) of circle 2 by the same amount keeping the given points and tangents fixed.
 
290
Geom::Point adjust_circles( Geom::Circle &circle1, Geom::Circle &circle2, Geom::Point const &point1, Geom::Point const &point2, Geom::Point const &tan1, Geom::Point const &tan2 ) {
 
291
 
 
292
    Geom::Point n1 = (circle1.center() - point1).normalized(); // Always points towards center
 
293
    Geom::Point n2 = (circle2.center() - point2).normalized();
 
294
    Geom::Point sum_n = n1 + n2;
 
295
 
 
296
    double r1 = circle1.radius();
 
297
    double r2 = circle2.radius();
 
298
    double delta_r = r2 - r1;
 
299
    Geom::Point c1 = circle1.center();
 
300
    Geom::Point c2 = circle2.center();
 
301
    Geom::Point delta_c = c2 - c1;
 
302
 
 
303
    // std::cout << "adjust_circles:" << std::endl;
 
304
    // std::cout << "    norm: " << n1 << "; " << n2 << std::endl;
 
305
    // std::cout << "    sum_n: " << sum_n << std::endl;
 
306
    // std::cout << "    delta_r: " << delta_r << std::endl;
 
307
    // std::cout << "    delta_c: " << delta_c << std::endl;
 
308
 
 
309
    // Quadratic equation
 
310
    double A = 4 - sum_n.length() * sum_n.length();
 
311
    double B = 4.0 * delta_r - 2.0 * Geom::dot( delta_c, sum_n );
 
312
    double C = delta_r * delta_r - delta_c.length() * delta_c.length();
 
313
 
 
314
    double s1 = 0;
 
315
    double s2 = 0;
 
316
 
 
317
    if( fabs(A) < 0.01 ) {
 
318
        // std::cout << "    A near zero! $$$$$$$$$$$$$$$$$$" << std::endl;
 
319
        if( B != 0 ) {
 
320
            s1 = -C/B;
 
321
            s2 = -s1;
 
322
        }
 
323
    } else {
 
324
        s1 = (-B + sqrt(B*B - 4*A*C))/(2*A);
 
325
        s2 = (-B - sqrt(B*B - 4*A*C))/(2*A);
 
326
    }
 
327
 
 
328
    double dr = (fabs(s1)<=fabs(s2)?s1:s2);
 
329
 
 
330
    // std::cout << "    A: " << A << std::endl;
 
331
    // std::cout << "    B: " << B << std::endl;
 
332
    // std::cout << "    C: " << C << std::endl;
 
333
    // std::cout << "    s1: " << s1 << " s2: " << s2 << " dr: " << dr << std::endl;
 
334
 
 
335
    circle1 = Geom::Circle( c1 - dr*n1, r1-dr );
 
336
    circle2 = Geom::Circle( c2 + dr*n2, r2+dr );
 
337
 
 
338
    // std::cout << "    C1: " << circle1 << std::endl;
 
339
    // std::cout << "    C2: " << circle2 << std::endl;
 
340
    // std::cout << "    d': " << Geom::Point( circle1.center() - circle2.center() ).length() << std::endl;
 
341
 
 
342
    Geom::Line bisector( circle1.center(), circle2.center() );
 
343
    std::vector<Geom::ShapeIntersection> points = circle1.intersect( bisector );
 
344
    Geom::Point p0 = points[0].point();
 
345
    Geom::Point p1 = points[1].point();
 
346
    // std::cout << "    points: " << p0 << "; " << p1 << std::endl;
 
347
    if( abs( Geom::distance( p0, circle2.center() ) - circle2.radius() ) <
 
348
        abs( Geom::distance( p1, circle2.center() ) - circle2.radius() ) ) {
 
349
        return p0;
 
350
    } else {
 
351
        return p1;
 
352
    }
 
353
}
 
354
 
 
355
void extrapolate_join_internal(join_data jd, int alternative)
180
356
{
 
357
    // std::cout << "\nextrapolate_join: entrance: alternative: " << alternative << std::endl;
181
358
    using namespace Geom;
182
359
 
183
360
    Geom::Path &res = jd.res;
187
364
    Geom::Point endPt = outgoing.initialPoint();
188
365
    Geom::Point tang1 = jd.in_tang;
189
366
    Geom::Point tang2 = jd.out_tang;
 
367
    // width is half stroke-width
190
368
    double width = jd.width, miter = jd.miter;
191
369
 
192
 
    Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
193
 
    Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
 
370
    // std::cout << "  startPt: " << startPt << "  endPt: " << endPt << std::endl;
 
371
    // std::cout << "  tang1: " << tang1 << "  tang2: " << tang2 <<  std::endl;
 
372
    // std::cout << "    dot product: " << Geom::dot( tang1, tang2 ) <<  std::endl;
 
373
    // std::cout << "  width: " << width << std::endl;
 
374
 
 
375
    // CIRCLE CALCULATION TESTING
 
376
    Geom::Circle circle1 = touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
 
377
    Geom::Circle circle2 = touching_circle(outgoing.toSBasis(), 0);
 
378
    // std::cout << "  circle1: " << circle1 << std::endl;
 
379
    // std::cout << "  circle2: " << circle2 << std::endl;
 
380
    if( Geom::CubicBezier const * in_bezier = dynamic_cast<Geom::CubicBezier const*>(&incoming) ) {
 
381
        Geom::Circle circle_test1 = touching_circle(*in_bezier, false);
 
382
        if( !Geom::are_near( circle1, circle_test1, 0.01 ) ) {
 
383
            // std::cout << "  Circle 1 error!!!!!!!!!!!!!!!!!" << std::endl;
 
384
            // std::cout << "           " << circle_test1 << std::endl;
 
385
        }
 
386
    }
 
387
    if( Geom::CubicBezier const * out_bezier = dynamic_cast<Geom::CubicBezier const*>(&outgoing) ) {
 
388
        Geom::Circle circle_test2 = touching_circle(*out_bezier, true);
 
389
        if( !Geom::are_near( circle2, circle_test2, 0.01 ) ) {
 
390
            // std::cout << "  Circle 2 error!!!!!!!!!!!!!!!!!" << std::endl;
 
391
            // std::cout << "           " << circle_test2 << std::endl;
 
392
        }
 
393
    }
 
394
    // END TESTING
 
395
 
 
396
    Geom::Point center1 = circle1.center();
 
397
    Geom::Point center2 = circle2.center();
 
398
    double side1 = tang1[Geom::X]*(startPt[Geom::Y]-center1[Geom::Y]) - tang1[Geom::Y]*(startPt[Geom::X]-center1[Geom::X]);
 
399
    double side2 = tang2[Geom::X]*(  endPt[Geom::Y]-center2[Geom::Y]) - tang2[Geom::Y]*(  endPt[Geom::X]-center2[Geom::X]);
 
400
    // std::cout << "  side1: " << side1 << "  side2: " << side2 << std::endl;
194
401
 
195
402
    bool inc_ls = !circle1.center().isFinite();
196
403
    bool out_ls = !circle2.center().isFinite();
199
406
 
200
407
    Geom::EllipticalArc *arc1 = NULL;
201
408
    Geom::EllipticalArc *arc2 = NULL;
 
409
    Geom::LineSegment *seg1 = NULL;
 
410
    Geom::LineSegment *seg2 = NULL;
202
411
    Geom::Point sol;
203
412
    Geom::Point p1;
204
413
    Geom::Point p2;
205
414
 
206
415
    if (!inc_ls && !out_ls) {
 
416
        // std::cout << " two circles" << std::endl;
 
417
 
 
418
        // See if tangent is backwards (radius < width/2 and circle is inside stroke).
 
419
        Geom::Point node_on_path = startPt + Geom::rot90(tang1)*width;
 
420
        // std::cout << "  node_on_path: " << node_on_path << "  -------------- " << std::endl;
 
421
        bool b1 = false;
 
422
        bool b2 = false;
 
423
        if (circle1.radius() < width &&  distance( circle1.center(), node_on_path ) < width) {
 
424
            b1 = true;
 
425
        }
 
426
        if (circle2.radius() < width &&  distance( circle2.center(), node_on_path ) < width) {
 
427
            b2 = true;
 
428
        }
 
429
        // std::cout << "  b1: " << (b1?"true":"false")
 
430
        //           << "  b2: " << (b2?"true":"false") << std::endl;
 
431
 
207
432
        // Two circles
208
433
        points = circle1.intersect(circle2);
 
434
 
 
435
        if (points.size() != 2) {
 
436
            // std::cout << "   Circles do not intersect, do backup" << std::endl;
 
437
            switch (alternative) {
 
438
                case 1:
 
439
                {
 
440
                    // Fallback to round if one path has radius smaller than half line width.
 
441
                    if(b1 || b2) {
 
442
                        // std::cout << "At one least path has radius smaller than half line width." << std::endl;
 
443
                        return( round_join(jd) );
 
444
                    }
 
445
 
 
446
                    Point p;
 
447
                    if( circle2.contains( startPt ) && !circle1.contains( endPt ) ) {
 
448
                        // std::cout << "Expand circle1" << std::endl;
 
449
                        p = expand_circle( circle1, circle2, startPt, tang1 );
 
450
                        points.push_back( ShapeIntersection( 0, 0, p) );
 
451
                        points.push_back( ShapeIntersection( 0, 0, p) );
 
452
                    } else if( circle1.contains( endPt ) && !circle2.contains( startPt ) ) {
 
453
                        // std::cout << "Expand circle2" << std::endl;
 
454
                        p = expand_circle( circle2, circle1, endPt, tang2 );
 
455
                        points.push_back( ShapeIntersection( 0, 0, p) );
 
456
                        points.push_back( ShapeIntersection( 0, 0, p) );
 
457
                    } else {
 
458
                        // std::cout << "Either both points inside or both outside" << std::endl;
 
459
                        return( miter_clip_join(jd) );
 
460
                    }
 
461
                    break;
 
462
                    
 
463
                }
 
464
                case 2:
 
465
                {
 
466
                    // Fallback to round if one path has radius smaller than half line width.
 
467
                    if(b1 || b2) {
 
468
                        // std::cout << "At one least path has radius smaller than half line width." << std::endl;
 
469
                        return( round_join(jd) );
 
470
                    }
 
471
 
 
472
                    if( ( circle2.contains( startPt ) && !circle1.contains( endPt ) ) ||
 
473
                        ( circle1.contains( endPt ) && !circle2.contains( startPt ) ) ) {
 
474
                        
 
475
                        Geom::Point apex = adjust_circles( circle1, circle2, startPt, endPt, tang1, tang2 );
 
476
                        points.push_back( ShapeIntersection( 0, 0, apex) );
 
477
                        points.push_back( ShapeIntersection( 0, 0, apex) );
 
478
                    } else {
 
479
                        // std::cout << "Either both points inside or both outside" << std::endl;
 
480
                        return( miter_clip_join(jd) );
 
481
                    }
 
482
                        
 
483
                    break;
 
484
                }
 
485
                case 3:
 
486
                    if( side1 > 0 ) {
 
487
                        Geom::Line secant(startPt, startPt + tang1);
 
488
                        points = circle2.intersect(secant);
 
489
                        circle1.setRadius(std::numeric_limits<float>::infinity());
 
490
                        circle1.setCenter(Geom::Point(0,std::numeric_limits<float>::infinity()));
 
491
                    } else {
 
492
                        Geom::Line secant(endPt, endPt + tang2);
 
493
                        points = circle1.intersect(secant);
 
494
                        circle2.setRadius(std::numeric_limits<float>::infinity());
 
495
                        circle2.setCenter(Geom::Point(0,std::numeric_limits<float>::infinity()));
 
496
                    }
 
497
                    break;
 
498
 
 
499
 
 
500
                case 0:
 
501
                default:
 
502
                    // Do nothing
 
503
                    break;
 
504
            }
 
505
        }
 
506
 
209
507
        if (points.size() == 2) {
210
508
            sol = pick_solution(points, tang2, endPt);
211
 
            arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol);
212
 
            arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt);
 
509
            if( circle1.radius() != std::numeric_limits<float>::infinity() ) {
 
510
                arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol);
 
511
            } else {
 
512
                seg1 = new Geom::LineSegment(startPt, sol);
 
513
            }
 
514
            if( circle2.radius() != std::numeric_limits<float>::infinity() ) {
 
515
                arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt);
 
516
            } else {
 
517
                seg2 = new Geom::LineSegment(sol, endPt);
 
518
            }
213
519
        }
214
520
    } else if (inc_ls && !out_ls) {
215
521
        // Line and circle
 
522
        // std::cout << " line circle" << std::endl;
216
523
        points = circle2.intersect(Line(incoming.initialPoint(), incoming.finalPoint()));
217
524
        if (points.size() == 2) {
218
525
            sol = pick_solution(points, tang2, endPt);
220
527
        }
221
528
    } else if (!inc_ls && out_ls) {
222
529
        // Circle and line
 
530
        // std::cout << " circle line" << std::endl;
223
531
        points = circle1.intersect(Line(outgoing.initialPoint(), outgoing.finalPoint()));
224
532
        if (points.size() == 2) {
225
533
            sol = pick_solution(points, tang2, endPt);
226
534
            arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol);
227
535
        }
228
536
    }
229
 
 
230
 
    if (points.size() != 2)
 
537
    if (points.size() != 2) {
 
538
        // std::cout << " no solutions" << std::endl;
231
539
        // no solutions available, fall back to miter
232
 
        return miter_clip_join(jd);
 
540
        return miter_join(jd);
 
541
    }
233
542
 
234
543
    // We have a solution, thus sol is defined.
235
544
    p1 = sol;
250
559
    Geom::Line limit_line;
251
560
    double miter_limit = 2.0 * width * miter;
252
561
    bool clipped = false;
253
 
    
 
562
 
254
563
    if (are_parallel(bisector_chord, ortho)) {
255
564
        // No intersection (can happen if curvatures are equal but opposite)
256
565
        if (Geom::distance(point_on_path, sol) > miter_limit) {
257
566
            clipped = true;
258
 
            Geom::Point limit_point = point_on_path + miter_limit * bisector.versor(); 
 
567
            Geom::Point temp = bisector.versor();
 
568
            Geom::Point limit_point = point_on_path + miter_limit * temp; 
259
569
            limit_line = make_parallel_line( limit_point, ortho );
260
570
        }
261
571
    } else {
311
621
    // Add initial
312
622
    if (arc1) {
313
623
        res.append(*arc1);
 
624
    } else if (seg1 ) {
 
625
        res.append(*seg1);
314
626
    } else {
315
627
        // Straight line segment: move last point
316
628
        res.setFinal(p1);
324
636
    if (arc2) {
325
637
        res.append(*arc2);
326
638
        res.append(outgoing);
 
639
    } else if (seg2 ) {
 
640
        res.append(*seg2);
 
641
        res.append(outgoing);
327
642
    } else {
328
643
        // Straight line segment:
329
644
        res.appendNew<Geom::LineSegment>(outgoing.finalPoint());
334
649
 
335
650
    delete arc1;
336
651
    delete arc2;
 
652
    delete seg1;
 
653
    delete seg2;
337
654
}
338
655
 
 
656
void extrapolate_join(     join_data jd) { extrapolate_join_internal(jd, 0); }
 
657
void extrapolate_join_alt1(join_data jd) { extrapolate_join_internal(jd, 1); }
 
658
void extrapolate_join_alt2(join_data jd) { extrapolate_join_internal(jd, 2); }
 
659
void extrapolate_join_alt3(join_data jd) { extrapolate_join_internal(jd, 3); }
 
660
 
 
661
 
339
662
void join_inside(join_data jd)
340
663
{
341
664
    Geom::Path &res = jd.res;
716
1039
            case Inkscape::JOIN_EXTRAPOLATE:
717
1040
                jf = &extrapolate_join;
718
1041
                break;
 
1042
            case Inkscape::JOIN_EXTRAPOLATE1:
 
1043
                jf = &extrapolate_join_alt1;
 
1044
                break;
 
1045
            case Inkscape::JOIN_EXTRAPOLATE2:
 
1046
                jf = &extrapolate_join_alt2;
 
1047
                break;
 
1048
            case Inkscape::JOIN_EXTRAPOLATE3:
 
1049
                jf = &extrapolate_join_alt3;
 
1050
                break;
719
1051
            case Inkscape::JOIN_MITER_CLIP:
720
1052
                jf = &miter_clip_join;
721
1053
                break;