X-Received: by 2002:a0c:9608:: with SMTP id 8mr47749821qvx.98.1563781664903; Mon, 22 Jul 2019 00:47:44 -0700 (PDT) X-Received: by 2002:a37:98c3:: with SMTP id a186mr46151090qke.498.1563781664698; Mon, 22 Jul 2019 00:47:44 -0700 (PDT) Path: csiph.com!xmission!news.snarked.org!border2.nntp.dca1.giganews.com!nntp.giganews.com!b26no1233581qtq.0!news-out.google.com!e17ni1055qtg.1!nntp.google.com!b26no1233579qtq.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.postscript Date: Mon, 22 Jul 2019 00:47:44 -0700 (PDT) In-Reply-To: <5661daa6-058f-4f70-97e8-af7b0568cfc9@googlegroups.com> Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=24.107.176.41; posting-account=G1KGwgkAAAAyw4z0LxHH0fja6wAbo7Cz NNTP-Posting-Host: 24.107.176.41 References: <5661daa6-058f-4f70-97e8-af7b0568cfc9@googlegroups.com> User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <9b8a3d34-e793-4f5c-bbb6-3509e7a20cd8@googlegroups.com> Subject: Re: Snipping the ears From: luser droog Injection-Date: Mon, 22 Jul 2019 07:47:44 +0000 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Lines: 264 Xref: csiph.com comp.lang.postscript:3428 On Saturday, July 20, 2019 at 6:51:02 PM UTC-5, luser droog wrote: > On Saturday, July 20, 2019 at 3:18:58 PM UTC-5, luser droog wrote: > > After 27 posts in the other thread, I thought it'd be nice to > > have a fresher start on the remaining issues with my code. > >=20 > > The task is to take the glyph of the number 9 using 'charpath', > > then traverse the curves like a turtlw with a paintbrush hanging > > out one arm's-length away.=20 > >=20 > > The tricky part would be dealing with the actual Bezier curves, > > so I call 'flattenpath' first so I can work with just line=20 > > segments. The 'setflat' operator can be used to control how > > finely the curves are cut into line segments. > >=20 > > (Or maybe, the curves true secret path to the desired result??) > >=20 > > Anyway, to traverse the line segments I use a control structure > > I cooked up, called 'fortuplem'. It works kind of like 'forall', > > but it takes 2 parameters n and m. n is the step-value between > > iterations, and m is the width of a slice of the array produce > > using 'getinterval'. Calling with n=3D2 m=3D2 iterates over the > > points in the line. Calling with n=3D2 m=3D4 iterates over 2 point > > slices. So I can run through these 2 points slices, get a vector > > between them, normalize, take the perpendicular vector, scale > > by my "arm's length" and produce a new transformed point. > > This just needs one special case for the wrap around the end > > from the last point to the first. > >=20 > >=20 > > So, this all *works* with the untidy caveat that it produces > > "ears" when the input path has a tight bend in the curve. > >=20 > > Detecting and pruning these ears would make the output nicer > > and more usable. A further nicety would be implementing miter > > or bevel joins for the other side of the tight bends. > >=20 > >=20 > > Any, here's the current state of the code, including the laborious > > fixes for the 2 "hacks" described at the end of the last thread. > >=20 >=20 > I've said this before, but I think I can detect the ears now. > I take the vector out of each point, take the angle, take the > diff between adjacent angles, then take the signs of that angular > change. >=20 > If I've reasoned correctly, this gives me a chart of left turns vs. > right turns for each point. Running it on the left hand offset curve > (-n offsetpath) gives me this: >=20 [snip]>=20 > And I see a lonely "1* -1 1*" in the first curve, and a "-1* 1 -1*" in th= e second, > which makes sense considering that the two curves are deliberately descri= bed > in differing orientations to take advantage of the even/odd rule.=20 >=20 > Running it one the right hand curve (+n offsetpath) gives me this: >=20 [snip]>=20 > Which shows no ears on the inner curve, but several spots of weirdness in > the outer curve. There's an interesting "-1* 1 1 1 -1*" which looks like = the > bunched up points on the foot the '9'.=20 >=20 > And two little wiggles "1* -1 1 -1 1 -1*" and "1* -1 1 -1*" which I don't > know what those are.=20 >=20 > So, now to try actually snipping. I'll tackly the simple ones first I thi= nk. > "-1* 1 -1*" and "1* -1 1*" patterns. I think I need the incoming and outg= oing vectors and then take their intersection as they approach their > points. >=20 > I'm not sure what to do with the fat ear and the ripples. Sigh. It's turning into the same rats' nest as before. So, let's start over= . This fresh program does not do any offsetting yet. It also preserves curves= . Just dumping the numbers for now to get a sense of what's going on in there= . A few 'linetos' here and there but lots of 'curvetos' (the 6 element subarr= ays). So, the question changes. Can we detect sharp turns in the curveto operands= ? And then do something sensible to produce an offset for that portion? Wikipedia has some info: https://en.wikipedia.org/wiki/Parallel_curve $ cat stroke3.ps %! /args-begin { dup length dict begin { exch def } forall } def /map { [ 3 1 roll forall ] } def /spill { aload pop } def /head { 0 exch getinterval } def /tail { 1 index length 1 index sub getinterval } def /last { 1 index length 1 index sub exch getinterval } def /droplast { 1 index length exch sub 0 exch getinterval } def /fortuplem { {p m n a} args-begin 0 n /a load length m sub [ /a load /exch cvx m /getinterval cvx /p load /exec cvx ] cvx end for } def /p-p { exch 3 1 roll sub 3 1 roll sub exch } def /p+v { exch 3 1 roll add 3 1 roll add exch } def /v*n { 3 2 roll 1 index mul 3 1 roll mul } def /perp { neg exch } def /mag { dup mul exch dup mul exch add sqrt } def /norm { 2 copy mag 1 exch div v*n } def /ang { exch atan } def /aa { array astore } def /closedsubpaths { [ {[ 3 1 roll 2 aa} {2 aa} {6 aa} {]} pathforall ] {{]}st= opped{exit}if}loop } def /drawpath { { dup length 1 eq { spill spill moveto }{ dup 1 head spill spill moveto 1 tail { dup length 2 eq { spill lineto }{ spill curveto } ifelse } = forall closepath } ifelse } forall } def /offsetbyvectors { /n exch def { dup length 2 ne { offsetsubpath } if } map } def /offsetpath { closedsubpaths exch pop dup =3D=3D%offsetbyvectors newpath drawpath } def /Calibri-Bold 600 selectfont 100 100 moveto (9) true charpath gsave stroke grestore gsave 20 setlinewidth strokepath 1 setlinewidth %stroke grestore 1 0 0 setrgbcolor gsave 10 offsetpath stroke grestore -10 offsetpath stroke showpage quit Output: $ gsnd -q stroke3.ps [[[380.375 306.421875] [380.25 290.875 379.59375 275.078125 378.03125 258.6= 09375] [376.457031 241.9375 373.492188 226.007813 369.109375 210.21875] [36= 4.695313 194.351563 358.691406 179.414063 350.984375 165.1875] [342.957031 = 150.90625 333.347656 138.546875 321.171875 127.921875] [308.9375 116.988281= 294.179688 108.863281 276.734375 102.625] [259.039063 96.1875 238.675781 9= 3.28125 214.90625 93.28125] [206.21875 93.1875 198.1875 93.8671875 189.9062= 5 95.03125] [181.320313 96.1875 174.066406 97.6640625 167.234375 99.421875]= [160.332031 101.03125 154.613281 103.019531 149.84375 104.96875] [144.7890= 63 106.59375 141.613281 108.910156 139.46875 110.953125] [137.164063 112.68= 75 135.765625 115.976563 134.796875 119.875] [133.5625 123.488281 133.34375= 129.238281 133.34375 136.25] [133.226563 142.601563 133.484375 147.851563 = 133.765625 151.75] [133.800781 155.394531 134.640625 158.660156 135.515625 = 160.796875] [136.226563 162.675781 137.472656 164.359375 138.734375 165.046= 875] [139.757813 165.71875 141.515625 166.078125 143.265625 166.078125] [14= 5.519531 166.050781 148.921875 165.394531 153.203125 164.03125] [157.425781= 162.65625 162.707031 161.101563 168.84375 159.34375] [174.707031 157.47656= 3 181.957031 156.035156 189.75 154.671875] [197.289063 153.082031 206.21875= 152.625 215.78125 152.625] [231.882813 152.414063 245.976563 155.546875 25= 7.28125 161.390625] [268.5 167.113281 277.753906 175.140625 284.765625 185.= 078125] [291.53125 195.0 296.953125 206.523438 300.265625 219.578125] [303.= 5 232.4375 305.441406 246.375 305.828125 260.8125] [296.582031 254.882813 2= 86.035156 250.226563 273.359375 246.03125] [260.570313 241.832031 246.17578= 1 239.75 229.8125 239.75] [209.46875 239.5 192.679688 242.378906 178.640625= 247.640625] [164.394531 252.6875 153.207031 260.5 144.4375 270.4375] [135.= 519531 280.238281 129.28125 292.472656 125.28125 306.703125] [121.195313 32= 0.695313 119.296875 337.007813 119.296875 354.9375] [119.195313 373.53125 1= 22.117188 391.238281 127.765625 407.125] [133.164063 422.96875 141.804688 4= 36.75 152.921875 448.34375] [163.726563 459.820313 177.875 468.953125 194.4= 375 475.390625] [210.851563 481.695313 230.195313 485.046875 252.03125 485.= 046875] [269.5625 485.03125 284.921875 482.992188 298.078125 478.890625] [3= 11.207031 474.5 322.535156 468.945313 331.984375 461.34375] [341.113281 453= .632813 349.335938 444.546875 355.671875 433.734375] [361.78125 422.675781 = 366.972656 410.882813 370.578125 397.625] [373.988281 384.164063 376.710938= 370.046875 378.171875 354.640625] [379.582031 339.03125 380.375 323.171875= 380.375 306.421875]] [[304.078125 316.9375] [304.050781 337.476563 302.906= 25 355.234375 300.5625 369.265625] [298.039063 383.207031 294.722656 394.5 = 290.046875 402.875] [285.351563 410.96875 279.519531 417.207031 272.5 420.7= 1875] [265.3125 423.988281 257.289063 425.984375 247.9375 425.984375] [238.= 457031 425.65625 230.875 424.375 224.25 421.15625] [217.539063 417.894531 2= 12.117188 413.414063 207.734375 407.5625] [203.113281 401.53125 200.09375 3= 94.796875 197.9375 386.796875] [195.476563 378.539063 194.71875 370.035156 = 194.71875 360.484375] [194.476563 350.0 195.644531 341.050781 197.5 333.156= 25] [199.1875 325.21875 202.273438 318.742188 206.265625 313.578125] [210.1= 75781 308.21875 215.476563 304.5625 221.90625 302.03125] [228.039063 299.48= 8281 236.144531 298.234375 245.3125 298.234375] [256.5 298.15625 267.269531= 299.9375 277.3125 303.34375] [287.25 306.632813 296.273438 311.28125 304.0= 78125 316.9375]] [[404.101563 100.0]]] [[[380.375 306.421875] [380.25 290.875 379.59375 275.078125 378.03125 258.6= 09375] [376.457031 241.9375 373.492188 226.007813 369.109375 210.21875] [36= 4.695313 194.351563 358.691406 179.414063 350.984375 165.1875] [342.957031 = 150.90625 333.347656 138.546875 321.171875 127.921875] [308.9375 116.988281= 294.179688 108.863281 276.734375 102.625] [259.039063 96.1875 238.675781 9= 3.28125 214.90625 93.28125] [206.21875 93.1875 198.1875 93.8671875 189.9062= 5 95.03125] [181.320313 96.1875 174.066406 97.6640625 167.234375 99.421875]= [160.332031 101.03125 154.613281 103.019531 149.84375 104.96875] [144.7890= 63 106.59375 141.613281 108.910156 139.46875 110.953125] [137.164063 112.68= 75 135.765625 115.976563 134.796875 119.875] [133.5625 123.488281 133.34375= 129.238281 133.34375 136.25] [133.226563 142.601563 133.484375 147.851563 = 133.765625 151.75] [133.800781 155.394531 134.640625 158.660156 135.515625 = 160.796875] [136.226563 162.675781 137.472656 164.359375 138.734375 165.046= 875] [139.757813 165.71875 141.515625 166.078125 143.265625 166.078125] [14= 5.519531 166.050781 148.921875 165.394531 153.203125 164.03125] [157.425781= 162.65625 162.707031 161.101563 168.84375 159.34375] [174.707031 157.47656= 3 181.957031 156.035156 189.75 154.671875] [197.289063 153.082031 206.21875= 152.625 215.78125 152.625] [231.882813 152.414063 245.976563 155.546875 25= 7.28125 161.390625] [268.5 167.113281 277.753906 175.140625 284.765625 185.= 078125] [291.53125 195.0 296.953125 206.523438 300.265625 219.578125] [303.= 5 232.4375 305.441406 246.375 305.828125 260.8125] [296.582031 254.882813 2= 86.035156 250.226563 273.359375 246.03125] [260.570313 241.832031 246.17578= 1 239.75 229.8125 239.75] [209.46875 239.5 192.679688 242.378906 178.640625= 247.640625] [164.394531 252.6875 153.207031 260.5 144.4375 270.4375] [135.= 519531 280.238281 129.28125 292.472656 125.28125 306.703125] [121.195313 32= 0.695313 119.296875 337.007813 119.296875 354.9375] [119.195313 373.53125 1= 22.117188 391.238281 127.765625 407.125] [133.164063 422.96875 141.804688 4= 36.75 152.921875 448.34375] [163.726563 459.820313 177.875 468.953125 194.4= 375 475.390625] [210.851563 481.695313 230.195313 485.046875 252.03125 485.= 046875] [269.5625 485.03125 284.921875 482.992188 298.078125 478.890625] [3= 11.207031 474.5 322.535156 468.945313 331.984375 461.34375] [341.113281 453= .632813 349.335938 444.546875 355.671875 433.734375] [361.78125 422.675781 = 366.972656 410.882813 370.578125 397.625] [373.988281 384.164063 376.710938= 370.046875 378.171875 354.640625] [379.582031 339.03125 380.375 323.171875= 380.375 306.421875]] [[304.078125 316.9375] [304.050781 337.476563 302.906= 25 355.234375 300.5625 369.265625] [298.039063 383.207031 294.722656 394.5 = 290.046875 402.875] [285.351563 410.96875 279.519531 417.207031 272.5 420.7= 1875] [265.3125 423.988281 257.289063 425.984375 247.9375 425.984375] [238.= 457031 425.65625 230.875 424.375 224.25 421.15625] [217.539063 417.894531 2= 12.117188 413.414063 207.734375 407.5625] [203.113281 401.53125 200.09375 3= 94.796875 197.9375 386.796875] [195.476563 378.539063 194.71875 370.035156 = 194.71875 360.484375] [194.476563 350.0 195.644531 341.050781 197.5 333.156= 25] [199.1875 325.21875 202.273438 318.742188 206.265625 313.578125] [210.1= 75781 308.21875 215.476563 304.5625 221.90625 302.03125] [228.039063 299.48= 8281 236.144531 298.234375 245.3125 298.234375] [256.5 298.15625 267.269531= 299.9375 277.3125 303.34375] [287.25 306.632813 296.273438 311.28125 304.0= 78125 316.9375]] [[404.101563 100.0]]]