summaryrefslogtreecommitdiff
path: root/support/lametex/src/breakpath.ps
blob: ebc63744c69e11b15b993da377a9e42a9a7269be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
%! This is a PostScript library meant to be included in other files %%%
%% Postscript Code by Jon Monsarrat Copyright 1991
%% permission given for anything except selling this or deleting the header.
%%%%%%%%%%%   -    Approx   array %%%%%%%%%%%%%%%%%
% Approx flattens a path into a series of lines.
% This new flattened path is returned as a triple-array path representation.
% The path is broken into sub-paths which have a double-array representation.
% Each sub-path breaks into vertices which have a single-array representation.
% Each vertex is of the form X Y. We're doing a fill here so any
% unclosed subpaths get closed. That's how postscript normally handles fill.
% It would be easier to use [ X Y ] vertices, but that would waste memory!
/Approx
  {
     [ [ { /Y exch def /X exch def ] [ X Y } 
         { } { } { X Y } pathforall ] ]
  } bind def

%%%%%%%%%%%%%%%%%%%  array num bool  SortArray  array   %%%%%%%%%%%%%%%
% SortArray bubble sorts "array" of packets in increasing order, packets are
% groups of numbers and a packet is of size "num". Sorting is done based
% on the value of the first item in each packet. When sorting is done,
% SortArray goes through and deletes all equal packets if "bool" is true.
/SortArray
{
   10 dict begin
   /DelEquals exch def /Pack exch def
   /newlist exch def
   0 Pack newlist length 2 Pack mul sub
   {
     /anum exch def
     anum Pack add Pack newlist length 1 Pack mul sub
     {
       /bnum exch def
       newlist anum get newlist bnum get ge
       {
         /flag true def
         newlist anum get newlist bnum get eq Pack 2 eq and
         {
           /flag false def
           newlist anum 1 add get newlist bnum 1 add get add 0 eq
           {
             newlist anum 1 add get 1 eq ontop xor { /flag true def } if
           } if
         } if
         flag
         {
           0 1 Pack 1 sub
           {
             /ind exch def
             /temp newlist anum ind add get def
             newlist anum ind add newlist bnum ind add get put
             newlist bnum ind add temp put
           } for
         } if
       } if
     } for
   } for

   DelEquals      % if this boolean is true, delete all equal packs
   {
     [
       0 Pack newlist length 2 Pack mul sub
       {
         /anum exch def
         newlist anum get newlist anum Pack add get ne
         {
           0 1 Pack 1 sub
           {
             anum add newlist exch get
           } for
         } if
       } for
       0 1 Pack 1 sub
       {
         /ind exch def
         newlist newlist length Pack sub ind add get
       } for
     ]
   } 
   {
     newlist
   } ifelse
   end % temp dict 10
} bind def

%%%%%%%%%%%%%%%%%%     bool     CheeseY      X1 W1  or nothing  %%%%%%%%%%
% CheeseY uses defined variables Y1 (a number), oldx, oldy, newx, newy.
% CheeseY asks "does the line segment bounded by oldxy, newxy cross y=Y1?
% If so, CheeseY leaves X1 W on the stack, where (X1,Y1) is the point of
% intersection. The winding value W is calculated from the sign of the slope.
% CheeseY takes one argument which is a boolean value. This boolean is
% true is the Y1 value is "on top" of the region of interest, false if "below".
% This is to deal correctly with line segments which end on the y=Y1 line.
% These special line segments are ignored if they don't pass through the
% region of interest. It would be easier to use [ X W ] but memory wasteful.
/CheeseY
{
  /top exch def
  oldy newy 2 copy gt { exch } if
  Y1 ge exch Y1 le and
  {  
     oldy newy ne
     {
        oldx newx sub oldy newy sub div
        oldy Y1 sub mul oldx exch sub 
        oldy newy lt { 1 } { -1 } ifelse
     }
     {
       newx 0
     } ifelse

     % If the line segment does NOT go through region of interest
     % but rather just happens to end on line y=Y1, don't use it.
     oldy Y1 eq
     {
       dup top { -1 } { 1 } ifelse ne { pop pop } if
     }
     {
       newy Y1 eq
       {
         dup top { 1 } { -1 } ifelse ne { pop pop } if
       } if
     } ifelse
  } if
} bind def

%%%%%%%%%%%%%%%%%%%%%   array num bool  CheeseWhiz   array  %%%%%%%%%%%%%%%%%
% CheeseWhiz traverses the flattened path as computed by Approx to find
% any points of intersection with the line y=Y1, where Y1 is it's num argument.
% It's boolean argument is true if y=Y1 bounds the region of interest "on top".
% For all points of intersection X1 goes on the stack, where [ X1 Y1 ]
% is the point, BUT ONLY IF the winding value or evenodd calculation says
% to. The winding value is complex and calculated from the sign of the slope.
% CheeseWhiz does this by breaking the path into line segments and passing
% it to CheeseY. The final array of X1 values is sorted, keeping duplicates.
/CheeseWhiz
{
  15 dict begin
  /ontop exch def
  /Y1 exch def
  [ exch
     {
        /oldx (Begin) def
        /flag false def
        {
           flag
           {
             /newy exch def
             oldx (Begin) eq
             { /firstx newx def /firsty newy def} { ontop CheeseY } ifelse
             /oldx newx def /oldy newy def
           }
           {
             /newx exch def
           } ifelse
           /flag flag not def
        } forall
        oldx (Begin) ne
        {
          /newx firstx def  % Even if the subpath is not closed, PostScript
          /newy firsty def  % fill methodology says close it. So wrap around.
          ontop CheeseY       
        } if
     } forall
  ]
  % Sort the array of X W values
  2 false SortArray
  % Now go through and take out X's where there is no inside/outside change
  [ exch
    fillout { LM exch } if
    /winding 0 def
    /inside false def   % always start off outside
    /flag false def
    {
      flag
      {
        winding add /winding exch def
        evenodd not
        {
          winding 0 eq inside xor
          { pop } { /inside inside not def } ifelse
        } if
      } if
      /flag flag not def
    } forall
    fillout { RM } if
  ]
  end  % temp dict 15
} def
%% End of PostScript Path-breaking Library