Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A path x points distant from the current path

37 views
Skip to first unread message

jdaw1

unread,
May 27, 2009, 10:45:57 PM5/27/09
to
Currently code does something like the following:

% Generate some complicated path
1 setlinecap 1 setlinejoin [] 0 setdash
gsave 51 setlinewidth 0 setgray stroke grestore
49 setlinewidth 1 setgray stroke

This draws the a black line 50 points away from the original path and
2 points wide. However, it erases to white everything within 49
points: any paint there is overwritten.

I'd like to replace this code with something along the lines of:

% Here generate some complicated path
50 ReplaceCurrentPathWithOneAFixedDistanceAway
2 setlinewidth 0 setgray stroke

Alas strokepath won't work for this task. From PLRM 3: “The path
produced by strokepath is suitable for use as the implicit operand to
a subsequent fill, clip, or pathbbox operation. In general, it is not
suitable for stroke, as it may contain interior segments or
disconnected subpaths produced by strokepath’s conversion from stroke
to outline.”

So what I want is a proper strokepath: please, has anybody written
such a thing?

Helge Blischke

unread,
May 28, 2009, 4:37:35 AM5/28/09
to
jdaw1 wrote:

IIt depends on the complexity of the original path if the path resulting
from strokepath really looks ugly when stroked ("not suitable" only means
that the result of stroking this path might not completely look as
exspected).
Perhaps you could try to generate two paths by strokepath the intended
strokewidth aart and fill the result using eofill. Surely you need to fool
the ps interpreter using gsave and grestore etc.

Helge

hoff...@fho-emden.de

unread,
May 29, 2009, 4:06:02 AM5/29/09
to
> Helge- Zitierten Text ausblenden -
>
> - Zitierten Text anzeigen -

The OP wants an offset path (or two offset paths ?)
strokepath is not suitable, see code below, because
of internal linecaps.

The calculation of offset paths is rather complex.
Adobe Illustrator does its job rather good:
http://www.fho-emden.de/~hoffmann/offsetpath.pdf

The handling of cusps is mostly correct, but some
users are blaming the program for generating too
many control points.

A mathematical concept for generating approximated
offset paths as Bézier offset curves can be found
here in chapter 7:
http://www.fho-emden.de/~hoffmann/bezier18122002.pdf

The algorithm is mathematically complex and doesn't
care about cusps.

A discussion about better algorithms ended in no result:
http://tinyurl.com/mo6sv5

Arbitrarily accurate approximations are probably available
in the field of CAD manufacturing.

Best regards --Gernot Hoffmann

---------------------------------------------------
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 500 500
%%Creator: Gernot Hoffmann
%%Title: Polyline
%%CreationDate: May 28 / 2009

% draw a polyline based on value pairs x y
% try to draw two offset paths by strokepath

/dat
[
10 0
6 6
0 8
-5 5
-5 0
-3 -3
0 -3
2 -2
2 0
] def

/mm {2.834646 mul} def
/mX 10 def
/mY 10 def
/sc 50 mm def
/of 60 mm def
/N dat length 2 div 1 sub def

of of translate
sc sc scale

/k 0 def
dat k get mX div dat k 1 add get mY div moveto
1 1 N
{pop
/k k 2 add def
dat k get mX div dat k 1 add get mY div lineto
} for

0 setlinecap

gsave
0 0 1 setrgbcolor
1 mm sc div setlinewidth
stroke
grestore

20 mm sc div setlinewidth
strokepath
1 0 0 setrgbcolor
1 mm sc div setlinewidth
stroke

showpage

jdaw1

unread,
May 30, 2009, 7:20:43 PM5/30/09
to
> IIt depends on the complexity of the original path if the path
My path will typically have been generated from a charpath of a string
of ≤20 characters.

And www.fho-emden.de/~hoffmann/offsetpath.pdf makes clear that this
will be too slow a task for a PostScript subroutine.

Ok, I'll proceed as now: setlinewidth thick and stroke black,
setlinewidth thinner and stroke white.

ThomasW

unread,
May 31, 2009, 4:53:37 PM5/31/09
to
On 31 Mai, 01:20, jdaw1 <jdawise...@gmail.com> wrote:
> > IIt depends on the complexity of the original path if the path
>
> My path will typically have been generated from a charpath of a string
> of ≤20 characters.
>
> Andwww.fho-emden.de/~hoffmann/offsetpath.pdfmakes clear that this

> will be too slow a task for a PostScript subroutine.
>
> Ok, I'll proceed as now: setlinewidth thick and stroke black,
> setlinewidth thinner and stroke white.

What about using flattenpath and calculating the offset path for that
polygon? It's at least feasible, though explicit cusp handling would
certainly be too complex. The PostScript addict in me feels
challenged by this...

Thomas W.

jdaw1

unread,
Jun 3, 2009, 12:53:35 PM6/3/09
to
> The PostScript addict in me feels challenged by this...

I hereby challenge the PostScript addict in you.

Examine the first two pages of www.jdawiseman.com/port/20090611_blind.pdf.
At two different levels there is painting of thick black strokes
followed by slightly thinner white strokes. Improve the code (based on
www.jdawiseman.com/papers/placemat/placemat.ps which is described at
www.jdawiseman.com/papers/placemat/placemat.html) so that if the page
is initially filled with other paint, where there is now white that
other paint would show through. I.e., use no white paint.

(An alternative idea, discussed at groups.google.com/group/
comp.lang.postscript/browse_thread/thread/56037ecd04a49552/, would be
an anticlip, such that painting happens only outside that region. Then
strokepath anticlip the narrow line width, and stroke the wider. Alas
impossible.)

ThomasW

unread,
Jun 4, 2009, 9:45:54 AM6/4/09
to
On 3 Jun., 18:53, jdaw1 <jdawise...@gmail.com> wrote:
> > The PostScript addict in me feels challenged by this...
>
> I hereby challenge the PostScript addict in you.
>
> Examine the first two pages of www.jdawiseman.com/port/20090611_blind.pdf.

Mh, I thought this was simply about creating a "parallel" path. What
I see there would be much more complicated to achieve. I would say
too much work for a just-for-fun project.

Anyway, I think I would do it like this with the flattened path
approach (might be flawed, though): From the flattened paths,
parallel polygons can be created with reasonable effort. Then I would
combine all those new polygons to one large polygon. I would look for
all intersection points and add them as explicit vertices. Finally, I
would delete all points that fully lie inside the polygon. (Could
maybe be done more efficiently earlier when checking for intersection
points because all vertices between two intersection points lie either
inside or outside.) Makes sense?

> At two different levels there is painting of thick black strokes

> followed by slightly thinner white strokes. Improve the code (based on www.jdawiseman.com/papers/placemat/placemat.pswhich is described at www.jdawiseman.com/papers/placemat/placemat.html) so that if the page


> is initially filled with other paint, where there is now white that
> other paint would show through. I.e., use no white paint.
>
> (An alternative idea, discussed at groups.google.com/group/
> comp.lang.postscript/browse_thread/thread/56037ecd04a49552/, would be
> an anticlip, such that painting happens only outside that region. Then
> strokepath anticlip the narrow line width, and stroke the wider. Alas
> impossible.)

This is because the path created by strokepath is too complicated,
right? With the polygon that I would get with the method described
above, "anticlip" might be possible.

Thomas W.

jdaw1

unread,
Jun 4, 2009, 11:44:17 AM6/4/09
to
> too much work for a just-for-fun project.
Agreed.

Work around the flattened path. At each join add a line segment and an
arc, centred on the join, to the next line segment. Problems:
• Is the path clockwise or anticlockwise: not trivial.
• What if the path is comprised of several disconnected pieces
(consider the glyph "8"): is the current piece internal, external, or
does it cross so it's both?
• If an internal piece, is there a offset path at all? Or should it be
computed then deleted because internal to the offset path of an outer
path? That feels inefficient.


*** anticlip ***
Though anticlip would have been a useful addition to the language when
first written, it's not there and not possible for anything other than
the simplest paths (for which add a same-clockwiseness huge outer
box).

jdaw1

unread,
Jun 4, 2009, 4:48:31 PM6/4/09
to
A sketch of an algorithm for you.

Assume Path not self-intersecting, and composed of various Subpaths.
Then:

For each of the Subpaths
-- Compose offsetsubpath that is offset in one direction.
-- Compose offsetsubpath that is offset in the other direction.
-- Store them somewhere
-- For each component of each of these two offsetsubpaths
-- -- For each component of each of the Subpaths of the original Path
-- -- -- If the component of one of the two offsetsubpaths too close
to the component of the Subpaths
-- -- -- -- Delete that component, or the part of that component that
is too close
-- -- -- -- If deleting a part, note in a list the location of the
loose end
-- -- -- End if
-- -- Next each component of each of the Subpaths of the original Path
-- Next component of each of the two offsetsubpaths
Next Subpaths
Tie up loose ends.

If original path has n components, and hence each offsetsubpath say
2n, then this takes time O(4 n^2). That's not good, but tolerable.

ThomasW

unread,
Jun 4, 2009, 5:57:32 PM6/4/09
to

I thought about making use of the insideness testing operators for
simplicity and efficiency, but what points are considered inside and
outside an area is probably highly implementation dependent, and the
"insideness status" of points on the boundary of the area is undefined
anyway.

Scott Prouty

unread,
Jun 10, 2009, 5:01:03 PM6/10/09
to
> anyway.- Hide quoted text -
>
> - Show quoted text -


I have thought about this for a while and I have come up with a
different approach to the issue. Here is the code:


%!
% 2009-06-10 SJP - Test of "stroking" a path by an offset amount
%

/OffsetAmount 50 def % The amount to offset
/StrokeThickness 2 def % The thickness of the line
/Helvetica 48 selectfont % Set a font

gsave clippath 1 1 0 setrgbcolor fill grestore % Put yellow background


72 648 moveto % Set intial position of path

gsave
72 OffsetAmount div dup scale % Scale the forthcoming path out to the
offset
OffsetAmount StrokeThickness mul 72 div setlinewidth % Get the stroke
thickness back into points

% START - Draw any path here, this example uses a text path
(Test) false charpath
% END - Draw any path here, this example uses a text path

stroke
grestore


showpage


There are two drawbacks that I can see with this approach:

1. The original (i.e. non-offset) path is not preserved, and if
needed must be re-drawn.

2. The offset this produces is not "centered" around the original
path (you can see this by adding a "gsave (Test) show grestore" line
just after the "72 648 moveto" line.

I also haven't tested this with more complicated paths, but maybe it
will help...

Thanks!
Scott Prouty

pd

unread,
Jun 22, 2009, 10:16:35 AM6/22/09
to

Actually, I think you're on to something with the two path approach.
I think 'aart' is a type, but I guess what you intended was doing
'strokepath' twice, once with a linewidth slightly larger (perhaps .5
pt) than the intended offset path, and one slightly smaller, and then
eofill the result. That should result in a thin black curve with no
interior edges.

Also, note that some RIPs generate strokepath results with no interior
edges. At one time, the Harlequin ScriptWorks RIP did this, though I
haven't checked this in some years.

-pd

jdaw1

unread,
Feb 13, 2021, 12:50:22 PM2/13/21
to
0 new messages