Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.postscript > #1998 > unrolled thread
| Started by | luser- -droog <mijoryx@yahoo.com> |
|---|---|
| First post | 2014-08-30 01:43 -0700 |
| Last post | 2014-11-16 23:40 -0800 |
| Articles | 8 — 2 participants |
Back to article view | Back to comp.lang.postscript
setdash luser- -droog <mijoryx@yahoo.com> - 2014-08-30 01:43 -0700
Re: setdash jdaw1 <jdawiseman@gmail.com> - 2014-08-30 02:51 -0700
Re: setdash luser- -droog <mijoryx@yahoo.com> - 2014-08-30 20:40 -0700
Re: setdash jdaw1 <jdawiseman@gmail.com> - 2014-09-01 02:39 -0700
Re: setdash jdaw1 <jdawiseman@gmail.com> - 2014-09-02 02:06 -0700
Re: setdash luser- -droog <mijoryx@yahoo.com> - 2014-09-04 16:51 -0700
Re: setdash luser- -droog <mijoryx@yahoo.com> - 2014-09-16 03:37 -0700
Re: setdash luser- -droog <mijoryx@yahoo.com> - 2014-11-16 23:40 -0800
| From | luser- -droog <mijoryx@yahoo.com> |
|---|---|
| Date | 2014-08-30 01:43 -0700 |
| Subject | setdash |
| Message-ID | <0410d6f7-a91f-4b56-a0f6-fd7f558676cd@googlegroups.com> |
I need to implement setdash for my interpreter, but I'm so lazy.. Anybody know any tricks?
[toc] | [next] | [standalone]
| From | jdaw1 <jdawiseman@gmail.com> |
|---|---|
| Date | 2014-08-30 02:51 -0700 |
| Message-ID | <f791cdde-84ed-484d-9f52-a242a52dca97@googlegroups.com> |
| In reply to | #1998 |
No. Is your interpreter converting PS to PDF, in which case the problem might be passed through. Or is it rendering the PS/PDF. Surely curves are rendered with an implicit flattenpath: do the same and the distance calculation becomes easy. Ensure that within the curve the dashes have 0 setlinecap 1 setlinejoin.
[toc] | [prev] | [next] | [standalone]
| From | luser- -droog <mijoryx@yahoo.com> |
|---|---|
| Date | 2014-08-30 20:40 -0700 |
| Message-ID | <6d617280-6964-4601-91c9-8600fa370bbe@googlegroups.com> |
| In reply to | #1999 |
On Saturday, August 30, 2014 4:51:14 AM UTC-5, jdaw1 wrote:
> No.
>
>
>
> Is your interpreter converting PS to PDF, in which case the problem might be passed through. Or is it rendering the PS/PDF. Surely curves are rendered with an implicit flattenpath: do the same and the distance calculation becomes easy. Ensure that within the curve the dashes have 0 setlinecap 1 setlinejoin.
It's rendering the image to a window. Although it can
also output to a file. But it reduces everything to polygon fills
at the postscript level.
Without bothering to look it up, I think applying dashing is the
first step of strokepath. And conceptually, it can work the same way.
So, this is the frame.
%apply dash parameters from graphics state to current path
%modifies current path
/dashpath {
% ...
} def
I've seen blown-up examples without rounded cap, and I think
it just follows the linejoin and linecap that are already set.
I think you've found the crux with "distance calculation".
It needs to traverse the path, measuring lengths against the
lengths in the dash array. It either needs to perform surgery
on the existing path data structure, or construct a new one as
it traverses. I remember Goswell's paper mentioned a funny edge
case with closepath, where the seam needed to be removed.
[toc] | [prev] | [next] | [standalone]
| From | jdaw1 <jdawiseman@gmail.com> |
|---|---|
| Date | 2014-09-01 02:39 -0700 |
| Message-ID | <1cdbf719-c10f-4cec-b48e-99291e028b3e@googlegroups.com> |
| In reply to | #2000 |
For computing the length you might use the method in http://steve.hollasch.net/cgindex/curves/cbezarclen.html Then render the painted parts of the dashes with a curveto: it's quite easy to compute the controls points for a subsection of a curve running from t1 to t2. (If needed I can post a file.)
[toc] | [prev] | [next] | [standalone]
| From | jdaw1 <jdawiseman@gmail.com> |
|---|---|
| Date | 2014-09-02 02:06 -0700 |
| Message-ID | <608ec2aa-687e-4fc2-b96c-030d9399bc12@googlegroups.com> |
| In reply to | #2000 |
I think you might need something like this.
% x0 y0 x1 y1 x2 y2 x3 y3 WantedDistance Tolerance FindDistanceInCurve real bool
% If the bool is true, the real is the t value within cure
% if the bool is false, the real is the length of the whole curve
/FindDistanceInCurve
{
...
} bind def % /FindDistanceInCurve
Obviously lots missing. It will use a variation of the splitting algorithm in http://steve.hollasch.net/cgindex/curves/cbezarclen.html
If within Tolerance of a straight line, then use the approximation in the linked article to compute estimated length. If length <= WantedDistance, return false and that length. Otherwise split curve. Repeat on first segment with Tolerance halved: if t found, then good. Obviously t's will need to be mapped from the sub-range into the whole. If t not found, subtract new-found length from target and repeat on second curve.
[toc] | [prev] | [next] | [standalone]
| From | luser- -droog <mijoryx@yahoo.com> |
|---|---|
| Date | 2014-09-04 16:51 -0700 |
| Message-ID | <35180be8-4d90-4a3c-9258-04bb99966999@googlegroups.com> |
| In reply to | #2004 |
On Tuesday, September 2, 2014 4:06:22 AM UTC-5, jdaw1 wrote:
> I think you might need something like this.
>
>
> % x0 y0 x1 y1 x2 y2 x3 y3 WantedDistance Tolerance FindDistanceInCurve real bool
> % If the bool is true, the real is the t value within cure
> % if the bool is false, the real is the length of the whole curve
> /FindDistanceInCurve
> {
> ...
> } bind def % /FindDistanceInCurve
>
>
> Obviously lots missing. It will use a variation of the splitting algorithm in http://steve.hollasch.net/cgindex/curves/cbezarclen.html
>
> If within Tolerance of a straight line, then use the approximation in the linked article to compute estimated length. If length <= WantedDistance, return false and that length. Otherwise split curve. Repeat on first segment with Tolerance halved: if t found, then good. Obviously t's will need to be mapped from the sub-range into the whole. If t not found, subtract new-found length from target and repeat on second curve.
On further thought, I think my task is simpler that all this. I can do the
dashing after converting curves to line segments. Then I just have to
measure lines with the good old Pythagorean distance formula.
I still need to iterate through the path and compare lengths against the
array of dash lengths, but the math should be much simpler than I feared.
[toc] | [prev] | [next] | [standalone]
| From | luser- -droog <mijoryx@yahoo.com> |
|---|---|
| Date | 2014-09-16 03:37 -0700 |
| Message-ID | <30d9f684-d1e3-40d8-8720-177653e9a8f5@googlegroups.com> |
| In reply to | #2019 |
On Thursday, September 4, 2014 6:51:59 PM UTC-5, luser- -droog wrote:
> On Tuesday, September 2, 2014 4:06:22 AM UTC-5, jdaw1 wrote:
>
> > I think you might need something like this.
>
> >
> >
> > % x0 y0 x1 y1 x2 y2 x3 y3 WantedDistance Tolerance FindDistanceInCurve real bool
> > % If the bool is true, the real is the t value within cure
> > % if the bool is false, the real is the length of the whole curve
> > /FindDistanceInCurve
> > {
> > ...
> > } bind def % /FindDistanceInCurve
> >
> >
> > Obviously lots missing. It will use a variation of the splitting algorithm in http://steve.hollasch.net/cgindex/curves/cbezarclen.html
> >
> > If within Tolerance of a straight line, then use the approximation in the linked article to compute estimated length. If length <= WantedDistance, return false and that length. Otherwise split curve. Repeat on first segment with Tolerance halved: if t found, then good. Obviously t's will need to be mapped from the sub-range into the whole. If t not found, subtract new-found length from target and repeat on second curve.
>
> On further thought, I think my task is simpler that all this. I can do the
> dashing after converting curves to line segments. Then I just have to
> measure lines with the good old Pythagorean distance formula.
>
> I still need to iterate through the path and compare lengths against the
> array of dash lengths, but the math should be much simpler than I feared.
Alright. It's written and (mostly) working. Ultimately the trickiest part
was keeping track of whether a point or vector was in user space or device
space. The path data structure stores points in device space coordinates,
but the lengths in the dash array are in user space. So itransform first,
and transform before storing a new path element.
One remaining bug appears to happen only in arcs. The dash pattern is
resetting in the middle of an arc. It probably means an extra 'moveto'
is in the path. But I think the bug is in arc/arcn, and not dashpath..
[toc] | [prev] | [next] | [standalone]
| From | luser- -droog <mijoryx@yahoo.com> |
|---|---|
| Date | 2014-11-16 23:40 -0800 |
| Message-ID | <553d3a58-3770-4959-b292-ac53ba256acc@googlegroups.com> |
| In reply to | #2054 |
On Tuesday, September 16, 2014 5:37:23 AM UTC-5, luser- -droog wrote:
> On Thursday, September 4, 2014 6:51:59 PM UTC-5, luser- -droog wrote:
> > On Tuesday, September 2, 2014 4:06:22 AM UTC-5, jdaw1 wrote:
> >
> > > I think you might need something like this.
> >
> > >
> > >
> > > % x0 y0 x1 y1 x2 y2 x3 y3 WantedDistance Tolerance FindDistanceInCurve real bool
> > > % If the bool is true, the real is the t value within cure
> > > % if the bool is false, the real is the length of the whole curve
> > > /FindDistanceInCurve
> > > {
> > > ...
> > > } bind def % /FindDistanceInCurve
> > >
> > >
> > > Obviously lots missing. It will use a variation of the splitting algorithm in http://steve.hollasch.net/cgindex/curves/cbezarclen.html
> > >
> > > If within Tolerance of a straight line, then use the approximation in the linked article to compute estimated length. If length <= WantedDistance, return false and that length. Otherwise split curve. Repeat on first segment with Tolerance halved: if t found, then good. Obviously t's will need to be mapped from the sub-range into the whole. If t not found, subtract new-found length from target and repeat on second curve.
> >
> > On further thought, I think my task is simpler that all this. I can do the
> > dashing after converting curves to line segments. Then I just have to
> > measure lines with the good old Pythagorean distance formula.
> >
> > I still need to iterate through the path and compare lengths against the
> > array of dash lengths, but the math should be much simpler than I feared.
>
> Alright. It's written and (mostly) working. Ultimately the trickiest part
> was keeping track of whether a point or vector was in user space or device
> space. The path data structure stores points in device space coordinates,
> but the lengths in the dash array are in user space. So itransform first,
> and transform before storing a new path element.
>
> One remaining bug appears to happen only in arcs. The dash pattern is
> resetting in the middle of an arc. It probably means an extra 'moveto'
> is in the path. But I think the bug is in arc/arcn, and not dashpath..
Buttoning-up this thread for the archive.
Dashing is implemented by the (obvious?) means of a
`dashpath` operator which replaces the current path
by its outline. As a special-effect, it may be called
prematurely to "show" the outline. But, as pre-
preemptively-caveat'ed in the PLRM, it's ugly-looking.
http://code.google.com/p/xpost/source/browse/data/path.ps#458
current version (warning long lines may break ill):
% PLRM 3ed, 667:
% The offset operand can be thought of as the "phase" of the dash pattern relative to
% the start of the path. It is interpreted as the distance into the dash pattern
% (measured in user space units) at which to start the pattern. Before beginning to
% stroke a path, the stroke operator cycles through the elements of array, adding up
% distances and alternating dashes and gaps as usual, but without generating any
% output. When the accumulated distance reaches the value specified by offset, it
% begins stroking from the starting point of the path, using the dash pattern from
% the point that has been reached. Each subpath of a path is treated independently;
% the dash pattern is restarted and the offset reapplied at the beginning of each
% subpath.
/initial_ipos {
{
pos dasharray ipos get lt { exit } if
/pos pos dasharray ipos get sub def
/ipos ipos 1 add dasharray length mod def
/parity parity 1 add 2 mod def
} loop
} def
/crossdashbound {
{/ang/rad/data}{exch def}forall
/partial dasharray ipos get pos sub def
{
%partial ang ravec parity 0 eq { rlineto }{ rmoveto } ifelse
<</cmd parity 0 eq{ /line
%(+)=
}{ /move
%(-)=
} ifelse /data
cp aload pop
partial ang ravec % x y dx dy
3 2 roll add % x dx Y
3 1 roll add exch % X Y
2 copy 2 array astore /cp exch def
transform 2 array astore >> cpath addtopath
/rad rad partial sub def
/ipos ipos 1 add dasharray length mod def
/parity parity 1 add 2 mod def
/partial dasharray ipos get def
rad partial lt { exit } if
} loop
/pos rad def
%rad ang ravec parity 0 eq { rlineto }{ rmoveto } ifelse
<</cmd parity 0 eq{ /line
%(+)=
}{ /move
%(-)=
} ifelse /data
cp aload pop
rad ang ravec % x y dx dy
3 2 roll add % x dx Y
3 1 roll add exch % X Y
2 copy 2 array astore /cp exch def
transform 2 array astore >> cpath addtopath
data rad ang % pop pop pop
} def
/dashdict << % path i subpath_i j elem
/move {
%(m)=
%pstack()=
/data get
aload pop itransform 2 array astore
%pstack()=
/cp exch def
parity 0 eq { % initially drawing, create initial move
<< /cmd /move /data cp aload pop transform 2 array astore >> cpath addtopath
} if
}
/line {
%(l)=
/data get
cp aload pop
2 index aload pop
itransform
ptdiff % [] dx dy
%idtransform
magang % [] rad ang
1 index pos add dasharray ipos get le { % same dash position
%(.)=
1 index pos add /pos exch def
parity 0 eq { % if drawing, continue line % [] rad ang
2 index /cp 1 index aload pop itransform 2 array astore def
<< /cmd /line /data 5 4 roll >> cpath addtopath
} if
}{ % cross a dash pattern boundary
crossdashbound
{
/partial dasharray ipos get pos sub def
1 index pos add dasharray ipos get sub /pos exch def
/ipos ipos 1 add dasharray length mod def
/parity parity 1 add 2 mod def
parity 0 eq { % begin new segment
%(+)=
partial exch ravec % [] rad dx dy
%dtransform
cp aload pop % [] rad dx dy x y
3 2 roll add % dx x y+dy
3 1 roll add exch % x+dx y+dy
2 array astore /cp 1 index def
<< /cmd /move /data 5 4 roll aload pop transform 2 array astore >> cpath addtopath
0
}{ % finish partial segment
%(-)=
%pstack()=
partial exch ravec % [] rad dx dy
%dtransform
cp aload pop
3 2 roll add
3 1 roll add exch
2 array astore /cp 1 index def
<< /cmd /line /data 5 4 roll aload pop transform 2 array astore >> cpath addtopath
0
} ifelse
} pop
} ifelse % [] rad ang
pop pop pop
}
/close { LINEPROC exec
%(c)=
closepath
} dup 0 4 index put
/curve { }
>> def
% apply dash parameters to current path
% modifies current path
/dashpath {
10 dict begin
currentdash % [] offset
/dashoffset exch def
/dasharray exch def
/pos dashoffset def
/ipos 0 def
/parity 0 def
dasharray length 0 ne {
initial_ipos
cpath length 0 gt {
cpath newpath
0 1 2 index length 1 sub { % path i
2 copy get % path i subpath_i
10 dict begin
/pos pos def
/ipos ipos def
/parity parity def
0 1 2 index length 1 sub { % path i subpath_i j
2 copy get % path i subpath_i j elem=subpath_i_j
dashdict 1 index /cmd get get exec % p i sp j
%(dp)=
%pstack()=
pop % p i sp
} for
pop pop % path
end
} for % path
pop
} if
} if
end
} def
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.postscript
csiph-web