12

I'd like to compute the union of a collection of outlines in MetaPost. I'm aware of the buildcycle macro (in combination with cutbefore and cutafter). However, that macro is not very useful because I don't know the shapes I want to join in advance, so it's difficult to predict how to "build" the cycles.

To complicate matters, some parts of the paths are very thin, which causes problems with rounding.

I'm aware of this related question but ideally I need a MetaPost solution.

The following is a possible example. The paths were actually computed using MetaPost and the union was also computed with MetaPost. Still, the way it was done wasn't ideal. I'd like to have a more robust solution.

beginfig(0);
    % Some paths
    draw (12.47017,32.24423)..controls (6.40797,28.74423) and (2.43744,20.24191)
           ..(0,0.39084)..controls (0.86858,1.25941) and (1.73717,2.128)
           ..(2.60574,2.99658)..controls (5.04318,22.84766) and (9.59935,30.58676)
           ..(15.66154,34.08676)..controls (14.59775,33.47258) and (13.53397,32.85841)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (15.66154,34.08676)..controls (9.59935,30.58676) and (5.04318,22.84766)
           ..(2.60574,2.99658)..controls (2.73602,2.8663) and (2.8663,2.73602)
           ..(2.99658,2.60574)..controls (5.43402,22.45682) and (9.87572,30.1081)
           ..(15.93791,33.6081)..controls (15.8458,33.76765) and (15.75366,33.9272)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (12.74654,31.76556)..controls (6.68434,28.26556) and (2.82828,19.85107)
           ..(0.39084,0)..controls (1.25941,0.86858) and (2.128,1.73717)
           ..(2.99658,2.60574)..controls (5.43402,22.45682) and (9.87572,30.1081)
           ..(15.93791,33.6081)..controls (14.87411,32.99391) and (13.81033,32.37975)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (12.47017,32.24423)..controls (6.40797,28.74423) and (2.43744,20.24191)
           ..(0,0.39084)..controls (0.13028,0.26056) and (0.26056,0.13028)
           ..(0.39084,0)..controls (2.82828,19.85107) and (6.68434,28.26556)
           ..(12.74654,31.76556)..controls (12.65442,31.92513) and (12.56229,32.08467)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (2.60574,2.99658)..controls (3.14021,7.34944) and (3.7446,12.08865)
           ..(5.58054,15.14981)..controls (5.58057,15.14986) and (5.58061,15.14992)
           ..(5.58064,15.14996)..controls (6.39726,15.58105) and (7.34497,15.81947)
           ..(8.4495,15.81947)..controls (9.31807,16.68805) and (10.18666,17.55664)
           ..(11.05524,18.42522)..controls (9.19986,18.42522) and (7.78699,17.75247)
           ..(6.69463,16.62376)..controls (5.84612,15.74702) and (4.95805,14.90953)
           ..(4.10631,14.03595)..controls (1.36111,11.22037) and (0.63171,5.53574)
           ..(0,0.39084)..controls (0.86858,1.25941) and (1.73717,2.128)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (2.60574,2.99658)..controls (2.73602,2.8663) and (2.8663,2.73602)
           ..(2.99658,2.60574)..controls (3.87912,9.79335) and (4.95229,18.03438)
           ..(11.44608,18.03438)..controls (11.3158,18.16466) and (11.18552,18.29494)
           ..(11.05524,18.42522)..controls (4.56145,18.42522) and (3.48828,10.18419)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (2.99658,2.60574)..controls (3.53105,6.9586) and (4.13544,11.69781)
           ..(5.97137,14.75897)..controls (5.9714,14.75902) and (5.97145,14.75908)
           ..(5.97148,14.75912)..controls (6.7881,15.19022) and (7.73581,15.42863)
           ..(8.84033,15.42863)..controls (9.70891,16.29721) and (10.5775,17.1658)
           ..(11.44608,18.03438)..controls (9.5907,18.03438) and (8.17783,17.36163)
           ..(7.08546,16.23293)..controls (6.23695,15.35619) and (5.34889,14.51869)
           ..(4.49715,13.64511)..controls (1.75195,10.82953) and (1.02255,5.1449)
           ..(0.39084,0)..controls (1.25941,0.86858) and (2.128,1.73717)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (0,0.39084)..controls (0.13028,0.26056) and (0.26056,0.13028)
           ..(0.39084,0)..controls (1.27338,7.1876) and (2.34654,15.42863)
           ..(8.84033,15.42863)..controls (8.71005,15.55891) and (8.57977,15.6892)
           ..(8.4495,15.81947)..controls (1.9557,15.81947) and (0.88254,7.57845)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (11.05524,18.42522)..controls (10.18666,17.55664) and (9.31807,16.68805)
           ..(8.4495,15.81947)..controls (14.4495,15.81947) and (12.27396,10.31638)
           ..(11.05524,0.39084)..controls (11.92381,1.25941) and (12.7924,2.128)
           ..(13.66098,2.99658)..controls (14.8797,12.92212) and (17.05524,18.42522)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (11.44608,18.03438)..controls (12.74173,18.03438) and (13.65614,17.77776)
           ..(14.2813,17.2754)..controls (14.28131,17.2754) and (14.28131,17.2754)
           ..(14.28133,17.2754)..controls (15.96465,15.1815) and (14.55524,10.27959)
           ..(13.66098,2.99658)..controls (13.79126,2.8663) and (13.92154,2.73602)
           ..(14.05182,2.60574)..controls (14.90062,9.5186) and (16.21355,14.28624)
           ..(14.90535,16.5436)..controls (14.57936,17.10611) and (14.11217,17.57391)
           ..(13.54927,17.89926)..controls (12.94624,18.2478) and (12.13252,18.42522)
           ..(11.05524,18.42522)..controls (11.18552,18.29494) and (11.3158,18.16466)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (11.44608,18.03438)..controls (10.5775,17.1658) and (9.70891,16.29721)
           ..(8.84033,15.42863)..controls (14.84033,15.42863) and (12.6648,9.92554)
           ..(11.44608,0)..controls (12.31465,0.86858) and (13.18324,1.73717)
           ..(14.05182,2.60574)..controls (15.27054,12.53128) and (17.44608,18.03438)
           ..cycle withpen pencircle scaled 0.2pt;

    draw (8.84033,15.42863)..controls (10.13599,15.42863) and (11.0504,15.17201)
           ..(11.67555,14.66966)..controls (11.67557,14.66966) and (11.67557,14.66966)
           ..(11.67558,14.66966)..controls (13.3589,12.57576) and (11.9495,7.67384)
           ..(11.05524,0.39084)..controls (11.18552,0.26056) and (11.3158,0.13028)
           ..(11.44608,0)..controls (12.29488,6.91286) and (13.6078,11.6805)
           ..(12.2996,13.93785)..controls (11.97362,14.50037) and (11.50642,14.96817)
           ..(10.94353,15.29352)..controls (10.3405,15.64206) and (9.52678,15.81947)
           ..(8.4495,15.81947)..controls (8.57977,15.6892) and (8.71005,15.55891)
           ..cycle withpen pencircle scaled 0.2pt;

    % The union
    draw (8.84033,15.42863)..controls (10.13599,15.42863) and (11.0504,15.17201)
           ..(11.67555,14.66966)..controls (13.35896,12.57596) and (11.94951,7.674)
           ..(11.05524,0.39084)..controls (11.18552,0.26056) and (11.3158,0.13028)
           ..(11.44608,0)..controls (12.31465,0.86858) and (13.18324,1.73717)
           ..(14.05182,2.60574)..controls (14.90062,9.51855) and (16.21353,14.2862)
           ..(14.90535,16.5436)..controls (14.58578,17.09502) and (14.13054,17.55544)
           ..(13.58244,17.87985)..controls (13.00317,18.2351) and (12.17043,18.42522)
           ..(11.05524,18.42522)..controls (9.19986,18.42522) and (7.78699,17.75247)
           ..(6.69463,16.62376)..controls (6.18193,16.09401) and (5.6548,15.57858)
           ..(5.12996,15.06087)..controls (7.69498,25.93929) and (11.35297,30.96098)
           ..(15.93791,33.6081)..controls (15.8458,33.76765) and (15.75366,33.9272)
           ..(15.66154,34.08676)..controls (14.59775,33.47258) and (13.53397,32.85841)
           ..(12.47017,32.24423)..controls (6.80194,28.97168) and (2.96234,21.32587)
           ..(0.49504,4.12018)..controls (0.30708,2.87721) and (0.15076,1.61865)
           ..(0,0.39084)..controls (0.13028,0.26056) and (0.26056,0.13028)
           ..(0.39084,0)..controls (1.25941,0.86858) and (2.128,1.73717)
           ..(2.99658,2.60574)..controls (3.19746,4.24173) and (3.41196,5.79485)
           ..(3.63985,7.2692)..controls (4.11122,10.09549) and (4.78354,12.77844)
           ..(5.97137,14.75897)..controls (6.78725,15.19) and (7.7353,15.42863)
           ..cycle withcolor red withpen pencircle scaled 0.1pt;
endfig;
end;

example of paths and their union

FWIW: If you're wondering, I'm making a calligraphic font, which I'm hoping to showcase for the TUG calendar, 2015. The font is based on my handwriting. The h above is a crude approximation:-)

4
  • 1
    Could you give a couple of examples?
    – egreg
    Commented Jul 22, 2014 at 11:50
  • @egreg I added one example as I only have one.
    – user10274
    Commented Jul 22, 2014 at 12:30
  • Could you draw the letters with a suitably slanted pen? Or some of the tricks described in The Metafont Book Ch.16 "Calligraphic effects"?
    – Thruston
    Commented Jul 22, 2014 at 22:52
  • 1
    @Thruston Nope. The pen slants at the end points of the ascender are not the same (30 degrees at the top and 45 degrees at the bottom). Had they been the same, I could have used a special pen shape. I don't have the metafont book, but I'm using my own version of a penpos command that defines the pen slant at a given position. The lack of built-in MetaPost support for path unions is disappointing as it's something that is almost always needed.
    – user10274
    Commented Jul 23, 2014 at 8:58

1 Answer 1

8

Here's an answer based on the idea in my comment of last year; while it does not directly answer your general question about a union of paths, it does show that MP can get close to drawing your characters directly.

And note that penpos certainly does allow you to vary the slant of the pen as the stroke moves, indeed that's the whole point of it. Here's an effort at drafting your h character. The only non-plain thing I've added is to make a version of penstroke that does a filldraw instead of a fill.

enter image description here

prologues := 3;
outputtemplate := "%j%c.eps";

def tt_penstroke text t =
 forsuffixes e = l,r: path_.e:=t; endfor
 filldraw path_.l -- reverse path_.r -- cycle enddef;
path path_.l,path_.r;

beginfig(1);
u = cm;
w = 3u;
h = 7u;

y1 = h; y2 = y4 = 0;
x1 = x4 = .9 w; x2 = 0;
x3 = .7w; y3 = .52h;

pair s, t; s = dir 264; t = dir 220;

penpos1(5mm,30);
penpos2(5mm,45);
penpos3(5mm,30);
penpos4(5mm,45);

pickup pensquare rotated 45 scaled 2;
tt_penstroke z1e{t} ..{s}z2e;
tt_penstroke z2e{-s} .. z3e{right} .. {s}z4e; 

endfig;
end.
1
  • Thanks. This is "similar" to how I created the outlines, except that I didn't use penpos. My question is about getting the outlines:-) Also note that there's an ugly dip in the shoulder of your h, which I've managed to avoid. With a "naive" penpos solution you can't avoid impediments like this.
    – user10274
    Commented Apr 10, 2015 at 9:46

This site is temporarily in read-only mode and not accepting new answers.