Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.postscript > #2341 > unrolled thread

On the path

Started byluser- -droog <mijoryx@yahoo.com>
First post2015-09-06 07:50 -0700
Last post2016-06-09 01:20 -0700
Articles 6 — 3 participants

Back to article view | Back to comp.lang.postscript


Contents

  On the path luser- -droog <mijoryx@yahoo.com> - 2015-09-06 07:50 -0700
    Re: On the path jdaw1 <jdawiseman@gmail.com> - 2015-09-07 01:43 -0700
      Re: On the path luser- -droog <mijoryx@yahoo.com> - 2015-09-07 16:48 -0700
        Re: On the path jdaw1 <jdawiseman@gmail.com> - 2015-09-08 02:02 -0700
          Re: On the path luser- -droog <mijoryx@yahoo.com> - 2015-09-08 13:47 -0700
    Re: On the path Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-06-09 01:20 -0700

#2341 — On the path

Fromluser- -droog <mijoryx@yahoo.com>
Date2015-09-06 07:50 -0700
SubjectOn the path
Message-ID<549740ac-3620-4dad-b437-7c08d7bdd7b3@googlegroups.com>
Inspired by Ken's insightful response to my question about 
organizing a high-level device interface, and browsing 
ghostscript's devices: http://ghostscript.com/doc/current/Drivers.htm ,
I want to go back and simplify everything.

Browsing my old threads 
https://groups.google.com/d/topic/xpost-discuss/KJCesIt-AGw/discussion
I looked again at the Path Stack idea.
https://groups.google.com/d/topic/comp.lang.postscript/dAwAN5x5goU/discussion

And I think it can be made still simpler. It can be an array (or stack) of
just coordinate-pairs or sextuples. A path must start with a pair (not a
sextuple) and this is the initial moveto element. Subsequent lineto or
curveto elements are pairs or sextuples respectively. And a closed path 
contains a duplicated (shared) copy of the moveto element, which will
compare equal "pointerwise" as 'the same pair'.

[0 0]
[1`1]
[2 2 3 3 4 4]
2 index % eg.

The process of iterating through the path with pathforall needs to use
a local variable to hold the moveto and compare each element (or just
pairs) against it to detect when to emit a /close call and reset to
moveto after the next pair (which must be a pair, as stipulated above).

This provides a direct translation from a flat-stack layout to a flat-array
layout, so I can use a stack for the "current path" and export arrays as 
necessary for gsave/grestore. 

This should be significantly less overhead than the dictionary-record 
implementation of elements and dictionary-array implementations of
subpaths, paths, and path-stacks.

And it should reduce conversions for internal algorithms like clipping:

https://github.com/luser-dr00g/xpost/blob/master/data/clip.ps#L200
%clip the current path by the clipregion
% convert the path to an array of polygons (arrays of points)
% convert clipregion to array of polygons
% traverse the clipregion
%    convert line to [A B C] form
%    feed polygon and line to hodgman-sutherland,
%       receiving new polygon.
% convert polygon array back to path structure
/doclip {

Producing a "polygon" becomes a getinterval.

[toc] | [next] | [standalone]


#2342

Fromjdaw1 <jdawiseman@gmail.com>
Date2015-09-07 01:43 -0700
Message-ID<bc7ada31-6c4a-4a0a-ae7f-de3a7e27aace@googlegroups.com>
In reply to#2341
The following is meant to be a crossed square, but the pointer-equivalence rule causes a problem on the first re-use of PointA. 

/PointA [0 0] def  /PointB [0 1] def  /PointC [1 1] def  /PointD [1 0] def
PointA PointB PointC PointD PointA PointC PointB PointD

Consider making an empty array, [], imply closepath.

[toc] | [prev] | [next] | [standalone]


#2343

Fromluser- -droog <mijoryx@yahoo.com>
Date2015-09-07 16:48 -0700
Message-ID<05803aff-0b4d-4cbd-86e1-c57972520919@googlegroups.com>
In reply to#2342
On Monday, September 7, 2015 at 3:43:23 AM UTC-5, jdaw1 wrote:
> The following is meant to be a crossed square, but the pointer-equivalence rule causes a problem on the first re-use of PointA. 
> 
> /PointA [0 0] def  /PointB [0 1] def  /PointC [1 1] def  /PointD [1 0] def
> PointA PointB PointC PointD PointA PointC PointB PointD
> 
> Consider making an empty array, [], imply closepath.

Excellent idea. I don't quite follow the problem you 
describe, but it makes algorithms like coalescing 
consecutive movetos much easier. 

/last-was-moveto-p { 1 index length 0 eq } def

[toc] | [prev] | [next] | [standalone]


#2344

Fromjdaw1 <jdawiseman@gmail.com>
Date2015-09-08 02:02 -0700
Message-ID<e8fdb408-8a41-4bbd-bdc0-e5bf0adad362@googlegroups.com>
In reply to#2343
> I don't quite follow the problem you describe

Paths can have points visited more than once. 
[0 0] [0 1] [1 1] [1 0] [0 0] [2 2]
Your old data setup would work with that. 

But if the repeated point had been def'd:
/SpecialPoint [0 0] def
Then 
SpecialPoint [0 1] [1 1] [1 0] SpecialPoint [2 2]
would contain an array equivalence that doesn't mean 'closepath'. Error!

[toc] | [prev] | [next] | [standalone]


#2345

Fromluser- -droog <mijoryx@yahoo.com>
Date2015-09-08 13:47 -0700
Message-ID<20d9b0b1-e5ca-498d-9b4a-3d1c5b2ca0ca@googlegroups.com>
In reply to#2344
On Tuesday, September 8, 2015 at 4:02:07 AM UTC-5, jdaw1 wrote:
> > I don't quite follow the problem you describe
> 
> Paths can have points visited more than once. 
> [0 0] [0 1] [1 1] [1 0] [0 0] [2 2]
> Your old data setup would work with that. 
> 
> But if the repeated point had been def'd:
> /SpecialPoint [0 0] def
> Then 
> SpecialPoint [0 1] [1 1] [1 0] SpecialPoint [2 2]
> would contain an array equivalence that doesn't mean 'closepath'. Error!

Ok. I see. This would all be for "internals", so the
user interaction is still with the normal operators
(moveto, lineto, curveto, closepath). But yes, the
idea does look very fragile and prone to mistakes
like you describe. 

A further refinement might be to use a 1-element array
which contains a reference back to the moveto element.
With the linear layout, this might more conveniently
be an integer index instead of a pointer.

[toc] | [prev] | [next] | [standalone]


#2636

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-06-09 01:20 -0700
Message-ID<06014966-3a71-4c03-8418-6960192d375a@googlegroups.com>
In reply to#2341
On Monday, September 7, 2015 at 2:50:13 AM UTC+12, luser- -droog wrote:
> It can be an array (or stack) of just coordinate-pairs or sextuples. A
> path must start with a pair (not a sextuple) and this is the initial moveto
> element. Subsequent lineto or curveto elements are pairs or sextuples
> respectively. And a closed path contains a duplicated (shared) copy of the
> moveto element, which will compare equal "pointerwise" as 'the same pair'.

For a path structure that you can perform useful manipulations on, this is just too fiddly. That was my verdict, after trying to do something similar for Qahirah <https://github.com/ldo/qahirah>.

In the end, I implemented my “Path” class in terms of one or more “Segment” objects. Each contains one or more “Point” objects, together with a “closed” flag. Each Point has a Vector (2D coordinate), together with an on-curve/off-curve flag. Two successive on-curve points define a straight line; one off-curve point in-between make a quadratic Bézier, and two successive in-between off-curve points a cubic Bézier.

This structure is 1) easy to construct, and 2) easy to convert to moveto/lineto/curveto/closepath calls.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.postscript


csiph-web