Here's some progress. The image is an inner curve 7 points in. All the
control points on the original curve are drawn with dots. And it produces
some text output which shows
[original line or curve point(s)]
length
angle
(angle out)
(angle out - angle in)
[new (inner) line or curve]
length
angle
(angle out)
(angle change)
I tweaked the formula for angular change, and it seems ok now.
Now, I'm just staring at the numbers to see if I can find that
nasty corner, and hopefully other similar corners more generally.
Then, to figure out how to snip it nicely...
Text Output:
$ gs
stroke7.ps
GPL Ghostscript 9.27 (2019-04-04)
Copyright (C) 2018 Artifex Software, Inc. All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
Querying operating system for font files...
Can't find (or can't open) font file /usr/share/ghostscript/9.27/Resource/Font/Calibri-Bold.
Can't find (or can't open) font file Calibri-Bold.
Loading Calibri-Bold font from /usr/share/fonts/microsoft/calibrib.ttf... 4678648 3034560 9299916 7891942 1 done.
[374.530243 302.102081]
0.0
270.0
[366.530243 302.109528]
0.0
270.0
[374.500824 286.917053 373.765564 271.421753 372.236176 255.297028]
46.8781166
269.889
264.581848
-5.30715942
[366.500854 286.932556 365.801514 272.179199 364.272125 256.054474]
46.1354637
269.889
264.581848
-5.30715942
[370.692078 239.106125 367.800934 223.379929 363.506897 207.921387]
48.2356453
264.552277
254.475891
-10.0763855
[362.728027 239.863571 360.09903 225.543411 355.805 210.084869]
46.80653
264.552277
254.475891
-10.0763855
[359.092285 192.377533 353.295319 177.766022 345.754272 163.833908]
47.6239052
254.144913
241.574615
-12.5702972
[351.390381 194.541016 346.266205 181.585892 338.725159 167.653778]
45.8383713
254.144913
241.574615
-12.5702972
[338.11618 149.834152 328.483978 137.737305 316.554779 127.334549]
46.9916382
241.383667
221.089783
-20.2938843
[331.087067 153.654022 323.218842 143.760437 311.289642 133.357681]
44.1787376
241.383667
221.089783
-20.2938843
[304.599121 116.858261 290.125824 108.681931 273.043762 102.576157]
50.3612518
221.226852
199.668808
-21.5580444
[299.333984 122.881401 287.41806 116.209747 270.336 110.103973]
47.4055
221.226852
199.668808
-21.5580444
[255.882309 96.3645 235.785599 93.4174881 212.503647 93.4174881]
61.5353737
199.897919
180.0
-19.8979187
[253.174545 103.892319 235.769211 101.417473 212.487259 101.417473]
58.8120461
199.897919
180.0
-19.8979187
[204.193497 93.3527832 196.140701 93.9910126 188.027603 95.1351089]
24.5589523
180.446106
171.973175
-8.47293091
[204.177109 101.352768 197.246796 101.914177 189.133698 103.058273]
23.4344864
180.446106
171.973175
-8.47293091
[179.813049 96.2703857 172.522 97.7115326 165.839752 99.4291534]
22.6118946
172.131393
165.584641
-6.54675293
[180.919144 104.19355 174.465073 105.471977 167.782822 107.189598]
21.7595253
172.131393
165.584641
-6.54675293
[159.048706 101.085007 153.48262 102.958504 148.804764 104.864349]
17.8974018
166.297012
157.833099
-8.46391296
[160.991776 108.845451 156.403641 110.406166 151.725784 112.312012]
16.8712521
166.297012
157.833099
-8.46391296
[144.048965 106.65844 140.741669 108.730461 138.640228 110.734833]
11.8126049
159.331375
136.354324
-22.9770508
[146.969986 114.106102 146.16127 114.615013 144.05983 116.619385]
8.88110638
159.331375
136.354324
-22.9770508
[136.460861 112.673035 135.016769 115.647987 134.063843 119.464096]
10.0036058
138.351974
104.020691
-34.3312836
[141.880463 118.557587 142.757706 117.667374 141.804779 121.483482]
5.57857656
138.351974
104.020691
-34.3312836
[133.049149 123.190498 132.63446 128.622757 132.63446 135.493225]
16.1340561
105.232254
90.0
-15.232254
[140.790085 125.209885 140.634293 128.675613 140.634293 135.546082]
14.155632
105.232254
90.0
-15.232254
[132.547699 141.754883 132.7771 146.847443 133.063858 150.663559]
15.1813326
90.7938385
85.7026367
-5.09120178
[140.547531 141.807739 140.761749 146.352173 141.048508 150.168289]
14.6331158
90.7938385
85.7026367
-5.09120178
[133.246216 154.410553 133.922668 157.441376 134.781479 159.539871]
9.08163
87.2137451
67.7431412
-19.4706039
[141.230865 153.915283 141.353363 154.477463 142.212173 156.575958]
6.56146193
87.2137451
67.7431412
-19.4706039
[135.590286 161.622192 136.688797 163.025101 137.928482 163.692734]
5.31567192
68.7730179
28.3047085
-40.4683075
[143.020981 158.658279 140.542328 156.014374 141.782013 156.682]
2.48282027
68.7730179
28.3047085
-40.4683075
[139.072571 164.335373 140.646088 164.692719 142.363693 164.692719]
4.59395552
29.3230934
0.0
-29.3230934
[142.926102 157.324646 140.431396 156.695602 142.149 156.695602]
1.69659424
29.3230934
0.0
-29.3230934
[144.590134 164.586838 147.90184 164.023621 152.098816 162.686874]
9.96525478
357.277283
342.333191
-14.9440918
[144.375443 156.589722 145.410614 156.421402 149.60759 155.084656]
7.65997934
357.277283
342.333191
-14.9440918
[156.248749 161.288361 161.401596 159.828094 167.410324 158.110489]
15.9821692
341.376343
344.047333
2.67099
[153.757523 153.686142 159.174896 152.144226 165.183624 150.42662]
16.2589684
341.376343
344.047333
2.67099
[173.413162 156.347275 180.245392 154.864944 187.880554 153.528214]
20.9876537
343.63089
350.06955
6.43865967
[171.186462 148.663406 178.85051 146.987488 186.485672 145.650757]
21.8413944
343.63089
350.06955
6.43865967
[195.459839 152.170883 204.009689 151.528244 213.362457 151.528244]
25.5931606
349.846863
0.0
10.1531372
[194.064957 144.293427 203.974915 143.52832 213.327682 143.52832]
26.9577065
349.846863
0.0
10.1531372
[229.376892 151.417953 242.94136 154.389954 254.00882 160.116333]
41.9528
359.605408
27.3573551
27.7519531
[229.342117 143.41803 246.596436 147.273743 257.663879 153.000122]
45.7254677
359.605408
27.3573551
27.7519531
[265.067444 165.754471 274.049652 173.570511 280.920105 183.304153]
35.8796844
27.0143433
54.7838
27.769455
[268.722504 158.63826 280.593048 168.967911 287.463501 178.701553]
39.6876183
27.0143433
54.7838
27.769455
[287.717041 193.001053 292.846375 204.294968 296.090424 217.080048]
37.2313118
54.9718819
75.762413
20.7905312
[294.260437 188.398453 300.608398 202.358261 303.852448 215.143341]
40.1534
54.9718819
75.762413
20.7905312
[299.227142 229.868057 301.150635 243.322235 301.531525 257.444061]
40.8069153
76.2182465
88.4550095
12.236763
[306.989166 227.931351 306.847 248.939316 307.227875 263.061157]
48.1180305
76.2182465
88.4550095
12.236763
[292.709595 251.882385 282.158325 247.092758 269.755585 242.991364]
34.993576
212.228867
198.298248
-13.9306183
[298.405945 257.499481 279.628632 254.682266 267.225891 250.580872]
42.0174217
212.228867
198.298248
-13.9306183
[257.235229 238.785553 243.134 236.838516 227.103394 236.838516]
43.2831955
198.568115
180.0
-18.5681152
[254.705536 246.375061 243.120193 244.838501 227.089584 244.838501]
40.741478
198.568115
180.0
-18.5681152
[207.369919 236.776764 190.748154 239.412 177.004272 244.56192]
50.9645348
180.179291
159.45871
-20.7205811
[207.35611 244.776749 193.55 246.905304 179.806122 252.055237]
48.1140137
180.179291
159.45871
-20.7205811
[163.194214 249.714767 152.098816 257.157288 143.510742 266.89093]
40.669857
159.538315
131.422226
-28.1160889
[165.996063 257.208069 158.081436 262.468445 149.493362 272.202087]
36.8386078
159.538315
131.422226
-28.1160889
[134.849121 276.58783 128.671295 288.461151 124.758125 302.39032]
40.5021286
131.772385
105.691833
-26.0805511
[140.831741 281.899 136.364914 290.653931 132.451752 304.583099]
36.965847
131.772385
105.691833
-26.0805511
[120.752312 316.245972 118.893517 332.067749 118.893517 349.624786]
47.7526741
106.125137
90.0
-16.1251373
[128.445938 318.438751 126.893517 332.072968 126.893517 349.63]
45.5485268
106.125137
90.0
-16.1251373
[118.869987 368.124481 121.659645 385.165344 127.193375 400.718018]
52.0193253
90.072876
70.4141541
-19.6587219
[126.869987 368.1297 129.196487 382.482819 134.730225 398.035492]
49.3005562
90.072876
70.4141541
-19.6587219
[132.696213 416.173645 140.931366 429.730743 151.810593 441.087921]
47.6400299
70.4021835
46.2313309
-24.1708527
[140.233063 413.491119 146.718033 424.206757 157.59726 435.563934]
44.3188629
70.4021835
46.2313309
-24.1708527
[162.610397 452.440643 176.236633 461.269897 192.45694 467.563904]
48.9071388
46.4297829
21.2078724
-25.2219105
[168.397064 446.916656 179.128 453.810669 195.348312 460.104675]
45.4430084
46.4297829
21.2078724
-25.2219105
[208.605194 473.816742 227.481339 477.010803 248.861847 477.010803]
57.5152283
21.1671257
0.0
-21.1671257
[211.496567 466.357513 227.469421 469.010803 248.84993 469.010803]
54.5728455
21.1671257
0.0
-21.1671257
[265.980652 476.953461 281.061279 475.006439 293.94342 470.999146]
45.6468887
359.808075
342.720459
-17.087616
[265.96875 468.953461 278.666473 467.373291 291.548615 463.366]
43.241848
359.808075
342.720459
-17.087616
[306.803467 466.930115 317.893 461.265503 327.148712 453.822968]
37.6011848
342.442169
321.197144
-21.2450256
[304.408661 459.296967 312.850464 455.05481 322.106171 447.612274]
34.6070518
342.442169
321.197144
-21.2450256
[336.360321 446.271637 344.136658 437.361511 350.336548 426.770508]
35.8204536
320.656403
300.34436
-20.3120422
[331.31778 440.060944 337.216156 433.348175 343.416046 422.757172]
32.9398384
320.656403
300.34436
-20.3120422
[356.418793 416.182465 361.406952 404.397369 364.936279 391.418182]
38.3531647
299.874969
285.212158
-14.6628113
[349.498291 412.169128 353.680267 402.324127 357.209595 389.34494]
36.2558594
299.874969
285.212158
-14.6628113
[368.374481 378.430176 370.950897 364.414246 372.383209 349.336578]
42.783493
284.827301
275.426575
-9.40072632
[360.647797 376.356934 362.985 363.676361 364.417297 348.598694]
41.4277954
284.827301
275.426575
-9.40072632
[373.747894 334.219177 374.530243 318.51358 374.530243 302.102081]
47.2993202
275.158264
270.0
-5.15826416
[365.781982 333.481293 366.530243 318.51358 366.530243 302.102081]
46.5608063
275.158264
270.0
-5.15826416
[299.813904 312.407806]
0.0
35.9335518
[307.49585
310.1745]
0.0
35.9335518
[299.716827 332.80304 298.66687 349.910095 296.372772 363.648071]
51.4078865
90.2727127
99.4803162
9.20760345
[307.716736 332.841125 306.553772 351.250519 304.259674 364.988495]
52.7141571
90.2727127
99.4803162
9.20760345
[294.003693 377.347839 290.646423 388.362366 286.067078 396.571045]
34.6546516
99.8110428
119.155678
19.344635
[301.890594 378.688263 297.617279 392.287567 293.037933 400.496246]
37.3885384
99.8110428
119.155678
19.344635
[281.458344 404.679718 275.767242 410.600189 268.89679 414.035431]
24.8555794
119.61264
153.434845
33.8222046
[288.429199 408.604919 279.319 417.768524 272.448547 421.203766]
29.5303707
119.61264
153.434845
33.8222046
[261.945435 417.448608 254.010284 419.188293 244.850143 419.188293]
24.8113022
153.848541
180.0
26.1514587
[265.497192 424.616943 253.962524 427.188141 244.802383 427.188141]
28.4879551
153.848541
180.0
26.1514587
[235.781189 419.079468 228.147491 417.613312 221.662323 414.464844]
23.8575554
180.6875
205.896
25.2084961
[235.733429 427.079315 224.64093 424.803864 218.155762 421.655396]
27.3933258
180.6875
205.896
25.2084961
[215.15361 411.276672 209.786057 406.878204 205.492 401.15332]
21.1453419
206.097061
233.127609
27.0305481
[211.647049 418.467224 203.369659 411.65625 199.075607 405.931366]
24.9063759
206.097061
233.127609
27.0305481
[201.170029 395.307831 197.999496 388.650574 195.898056 380.824249]
22.6140194
233.521912
254.970062
21.4481506
[194.753632 400.085876 190.280334 390.751678 188.178894 382.925354]
25.5813694
233.521912
254.970062
21.4481506
[193.706924 372.88028 192.751053 364.412781 192.751053 355.06]
26.0351067
254.57991
270.0
15.4200897
[185.987762 374.981384 184.751083 364.432068 184.751083 355.079285]
28.1320286
254.57991
270.0
15.4200897
[192.704 344.880768 193.656921 336.025024 195.468658 328.295746]
26.9633083
269.735138
283.191925
13.4567871
[184.704025 344.900055 185.858459 334.240692 187.670197 326.511414]
28.7757702
269.735138
283.191925
13.4567871
[197.205383 320.516479 200.142105 314.178345 204.056747 309.119629]
21.1823483
282.58493
307.734192
25.1492615
[189.406921 318.732147 193.784897 309.321808 197.699539 304.263092]
24.5610504
282.58493
307.734192
25.1492615
[207.918442 303.999115 213.074234 300.290344 219.36824 297.808044]
19.2845936
307.022186
338.476166
31.4539795
[201.561234 299.142578 210.109406 292.860016 216.403412 290.377716]
23.5147915
307.022186
338.476166
31.4539795
[225.656372 295.269867 233.300354 294.084595 242.273727 294.084595]
23.3466854
338.018738
0.0
21.9812622
[222.691544 287.839539 233.272598 286.084656 242.245972 286.084656]
26.3277283
338.018738
0.0
21.9812622
[253.223526 294.015472 263.786591 295.755157 273.614349 299.096252]
31.8869267
359.638306
18.7762413
19.1379395
[253.19577 286.015533 266.326111 288.168945 276.15387 291.51004]
34.4805
359.638306
18.7762413
19.1379395
[283.423 302.328552 292.178741 306.874054 299.813904 312.407806]
29.5047092
18.2388859
35.9335518
17.6946659
[285.962524 294.74234 296.873505 300.396484 304.508667 305.930237]
31.9229279
18.2388859
35.9335518
17.6946659
>>showpage, press <return> to continue<<
Code:
$ cat
stroke7.ps
%!
%errordict/rangecheck{pstack countexecstack array execstack == quit}put
%errordict/typecheck{pstack countexecstack array execstack == quit}put
%errordict/rangecheck{pstack countexecstack array execstack == quit}put
/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 { exch neg } def
/mag { dup mul exch dup mul exch add sqrt } def
/norm { 2 copy mag dup 0 eq { }{ 1 exch div } ifelse v*n } def
/ang { exch atan } def
/aa { array astore } def
/cat { 2 aa {spill} map } def
/median { p+v .5 v*n } def
/closedsubpaths { [ {[ 3 1 roll 2 aa} {2 aa} {6 aa} {]} pathforall ] {{]}stopped{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 {
{ dup length 1 ne {offsetsubpath} if } map
} def
/pq { pstack / = quit } def
/offsetsubpath {
[ exch
dup dup 2 last exch 2 head cat offsetelement
1 index dup 1 last exch 3 head cat offsetelement
2 index 1 4 { offsetelement } fortuplem
counttomark -1 roll
dup 3 last exch 1 head cat offsetelement
]
} def
/offsetelement {
dup 2 get length 2 eq { offsetline }{ offsetcurve } ifelse
} def
/offsetline {
dup def_vin dup def_vout
dup 1 tail 2 head spill exch 2 last exch printelement
dup 2 get spill
vin vout p+v norm perp n v*n p+v
%vin norm perp n v*n p+v
%vout norm perp n v*n p+v
%vin mag 0 ne vout mag 0 ne and {vin ang dup =only ( )print vout ang dup =only ( )print exch sub =} if
2 aa
exch 1 get 2 last fixline 1 index printelement / =
} def
/fixline {
spill vin vout p+v norm perp n v*n p+v 2 aa
} def
/offsetcurve {
dup def_vin dup def_vout dup def_venter dup def_vexit
dup 1 tail 2 head spill exch 2 last exch printelement
dup 2 get spill
6 4 roll
%vin norm perp n v*n p+v
vin venter p+v norm perp n v*n p+v
6 4 roll
%vout norm perp n v*n p+v
vout vexit p+v norm perp n v*n p+v
6 4 roll
%vout norm perp n v*n p+v
vout vexit p+v norm perp n v*n p+v
6 aa
exch 1 get 2 last fixcurve 1 index printelement / =
} def
/fixcurve {
spill vin venter p+v norm perp n v*n p+v 2 aa
} def
/def_vin {
dup 1 get 2 last spill 2 index 2 get 2 head spill 4 2 roll p-p
2 copy mag .05 lt {
pop pop dup 1 get length 2 eq {
dup 0 get 2 last spill 2 index 1 get spill 4 2 roll p-p
}{ dup 1 get 4 last spill 4 2 roll p-p } ifelse
} if
2 aa exch pop cvx /vin exch def
} def
/def_vout {
dup 2 get 2 last spill 2 index 3 get 2 head spill 4 2 roll p-p
2 aa exch pop cvx /vout exch def
} def
/def_venter { % quad
dup 1 get dup length 6 eq { % q q1
%dup ==
4 last spill % q x1 y1 x2 y2
4 2 roll p-p % q dx dy
3 2 roll pop
}{ % q q1
spill % q x1 y1
3 2 roll % x1 y1 q
0 get 2 last % x1 y1 q0{..2}
spill % x1 y1 x2 y2
p-p
} ifelse
2 aa cvx /venter exch def
%/venter load == / =
} def
/def_vexit {
2 get 4 last spill 4 2 roll p-p
2 aa cvx /vexit exch def
} def
/offsetpath {
/n exch def
closedsubpaths
%dup printlengths
%dup drawpoints
offsetbyvectors %dup ==
newpath
drawpath
} def
/drawpathpoints {
closedsubpaths drawpoints
} def
/circ {
gsave
0 setgray
newpath 1 0 360 arc stroke
grestore
} def
/drawpoints {
{ { 2 2 { spill circ } fortuplem } forall } forall
} def
/xtt {
x3 x2 3 mul sub
x1 3 mul add x0 sub tt 3 exp mul
x2 3 mul x1 6 mul neg add
x0 3 mul add tt dup mul mul add
x1 3 mul x0 3 mul neg add tt mul add x0 add
} def % x coefficients as f(t)
/ytt {
y3 y2 3 mul sub
y1 3 mul add y0 sub tt 3 exp mul
y2 3 mul y1 6 mul neg add
y0 3 mul add tt dup mul mul add
y1 3 mul y0 3 mul neg add tt mul add y0 add
} def % y coefficients as f(t)
/bezierlength {
/oldx x0 def /oldy y0 def /blength 0 def
0 1 numpoints 1 sub div 1.0001 {
/tt exch def
xtt ytt /newy exch def /newx exch def
newx oldx sub dup mul
newy oldy sub dup mul add sqrt
blength add /blength exch def
/oldy newy def /oldx newx def
} for
}def % approximate curve with line segments
/numpoints 37 def
/printelement {
dup ==
2 copy printelementlength
printelementangles
} def
/printelementangles {
dup length 2 eq {
vin ang ==
}{
vin ang == vexit ang ==
vexit ang vin ang a-a ==
} ifelse
pop pop
} def
/a-a {
2 copy 270 gt exch 90 lt and { exch 360 add exch } if
sub
} def
/printlengths {
{ printsubpathlengths } forall
} def
/printsubpathlengths {
dup 1 last spill 2 last 1 index 0 get printelementlength
1 2 { spill exch 2 last printelementlength }fortuplem
} def
/printelementlength {
dup length 2 eq { printlinelength }{ printcurvelength } ifelse
} def
/printlinelength {
exch spill 3 2 roll
spill 4 2 roll p-p mag ==
} def
/printcurvelength {
exch spill 3 2 roll
spill {y3 x3 y2 x2 y1 x1 y0 x0}{exch def}forall
bezierlength blength ==
} def
3 3 scale
/Calibri-Bold 600 selectfont
100 100 moveto (9) true charpath
gsave stroke grestore
gsave drawpathpoints grestore
%gsave 20 setlinewidth strokepath 1 setlinewidth stroke grestore
%flattenpath
1 0 0 setrgbcolor
gsave 8 offsetpath stroke grestore
%gsave 7 offsetpath 3 offsetpath stroke grestore
%gsave 7 offsetpath 3 offsetpath 3 offsetpath stroke grestore
%gsave 10 offsetpath stroke grestore
%gsave -20 offsetpath stroke grestore
showpage quit