On 24 Jul 2019, luser droog wrote:
When running through the path, transforming one 'lineto' or 'curveto' at
a time, we need a little surrounding context to get all the interesting vectors that contribute to the result.
I'm afraid that with this kind of thing I always did flattenpath then
just had lineto's to deal with.
On Wednesday, July 24, 2019 at 2:50:05 AM UTC-5, Mark Carroll wrote:
On 24 Jul 2019, luser droog wrote:
When running through the path, transforming one 'lineto' or 'curveto' at a time, we need a little surrounding context to get all the interesting vectors that contribute to the result.
I'm afraid that with this kind of thing I always did flattenpath then
just had lineto's to deal with.
I tried that first of course, but it leads to these ugly artifacts at the discontinuities. I tried flattening and then using the outgoing vectors
from each point. Then I tried the incoming vectors. Then I tried taking clusters of 3, 4 or 5 consecutive points and averaging the interstitial vectors. All of these led to ears.
But there may have been errors in my implementation which concealed
positive (or promising) results. Thinking over it, using 3 consecutive
points should have been pretty close if it were done correctly.
But I have a new idea which really seems like it should work.
For lineto segments average the incoming and outgoing vectors as
described earlier. But for curveto segments, if I do a de Casteljau subdivision just once, then I get a middle point and two tangent
vectors at that point for cheap. If it doubles the number of curves,
that's not too terrible I think.
On Tuesday, July 30, 2019 at 1:18:40 AM UTC-5, luser droog wrote:
But there may have been errors in my implementation which concealed positive (or promising) results. Thinking over it, using 3 consecutive points should have been pretty close if it were done correctly.
But I have a new idea which really seems like it should work.
For lineto segments average the incoming and outgoing vectors as
described earlier. But for curveto segments, if I do a de Casteljau subdivision just once, then I get a middle point and two tangent
vectors at that point for cheap. If it doubles the number of curves,
that's not too terrible I think.
At long last I've implemented all of these ideas without errors this time. And it still makes ears. But I think this is good progress.
I found some code in Don Lancaster's pages to measure the length of a curve. I think I can use that to determine if my new offset curve is bigger or smaller than the original. And that should tell me whether we're inside or outside of a bend.
But a numerical/conceptual problem keeps cropping up. Whenever I try to
run through a series of line segments to get the angular change, I don't
know how to bound the output to be 0-360. My modular arithmetic skills
keep crapping out. Maybe pen and paper are the tool for that too.
This problem of getting a usable figure for angular change is exactly
what I need to solve to find out how "tight" the bend is in the curve.
If that all works, then I ought to be able to control ears by snipping
curves that are all clustered up in a corner.
showpage, press <return> to continue<<
On Wednesday, August 7, 2019 at 12:05:51 AM UTC-5, luser droog wrote:
On Tuesday, July 30, 2019 at 1:18:40 AM UTC-5, luser droog wrote:
But there may have been errors in my implementation which concealed positive (or promising) results. Thinking over it, using 3 consecutive points should have been pretty close if it were done correctly.
But I have a new idea which really seems like it should work.
For lineto segments average the incoming and outgoing vectors as described earlier. But for curveto segments, if I do a de Casteljau subdivision just once, then I get a middle point and two tangent
vectors at that point for cheap. If it doubles the number of curves, that's not too terrible I think.
At long last I've implemented all of these ideas without errors this time. And it still makes ears. But I think this is good progress.
I found some code in Don Lancaster's pages to measure the length of a curve.
I think I can use that to determine if my new offset curve is bigger or smaller than the original. And that should tell me whether we're inside or outside of a bend.
But a numerical/conceptual problem keeps cropping up. Whenever I try to
run through a series of line segments to get the angular change, I don't know how to bound the output to be 0-360. My modular arithmetic skills
keep crapping out. Maybe pen and paper are the tool for that too.
This problem of getting a usable figure for angular change is exactly
what I need to solve to find out how "tight" the bend is in the curve.
If that all works, then I ought to be able to control ears by snipping curves that are all clustered up in a corner.
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:[snip]
$ gs stroke7.ps
[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
On Thursday, August 8, 2019 at 2:22:52 AM UTC-5, luser droog wrote:
On Wednesday, August 7, 2019 at 12:05:51 AM UTC-5, luser droog wrote:
At long last I've implemented all of these ideas without errors this time.
And it still makes ears. But I think this is good progress.
I found some code in Don Lancaster's pages to measure the length of a curve.
I think I can use that to determine if my new offset curve is bigger or smaller than the original. And that should tell me whether we're inside or
outside of a bend.
But a numerical/conceptual problem keeps cropping up. Whenever I try to run through a series of line segments to get the angular change, I don't know how to bound the output to be 0-360. My modular arithmetic skills keep crapping out. Maybe pen and paper are the tool for that too.
This problem of getting a usable figure for angular change is exactly what I need to solve to find out how "tight" the bend is in the curve.
[snip]
Using this output was enough to isolate that bad corner. This is the
bottom left corner of the '9' where it turns from about 90 degrees
(North) to about 342 degrees (ENE). I translated and scaled and got
some smaller numbers, then copied them 3 places in my notebook and
plotted the points by hand. And then, I found something.
The shapes of the control polygons of the curves in the input curve
are all disjoint and "normal". But each of these maps to a strange
shape and several of them overlap each other. One of them is "twisted"
where the incoming tangent vector intersects the outgoing one. Two of
them look like a "thorny triangle", where the vector from the first
control point to the second is almost perpendicular to the vector from
the start point the final point. And one of them is "inverted", where
the vector from the first control point to the second is much longer
than the vector from the start point to the final point.
So, the new strategy is: run through the original curve and the new
generated curve and discover where a "normal, disjoint" curve maps
to a "strange, overlapping" curve, and replace sequences of these
with a new curve built from the incoming tangent vector of the first
curve and the outgoing tangent of the last curve. Checking for overlap
is going to be a little painful, so hopefully I can get away with
just checking for strangeness. This involves computing an intersection
for the "twisted" case, but for the other cases it's simple vector operations.
I'm thinking about using a PostScript trick to keep all this data
organized. I have a path array of subpath arrays of element arrays of coordinates. I can make associations between the element arrays and
other useful data by making definitions in a dictionary, using the
element arrays as keys. Then I can use simple 'forall' loops and load associated data back out of the dict, having the element to hand.
This should help clean up a lot of the crazy loops, I think. I just
need one crazy loop to collect all of the contextual vectors, then
just 'forall' loops after that.
Mostly there. Everything works. Ear detection seems to be working just
by checking two vectors from each curve, the "control vector" that goes
from the first control point to the second, and the "transit vector"
that goes straight from the first point to the final point. If the
control vector is bigger than the transit vector, that's an "inverted
curve" by my definition. And if the angular difference between the
control vector and the transit vector is more than about 80 degrees,
then that's either a thorny triangle or a twisted curve if it's even
bigger, closer to 180 degrees.
When drawing an offset curve 10 points away, I get 2 ears which matches
the visual results. At 5 points away, I get this "ear report":
[(00000000000000011000000000000000000000000) (000000000000000)]
which matches the visual results. At only 2 points away, no ears are
found, which also looks right.
So, now for the chore of actually snipping the ears. I think the same PostScript trick of using a dict as an associative array will help.
I can associate each string of the ear report with the subpath array
it belongs to. Then I can use a plain 'forall' loop instead of a weird
'for' loop to access parallel arrays.
I expect to have some pretty output soon. Wish me luck!
On Tuesday, August 13, 2019 at 6:03:58 PM UTC-5, luser droog wrote:
So, now for the chore of actually snipping the ears. I think the same PostScript trick of using a dict as an associative array will help.
I can associate each string of the ear report with the subpath array
it belongs to. Then I can use a plain 'forall' loop instead of a weird 'for' loop to access parallel arrays.
I expect to have some pretty output soon. Wish me luck!
Sigh. Same story again. It all works, but it doesn't "work". I tried
snipping the ears by replacing the subsequence of curves with a single
curve. And I tried grabbing earlier and/or later curves as well.
I think it might work if I use 2 curves. I have a sketch of how to
do it, but nothing typed in yet.
Now that you mention it, I pulled up the code I have and took a look at[...]
where I had left off. Just like all the other versions, it *almost*
works. That is the code all functions correctly but it still *doesn't
quite look right*. It looks like my last several messages were all talk,
so here's what I've got. The descriptive comments were added just now
because I didn't bother with anything like that while writing it.
%!
%errordict/typecheck{countexecstack array execstack == quit}put
showpage quit
This is an important and difficult problem. I want this to work, but I want this to work when applied to complicated path returned by charpath, and to work with total reliability. Which is a big ask.
E.g., a different route to this answer was requested in 2005: https://groups.google.com/forum/#!msg/comp.lang.postscript/VgN-zQSklVI/ (“What is wanted is to do the partial stroke of this path that is ≤6pt from the path, but >5pt.”)
Currently the equivalent is achieved by the ugly-tastic likes of 1 setlinejoin 1 setlinecap gsave 0 setgray 12 setlinewidth stroke grestore 1 setgray 10 setlinewidth stroke.
As a marker, this is still wanted. But only if it works with total reliability, even on the nasty paths made by charpath, whether the font be a Helvetica, a Garamond, or a Blackletter monstrosity.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 296 |
Nodes: | 16 (2 / 14) |
Uptime: | 74:09:33 |
Calls: | 6,657 |
Calls today: | 3 |
Files: | 12,203 |
Messages: | 5,332,501 |
Posted today: | 1 |