geomerative 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/LICENSE +662 -0
  4. data/LICENSE.md +9 -0
  5. data/README.md +2 -0
  6. data/Rakefile +37 -0
  7. data/examples/README.md +7 -0
  8. data/examples/data/FreeSans.ttf +0 -0
  9. data/examples/data/ReplicaBold.ttf +0 -0
  10. data/examples/data/bot1.svg +160 -0
  11. data/examples/hello_svg_to_pdf.rb +26 -0
  12. data/examples/hello_world.rb +23 -0
  13. data/examples/physics_type.rb +77 -0
  14. data/examples/rotate_first_letter.rb +28 -0
  15. data/geomerative.gemspec +32 -0
  16. data/lib/geomerative.rb +12 -0
  17. data/lib/geomerative/version.rb +3 -0
  18. data/pom.xml +110 -0
  19. data/src/geomerative/FastRClip.java +2715 -0
  20. data/src/geomerative/RClip.java +2892 -0
  21. data/src/geomerative/RClosest.java +64 -0
  22. data/src/geomerative/RCommand.java +1941 -0
  23. data/src/geomerative/RContour.java +348 -0
  24. data/src/geomerative/RFont.java +583 -0
  25. data/src/geomerative/RG.java +753 -0
  26. data/src/geomerative/RGeomElem.java +1075 -0
  27. data/src/geomerative/RGroup.java +888 -0
  28. data/src/geomerative/RMatrix.java +401 -0
  29. data/src/geomerative/RMesh.java +420 -0
  30. data/src/geomerative/RPath.java +1095 -0
  31. data/src/geomerative/RPoint.java +419 -0
  32. data/src/geomerative/RPolygon.java +1110 -0
  33. data/src/geomerative/RRectangle.java +91 -0
  34. data/src/geomerative/RSVG.java +976 -0
  35. data/src/geomerative/RShape.java +2045 -0
  36. data/src/geomerative/RStrip.java +221 -0
  37. data/src/geomerative/RStyle.java +469 -0
  38. data/src/org/apache/batik/svggen/font/.SVGFont.java.swp +0 -0
  39. data/src/org/apache/batik/svggen/font/Font.java +188 -0
  40. data/src/org/apache/batik/svggen/font/Glyph.java +113 -0
  41. data/src/org/apache/batik/svggen/font/Messages.java.bak +72 -0
  42. data/src/org/apache/batik/svggen/font/Point.java +38 -0
  43. data/src/org/apache/batik/svggen/font/RandomAccessFileEmulator.java +15 -0
  44. data/src/org/apache/batik/svggen/font/table/ClassDef.java +42 -0
  45. data/src/org/apache/batik/svggen/font/table/ClassDefFormat1.java +55 -0
  46. data/src/org/apache/batik/svggen/font/table/ClassDefFormat2.java +49 -0
  47. data/src/org/apache/batik/svggen/font/table/CmapFormat.java +81 -0
  48. data/src/org/apache/batik/svggen/font/table/CmapFormat0.java +60 -0
  49. data/src/org/apache/batik/svggen/font/table/CmapFormat2.java +48 -0
  50. data/src/org/apache/batik/svggen/font/table/CmapFormat4.java +147 -0
  51. data/src/org/apache/batik/svggen/font/table/CmapFormat6.java +60 -0
  52. data/src/org/apache/batik/svggen/font/table/CmapIndexEntry.java +84 -0
  53. data/src/org/apache/batik/svggen/font/table/CmapTable.java +87 -0
  54. data/src/org/apache/batik/svggen/font/table/Coverage.java +50 -0
  55. data/src/org/apache/batik/svggen/font/table/CoverageFormat1.java +59 -0
  56. data/src/org/apache/batik/svggen/font/table/CoverageFormat2.java +56 -0
  57. data/src/org/apache/batik/svggen/font/table/CvtTable.java +48 -0
  58. data/src/org/apache/batik/svggen/font/table/Device.java +63 -0
  59. data/src/org/apache/batik/svggen/font/table/DirectoryEntry.java +73 -0
  60. data/src/org/apache/batik/svggen/font/table/Feature.java +56 -0
  61. data/src/org/apache/batik/svggen/font/table/FeatureList.java +70 -0
  62. data/src/org/apache/batik/svggen/font/table/FeatureRecord.java +52 -0
  63. data/src/org/apache/batik/svggen/font/table/FeatureTags.java +30 -0
  64. data/src/org/apache/batik/svggen/font/table/FpgmTable.java +38 -0
  65. data/src/org/apache/batik/svggen/font/table/GlyfCompositeComp.java +165 -0
  66. data/src/org/apache/batik/svggen/font/table/GlyfCompositeDescript.java +160 -0
  67. data/src/org/apache/batik/svggen/font/table/GlyfDescript.java +79 -0
  68. data/src/org/apache/batik/svggen/font/table/GlyfSimpleDescript.java +155 -0
  69. data/src/org/apache/batik/svggen/font/table/GlyfTable.java +111 -0
  70. data/src/org/apache/batik/svggen/font/table/GlyphDescription.java +39 -0
  71. data/src/org/apache/batik/svggen/font/table/GposTable.java +80 -0
  72. data/src/org/apache/batik/svggen/font/table/GsubTable.java +118 -0
  73. data/src/org/apache/batik/svggen/font/table/HeadTable.java +159 -0
  74. data/src/org/apache/batik/svggen/font/table/HheaTable.java +109 -0
  75. data/src/org/apache/batik/svggen/font/table/HmtxTable.java +99 -0
  76. data/src/org/apache/batik/svggen/font/table/KernSubtable.java +58 -0
  77. data/src/org/apache/batik/svggen/font/table/KernSubtableFormat0.java +65 -0
  78. data/src/org/apache/batik/svggen/font/table/KernSubtableFormat2.java +56 -0
  79. data/src/org/apache/batik/svggen/font/table/KernTable.java +64 -0
  80. data/src/org/apache/batik/svggen/font/table/KerningPair.java +53 -0
  81. data/src/org/apache/batik/svggen/font/table/LangSys.java +58 -0
  82. data/src/org/apache/batik/svggen/font/table/LangSysRecord.java +52 -0
  83. data/src/org/apache/batik/svggen/font/table/Ligature.java +57 -0
  84. data/src/org/apache/batik/svggen/font/table/LigatureSet.java +55 -0
  85. data/src/org/apache/batik/svggen/font/table/LigatureSubst.java +40 -0
  86. data/src/org/apache/batik/svggen/font/table/LigatureSubstFormat1.java +63 -0
  87. data/src/org/apache/batik/svggen/font/table/LocaTable.java +72 -0
  88. data/src/org/apache/batik/svggen/font/table/Lookup.java +77 -0
  89. data/src/org/apache/batik/svggen/font/table/LookupList.java +68 -0
  90. data/src/org/apache/batik/svggen/font/table/LookupSubtable.java +27 -0
  91. data/src/org/apache/batik/svggen/font/table/LookupSubtableFactory.java +31 -0
  92. data/src/org/apache/batik/svggen/font/table/MaxpTable.java +124 -0
  93. data/src/org/apache/batik/svggen/font/table/NameRecord.java +98 -0
  94. data/src/org/apache/batik/svggen/font/table/NameTable.java +67 -0
  95. data/src/org/apache/batik/svggen/font/table/Os2Table.java +232 -0
  96. data/src/org/apache/batik/svggen/font/table/Panose.java +108 -0
  97. data/src/org/apache/batik/svggen/font/table/PostTable.java +379 -0
  98. data/src/org/apache/batik/svggen/font/table/PrepTable.java +38 -0
  99. data/src/org/apache/batik/svggen/font/table/Program.java +49 -0
  100. data/src/org/apache/batik/svggen/font/table/RangeRecord.java +57 -0
  101. data/src/org/apache/batik/svggen/font/table/Script.java +72 -0
  102. data/src/org/apache/batik/svggen/font/table/ScriptList.java +78 -0
  103. data/src/org/apache/batik/svggen/font/table/ScriptRecord.java +52 -0
  104. data/src/org/apache/batik/svggen/font/table/ScriptTags.java +28 -0
  105. data/src/org/apache/batik/svggen/font/table/SingleSubst.java +47 -0
  106. data/src/org/apache/batik/svggen/font/table/SingleSubstFormat1.java +67 -0
  107. data/src/org/apache/batik/svggen/font/table/SingleSubstFormat2.java +67 -0
  108. data/src/org/apache/batik/svggen/font/table/Table.java +204 -0
  109. data/src/org/apache/batik/svggen/font/table/TableDirectory.java +94 -0
  110. data/src/org/apache/batik/svggen/font/table/TableFactory.java +121 -0
  111. metadata +206 -0
@@ -0,0 +1,2892 @@
1
+ /*
2
+ * The SEI Software Open Source License, Version 1.0
3
+ *
4
+ * Copyright (c) 2004, Solution Engineering, Inc.
5
+ * All rights reserved.
6
+ *
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions
10
+ * are met:
11
+ *
12
+ * 1. Redistributions of source code must retain the above copyright
13
+ * notice, this list of conditions and the following disclaimer.
14
+ *
15
+ * 2. The end-user documentation included with the redistribution,
16
+ * if any, must include the following acknowledgment:
17
+ * "This product includes software developed by the
18
+ * Solution Engineering, Inc. (http://www.seisw.com/)."
19
+ * Alternately, this acknowledgment may appear in the software itself,
20
+ * if and wherever such third-party acknowledgments normally appear.
21
+ *
22
+ * 3. The name "Solution Engineering" must not be used to endorse or
23
+ * promote products derived from this software without prior
24
+ * written permission. For written permission, please contact
25
+ * admin@seisw.com.
26
+ *
27
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
28
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30
+ * DISCLAIMED. IN NO EVENT SHALL SOLUTION ENGINEERING, INC. OR
31
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
34
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
+ * SUCH DAMAGE.
39
+ * ====================================================================
40
+ */
41
+
42
+ package geomerative ;
43
+
44
+ import java.util.ArrayList ;
45
+ import java.util.List ;
46
+
47
+ /**
48
+ * <code>Clip</code> is a Java version of the <i>General RPolygon Clipper</i> algorithm
49
+ * developed by Alan Murta (gpc@cs.man.ac.uk). The home page for the original source can be
50
+ * found at <a href="http://www.cs.man.ac.uk/aig/staff/alan/software/" target="_blank">
51
+ * http://www.cs.man.ac.uk/aig/staff/alan/software/</a>.
52
+ * <p>
53
+ * <b><code>polyClass:</code></b> Some of the public methods below take a <code>polyClass</code>
54
+ * argument. This <code>java.lang.Class</code> object is assumed to implement the <code>RPolygon</code>
55
+ * interface and have a no argument constructor. This was done so that the user of the algorithm
56
+ * could create their own classes that implement the <code>RPolygon</code> interface and still uses
57
+ * this algorithm.
58
+ * <p>
59
+ * <strong>Implementation Note:</strong> The converted algorithm does support the <i>difference</i>
60
+ * operation, but a public method has not been provided and it has not been tested. To do so,
61
+ * simply follow what has been done for <i>intersection</i>.
62
+ *
63
+ * @author Dan Bridenbecker, Solution Engineering, Inc.
64
+ */
65
+ class RClip
66
+ {
67
+ // -----------------
68
+ // --- Constants ---
69
+ // -----------------
70
+ private static final boolean DEBUG = false ;
71
+
72
+ // Maximum precision for floats
73
+ private static final double GPC_EPSILON = 2.2204460492503131e-016 ;
74
+ //private static final float GPC_EPSILON = 1.192092896e-07F;
75
+ static final String GPC_VERSION = "2.31";
76
+
77
+ private static final int LEFT = 0 ;
78
+ private static final int RIGHT = 1 ;
79
+
80
+ private static final int ABOVE = 0 ;
81
+ private static final int BELOW = 1 ;
82
+
83
+ private static final int CLIP = 0 ;
84
+ private static final int SUBJ = 1 ;
85
+
86
+ private static final boolean INVERT_TRISTRIPS = false ;
87
+
88
+ // ------------------------
89
+ // --- Member Variables ---
90
+ // ------------------------
91
+
92
+ // --------------------
93
+ // --- Constructors ---
94
+ // --------------------
95
+ /** Creates a new instance of Clip */
96
+ private RClip()
97
+ {
98
+ }
99
+
100
+ // ----------------------
101
+ // --- Static Methods ---
102
+ // ----------------------
103
+ /**
104
+ * Return the intersection of <code>p1</code> and <code>p2</code> where the
105
+ * return type is of <code>polyClass</code>. See the note in the class description
106
+ * for more on <ocde>polyClass</code>.
107
+ *
108
+ * @param p1 One of the polygons to performt he intersection with
109
+ * @param p2 One of the polygons to performt he intersection with
110
+ * @param polyClass The type of <code>RPolygon</code> to return
111
+ */
112
+ static RPolygon intersection( RPolygon p1, RPolygon p2, Class polyClass )
113
+ {
114
+ return clip( OperationType.GPC_INT, p1, p2, polyClass );
115
+ }
116
+
117
+ /**
118
+ * Return the union of <code>p1</code> and <code>p2</code> where the
119
+ * return type is of <code>polyClass</code>. See the note in the class description
120
+ * for more on <ocde>polyClass</code>.
121
+ *
122
+ * @param p1 One of the polygons to performt he union with
123
+ * @param p2 One of the polygons to performt he union with
124
+ * @param polyClass The type of <code>RPolygon</code> to return
125
+ */
126
+ static RPolygon union( RPolygon p1, RPolygon p2, Class polyClass )
127
+ {
128
+ return clip( OperationType.GPC_UNION, p1, p2, polyClass );
129
+ }
130
+
131
+ /**
132
+ * Return the xor of <code>p1</code> and <code>p2</code> where the
133
+ * return type is of <code>polyClass</code>. See the note in the class description
134
+ * for more on <ocde>polyClass</code>.
135
+ *
136
+ * @param p1 One of the polygons to performt he xor with
137
+ * @param p2 One of the polygons to performt he xor with
138
+ * @param polyClass The type of <code>RPolygon</code> to return
139
+ */
140
+ static RPolygon xor( RPolygon p1, RPolygon p2, Class polyClass )
141
+ {
142
+ return clip( OperationType.GPC_XOR, p1, p2, polyClass );
143
+ }
144
+
145
+ /**
146
+ * Return the diff of <code>p1</code> and <code>p2</code> where the
147
+ * return type is of <code>polyClass</code>. See the note in the class description
148
+ * for more on <ocde>polyClass</code>.
149
+ *
150
+ * @param p1 One of the polygons to performt he diff with
151
+ * @param p2 One of the polygons to performt he diff with
152
+ * @param polyClass The type of <code>RPolygon</code> to return
153
+ */
154
+ static RPolygon diff( RPolygon p1, RPolygon p2, Class polyClass )
155
+ {
156
+ return clip( OperationType.GPC_DIFF, p1, p2, polyClass );
157
+ }
158
+
159
+ /**
160
+ * Return the intersection of <code>p1</code> and <code>p2</code> where the
161
+ * return type is of <code>PolyDefault</code>.
162
+ *
163
+ * @param p1 One of the polygons to performt he intersection with
164
+ * @param p2 One of the polygons to performt he intersection with
165
+ */
166
+ static RPolygon intersection( RPolygon p1, RPolygon p2 )
167
+ {
168
+ return clip( OperationType.GPC_INT, p1, p2, RPolygon.class );
169
+ }
170
+
171
+ /**
172
+ * Return the union of <code>p1</code> and <code>p2</code> where the
173
+ * return type is of <code>PolyDefault</code>.
174
+ *
175
+ * @param p1 One of the polygons to performt he union with
176
+ * @param p2 One of the polygons to performt he union with
177
+ */
178
+ static RPolygon union( RPolygon p1, RPolygon p2 )
179
+ {
180
+ return clip( OperationType.GPC_UNION, p1, p2, RPolygon.class );
181
+ }
182
+
183
+ /**
184
+ * Return the xor of <code>p1</code> and <code>p2</code> where the
185
+ * return type is of <code>PolyDefault</code>.
186
+ *
187
+ * @param p1 One of the polygons to performt he xor with
188
+ * @param p2 One of the polygons to performt he xor with
189
+ */
190
+ static RPolygon xor( RPolygon p1, RPolygon p2 )
191
+ {
192
+ return clip( OperationType.GPC_XOR, p1, p2, RPolygon.class );
193
+ }
194
+
195
+ /**
196
+ * Return the diff of <code>p1</code> and <code>p2</code> where the
197
+ * return type is of <code>PolyDefault</code>.
198
+ *
199
+ * @param p1 One of the polygons to performt he diff with
200
+ * @param p2 One of the polygons to performt he diff with
201
+ */
202
+ static RPolygon diff( RPolygon p1, RPolygon p2 )
203
+ {
204
+ return clip( OperationType.GPC_DIFF, p1, p2, RPolygon.class );
205
+ }
206
+
207
+ /**
208
+ * Updates <code>p1</code>.
209
+ *
210
+ * @param p1 One of the polygons to performt he diff with
211
+ */
212
+ static RPolygon update( RPolygon p1 )
213
+ {
214
+ return clip( OperationType.GPC_DIFF, p1, new RPolygon(), RPolygon.class );
215
+ }
216
+
217
+
218
+ // -----------------------
219
+ // --- Private Methods ---
220
+ // -----------------------
221
+
222
+ /**
223
+ * Create a new <code>RPolygon</code> type object using <code>polyClass</code>.
224
+ */
225
+ private static RPolygon createNewPoly( Class polyClass )
226
+ {
227
+ try
228
+ {
229
+ return (RPolygon)polyClass.newInstance();
230
+ }
231
+ catch( InstantiationException | IllegalAccessException e )
232
+ {
233
+ throw new RuntimeException(e);
234
+ }
235
+ }
236
+
237
+ /**
238
+ * <code>clip()</code> is the main method of the clipper algorithm.
239
+ * This is where the conversion from really begins.
240
+ */
241
+ private static RPolygon clip( OperationType op, RPolygon subj, RPolygon clip, Class polyClass )
242
+ {
243
+ if(RG.useFastClip) {
244
+ return FastRClip.clip(op, subj, clip, polyClass);
245
+ }
246
+
247
+ RPolygon result = createNewPoly( polyClass ) ;
248
+
249
+ /* Test for trivial NULL result cases */
250
+ if( (subj.isEmpty() && clip.isEmpty()) ||
251
+ (subj.isEmpty() && ((op == OperationType.GPC_INT) || (op == OperationType.GPC_DIFF))) ||
252
+ (clip.isEmpty() && (op == OperationType.GPC_INT)) )
253
+ {
254
+ return result ;
255
+ }
256
+
257
+ /* Identify potentialy contributing contours */
258
+ if( ((op == OperationType.GPC_INT) || (op == OperationType.GPC_DIFF)) &&
259
+ !subj.isEmpty() && !clip.isEmpty() )
260
+ {
261
+ minimax_test(subj, clip, op);
262
+ }
263
+
264
+ /* Build LMT */
265
+ LmtTable lmt_table = new LmtTable();
266
+ ScanBeamTreeEntries sbte = new ScanBeamTreeEntries();
267
+ if (!subj.isEmpty())
268
+ {
269
+ build_lmt(lmt_table, sbte, subj, SUBJ, op);
270
+ }
271
+ if( DEBUG )
272
+ {
273
+ System.out.println("");
274
+ System.out.println(" ------------ After build_lmt for subj ---------");
275
+ lmt_table.print();
276
+ }
277
+ if (!clip.isEmpty())
278
+ {
279
+ build_lmt(lmt_table, sbte, clip, CLIP, op);
280
+ }
281
+ if( DEBUG )
282
+ {
283
+ System.out.println("");
284
+ System.out.println(" ------------ After build_lmt for clip ---------");
285
+ lmt_table.print();
286
+ }
287
+
288
+ /* Return a NULL result if no contours contribute */
289
+ if (lmt_table.top_node == null)
290
+ {
291
+ return result;
292
+ }
293
+
294
+ /* Build scanbeam table from scanbeam tree */
295
+ float[] sbt = sbte.build_sbt();
296
+
297
+ int[] parity = new int[2] ;
298
+ parity[0] = LEFT ;
299
+ parity[1] = LEFT ;
300
+
301
+ /* Invert clip polygon for difference operation */
302
+ if (op == OperationType.GPC_DIFF)
303
+ {
304
+ parity[CLIP]= RIGHT;
305
+ }
306
+
307
+ if( DEBUG )
308
+ {
309
+ print_sbt(sbt);
310
+ }
311
+
312
+ LmtNode local_min = lmt_table.top_node ;
313
+
314
+ TopPolygonNode out_poly = new TopPolygonNode(); // used to create resulting RPolygon
315
+
316
+ AetTree aet = new AetTree();
317
+ int scanbeam = 0 ;
318
+
319
+ /* Process each scanbeam */
320
+ while( scanbeam < sbt.length )
321
+ {
322
+ /* Set yb and yt to the bottom and top of the scanbeam */
323
+ float yb = sbt[scanbeam++];
324
+ float yt = 0.0F ;
325
+ float dy = 0.0F ;
326
+ if( scanbeam < sbt.length )
327
+ {
328
+ yt = sbt[scanbeam];
329
+ dy = yt - yb;
330
+ }
331
+
332
+ /* === SCANBEAM BOUNDARY PROCESSING ================================ */
333
+
334
+ /* If LMT node corresponding to yb exists */
335
+ if (local_min != null )
336
+ {
337
+ if (local_min.y == yb)
338
+ {
339
+ /* Add edges starting at this local minimum to the AET */
340
+ for( EdgeNode edge = local_min.first_bound; (edge != null) ; edge= edge.next_bound)
341
+ {
342
+ add_edge_to_aet( aet, edge );
343
+ }
344
+
345
+ local_min = local_min.next;
346
+ }
347
+ }
348
+
349
+ if( DEBUG )
350
+ {
351
+ aet.print();
352
+ }
353
+ /* Set dummy previous x value */
354
+ float px = -Float.MAX_VALUE ;
355
+
356
+ /* Create bundles within AET */
357
+ EdgeNode e0 = aet.top_node ;
358
+ EdgeNode e1 = aet.top_node ;
359
+
360
+ /* Set up bundle fields of first edge */
361
+ aet.top_node.bundle[ABOVE][ aet.top_node.type ] = (aet.top_node.top.y != yb) ? 1 : 0;
362
+ aet.top_node.bundle[ABOVE][ ((aet.top_node.type==0) ? 1 : 0) ] = 0;
363
+ aet.top_node.bstate[ABOVE] = BundleState.UNBUNDLED;
364
+
365
+ for (EdgeNode next_edge= aet.top_node.next ; (next_edge != null); next_edge = next_edge.next)
366
+ {
367
+ int ne_type = next_edge.type ;
368
+ int ne_type_opp = ((next_edge.type==0) ? 1 : 0); //next edge type opposite
369
+
370
+ /* Set up bundle fields of next edge */
371
+ next_edge.bundle[ABOVE][ ne_type ]= (next_edge.top.y != yb) ? 1 : 0;
372
+ next_edge.bundle[ABOVE][ ne_type_opp ] = 0 ;
373
+ next_edge.bstate[ABOVE] = BundleState.UNBUNDLED;
374
+
375
+ /* Bundle edges above the scanbeam boundary if they coincide */
376
+ if ( next_edge.bundle[ABOVE][ne_type] == 1 )
377
+ {
378
+ if (EQ(e0.xb, next_edge.xb) && EQ(e0.dx, next_edge.dx) && (e0.top.y != yb))
379
+ {
380
+ next_edge.bundle[ABOVE][ ne_type ] ^= e0.bundle[ABOVE][ ne_type ];
381
+ next_edge.bundle[ABOVE][ ne_type_opp ] = e0.bundle[ABOVE][ ne_type_opp ];
382
+ next_edge.bstate[ABOVE] = BundleState.BUNDLE_HEAD;
383
+ e0.bundle[ABOVE][CLIP] = 0;
384
+ e0.bundle[ABOVE][SUBJ] = 0;
385
+ e0.bstate[ABOVE] = BundleState.BUNDLE_TAIL;
386
+ }
387
+ e0 = next_edge;
388
+ }
389
+ }
390
+
391
+ int[] horiz = new int[2] ;
392
+ horiz[CLIP]= HState.NH;
393
+ horiz[SUBJ]= HState.NH;
394
+
395
+ int[] exists = new int[2] ;
396
+ exists[CLIP] = 0 ;
397
+ exists[SUBJ] = 0 ;
398
+
399
+ PolygonNode cf = null ;
400
+
401
+ /* Process each edge at this scanbeam boundary */
402
+ for (EdgeNode edge= aet.top_node ; (edge != null); edge = edge.next )
403
+ {
404
+ exists[CLIP] = edge.bundle[ABOVE][CLIP] + (edge.bundle[BELOW][CLIP] << 1);
405
+ exists[SUBJ] = edge.bundle[ABOVE][SUBJ] + (edge.bundle[BELOW][SUBJ] << 1);
406
+
407
+ if( (exists[CLIP] != 0) || (exists[SUBJ] != 0) )
408
+ {
409
+ /* Set bundle side */
410
+ edge.bside[CLIP] = parity[CLIP];
411
+ edge.bside[SUBJ] = parity[SUBJ];
412
+
413
+ boolean contributing = false ;
414
+ int br=0, bl=0, tr=0, tl=0 ;
415
+ /* Determine contributing status and quadrant occupancies */
416
+ if( (op == OperationType.GPC_DIFF) || (op == OperationType.GPC_INT) )
417
+ {
418
+ contributing= ((exists[CLIP]!=0) && ((parity[SUBJ]!=0) || (horiz[SUBJ]!=0))) ||
419
+ ((exists[SUBJ]!=0) && ((parity[CLIP]!=0) || (horiz[CLIP]!=0))) ||
420
+ ((exists[CLIP]!=0) && (exists[SUBJ]!=0) && (parity[CLIP] == parity[SUBJ]));
421
+ br = ((parity[CLIP]!=0) && (parity[SUBJ]!=0)) ? 1 : 0;
422
+ bl = ( ((parity[CLIP] ^ edge.bundle[ABOVE][CLIP])!=0) &&
423
+ ((parity[SUBJ] ^ edge.bundle[ABOVE][SUBJ])!=0) ) ? 1 : 0;
424
+ tr = ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0)) !=0) &&
425
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0)) !=0) ) ? 1 : 0;
426
+ tl = (((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW][CLIP])!=0) &&
427
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW][SUBJ])!=0))?1:0;
428
+ }
429
+ else if( op == OperationType.GPC_XOR )
430
+ {
431
+ contributing= (exists[CLIP]!=0) || (exists[SUBJ]!=0);
432
+ br= (parity[CLIP]) ^ (parity[SUBJ]);
433
+ bl= (parity[CLIP] ^ edge.bundle[ABOVE][CLIP]) ^ (parity[SUBJ] ^ edge.bundle[ABOVE][SUBJ]);
434
+ tr= (parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0)) ^ (parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0));
435
+ tl= (parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW][CLIP])
436
+ ^ (parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW][SUBJ]);
437
+ }
438
+ else if( op == OperationType.GPC_UNION )
439
+ {
440
+ contributing= ((exists[CLIP]!=0) && (!(parity[SUBJ]!=0) || (horiz[SUBJ]!=0))) ||
441
+ ((exists[SUBJ]!=0) && (!(parity[CLIP]!=0) || (horiz[CLIP]!=0))) ||
442
+ ((exists[CLIP]!=0) && (exists[SUBJ]!=0) && (parity[CLIP] == parity[SUBJ]));
443
+ br= ((parity[CLIP]!=0) || (parity[SUBJ]!=0))?1:0;
444
+ bl= (((parity[CLIP] ^ edge.bundle[ABOVE][CLIP])!=0) || ((parity[SUBJ] ^ edge.bundle[ABOVE][SUBJ])!=0))?1:0;
445
+ tr= ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0))!=0) ||
446
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0))!=0) ) ?1:0;
447
+ tl= ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW][CLIP])!=0) ||
448
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW][SUBJ])!=0) ) ? 1:0;
449
+ }
450
+ else
451
+ {
452
+ throw new IllegalStateException("Unknown op");
453
+ }
454
+
455
+ /* Update parity */
456
+ parity[CLIP] ^= edge.bundle[ABOVE][CLIP];
457
+ parity[SUBJ] ^= edge.bundle[ABOVE][SUBJ];
458
+
459
+ /* Update horizontal state */
460
+ if (exists[CLIP]!=0)
461
+ {
462
+ horiz[CLIP] = HState.next_h_state[horiz[CLIP]][((exists[CLIP] - 1) << 1) + parity[CLIP]];
463
+ }
464
+ if( exists[SUBJ]!=0)
465
+ {
466
+ horiz[SUBJ] = HState.next_h_state[horiz[SUBJ]][((exists[SUBJ] - 1) << 1) + parity[SUBJ]];
467
+ }
468
+
469
+ if (contributing)
470
+ {
471
+ float xb = edge.xb;
472
+
473
+ int vclass = VertexType.getType( tr, tl, br, bl );
474
+ switch (vclass)
475
+ {
476
+ case VertexType.EMN:
477
+ case VertexType.IMN:
478
+ edge.outp[ABOVE] = out_poly.add_local_min(xb, yb);
479
+ px = xb;
480
+ cf = edge.outp[ABOVE];
481
+ break;
482
+ case VertexType.ERI:
483
+ if (xb != px)
484
+ {
485
+ cf.add_right( xb, yb);
486
+ px= xb;
487
+ }
488
+ edge.outp[ABOVE]= cf;
489
+ cf= null;
490
+ break;
491
+ case VertexType.ELI:
492
+ edge.outp[BELOW].add_left( xb, yb);
493
+ px= xb;
494
+ cf= edge.outp[BELOW];
495
+ break;
496
+ case VertexType.EMX:
497
+ if (xb != px)
498
+ {
499
+ cf.add_left( xb, yb);
500
+ px= xb;
501
+ }
502
+ out_poly.merge_right(cf, edge.outp[BELOW]);
503
+ cf= null;
504
+ break;
505
+ case VertexType.ILI:
506
+ if (xb != px)
507
+ {
508
+ cf.add_left( xb, yb);
509
+ px= xb;
510
+ }
511
+ edge.outp[ABOVE]= cf;
512
+ cf= null;
513
+ break;
514
+ case VertexType.IRI:
515
+ edge.outp[BELOW].add_right( xb, yb );
516
+ px= xb;
517
+ cf= edge.outp[BELOW];
518
+ edge.outp[BELOW]= null;
519
+ break;
520
+ case VertexType.IMX:
521
+ if (xb != px)
522
+ {
523
+ cf.add_right( xb, yb );
524
+ px= xb;
525
+ }
526
+ out_poly.merge_left(cf, edge.outp[BELOW]);
527
+ cf= null;
528
+ edge.outp[BELOW]= null;
529
+ break;
530
+ case VertexType.IMM:
531
+ if (xb != px)
532
+ {
533
+ cf.add_right( xb, yb);
534
+ px= xb;
535
+ }
536
+ out_poly.merge_left(cf, edge.outp[BELOW]);
537
+ edge.outp[BELOW]= null;
538
+ edge.outp[ABOVE] = out_poly.add_local_min(xb, yb);
539
+ cf= edge.outp[ABOVE];
540
+ break;
541
+ case VertexType.EMM:
542
+ if (xb != px)
543
+ {
544
+ cf.add_left( xb, yb);
545
+ px= xb;
546
+ }
547
+ out_poly.merge_right(cf, edge.outp[BELOW]);
548
+ edge.outp[BELOW]= null;
549
+ edge.outp[ABOVE] = out_poly.add_local_min(xb, yb);
550
+ cf= edge.outp[ABOVE];
551
+ break;
552
+ case VertexType.LED:
553
+ if (edge.bot.y == yb)
554
+ edge.outp[BELOW].add_left( xb, yb);
555
+ edge.outp[ABOVE]= edge.outp[BELOW];
556
+ px= xb;
557
+ break;
558
+ case VertexType.RED:
559
+ if (edge.bot.y == yb)
560
+ edge.outp[BELOW].add_right( xb, yb );
561
+ edge.outp[ABOVE]= edge.outp[BELOW];
562
+ px= xb;
563
+ break;
564
+ default:
565
+ break;
566
+ } /* End of switch */
567
+ } /* End of contributing conditional */
568
+ } /* End of edge exists conditional */
569
+ if( DEBUG )
570
+ {
571
+ out_poly.print();
572
+ }
573
+ } /* End of AET loop */
574
+
575
+ /* Delete terminating edges from the AET, otherwise compute xt */
576
+ for (EdgeNode edge = aet.top_node ; (edge != null); edge = edge.next)
577
+ {
578
+ if (edge.top.y == yb)
579
+ {
580
+ EdgeNode prev_edge = edge.prev;
581
+ EdgeNode next_edge= edge.next;
582
+
583
+ if (prev_edge != null)
584
+ prev_edge.next = next_edge;
585
+ else
586
+ aet.top_node = next_edge;
587
+
588
+ if (next_edge != null )
589
+ next_edge.prev = prev_edge;
590
+
591
+ /* Copy bundle head state to the adjacent tail edge if required */
592
+ if ((edge.bstate[BELOW] == BundleState.BUNDLE_HEAD) && (prev_edge!=null))
593
+ {
594
+ if (prev_edge.bstate[BELOW] == BundleState.BUNDLE_TAIL)
595
+ {
596
+ prev_edge.outp[BELOW]= edge.outp[BELOW];
597
+ prev_edge.bstate[BELOW]= BundleState.UNBUNDLED;
598
+ if ( prev_edge.prev != null)
599
+ {
600
+ if (prev_edge.prev.bstate[BELOW] == BundleState.BUNDLE_TAIL)
601
+ {
602
+ prev_edge.bstate[BELOW] = BundleState.BUNDLE_HEAD;
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
+ else
609
+ {
610
+ if (edge.top.y == yt)
611
+ edge.xt= edge.top.x;
612
+ else
613
+ edge.xt= edge.bot.x + edge.dx * (yt - edge.bot.y);
614
+ }
615
+ }
616
+
617
+ if (scanbeam < sbte.sbt_entries )
618
+ {
619
+ /* === SCANBEAM INTERIOR PROCESSING ============================== */
620
+
621
+ /* Build intersection table for the current scanbeam */
622
+ ItNodeTable it_table = new ItNodeTable();
623
+ it_table.build_intersection_table(aet, dy);
624
+
625
+ /* Process each node in the intersection table */
626
+ for (ItNode intersect = it_table.top_node ; (intersect != null); intersect = intersect.next)
627
+ {
628
+ e0= intersect.ie[0];
629
+ e1= intersect.ie[1];
630
+
631
+ /* Only generate output for contributing intersections */
632
+ if ( ((e0.bundle[ABOVE][CLIP]!=0) || (e0.bundle[ABOVE][SUBJ]!=0)) &&
633
+ ((e1.bundle[ABOVE][CLIP]!=0) || (e1.bundle[ABOVE][SUBJ]!=0)))
634
+ {
635
+ PolygonNode p = e0.outp[ABOVE];
636
+ PolygonNode q = e1.outp[ABOVE];
637
+ float ix = intersect.point.x;
638
+ float iy = intersect.point.y + yb;
639
+
640
+ int in_clip = ( ( (e0.bundle[ABOVE][CLIP]!=0) && !(e0.bside[CLIP]!=0)) ||
641
+ ( (e1.bundle[ABOVE][CLIP]!=0) && (e1.bside[CLIP]!=0)) ||
642
+ (!(e0.bundle[ABOVE][CLIP]!=0) && !(e1.bundle[ABOVE][CLIP]!=0) &&
643
+ (e0.bside[CLIP]!=0) && (e1.bside[CLIP]!=0) ) ) ? 1 : 0;
644
+
645
+ int in_subj = ( ( (e0.bundle[ABOVE][SUBJ]!=0) && !(e0.bside[SUBJ]!=0)) ||
646
+ ( (e1.bundle[ABOVE][SUBJ]!=0) && (e1.bside[SUBJ]!=0)) ||
647
+ (!(e0.bundle[ABOVE][SUBJ]!=0) && !(e1.bundle[ABOVE][SUBJ]!=0) &&
648
+ (e0.bside[SUBJ]!=0) && (e1.bside[SUBJ]!=0) ) ) ? 1 : 0;
649
+
650
+ int tr=0, tl=0, br=0, bl=0 ;
651
+ /* Determine quadrant occupancies */
652
+ if( (op == OperationType.GPC_DIFF) || (op == OperationType.GPC_INT) )
653
+ {
654
+ tr= ((in_clip!=0) && (in_subj!=0)) ? 1 : 0;
655
+ tl= (((in_clip ^ e1.bundle[ABOVE][CLIP])!=0) && ((in_subj ^ e1.bundle[ABOVE][SUBJ])!=0))?1:0;
656
+ br= (((in_clip ^ e0.bundle[ABOVE][CLIP])!=0) && ((in_subj ^ e0.bundle[ABOVE][SUBJ])!=0))?1:0;
657
+ bl= (((in_clip ^ e1.bundle[ABOVE][CLIP] ^ e0.bundle[ABOVE][CLIP])!=0) &&
658
+ ((in_subj ^ e1.bundle[ABOVE][SUBJ] ^ e0.bundle[ABOVE][SUBJ])!=0) ) ? 1:0;
659
+ }
660
+ else if( op == OperationType.GPC_XOR )
661
+ {
662
+ tr= (in_clip)^ (in_subj);
663
+ tl= (in_clip ^ e1.bundle[ABOVE][CLIP]) ^ (in_subj ^ e1.bundle[ABOVE][SUBJ]);
664
+ br= (in_clip ^ e0.bundle[ABOVE][CLIP]) ^ (in_subj ^ e0.bundle[ABOVE][SUBJ]);
665
+ bl= (in_clip ^ e1.bundle[ABOVE][CLIP] ^ e0.bundle[ABOVE][CLIP])
666
+ ^ (in_subj ^ e1.bundle[ABOVE][SUBJ] ^ e0.bundle[ABOVE][SUBJ]);
667
+ }
668
+ else if( op == OperationType.GPC_UNION )
669
+ {
670
+ tr= ((in_clip!=0) || (in_subj!=0)) ? 1 : 0;
671
+ tl= (((in_clip ^ e1.bundle[ABOVE][CLIP])!=0) || ((in_subj ^ e1.bundle[ABOVE][SUBJ])!=0)) ? 1 : 0;
672
+ br= (((in_clip ^ e0.bundle[ABOVE][CLIP])!=0) || ((in_subj ^ e0.bundle[ABOVE][SUBJ])!=0)) ? 1 : 0;
673
+ bl= (((in_clip ^ e1.bundle[ABOVE][CLIP] ^ e0.bundle[ABOVE][CLIP])!=0) ||
674
+ ((in_subj ^ e1.bundle[ABOVE][SUBJ] ^ e0.bundle[ABOVE][SUBJ])!=0)) ? 1 : 0;
675
+ }
676
+ else
677
+ {
678
+ throw new IllegalStateException("Unknown op type, "+op);
679
+ }
680
+
681
+ int vclass = VertexType.getType( tr, tl, br, bl );
682
+ switch (vclass)
683
+ {
684
+ case VertexType.EMN:
685
+ e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
686
+ e1.outp[ABOVE] = e0.outp[ABOVE];
687
+ break;
688
+ case VertexType.ERI:
689
+ if (p != null)
690
+ {
691
+ p.add_right(ix, iy);
692
+ e1.outp[ABOVE]= p;
693
+ e0.outp[ABOVE]= null;
694
+ }
695
+ break;
696
+ case VertexType.ELI:
697
+ if (q != null)
698
+ {
699
+ q.add_left(ix, iy);
700
+ e0.outp[ABOVE]= q;
701
+ e1.outp[ABOVE]= null;
702
+ }
703
+ break;
704
+ case VertexType.EMX:
705
+ if ((p!=null) && (q!=null))
706
+ {
707
+ p.add_left( ix, iy);
708
+ out_poly.merge_right(p, q);
709
+ e0.outp[ABOVE]= null;
710
+ e1.outp[ABOVE]= null;
711
+ }
712
+ break;
713
+ case VertexType.IMN:
714
+ e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
715
+ e1.outp[ABOVE]= e0.outp[ABOVE];
716
+ break;
717
+ case VertexType.ILI:
718
+ if (p != null)
719
+ {
720
+ p.add_left(ix, iy);
721
+ e1.outp[ABOVE]= p;
722
+ e0.outp[ABOVE]= null;
723
+ }
724
+ break;
725
+ case VertexType.IRI:
726
+ if (q!=null)
727
+ {
728
+ q.add_right(ix, iy);
729
+ e0.outp[ABOVE]= q;
730
+ e1.outp[ABOVE]= null;
731
+ }
732
+ break;
733
+ case VertexType.IMX:
734
+ if ((p!=null) && (q!=null))
735
+ {
736
+ p.add_right(ix, iy);
737
+ out_poly.merge_left(p, q);
738
+ e0.outp[ABOVE]= null;
739
+ e1.outp[ABOVE]= null;
740
+ }
741
+ break;
742
+ case VertexType.IMM:
743
+ if ((p!=null) && (q!=null))
744
+ {
745
+ p.add_right(ix, iy);
746
+ out_poly.merge_left(p, q);
747
+ e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
748
+ e1.outp[ABOVE]= e0.outp[ABOVE];
749
+ }
750
+ break;
751
+ case VertexType.EMM:
752
+ if ((p!=null) && (q!=null))
753
+ {
754
+ p.add_left(ix, iy);
755
+ out_poly.merge_right(p, q);
756
+ e0.outp[ABOVE] = out_poly.add_local_min(ix, iy);
757
+ e1.outp[ABOVE] = e0.outp[ABOVE];
758
+ }
759
+ break;
760
+ default:
761
+ break;
762
+ } /* End of switch */
763
+ } /* End of contributing intersection conditional */
764
+
765
+ /* Swap bundle sides in response to edge crossing */
766
+ if (e0.bundle[ABOVE][CLIP]!=0)
767
+ e1.bside[CLIP] = (e1.bside[CLIP]==0)?1:0;
768
+ if (e1.bundle[ABOVE][CLIP]!=0)
769
+ e0.bside[CLIP]= (e0.bside[CLIP]==0)?1:0;
770
+ if (e0.bundle[ABOVE][SUBJ]!=0)
771
+ e1.bside[SUBJ]= (e1.bside[SUBJ]==0)?1:0;
772
+ if (e1.bundle[ABOVE][SUBJ]!=0)
773
+ e0.bside[SUBJ]= (e0.bside[SUBJ]==0)?1:0;
774
+
775
+ /* Swap e0 and e1 bundles in the AET */
776
+ EdgeNode prev_edge = e0.prev;
777
+ EdgeNode next_edge = e1.next;
778
+ if (next_edge != null)
779
+ {
780
+ next_edge.prev = e0;
781
+ }
782
+
783
+ if (e0.bstate[ABOVE] == BundleState.BUNDLE_HEAD)
784
+ {
785
+ boolean search = true;
786
+ while (search)
787
+ {
788
+ prev_edge= prev_edge.prev;
789
+ if (prev_edge != null)
790
+ {
791
+ if (prev_edge.bstate[ABOVE] != BundleState.BUNDLE_TAIL)
792
+ {
793
+ search= false;
794
+ }
795
+ }
796
+ else
797
+ {
798
+ search= false;
799
+ }
800
+ }
801
+ }
802
+ if (prev_edge == null)
803
+ {
804
+ aet.top_node.prev = e1;
805
+ e1.next = aet.top_node;
806
+ aet.top_node = e0.next;
807
+ }
808
+ else
809
+ {
810
+ prev_edge.next.prev = e1;
811
+ e1.next = prev_edge.next;
812
+ prev_edge.next = e0.next;
813
+ }
814
+ e0.next.prev = prev_edge;
815
+ e1.next.prev = e1;
816
+ e0.next = next_edge;
817
+ if( DEBUG )
818
+ {
819
+ out_poly.print();
820
+ }
821
+ } /* End of IT loop*/
822
+
823
+ /* Prepare for next scanbeam */
824
+ for ( EdgeNode edge = aet.top_node; (edge != null); edge = edge.next)
825
+ {
826
+ EdgeNode next_edge = edge.next;
827
+ EdgeNode succ_edge = edge.succ;
828
+ if ((edge.top.y == yt) && (succ_edge!=null))
829
+ {
830
+ /* Replace AET edge by its successor */
831
+ succ_edge.outp[BELOW]= edge.outp[ABOVE];
832
+ succ_edge.bstate[BELOW]= edge.bstate[ABOVE];
833
+ succ_edge.bundle[BELOW][CLIP]= edge.bundle[ABOVE][CLIP];
834
+ succ_edge.bundle[BELOW][SUBJ]= edge.bundle[ABOVE][SUBJ];
835
+ EdgeNode prev_edge = edge.prev;
836
+ if ( prev_edge != null )
837
+ prev_edge.next = succ_edge;
838
+ else
839
+ aet.top_node = succ_edge;
840
+ if (next_edge != null)
841
+ next_edge.prev= succ_edge;
842
+ succ_edge.prev = prev_edge;
843
+ succ_edge.next = next_edge;
844
+ }
845
+ else
846
+ {
847
+ /* Update this edge */
848
+ edge.outp[BELOW]= edge.outp[ABOVE];
849
+ edge.bstate[BELOW]= edge.bstate[ABOVE];
850
+ edge.bundle[BELOW][CLIP]= edge.bundle[ABOVE][CLIP];
851
+ edge.bundle[BELOW][SUBJ]= edge.bundle[ABOVE][SUBJ];
852
+ edge.xb= edge.xt;
853
+ }
854
+ edge.outp[ABOVE]= null;
855
+ }
856
+ }
857
+ } /* === END OF SCANBEAM PROCESSING ================================== */
858
+
859
+ /* Generate result polygon from out_poly */
860
+ result = out_poly.getResult(polyClass);
861
+
862
+ return result ;
863
+ }
864
+
865
+ /**
866
+ * Clipper to output tristrips
867
+ */
868
+ private static RMesh clip( OperationType op, RPolygon subj, RPolygon clip )
869
+ {
870
+ if(RG.useFastClip) {
871
+ return FastRClip.clip(op, subj, clip);
872
+ }
873
+
874
+ PolygonNode tlist=null, tnn, tn;
875
+ EdgeNode prev_edge, next_edge, edge, cf=null, succ_edge, e0, e1;
876
+ VertexNode lt, ltn, rt, rtn;
877
+ int cft=VertexType.LED;
878
+ float []sbt;
879
+ float xb, px, nx=0, yb, yt, dy, ix, iy;
880
+
881
+ /* Test for trivial NULL result cases */
882
+ if( (subj.isEmpty() && clip.isEmpty()) ||
883
+ (subj.isEmpty() && ((op == OperationType.GPC_INT) || (op == OperationType.GPC_DIFF))) ||
884
+ (clip.isEmpty() && (op == OperationType.GPC_INT)) )
885
+ {
886
+ return new RMesh() ;
887
+ }
888
+
889
+ /* Identify potentialy contributing contours */
890
+ if( ((op == OperationType.GPC_INT) || (op == OperationType.GPC_DIFF)) &&
891
+ !subj.isEmpty() && !clip.isEmpty() )
892
+ {
893
+ minimax_test(subj, clip, op);
894
+ }
895
+
896
+ /* Build LMT */
897
+ LmtTable lmt_table = new LmtTable();
898
+ ScanBeamTreeEntries sbte = new ScanBeamTreeEntries();
899
+ if (!subj.isEmpty())
900
+ {
901
+ build_lmt(lmt_table, sbte, subj, SUBJ, op);
902
+ }
903
+ if( DEBUG )
904
+ {
905
+ System.out.println("");
906
+ System.out.println(" ------------ After build_lmt for subj ---------");
907
+ lmt_table.print();
908
+ }
909
+ if (!clip.isEmpty())
910
+ {
911
+ build_lmt(lmt_table, sbte, clip, CLIP, op);
912
+ }
913
+ if( DEBUG )
914
+ {
915
+ System.out.println("");
916
+ System.out.println(" ------------ After build_lmt for clip ---------");
917
+ lmt_table.print();
918
+ }
919
+
920
+ /* Return a NULL result if no contours contribute */
921
+ if (lmt_table.top_node == null)
922
+ {
923
+ return new RMesh();
924
+ }
925
+
926
+ /* Build scanbeam table from scanbeam tree */
927
+ sbt = sbte.build_sbt();
928
+
929
+ int[] parity = new int[2] ;
930
+ parity[0] = LEFT ;
931
+ parity[1] = LEFT ;
932
+
933
+ /* Invert clip polygon for difference operation */
934
+ if (op == OperationType.GPC_DIFF)
935
+ {
936
+ parity[CLIP]= RIGHT;
937
+ }
938
+
939
+ if( DEBUG )
940
+ {
941
+ print_sbt(sbt);
942
+ }
943
+
944
+ LmtNode local_min = lmt_table.top_node ;
945
+
946
+ AetTree aet = new AetTree();
947
+ int scanbeam = 0 ;
948
+
949
+ /* Process each scanbeam */
950
+ while( scanbeam < sbt.length )
951
+ {
952
+ /* Set yb and yt to the bottom and top of the scanbeam */
953
+ yb = sbt[scanbeam++];
954
+ yt = 0.0F ;
955
+ dy = 0.0F ;
956
+ if( scanbeam < sbt.length )
957
+ {
958
+ yt = sbt[scanbeam];
959
+ dy = yt - yb;
960
+ }
961
+
962
+ /* === SCANBEAM BOUNDARY PROCESSING ================================ */
963
+
964
+ /* If LMT node corresponding to yb exists */
965
+ if (local_min != null )
966
+ {
967
+ if (local_min.y == yb)
968
+ {
969
+ /* Add edges starting at this local minimum to the AET */
970
+ for( edge = local_min.first_bound; (edge != null) ; edge= edge.next_bound)
971
+ {
972
+ add_edge_to_aet( aet, edge );
973
+ }
974
+
975
+ local_min = local_min.next;
976
+ }
977
+ }
978
+
979
+ if( DEBUG )
980
+ {
981
+ aet.print();
982
+ }
983
+ /* Set dummy previous x value */
984
+ px = -Float.MAX_VALUE ;
985
+
986
+ /* Create bundles within AET */
987
+ e0 = aet.top_node ;
988
+ e1 = aet.top_node ;
989
+
990
+ /* Set up bundle fields of first edge */
991
+ aet.top_node.bundle[ABOVE][ aet.top_node.type ] = (aet.top_node.top.y != yb) ? 1 : 0;
992
+ aet.top_node.bundle[ABOVE][ ((aet.top_node.type==0) ? 1 : 0) ] = 0;
993
+ aet.top_node.bstate[ABOVE] = BundleState.UNBUNDLED;
994
+
995
+ for (next_edge= aet.top_node.next ; (next_edge != null); next_edge = next_edge.next)
996
+ {
997
+ int ne_type = next_edge.type ;
998
+ int ne_type_opp = ((next_edge.type==0) ? 1 : 0); //next edge type opposite
999
+
1000
+ /* Set up bundle fields of next edge */
1001
+ next_edge.bundle[ABOVE][ ne_type ]= (next_edge.top.y != yb) ? 1 : 0;
1002
+ next_edge.bundle[ABOVE][ ne_type_opp ] = 0 ;
1003
+ next_edge.bstate[ABOVE] = BundleState.UNBUNDLED;
1004
+
1005
+ /* Bundle edges above the scanbeam boundary if they coincide */
1006
+ if ( next_edge.bundle[ABOVE][ne_type] == 1 )
1007
+ {
1008
+ if (EQ(e0.xb, next_edge.xb) && EQ(e0.dx, next_edge.dx) && (e0.top.y != yb))
1009
+ {
1010
+ next_edge.bundle[ABOVE][ ne_type ] ^= e0.bundle[ABOVE][ ne_type ];
1011
+ next_edge.bundle[ABOVE][ ne_type_opp ] = e0.bundle[ABOVE][ ne_type_opp ];
1012
+ next_edge.bstate[ABOVE] = BundleState.BUNDLE_HEAD;
1013
+ e0.bundle[ABOVE][CLIP] = 0;
1014
+ e0.bundle[ABOVE][SUBJ] = 0;
1015
+ e0.bstate[ABOVE] = BundleState.BUNDLE_TAIL;
1016
+ }
1017
+ e0 = next_edge;
1018
+ }
1019
+ }
1020
+
1021
+ int[] horiz = new int[2] ;
1022
+ horiz[CLIP]= HState.NH;
1023
+ horiz[SUBJ]= HState.NH;
1024
+
1025
+ int[] exists = new int[2] ;
1026
+ exists[CLIP] = 0 ;
1027
+ exists[SUBJ] = 0 ;
1028
+
1029
+ /* Process each edge at this scanbeam boundary */
1030
+ for (edge= aet.top_node ; (edge != null); edge = edge.next )
1031
+ {
1032
+ exists[CLIP] = edge.bundle[ABOVE][CLIP] + (edge.bundle[BELOW][CLIP] << 1);
1033
+ exists[SUBJ] = edge.bundle[ABOVE][SUBJ] + (edge.bundle[BELOW][SUBJ] << 1);
1034
+
1035
+ if( (exists[CLIP] != 0) || (exists[SUBJ] != 0) )
1036
+ {
1037
+ /* Set bundle side */
1038
+ edge.bside[CLIP] = parity[CLIP];
1039
+ edge.bside[SUBJ] = parity[SUBJ];
1040
+
1041
+ boolean contributing = false ;
1042
+ int br=0, bl=0, tr=0, tl=0 ;
1043
+ /* Determine contributing status and quadrant occupancies */
1044
+ if( (op == OperationType.GPC_DIFF) || (op == OperationType.GPC_INT) )
1045
+ {
1046
+ contributing= ((exists[CLIP]!=0) && ((parity[SUBJ]!=0) || (horiz[SUBJ]!=0))) ||
1047
+ ((exists[SUBJ]!=0) && ((parity[CLIP]!=0) || (horiz[CLIP]!=0))) ||
1048
+ ((exists[CLIP]!=0) && (exists[SUBJ]!=0) && (parity[CLIP] == parity[SUBJ]));
1049
+ br = ((parity[CLIP]!=0) && (parity[SUBJ]!=0)) ? 1 : 0;
1050
+ bl = ( ((parity[CLIP] ^ edge.bundle[ABOVE][CLIP])!=0) &&
1051
+ ((parity[SUBJ] ^ edge.bundle[ABOVE][SUBJ])!=0) ) ? 1 : 0;
1052
+ tr = ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0)) !=0) &&
1053
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0)) !=0) ) ? 1 : 0;
1054
+ tl = (((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW][CLIP])!=0) &&
1055
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW][SUBJ])!=0))?1:0;
1056
+ }
1057
+ else if( op == OperationType.GPC_XOR )
1058
+ {
1059
+ contributing= (exists[CLIP]!=0) || (exists[SUBJ]!=0);
1060
+ br= (parity[CLIP]) ^ (parity[SUBJ]);
1061
+ bl= (parity[CLIP] ^ edge.bundle[ABOVE][CLIP]) ^ (parity[SUBJ] ^ edge.bundle[ABOVE][SUBJ]);
1062
+ tr= (parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0)) ^ (parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0));
1063
+ tl= (parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW][CLIP])
1064
+ ^ (parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW][SUBJ]);
1065
+ }
1066
+ else if( op == OperationType.GPC_UNION )
1067
+ {
1068
+ contributing= ((exists[CLIP]!=0) && (!(parity[SUBJ]!=0) || (horiz[SUBJ]!=0))) ||
1069
+ ((exists[SUBJ]!=0) && (!(parity[CLIP]!=0) || (horiz[CLIP]!=0))) ||
1070
+ ((exists[CLIP]!=0) && (exists[SUBJ]!=0) && (parity[CLIP] == parity[SUBJ]));
1071
+ br= ((parity[CLIP]!=0) || (parity[SUBJ]!=0))?1:0;
1072
+ bl= (((parity[CLIP] ^ edge.bundle[ABOVE][CLIP])!=0) || ((parity[SUBJ] ^ edge.bundle[ABOVE][SUBJ])!=0))?1:0;
1073
+ tr= ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0))!=0) ||
1074
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0))!=0) ) ?1:0;
1075
+ tl= ( ((parity[CLIP] ^ ((horiz[CLIP]!=HState.NH)?1:0) ^ edge.bundle[BELOW][CLIP])!=0) ||
1076
+ ((parity[SUBJ] ^ ((horiz[SUBJ]!=HState.NH)?1:0) ^ edge.bundle[BELOW][SUBJ])!=0) ) ? 1:0;
1077
+ }
1078
+ else
1079
+ {
1080
+ throw new IllegalStateException("Unknown op");
1081
+ }
1082
+
1083
+ /* Update parity */
1084
+ parity[CLIP] ^= edge.bundle[ABOVE][CLIP];
1085
+ parity[SUBJ] ^= edge.bundle[ABOVE][SUBJ];
1086
+
1087
+ /* Update horizontal state */
1088
+ if (exists[CLIP]!=0)
1089
+ {
1090
+ horiz[CLIP] = HState.next_h_state[horiz[CLIP]][((exists[CLIP] - 1) << 1) + parity[CLIP]];
1091
+ }
1092
+ if( exists[SUBJ]!=0)
1093
+ {
1094
+ horiz[SUBJ] = HState.next_h_state[horiz[SUBJ]][((exists[SUBJ] - 1) << 1) + parity[SUBJ]];
1095
+ }
1096
+
1097
+ if (contributing)
1098
+ {
1099
+ xb = edge.xb;
1100
+
1101
+
1102
+ int vclass = VertexType.getType( tr, tl, br, bl );
1103
+ switch (vclass)
1104
+ {
1105
+ case VertexType.EMN:
1106
+ tlist=new_tristrip(tlist, edge, xb, yb);
1107
+ cf= edge;
1108
+ break;
1109
+ case VertexType.ERI:
1110
+ edge.outp[ABOVE]= cf.outp[ABOVE];
1111
+ if (xb != cf.xb)
1112
+ {
1113
+ VERTEX(edge, ABOVE, RIGHT, xb, yb);
1114
+ }
1115
+ cf= null;
1116
+ break;
1117
+ case VertexType.ELI:
1118
+ VERTEX(edge, BELOW, LEFT, xb, yb);
1119
+ edge.outp[ABOVE]= null;
1120
+ cf= edge;
1121
+ break;
1122
+ case VertexType.EMX:
1123
+ if (xb != cf.xb)
1124
+ {
1125
+ VERTEX(edge, BELOW, RIGHT, xb, yb);
1126
+ }
1127
+ edge.outp[ABOVE] = null;
1128
+ cf= null;
1129
+ break;
1130
+ case VertexType.IMN:
1131
+ if (cft == VertexType.LED)
1132
+ {
1133
+ if (cf.bot.y != yb)
1134
+ {
1135
+ VERTEX(cf, BELOW, LEFT, cf.xb, yb);
1136
+ }
1137
+ tlist=new_tristrip(tlist, cf, cf.xb, yb);
1138
+ }
1139
+ edge.outp[ABOVE]= cf.outp[ABOVE];
1140
+ VERTEX(edge, ABOVE, RIGHT, xb, yb);
1141
+ break;
1142
+ case VertexType.ILI:
1143
+ tlist=new_tristrip(tlist, edge, xb, yb);
1144
+ cf= edge;
1145
+ cft= VertexType.ILI;
1146
+ break;
1147
+ case VertexType.IRI:
1148
+ if (cft == VertexType.LED)
1149
+ {
1150
+ if (cf.bot.y != yb)
1151
+ {
1152
+ VERTEX(cf, BELOW, LEFT, cf.xb, yb);
1153
+ }
1154
+ tlist=new_tristrip(tlist, cf, cf.xb, yb);
1155
+ }
1156
+ VERTEX(edge, BELOW, RIGHT, xb, yb);
1157
+ edge.outp[ABOVE]= null;
1158
+ break;
1159
+ case VertexType.IMX:
1160
+ VERTEX(edge, BELOW, LEFT, xb, yb);
1161
+ edge.outp[ABOVE]= null;
1162
+ cft= VertexType.IMX;
1163
+ break;
1164
+ case VertexType.IMM:
1165
+ VERTEX(edge, BELOW, LEFT, xb, yb);
1166
+ edge.outp[ABOVE]= cf.outp[ABOVE];
1167
+ if (xb != cf.xb)
1168
+ {
1169
+ VERTEX(cf, ABOVE, RIGHT, xb, yb);
1170
+ }
1171
+ cf= edge;
1172
+ break;
1173
+ case VertexType.EMM:
1174
+ VERTEX(edge, BELOW, RIGHT, xb, yb);
1175
+ edge.outp[ABOVE]= null;
1176
+ tlist=new_tristrip(tlist, edge, xb, yb);
1177
+ cf= edge;
1178
+ break;
1179
+ case VertexType.LED:
1180
+ if (edge.bot.y == yb)
1181
+ VERTEX(edge, BELOW, LEFT, xb, yb);
1182
+ edge.outp[ABOVE]= edge.outp[BELOW];
1183
+ cf= edge;
1184
+ cft= VertexType.LED;
1185
+ break;
1186
+ case VertexType.RED:
1187
+ edge.outp[ABOVE]= cf.outp[ABOVE];
1188
+ if (cft == VertexType.LED)
1189
+ {
1190
+ if (cf.bot.y == yb)
1191
+ {
1192
+ VERTEX(edge, BELOW, RIGHT, xb, yb);
1193
+ }
1194
+ else
1195
+ {
1196
+ if (edge.bot.y == yb)
1197
+ {
1198
+ VERTEX(cf, BELOW, LEFT, cf.xb, yb);
1199
+ VERTEX(edge, BELOW, RIGHT, xb, yb);
1200
+ }
1201
+ }
1202
+ }
1203
+ else
1204
+ {
1205
+ VERTEX(edge, BELOW, RIGHT, xb, yb);
1206
+ VERTEX(edge, ABOVE, RIGHT, xb, yb);
1207
+ }
1208
+ cf= null;
1209
+ break;
1210
+ default:
1211
+ break;
1212
+ } /* End of switch */
1213
+ } /* End of contributing conditional */
1214
+ } /* End of edge exists conditional */
1215
+ } /* End of AET loop */
1216
+
1217
+ /* Delete terminating edges from the AET, otherwise compute xt */
1218
+ for (edge = aet.top_node ; (edge != null); edge = edge.next)
1219
+ {
1220
+ if (edge.top.y == yb)
1221
+ {
1222
+ prev_edge = edge.prev;
1223
+ next_edge= edge.next;
1224
+
1225
+ if (prev_edge != null)
1226
+ prev_edge.next = next_edge;
1227
+ else
1228
+ aet.top_node = next_edge;
1229
+
1230
+ if (next_edge != null )
1231
+ next_edge.prev = prev_edge;
1232
+
1233
+ /* Copy bundle head state to the adjacent tail edge if required */
1234
+ if ((edge.bstate[BELOW] == BundleState.BUNDLE_HEAD) && (prev_edge!=null))
1235
+ {
1236
+ if (prev_edge.bstate[BELOW] == BundleState.BUNDLE_TAIL)
1237
+ {
1238
+ prev_edge.outp[BELOW]= edge.outp[BELOW];
1239
+ prev_edge.bstate[BELOW]= BundleState.UNBUNDLED;
1240
+ if ( prev_edge.prev != null)
1241
+ {
1242
+ if (prev_edge.prev.bstate[BELOW] == BundleState.BUNDLE_TAIL)
1243
+ {
1244
+ prev_edge.bstate[BELOW] = BundleState.BUNDLE_HEAD;
1245
+ }
1246
+ }
1247
+ }
1248
+ }
1249
+ }
1250
+ else
1251
+ {
1252
+ if (edge.top.y == yt)
1253
+ edge.xt= edge.top.x;
1254
+ else
1255
+ edge.xt= edge.bot.x + edge.dx * (yt - edge.bot.y);
1256
+ }
1257
+ }
1258
+
1259
+ if (scanbeam < sbte.sbt_entries )
1260
+ {
1261
+ /* === SCANBEAM INTERIOR PROCESSING ============================== */
1262
+ /* Build intersection table for the current scanbeam */
1263
+ ItNodeTable it_table = new ItNodeTable();
1264
+ it_table.build_intersection_table(aet, dy);
1265
+
1266
+ /* Process each node in the intersection table */
1267
+ for (ItNode intersect = it_table.top_node ; (intersect != null); intersect = intersect.next)
1268
+ {
1269
+ e0= intersect.ie[0];
1270
+ e1= intersect.ie[1];
1271
+
1272
+ /* Only generate output for contributing intersections */
1273
+ if ( ((e0.bundle[ABOVE][CLIP]!=0) || (e0.bundle[ABOVE][SUBJ]!=0)) &&
1274
+ ((e1.bundle[ABOVE][CLIP]!=0) || (e1.bundle[ABOVE][SUBJ]!=0)))
1275
+ {
1276
+ PolygonNode p = e0.outp[ABOVE];
1277
+ PolygonNode q = e1.outp[ABOVE];
1278
+ ix = intersect.point.x;
1279
+ iy = intersect.point.y + yb;
1280
+
1281
+ int in_clip = ( ( (e0.bundle[ABOVE][CLIP]!=0) && !(e0.bside[CLIP]!=0)) ||
1282
+ ( (e1.bundle[ABOVE][CLIP]!=0) && (e1.bside[CLIP]!=0)) ||
1283
+ (!(e0.bundle[ABOVE][CLIP]!=0) && !(e1.bundle[ABOVE][CLIP]!=0) &&
1284
+ (e0.bside[CLIP]!=0) && (e1.bside[CLIP]!=0) ) ) ? 1 : 0;
1285
+
1286
+ int in_subj = ( ( (e0.bundle[ABOVE][SUBJ]!=0) && !(e0.bside[SUBJ]!=0)) ||
1287
+ ( (e1.bundle[ABOVE][SUBJ]!=0) && (e1.bside[SUBJ]!=0)) ||
1288
+ (!(e0.bundle[ABOVE][SUBJ]!=0) && !(e1.bundle[ABOVE][SUBJ]!=0) &&
1289
+ (e0.bside[SUBJ]!=0) && (e1.bside[SUBJ]!=0) ) ) ? 1 : 0;
1290
+
1291
+ int tr=0, tl=0, br=0, bl=0 ;
1292
+ /* Determine quadrant occupancies */
1293
+ if( (op == OperationType.GPC_DIFF) || (op == OperationType.GPC_INT) )
1294
+ {
1295
+ tr= ((in_clip!=0) && (in_subj!=0)) ? 1 : 0;
1296
+ tl= (((in_clip ^ e1.bundle[ABOVE][CLIP])!=0) && ((in_subj ^ e1.bundle[ABOVE][SUBJ])!=0))?1:0;
1297
+ br= (((in_clip ^ e0.bundle[ABOVE][CLIP])!=0) && ((in_subj ^ e0.bundle[ABOVE][SUBJ])!=0))?1:0;
1298
+ bl= (((in_clip ^ e1.bundle[ABOVE][CLIP] ^ e0.bundle[ABOVE][CLIP])!=0) &&
1299
+ ((in_subj ^ e1.bundle[ABOVE][SUBJ] ^ e0.bundle[ABOVE][SUBJ])!=0) ) ? 1:0;
1300
+ }
1301
+ else if( op == OperationType.GPC_XOR )
1302
+ {
1303
+ tr= (in_clip)^ (in_subj);
1304
+ tl= (in_clip ^ e1.bundle[ABOVE][CLIP]) ^ (in_subj ^ e1.bundle[ABOVE][SUBJ]);
1305
+ br= (in_clip ^ e0.bundle[ABOVE][CLIP]) ^ (in_subj ^ e0.bundle[ABOVE][SUBJ]);
1306
+ bl= (in_clip ^ e1.bundle[ABOVE][CLIP] ^ e0.bundle[ABOVE][CLIP])
1307
+ ^ (in_subj ^ e1.bundle[ABOVE][SUBJ] ^ e0.bundle[ABOVE][SUBJ]);
1308
+ }
1309
+ else if( op == OperationType.GPC_UNION )
1310
+ {
1311
+ tr= ((in_clip!=0) || (in_subj!=0)) ? 1 : 0;
1312
+ tl= (((in_clip ^ e1.bundle[ABOVE][CLIP])!=0) || ((in_subj ^ e1.bundle[ABOVE][SUBJ])!=0)) ? 1 : 0;
1313
+ br= (((in_clip ^ e0.bundle[ABOVE][CLIP])!=0) || ((in_subj ^ e0.bundle[ABOVE][SUBJ])!=0)) ? 1 : 0;
1314
+ bl= (((in_clip ^ e1.bundle[ABOVE][CLIP] ^ e0.bundle[ABOVE][CLIP])!=0) ||
1315
+ ((in_subj ^ e1.bundle[ABOVE][SUBJ] ^ e0.bundle[ABOVE][SUBJ])!=0)) ? 1 : 0;
1316
+ }
1317
+ else
1318
+ {
1319
+ throw new IllegalStateException("Unknown op type, "+op);
1320
+ }
1321
+
1322
+ next_edge = e1.next;
1323
+ prev_edge = e0.prev;
1324
+
1325
+ int vclass = VertexType.getType( tr, tl, br, bl );
1326
+ switch (vclass)
1327
+ {
1328
+ case VertexType.EMN:
1329
+ tlist=new_tristrip(tlist, e1, ix, iy);
1330
+ e1.outp[ABOVE] = e0.outp[ABOVE];
1331
+ break;
1332
+ case VertexType.ERI:
1333
+ if (p != null)
1334
+ {
1335
+ px = P_EDGE(prev_edge, e0, ABOVE, px, iy);
1336
+ VERTEX(prev_edge, ABOVE, LEFT, px, iy);
1337
+ VERTEX(e0, ABOVE, RIGHT, ix, iy);
1338
+ e1.outp[ABOVE]= e0.outp[ABOVE];
1339
+ e0.outp[ABOVE]= null;
1340
+ }
1341
+ break;
1342
+ case VertexType.ELI:
1343
+ if (q != null)
1344
+ {
1345
+ nx = N_EDGE(next_edge, e1, ABOVE, nx, iy);
1346
+ VERTEX(e1, ABOVE, LEFT, ix, iy);
1347
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1348
+ e0.outp[ABOVE]= e1.outp[ABOVE];
1349
+ e1.outp[ABOVE]= null;
1350
+ }
1351
+ break;
1352
+ case VertexType.EMX:
1353
+ if ((p!=null) && (q!=null))
1354
+ {
1355
+ VERTEX(e0, ABOVE, LEFT, ix, iy);
1356
+ e0.outp[ABOVE]= null;
1357
+ e1.outp[ABOVE]= null;
1358
+ }
1359
+ break;
1360
+ case VertexType.IMN:
1361
+ px = P_EDGE(prev_edge, e0, ABOVE, px, iy);
1362
+ VERTEX(prev_edge, ABOVE, LEFT, px, iy);
1363
+ nx = N_EDGE(next_edge, e1, ABOVE, nx, iy);
1364
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1365
+ tlist=new_tristrip(tlist, prev_edge, px, iy);
1366
+ e1.outp[ABOVE]= prev_edge.outp[ABOVE];
1367
+ VERTEX(e1, ABOVE, RIGHT, ix, iy);
1368
+ tlist=new_tristrip(tlist, e0, ix, iy);
1369
+ next_edge.outp[ABOVE]= e0.outp[ABOVE];
1370
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1371
+ break;
1372
+ case VertexType.ILI:
1373
+ if (p != null)
1374
+ {
1375
+ VERTEX(e0, ABOVE, LEFT, ix, iy);
1376
+ nx = N_EDGE(next_edge, e1, ABOVE, nx, iy);
1377
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1378
+ e1.outp[ABOVE]= e0.outp[ABOVE];
1379
+ e0.outp[ABOVE]= null;
1380
+ }
1381
+ break;
1382
+ case VertexType.IRI:
1383
+ if (q!=null)
1384
+ {
1385
+ VERTEX(e1, ABOVE, RIGHT, ix, iy);
1386
+ px = P_EDGE(prev_edge, e0, ABOVE, px, iy);
1387
+ VERTEX(prev_edge, ABOVE, LEFT, px, iy);
1388
+ e0.outp[ABOVE]= e1.outp[ABOVE];
1389
+ e1.outp[ABOVE]= null;
1390
+ }
1391
+ break;
1392
+ case VertexType.IMX:
1393
+ if ((p!=null) && (q!=null))
1394
+ {
1395
+ VERTEX(e0, ABOVE, RIGHT, ix, iy);
1396
+ VERTEX(e1, ABOVE, LEFT, ix, iy);
1397
+ e0.outp[ABOVE]= null;
1398
+ e1.outp[ABOVE]= null;
1399
+ px = P_EDGE(prev_edge, e0, ABOVE, px, iy);
1400
+ VERTEX(prev_edge, ABOVE, LEFT, px, iy);
1401
+ tlist=new_tristrip(tlist, prev_edge, px, iy);
1402
+ nx = N_EDGE(next_edge, e1, ABOVE, nx, iy);
1403
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1404
+ next_edge.outp[ABOVE]= prev_edge.outp[ABOVE];
1405
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1406
+ }
1407
+ break;
1408
+ case VertexType.IMM:
1409
+ if ((p!=null) && (q!=null))
1410
+ {
1411
+ VERTEX(e0, ABOVE, RIGHT, ix, iy);
1412
+ VERTEX(e1, ABOVE, LEFT, ix, iy);
1413
+ px = P_EDGE(prev_edge, e0, ABOVE, px, iy);
1414
+ VERTEX(prev_edge, ABOVE, LEFT, px, iy);
1415
+ tlist=new_tristrip(tlist, prev_edge, px, iy);
1416
+ nx = N_EDGE(next_edge, e1, ABOVE, nx, iy);
1417
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1418
+ e1.outp[ABOVE]= prev_edge.outp[ABOVE];
1419
+ VERTEX(e1, ABOVE, RIGHT, ix, iy);
1420
+ tlist=new_tristrip(tlist, e0, ix, iy);
1421
+ next_edge.outp[ABOVE]= e0.outp[ABOVE];
1422
+ VERTEX(next_edge, ABOVE, RIGHT, nx, iy);
1423
+ }
1424
+ break;
1425
+ case VertexType.EMM:
1426
+ if ((p!=null) && (q!=null))
1427
+ {
1428
+ VERTEX(e0, ABOVE, LEFT, ix, iy);
1429
+ tlist=new_tristrip(tlist, e1, ix, iy);
1430
+ e1.outp[ABOVE] = e0.outp[ABOVE];
1431
+ }
1432
+ break;
1433
+ default:
1434
+ break;
1435
+ } /* End of switch */
1436
+ } /* End of contributing intersection conditional */
1437
+
1438
+ /* Swap bundle sides in response to edge crossing */
1439
+ if (e0.bundle[ABOVE][CLIP]!=0)
1440
+ e1.bside[CLIP] = (e1.bside[CLIP]==0)?1:0;
1441
+ if (e1.bundle[ABOVE][CLIP]!=0)
1442
+ e0.bside[CLIP]= (e0.bside[CLIP]==0)?1:0;
1443
+ if (e0.bundle[ABOVE][SUBJ]!=0)
1444
+ e1.bside[SUBJ]= (e1.bside[SUBJ]==0)?1:0;
1445
+ if (e1.bundle[ABOVE][SUBJ]!=0)
1446
+ e0.bside[SUBJ]= (e0.bside[SUBJ]==0)?1:0;
1447
+
1448
+ /* Swap e0 and e1 bundles in the AET */
1449
+ prev_edge = e0.prev;
1450
+ next_edge = e1.next;
1451
+ if (next_edge != null)
1452
+ {
1453
+ next_edge.prev = e0;
1454
+ }
1455
+
1456
+ if (e0.bstate[ABOVE] == BundleState.BUNDLE_HEAD)
1457
+ {
1458
+ boolean search = true;
1459
+ while (search)
1460
+ {
1461
+ prev_edge= prev_edge.prev;
1462
+ if (prev_edge != null)
1463
+ {
1464
+ if (prev_edge.bundle[ABOVE][CLIP]!=0
1465
+ || prev_edge.bundle[ABOVE][SUBJ]!=0
1466
+ || (prev_edge.bstate[ABOVE] == BundleState.BUNDLE_HEAD))
1467
+ {
1468
+ search= false;
1469
+ }
1470
+ }
1471
+ else
1472
+ {
1473
+ search= false;
1474
+ }
1475
+ }
1476
+ }
1477
+ if (prev_edge == null)
1478
+ {
1479
+ e1.next = aet.top_node;
1480
+ aet.top_node = e0.next;
1481
+ }
1482
+ else
1483
+ {
1484
+ e1.next = prev_edge.next;
1485
+ prev_edge.next = e0.next;
1486
+ }
1487
+ e0.next.prev = prev_edge;
1488
+ e1.next.prev = e1;
1489
+ e0.next = next_edge;
1490
+
1491
+ } /* End of IT loop*/
1492
+
1493
+ /* Prepare for next scanbeam */
1494
+ for ( edge = aet.top_node; (edge != null); edge = edge.next)
1495
+ {
1496
+ next_edge = edge.next;
1497
+ succ_edge = edge.succ;
1498
+ if ((edge.top.y == yt) && (succ_edge!=null))
1499
+ {
1500
+ /* Replace AET edge by its successor */
1501
+ succ_edge.outp[BELOW]= edge.outp[ABOVE];
1502
+ succ_edge.bstate[BELOW]= edge.bstate[ABOVE];
1503
+ succ_edge.bundle[BELOW][CLIP]= edge.bundle[ABOVE][CLIP];
1504
+ succ_edge.bundle[BELOW][SUBJ]= edge.bundle[ABOVE][SUBJ];
1505
+ prev_edge = edge.prev;
1506
+ if ( prev_edge != null )
1507
+ prev_edge.next = succ_edge;
1508
+ else
1509
+ aet.top_node = succ_edge;
1510
+ if (next_edge != null)
1511
+ next_edge.prev= succ_edge;
1512
+ succ_edge.prev = prev_edge;
1513
+ succ_edge.next = next_edge;
1514
+ }
1515
+ else
1516
+ {
1517
+ /* Update this edge */
1518
+ edge.outp[BELOW]= edge.outp[ABOVE];
1519
+ edge.bstate[BELOW]= edge.bstate[ABOVE];
1520
+ edge.bundle[BELOW][CLIP]= edge.bundle[ABOVE][CLIP];
1521
+ edge.bundle[BELOW][SUBJ]= edge.bundle[ABOVE][SUBJ];
1522
+ edge.xb= edge.xt;
1523
+ }
1524
+ edge.outp[ABOVE]= null;
1525
+ }
1526
+ }
1527
+ } /* === END OF SCANBEAM PROCESSING ================================== */
1528
+
1529
+ /* Generate result tristrip from tlist */
1530
+ RMesh result = new RMesh();
1531
+ if (count_tristrips(tlist) > 0)
1532
+ {
1533
+ int s, v;
1534
+
1535
+ s= 0;
1536
+ for (tn= tlist; tn!=null; tn= tnn)
1537
+ {
1538
+ tnn= tn.next;
1539
+
1540
+ if (tn.active > 2)
1541
+ {
1542
+ /* Valid tristrip: copy the vertices and free the heap */
1543
+ RStrip strip = new RStrip();
1544
+ v= 0;
1545
+ if (INVERT_TRISTRIPS == true)
1546
+ {
1547
+ lt= tn.v[RIGHT];
1548
+ rt= tn.v[LEFT];
1549
+ }
1550
+ else
1551
+ {
1552
+ lt= tn.v[LEFT];
1553
+ rt= tn.v[RIGHT];
1554
+ }
1555
+ while (lt!=null || rt!=null)
1556
+ {
1557
+ if (lt!=null)
1558
+ {
1559
+ ltn= lt.next;
1560
+ strip.add(lt.x,lt.y);
1561
+ v++;
1562
+ lt= ltn;
1563
+ }
1564
+ if (rt!=null)
1565
+ {
1566
+ rtn= rt.next;
1567
+ strip.add(rt.x,rt.y);
1568
+ v++;
1569
+ rt= rtn;
1570
+ }
1571
+ }
1572
+ result.addStrip(strip);
1573
+ s++;
1574
+ }
1575
+ else
1576
+ {
1577
+ /* Invalid tristrip: just free the heap */
1578
+ for (lt= tn.v[LEFT]; lt!=null; lt= ltn)
1579
+ {
1580
+ ltn= lt.next;
1581
+ }
1582
+ for (rt= tn.v[RIGHT]; rt!=null; rt= rtn)
1583
+ {
1584
+ rtn= rt.next;
1585
+ }
1586
+ }
1587
+ }
1588
+ }
1589
+ return result ;
1590
+ }
1591
+
1592
+ public static RMesh polygonToMesh(RPolygon s)
1593
+ {
1594
+ RPolygon c = new RPolygon();
1595
+ RPolygon s_clean = s.removeOpenContours();
1596
+ /*
1597
+ for(int i=0; i<s_clean.countContours(); i++)
1598
+ {
1599
+ System.out.println(" " + s_clean.contours[i]);
1600
+ System.out.println("Contour " + (i + 1) + "/" + s_clean.countContours() + ":");
1601
+ for(int j=0;j<s_clean.contours[i].countPoints();j++)
1602
+ {
1603
+ System.out.println(" Point " + (j + 1) + "/" + s_clean.contours[i].countPoints() + ":" + "(" + s_clean.contours[i].points[j].x + ", " + s_clean.contours[i].points[j].y + ")");
1604
+ }
1605
+ }
1606
+ */
1607
+ return clip(OperationType.GPC_UNION, s_clean, c);
1608
+ }
1609
+
1610
+ private static boolean EQ(float a, float b)
1611
+ {
1612
+ return (Math.abs(a - b) <= GPC_EPSILON);
1613
+ }
1614
+
1615
+ private static int PREV_INDEX( int i, int n)
1616
+ {
1617
+ return ((i - 1 + n) % n);
1618
+ }
1619
+
1620
+ private static int NEXT_INDEX(int i, int n)
1621
+ {
1622
+ return ((i + 1 ) % n);
1623
+ }
1624
+
1625
+ private static boolean OPTIMAL( RPolygon p, int i )
1626
+ {
1627
+ return (p.getY(PREV_INDEX(i, p.getNumPoints())) != p.getY(i)) ||
1628
+ (p.getY(NEXT_INDEX(i, p.getNumPoints())) != p.getY(i)) ;
1629
+ }
1630
+
1631
+ private static void VERTEX( EdgeNode e, int p, int s, float x, float y )
1632
+ {
1633
+ e.outp[p].v[s]=add_vertex(e.outp[p].v[s], x, y);
1634
+ e.outp[p].active++;
1635
+ }
1636
+
1637
+ private static float P_EDGE( EdgeNode d, EdgeNode e, int p, float i, float j)
1638
+ {
1639
+ d= e;
1640
+ do
1641
+ {
1642
+ d= d.prev;
1643
+ }
1644
+ while(d.outp[p] == null);
1645
+ return d.bot.x + d.dx*(j-d.bot.y);
1646
+ }
1647
+
1648
+ private static float N_EDGE( EdgeNode d, EdgeNode e, int p, float i, float j)
1649
+ {
1650
+ d= e;
1651
+ do
1652
+ {
1653
+ d= d.next;
1654
+ }
1655
+ while(d.outp[p] == null);
1656
+ return d.bot.x + d.dx*(j-d.bot.y);
1657
+ }
1658
+
1659
+ private static RRectangle[] create_contour_bboxes( RPolygon p )
1660
+ {
1661
+ RRectangle[] box = new RRectangle[p.getNumInnerPoly()] ;
1662
+
1663
+ /* Construct contour bounding boxes */
1664
+ for ( int c= 0; c < p.getNumInnerPoly(); c++)
1665
+ {
1666
+ RPolygon inner_poly = p.getInnerPoly(c);
1667
+ box[c] = inner_poly.getBBox();
1668
+ }
1669
+ return box;
1670
+ }
1671
+
1672
+ private static void minimax_test( RPolygon subj, RPolygon clip, OperationType op )
1673
+ {
1674
+ RRectangle[] s_bbox = create_contour_bboxes(subj);
1675
+ RRectangle[] c_bbox = create_contour_bboxes(clip);
1676
+
1677
+ int subj_num_poly = subj.getNumInnerPoly();
1678
+ int clip_num_poly = clip.getNumInnerPoly();
1679
+ boolean[][] o_table = new boolean[subj_num_poly][clip_num_poly] ;
1680
+
1681
+ /* Check all subject contour bounding boxes against clip boxes */
1682
+ for( int s = 0; s < subj_num_poly; s++ )
1683
+ {
1684
+ for( int c= 0; c < clip_num_poly ; c++ )
1685
+ {
1686
+ o_table[s][c] =
1687
+ (!((s_bbox[s].getMaxX() < c_bbox[c].getMinX()) ||
1688
+ (s_bbox[s].getMinX() > c_bbox[c].getMaxX()))) &&
1689
+ (!((s_bbox[s].getMaxY() < c_bbox[c].getMinY()) ||
1690
+ (s_bbox[s].getMinY() > c_bbox[c].getMaxY())));
1691
+ }
1692
+ }
1693
+
1694
+ /* For each clip contour, search for any subject contour overlaps */
1695
+ for( int c = 0; c < clip_num_poly; c++ )
1696
+ {
1697
+ boolean overlap = false;
1698
+ for( int s = 0; !overlap && (s < subj_num_poly) ; s++)
1699
+ {
1700
+ overlap = o_table[s][c];
1701
+ }
1702
+ if (!overlap)
1703
+ {
1704
+ clip.setContributing( c, false ); // Flag non contributing status
1705
+ }
1706
+ }
1707
+
1708
+ if (op == OperationType.GPC_INT)
1709
+ {
1710
+ /* For each subject contour, search for any clip contour overlaps */
1711
+ for ( int s= 0; s < subj_num_poly; s++)
1712
+ {
1713
+ boolean overlap = false;
1714
+ for ( int c= 0; !overlap && (c < clip_num_poly); c++)
1715
+ {
1716
+ overlap = o_table[s][c];
1717
+ }
1718
+ if (!overlap)
1719
+ {
1720
+ subj.setContributing( s, false ); // Flag non contributing status
1721
+ }
1722
+ }
1723
+ }
1724
+ }
1725
+
1726
+ private static LmtNode bound_list( LmtTable lmt_table, float y )
1727
+ {
1728
+ if( lmt_table.top_node == null )
1729
+ {
1730
+ lmt_table.top_node = new LmtNode(y);
1731
+ return lmt_table.top_node ;
1732
+ }
1733
+ else
1734
+ {
1735
+ LmtNode prev = null ;
1736
+ LmtNode node = lmt_table.top_node ;
1737
+ boolean done = false ;
1738
+ while( !done )
1739
+ {
1740
+ if( y < node.y )
1741
+ {
1742
+ /* Insert a new LMT node before the current node */
1743
+ LmtNode existing_node = node ;
1744
+ node = new LmtNode(y);
1745
+ node.next = existing_node ;
1746
+ if( prev == null )
1747
+ {
1748
+ lmt_table.top_node = node ;
1749
+ }
1750
+ else
1751
+ {
1752
+ prev.next = node ;
1753
+ }
1754
+ // if( existing_node == lmt_table.top_node )
1755
+ // {
1756
+ // lmt_table.top_node = node ;
1757
+ // }
1758
+ done = true ;
1759
+ }
1760
+ else if ( y > node.y )
1761
+ {
1762
+ /* Head further up the LMT */
1763
+ if( node.next == null )
1764
+ {
1765
+ node.next = new LmtNode(y);
1766
+ node = node.next ;
1767
+ done = true ;
1768
+ }
1769
+ else
1770
+ {
1771
+ prev = node ;
1772
+ node = node.next ;
1773
+ }
1774
+ }
1775
+ else
1776
+ {
1777
+ /* Use this existing LMT node */
1778
+ done = true ;
1779
+ }
1780
+ }
1781
+ return node ;
1782
+ }
1783
+ }
1784
+
1785
+ private static void insert_bound( LmtNode lmt_node, EdgeNode e)
1786
+ {
1787
+ if( lmt_node.first_bound == null )
1788
+ {
1789
+ /* Link node e to the tail of the list */
1790
+ lmt_node.first_bound = e ;
1791
+ }
1792
+ else
1793
+ {
1794
+ boolean done = false ;
1795
+ EdgeNode prev_bound = null ;
1796
+ EdgeNode current_bound = lmt_node.first_bound ;
1797
+ while( !done )
1798
+ {
1799
+ /* Do primary sort on the x field */
1800
+ if (e.bot.x < current_bound.bot.x)
1801
+ {
1802
+ /* Insert a new node mid-list */
1803
+ if( prev_bound == null )
1804
+ {
1805
+ lmt_node.first_bound = e ;
1806
+ }
1807
+ else
1808
+ {
1809
+ prev_bound.next_bound = e ;
1810
+ }
1811
+ e.next_bound = current_bound ;
1812
+
1813
+ // EdgeNode existing_bound = current_bound ;
1814
+ // current_bound = e ;
1815
+ // current_bound.next_bound = existing_bound ;
1816
+ // if( lmt_node.first_bound == existing_bound )
1817
+ // {
1818
+ // lmt_node.first_bound = current_bound ;
1819
+ // }
1820
+ done = true ;
1821
+ }
1822
+ else if (e.bot.x == current_bound.bot.x)
1823
+ {
1824
+ /* Do secondary sort on the dx field */
1825
+ if (e.dx < current_bound.dx)
1826
+ {
1827
+ /* Insert a new node mid-list */
1828
+ if( prev_bound == null )
1829
+ {
1830
+ lmt_node.first_bound = e ;
1831
+ }
1832
+ else
1833
+ {
1834
+ prev_bound.next_bound = e ;
1835
+ }
1836
+ e.next_bound = current_bound ;
1837
+ // EdgeNode existing_bound = current_bound ;
1838
+ // current_bound = e ;
1839
+ // current_bound.next_bound = existing_bound ;
1840
+ // if( lmt_node.first_bound == existing_bound )
1841
+ // {
1842
+ // lmt_node.first_bound = current_bound ;
1843
+ // }
1844
+ done = true ;
1845
+ }
1846
+ else
1847
+ {
1848
+ /* Head further down the list */
1849
+ if( current_bound.next_bound == null )
1850
+ {
1851
+ current_bound.next_bound = e ;
1852
+ done = true ;
1853
+ }
1854
+ else
1855
+ {
1856
+ prev_bound = current_bound ;
1857
+ current_bound = current_bound.next_bound ;
1858
+ }
1859
+ }
1860
+ }
1861
+ else
1862
+ {
1863
+ /* Head further down the list */
1864
+ if( current_bound.next_bound == null )
1865
+ {
1866
+ current_bound.next_bound = e ;
1867
+ done = true ;
1868
+ }
1869
+ else
1870
+ {
1871
+ prev_bound = current_bound ;
1872
+ current_bound = current_bound.next_bound ;
1873
+ }
1874
+ }
1875
+ }
1876
+ }
1877
+ }
1878
+
1879
+ private static void add_edge_to_aet( AetTree aet , EdgeNode edge )
1880
+ {
1881
+ if ( aet.top_node == null )
1882
+ {
1883
+ /* Append edge onto the tail end of the AET */
1884
+ aet.top_node = edge;
1885
+ edge.prev = null ;
1886
+ edge.next= null;
1887
+ }
1888
+ else
1889
+ {
1890
+ EdgeNode current_edge = aet.top_node ;
1891
+ EdgeNode prev = null ;
1892
+ boolean done = false ;
1893
+ while( !done )
1894
+ {
1895
+ /* Do primary sort on the xb field */
1896
+ if (edge.xb < current_edge.xb)
1897
+ {
1898
+ /* Insert edge here (before the AET edge) */
1899
+ edge.prev= prev;
1900
+ edge.next= current_edge ;
1901
+ current_edge.prev = edge ;
1902
+ if( prev == null )
1903
+ {
1904
+ aet.top_node = edge ;
1905
+ }
1906
+ else
1907
+ {
1908
+ prev.next = edge ;
1909
+ }
1910
+ // if( current_edge == aet.top_node )
1911
+ // {
1912
+ // aet.top_node = edge ;
1913
+ // }
1914
+ // current_edge = edge ;
1915
+ done = true;
1916
+ }
1917
+ else if (edge.xb == current_edge.xb)
1918
+ {
1919
+ /* Do secondary sort on the dx field */
1920
+ if (edge.dx < current_edge.dx)
1921
+ {
1922
+ /* Insert edge here (before the AET edge) */
1923
+ edge.prev= prev;
1924
+ edge.next= current_edge ;
1925
+ current_edge.prev = edge ;
1926
+ if( prev == null )
1927
+ {
1928
+ aet.top_node = edge ;
1929
+ }
1930
+ else
1931
+ {
1932
+ prev.next = edge ;
1933
+ }
1934
+ // if( current_edge == aet.top_node )
1935
+ // {
1936
+ // aet.top_node = edge ;
1937
+ // }
1938
+ // current_edge = edge ;
1939
+ done = true;
1940
+ }
1941
+ else
1942
+ {
1943
+ /* Head further into the AET */
1944
+ prev = current_edge ;
1945
+ if( current_edge.next == null )
1946
+ {
1947
+ current_edge.next = edge ;
1948
+ edge.prev = current_edge ;
1949
+ edge.next = null ;
1950
+ done = true ;
1951
+ }
1952
+ else
1953
+ {
1954
+ current_edge = current_edge.next ;
1955
+ }
1956
+ }
1957
+ }
1958
+ else
1959
+ {
1960
+ /* Head further into the AET */
1961
+ prev = current_edge ;
1962
+ if( current_edge.next == null )
1963
+ {
1964
+ current_edge.next = edge ;
1965
+ edge.prev = current_edge ;
1966
+ edge.next = null ;
1967
+ done = true ;
1968
+ }
1969
+ else
1970
+ {
1971
+ current_edge = current_edge.next ;
1972
+ }
1973
+ }
1974
+ }
1975
+ }
1976
+ }
1977
+
1978
+ private static void add_to_sbtree( ScanBeamTreeEntries sbte, float y )
1979
+ {
1980
+ if( sbte.sb_tree == null )
1981
+ {
1982
+ /* Add a new tree node here */
1983
+ sbte.sb_tree = new ScanBeamTree( y );
1984
+ sbte.sbt_entries++ ;
1985
+ return ;
1986
+ }
1987
+ ScanBeamTree tree_node = sbte.sb_tree ;
1988
+ boolean done = false ;
1989
+ while( !done )
1990
+ {
1991
+ if ( tree_node.y > y)
1992
+ {
1993
+ if( tree_node.less == null )
1994
+ {
1995
+ tree_node.less = new ScanBeamTree(y);
1996
+ sbte.sbt_entries++ ;
1997
+ done = true ;
1998
+ }
1999
+ else
2000
+ {
2001
+ tree_node = tree_node.less ;
2002
+ }
2003
+ }
2004
+ else if ( tree_node.y < y)
2005
+ {
2006
+ if( tree_node.more == null )
2007
+ {
2008
+ tree_node.more = new ScanBeamTree(y);
2009
+ sbte.sbt_entries++ ;
2010
+ done = true ;
2011
+ }
2012
+ else
2013
+ {
2014
+ tree_node = tree_node.more ;
2015
+ }
2016
+ }
2017
+ else
2018
+ {
2019
+ done = true ;
2020
+ }
2021
+ }
2022
+ }
2023
+
2024
+ private static EdgeTable build_lmt( LmtTable lmt_table,
2025
+ ScanBeamTreeEntries sbte,
2026
+ RPolygon p,
2027
+ int type, //poly type SUBJ/CLIP
2028
+ OperationType op)
2029
+ {
2030
+ /* Create the entire input polygon edge table in one go */
2031
+ EdgeTable edge_table = new EdgeTable();
2032
+
2033
+ for ( int c= 0; c < p.getNumInnerPoly(); c++)
2034
+ {
2035
+ RPolygon ip = p.getInnerPoly(c);
2036
+ if( !ip.isContributing(0) )
2037
+ {
2038
+ /* Ignore the non-contributing contour */
2039
+ ip.setContributing(0, true);
2040
+ }
2041
+ else
2042
+ {
2043
+ /* Perform contour optimisation */
2044
+ int num_vertices= 0;
2045
+ int e_index = 0 ;
2046
+ edge_table = new EdgeTable();
2047
+ for ( int i= 0; i < ip.getNumPoints(); i++)
2048
+ {
2049
+ if( OPTIMAL(ip, i) )
2050
+ {
2051
+ float x = ip.getX(i);
2052
+ float y = ip.getY(i);
2053
+ edge_table.addNode( x, y );
2054
+
2055
+ /* Record vertex in the scanbeam table */
2056
+ add_to_sbtree( sbte, ip.getY(i) );
2057
+
2058
+ num_vertices++;
2059
+ }
2060
+ }
2061
+
2062
+ /* Do the contour forward pass */
2063
+ for ( int min= 0; min < num_vertices; min++)
2064
+ {
2065
+ /* If a forward local minimum... */
2066
+ if( edge_table.FWD_MIN( min ) )
2067
+ {
2068
+ /* Search for the next local maximum... */
2069
+ int num_edges = 1;
2070
+ int max = NEXT_INDEX( min, num_vertices );
2071
+ while( edge_table.NOT_FMAX( max ) )
2072
+ {
2073
+ num_edges++;
2074
+ max = NEXT_INDEX( max, num_vertices );
2075
+ }
2076
+
2077
+ /* Build the next edge list */
2078
+ int v = min;
2079
+ EdgeNode e = edge_table.getNode( e_index );
2080
+ e.bstate[BELOW] = BundleState.UNBUNDLED;
2081
+ e.bundle[BELOW][CLIP] = 0;
2082
+ e.bundle[BELOW][SUBJ] = 0;
2083
+
2084
+ for ( int i= 0; i < num_edges; i++)
2085
+ {
2086
+ EdgeNode ei = edge_table.getNode( e_index+i );
2087
+ EdgeNode ev = edge_table.getNode( v );
2088
+
2089
+ ei.xb = ev.vertex.x;
2090
+ ei.bot.x = ev.vertex.x;
2091
+ ei.bot.y = ev.vertex.y;
2092
+
2093
+ v = NEXT_INDEX(v, num_vertices);
2094
+ ev = edge_table.getNode( v );
2095
+
2096
+ ei.top.x= ev.vertex.x;
2097
+ ei.top.y= ev.vertex.y;
2098
+ ei.dx= (ev.vertex.x - ei.bot.x) / (ei.top.y - ei.bot.y);
2099
+ ei.type = type;
2100
+ ei.outp[ABOVE] = null ;
2101
+ ei.outp[BELOW] = null;
2102
+ ei.next = null;
2103
+ ei.prev = null;
2104
+ ei.succ = ((num_edges > 1) && (i < (num_edges - 1))) ? edge_table.getNode(e_index+i+1) : null;
2105
+ ei.pred = ((num_edges > 1) && (i > 0)) ? edge_table.getNode(e_index+i-1) : null ;
2106
+ ei.next_bound = null ;
2107
+ ei.bside[CLIP] = (op == OperationType.GPC_DIFF) ? RIGHT : LEFT;
2108
+ ei.bside[SUBJ] = LEFT ;
2109
+ }
2110
+ insert_bound( bound_list(lmt_table, edge_table.getNode(min).vertex.y), e);
2111
+ if( DEBUG )
2112
+ {
2113
+ System.out.println("fwd");
2114
+ lmt_table.print();
2115
+ }
2116
+ e_index += num_edges;
2117
+ }
2118
+ }
2119
+
2120
+ /* Do the contour reverse pass */
2121
+ for ( int min= 0; min < num_vertices; min++)
2122
+ {
2123
+ /* If a reverse local minimum... */
2124
+ if ( edge_table.REV_MIN( min ) )
2125
+ {
2126
+ /* Search for the previous local maximum... */
2127
+ int num_edges= 1;
2128
+ int max = PREV_INDEX(min, num_vertices);
2129
+ while( edge_table.NOT_RMAX( max ) )
2130
+ {
2131
+ num_edges++;
2132
+ max = PREV_INDEX(max, num_vertices);
2133
+ }
2134
+
2135
+ /* Build the previous edge list */
2136
+ int v = min;
2137
+ EdgeNode e = edge_table.getNode( e_index );
2138
+ e.bstate[BELOW] = BundleState.UNBUNDLED;
2139
+ e.bundle[BELOW][CLIP] = 0;
2140
+ e.bundle[BELOW][SUBJ] = 0;
2141
+
2142
+ for (int i= 0; i < num_edges; i++)
2143
+ {
2144
+ EdgeNode ei = edge_table.getNode( e_index+i );
2145
+ EdgeNode ev = edge_table.getNode( v );
2146
+
2147
+ ei.xb = ev.vertex.x;
2148
+ ei.bot.x = ev.vertex.x;
2149
+ ei.bot.y = ev.vertex.y;
2150
+
2151
+ v= PREV_INDEX(v, num_vertices);
2152
+ ev = edge_table.getNode( v );
2153
+
2154
+ ei.top.x = ev.vertex.x;
2155
+ ei.top.y = ev.vertex.y;
2156
+ ei.dx = (ev.vertex.x - ei.bot.x) / (ei.top.y - ei.bot.y);
2157
+ ei.type = type;
2158
+ ei.outp[ABOVE] = null;
2159
+ ei.outp[BELOW] = null;
2160
+ ei.next = null ;
2161
+ ei.prev = null;
2162
+ ei.succ = ((num_edges > 1) && (i < (num_edges - 1))) ? edge_table.getNode(e_index+i+1) : null;
2163
+ ei.pred = ((num_edges > 1) && (i > 0)) ? edge_table.getNode(e_index+i-1) : null ;
2164
+ ei.next_bound = null ;
2165
+ ei.bside[CLIP] = (op == OperationType.GPC_DIFF) ? RIGHT : LEFT;
2166
+ ei.bside[SUBJ] = LEFT;
2167
+ }
2168
+ insert_bound( bound_list(lmt_table, edge_table.getNode(min).vertex.y), e);
2169
+ if( DEBUG )
2170
+ {
2171
+ System.out.println("rev");
2172
+ lmt_table.print();
2173
+ }
2174
+ e_index+= num_edges;
2175
+ }
2176
+ }
2177
+ }
2178
+ }
2179
+ return edge_table;
2180
+ }
2181
+
2182
+ private static StNode add_st_edge( StNode st, ItNodeTable it, EdgeNode edge, float dy)
2183
+ {
2184
+ if (st == null)
2185
+ {
2186
+ /* Append edge onto the tail end of the ST */
2187
+ st = new StNode( edge, null );
2188
+ }
2189
+ else
2190
+ {
2191
+ float den= (st.xt - st.xb) - (edge.xt - edge.xb);
2192
+
2193
+ /* If new edge and ST edge don't cross */
2194
+ if( (edge.xt >= st.xt) || (edge.dx == st.dx) || (Math.abs(den) <= GPC_EPSILON))
2195
+ {
2196
+ /* No intersection - insert edge here (before the ST edge) */
2197
+ StNode existing_node = st;
2198
+ st = new StNode( edge, existing_node );
2199
+ }
2200
+ else
2201
+ {
2202
+ /* Compute intersection between new edge and ST edge */
2203
+ float r= (edge.xb - st.xb) / den;
2204
+ float x= st.xb + r * (st.xt - st.xb);
2205
+ float y= r * dy;
2206
+
2207
+ /* Insert the edge pointers and the intersection point in the IT */
2208
+ it.top_node = add_intersection(it.top_node, st.edge, edge, x, y);
2209
+
2210
+ /* Head further into the ST */
2211
+ st.prev = add_st_edge(st.prev, it, edge, dy);
2212
+ }
2213
+ }
2214
+ return st ;
2215
+ }
2216
+
2217
+ private static ItNode add_intersection( ItNode it_node,
2218
+ EdgeNode edge0,
2219
+ EdgeNode edge1,
2220
+ float x,
2221
+ float y)
2222
+ {
2223
+ if (it_node == null)
2224
+ {
2225
+ /* Append a new node to the tail of the list */
2226
+ it_node = new ItNode( edge0, edge1, x, y, null );
2227
+ }
2228
+ else
2229
+ {
2230
+ if ( it_node.point.y > y)
2231
+ {
2232
+ /* Insert a new node mid-list */
2233
+ ItNode existing_node = it_node ;
2234
+ it_node = new ItNode( edge0, edge1, x, y, existing_node );
2235
+ }
2236
+ else
2237
+ {
2238
+ /* Head further down the list */
2239
+ it_node.next = add_intersection( it_node.next, edge0, edge1, x, y);
2240
+ }
2241
+ }
2242
+ return it_node ;
2243
+ }
2244
+
2245
+ private static int count_tristrips(PolygonNode tn)
2246
+ {
2247
+ int total;
2248
+
2249
+ for (total= 0; tn!=null; tn= tn.next)
2250
+ {
2251
+ if (tn.active > 2)
2252
+ {
2253
+ total++;
2254
+ }
2255
+ }
2256
+ return total;
2257
+ }
2258
+
2259
+ private static VertexNode add_vertex(VertexNode ve_node, float x, float y)
2260
+ {
2261
+ if (ve_node == null)
2262
+ {
2263
+ /* Append a new node to the tail of the list */
2264
+ ve_node = new VertexNode( x, y);
2265
+ }
2266
+ else
2267
+ {
2268
+ /* Head further down the list */
2269
+ ve_node.next = add_vertex( ve_node.next, x, y);
2270
+ }
2271
+ return ve_node;
2272
+ }
2273
+
2274
+ private static PolygonNode new_tristrip(PolygonNode po_node, EdgeNode edge, float x, float y)
2275
+ {
2276
+ if (po_node == null)
2277
+ {
2278
+ /* Append a new node to the tail of the list */
2279
+ po_node = new PolygonNode();
2280
+ po_node.v[LEFT]=add_vertex(po_node.v[LEFT], x, y);
2281
+ edge.outp[ABOVE]= po_node;
2282
+ }
2283
+ else
2284
+ {
2285
+ /* Head further down the list */
2286
+ po_node.next = new_tristrip( po_node.next, edge, x, y);
2287
+ }
2288
+ return po_node;
2289
+ }
2290
+
2291
+ // ---------------------
2292
+ // --- Inner Classes ---
2293
+ // ---------------------
2294
+ public static class OperationType
2295
+ {
2296
+ private String m_Type ;
2297
+ private OperationType( String type ) { m_Type = type; }
2298
+
2299
+ public static final OperationType GPC_DIFF = new OperationType( "Difference" );
2300
+ public static final OperationType GPC_INT = new OperationType( "Intersection" );
2301
+ public static final OperationType GPC_XOR = new OperationType( "Exclusive or" );
2302
+ public static final OperationType GPC_UNION = new OperationType( "Union" );
2303
+
2304
+ @Override
2305
+ public String toString() { return m_Type; }
2306
+ }
2307
+
2308
+ /**
2309
+ * Edge intersection classes
2310
+ */
2311
+ private static class VertexType
2312
+ {
2313
+ public static final int NUL = 0 ; /* Empty non-intersection */
2314
+ public static final int EMX = 1 ; /* External maximum */
2315
+ public static final int ELI = 2 ; /* External left intermediate */
2316
+ public static final int TED = 3 ; /* Top edge */
2317
+ public static final int ERI = 4 ; /* External right intermediate */
2318
+ public static final int RED = 5 ; /* Right edge */
2319
+ public static final int IMM = 6 ; /* Internal maximum and minimum */
2320
+ public static final int IMN = 7 ; /* Internal minimum */
2321
+ public static final int EMN = 8 ; /* External minimum */
2322
+ public static final int EMM = 9 ; /* External maximum and minimum */
2323
+ public static final int LED = 10 ; /* Left edge */
2324
+ public static final int ILI = 11 ; /* Internal left intermediate */
2325
+ public static final int BED = 12 ; /* Bottom edge */
2326
+ public static final int IRI = 13 ; /* Internal right intermediate */
2327
+ public static final int IMX = 14 ; /* Internal maximum */
2328
+ public static final int FUL = 15 ; /* Full non-intersection */
2329
+
2330
+ public static int getType( int tr, int tl, int br, int bl )
2331
+ {
2332
+ return tr + (tl << 1) + (br << 2) + (bl << 3);
2333
+ }
2334
+ }
2335
+
2336
+ /**
2337
+ * Horizontal edge states
2338
+ */
2339
+ private static class HState
2340
+ {
2341
+ public static final int NH = 0 ; /* No horizontal edge */
2342
+ public static final int BH = 1 ; /* Bottom horizontal edge */
2343
+ public static final int TH = 2 ; /* Top horizontal edge */
2344
+
2345
+ /* Horizontal edge state transitions within scanbeam boundary */
2346
+ public static final int[][] next_h_state =
2347
+ {
2348
+ /* ABOVE BELOW CROSS */
2349
+ /* L R L R L R */
2350
+ /* NH */ {BH, TH, TH, BH, NH, NH},
2351
+ /* BH */ {NH, NH, NH, NH, TH, TH},
2352
+ /* TH */ {NH, NH, NH, NH, BH, BH}
2353
+ };
2354
+ }
2355
+
2356
+ /**
2357
+ * Edge bundle state
2358
+ */
2359
+ private static class BundleState
2360
+ {
2361
+ private String m_State ;
2362
+ private BundleState( String state ) { m_State = state ; }
2363
+
2364
+ public static final BundleState UNBUNDLED = new BundleState( "UNBUNDLED" ); // Isolated edge not within a bundle
2365
+ public static final BundleState BUNDLE_HEAD = new BundleState( "BUNDLE_HEAD" ); // Bundle head node
2366
+ public static final BundleState BUNDLE_TAIL = new BundleState( "BUNDLE_TAIL" ); // Passive bundle tail node
2367
+
2368
+ @Override
2369
+ public String toString() { return m_State; }
2370
+ }
2371
+
2372
+ /**
2373
+ * Internal vertex list datatype
2374
+ */
2375
+ private static class VertexNode
2376
+ {
2377
+ float x; // X coordinate component
2378
+ float y; // Y coordinate component
2379
+ VertexNode next; // Pointer to next vertex in list
2380
+
2381
+ public VertexNode( float x, float y )
2382
+ {
2383
+ this.x = x ;
2384
+ this.y = y ;
2385
+ this.next = null ;
2386
+ }
2387
+ }
2388
+
2389
+ /**
2390
+ * Internal contour / tristrip type
2391
+ */
2392
+ private static class PolygonNode
2393
+ {
2394
+ int active; /* Active flag / vertex count */
2395
+ boolean hole; /* Hole / external contour flag */
2396
+ VertexNode[] v = new VertexNode[2] ; /* Left and right vertex list ptrs */
2397
+ PolygonNode next; /* Pointer to next polygon contour */
2398
+ PolygonNode proxy; /* Pointer to actual structure used */
2399
+
2400
+ public PolygonNode()
2401
+ {
2402
+ /* Make v[LEFT] and v[RIGHT] point to new vertex */
2403
+ this.v[LEFT ] = null ;
2404
+ this.v[RIGHT] = null ;
2405
+ this.next = null ;
2406
+ this.proxy = this ; /* Initialise proxy to point to p itself */
2407
+ this.active = 1 ; //TRUE
2408
+ }
2409
+
2410
+ public PolygonNode( PolygonNode next, float x, float y )
2411
+ {
2412
+ /* Make v[LEFT] and v[RIGHT] point to new vertex */
2413
+ VertexNode vn = new VertexNode( x, y );
2414
+ this.v[LEFT ] = vn ;
2415
+ this.v[RIGHT] = vn ;
2416
+
2417
+ this.next = next ;
2418
+ this.proxy = this ; /* Initialise proxy to point to p itself */
2419
+ this.active = 1 ; //TRUE
2420
+ }
2421
+
2422
+ public void add_right( float x, float y )
2423
+ {
2424
+ VertexNode nv = new VertexNode( x, y );
2425
+
2426
+ /* Add vertex nv to the right end of the polygon's vertex list */
2427
+ proxy.v[RIGHT].next= nv;
2428
+
2429
+ /* Update proxy->v[RIGHT] to point to nv */
2430
+ proxy.v[RIGHT]= nv;
2431
+ }
2432
+
2433
+ public void add_left( float x, float y)
2434
+ {
2435
+ VertexNode nv = new VertexNode( x, y );
2436
+
2437
+ /* Add vertex nv to the left end of the polygon's vertex list */
2438
+ nv.next= proxy.v[LEFT];
2439
+
2440
+ /* Update proxy->[LEFT] to point to nv */
2441
+ proxy.v[LEFT]= nv;
2442
+ }
2443
+
2444
+ }
2445
+
2446
+ private static class TopPolygonNode
2447
+ {
2448
+ PolygonNode top_node = null ;
2449
+
2450
+ public PolygonNode add_local_min( float x, float y )
2451
+ {
2452
+ PolygonNode existing_min = top_node;
2453
+
2454
+ top_node = new PolygonNode( existing_min, x, y );
2455
+
2456
+ return top_node ;
2457
+ }
2458
+
2459
+ public void merge_left( PolygonNode p, PolygonNode q )
2460
+ {
2461
+ /* Label contour as a hole */
2462
+ q.proxy.hole = true ;
2463
+
2464
+ if (p.proxy != q.proxy)
2465
+ {
2466
+ /* Assign p's vertex list to the left end of q's list */
2467
+ p.proxy.v[RIGHT].next= q.proxy.v[LEFT];
2468
+ q.proxy.v[LEFT]= p.proxy.v[LEFT];
2469
+
2470
+ /* Redirect any p.proxy references to q.proxy */
2471
+ PolygonNode target = p.proxy ;
2472
+ for(PolygonNode node = top_node; (node != null); node = node.next)
2473
+ {
2474
+ if (node.proxy == target)
2475
+ {
2476
+ node.active= 0;
2477
+ node.proxy= q.proxy;
2478
+ }
2479
+ }
2480
+ }
2481
+ }
2482
+
2483
+ public void merge_right( PolygonNode p, PolygonNode q )
2484
+ {
2485
+ /* Label contour as external */
2486
+ q.proxy.hole = false ;
2487
+
2488
+ if (p.proxy != q.proxy)
2489
+ {
2490
+ /* Assign p's vertex list to the right end of q's list */
2491
+ q.proxy.v[RIGHT].next= p.proxy.v[LEFT];
2492
+ q.proxy.v[RIGHT]= p.proxy.v[RIGHT];
2493
+
2494
+ /* Redirect any p->proxy references to q->proxy */
2495
+ PolygonNode target = p.proxy ;
2496
+ for (PolygonNode node = top_node ; (node != null ); node = node.next)
2497
+ {
2498
+ if (node.proxy == target)
2499
+ {
2500
+ node.active = 0;
2501
+ node.proxy= q.proxy;
2502
+ }
2503
+ }
2504
+ }
2505
+ }
2506
+
2507
+ public int count_contours()
2508
+ {
2509
+ int nc = 0 ;
2510
+ for ( PolygonNode polygon = top_node; (polygon != null) ; polygon = polygon.next)
2511
+ {
2512
+ if (polygon.active != 0)
2513
+ {
2514
+ /* Count the vertices in the current contour */
2515
+ int nv= 0;
2516
+ for (VertexNode v= polygon.proxy.v[LEFT]; (v != null); v = v.next)
2517
+ {
2518
+ nv++;
2519
+ }
2520
+
2521
+ /* Record valid vertex counts in the active field */
2522
+ if (nv > 2)
2523
+ {
2524
+ polygon.active = nv;
2525
+ nc++;
2526
+ }
2527
+ else
2528
+ {
2529
+ /* Invalid contour: just free the heap */
2530
+ // VertexNode nextv = null ;
2531
+ // for (VertexNode v= polygon.proxy.v[LEFT]; (v != null); v = nextv)
2532
+ // {
2533
+ // nextv= v.next;
2534
+ // v = null ;
2535
+ // }
2536
+ polygon.active= 0;
2537
+ }
2538
+ }
2539
+ }
2540
+ return nc;
2541
+ }
2542
+
2543
+ public RPolygon getResult( Class polyClass )
2544
+ {
2545
+ //RPolygon result = createNewPoly( polyClass );
2546
+ RPolygon result = new RPolygon();
2547
+ int num_contours = count_contours();
2548
+ if (num_contours > 0)
2549
+ {
2550
+ int c= 0;
2551
+ PolygonNode npoly_node = null ;
2552
+ for (PolygonNode poly_node= top_node; (poly_node != null); poly_node = npoly_node)
2553
+ {
2554
+ npoly_node = poly_node.next;
2555
+ if (poly_node.active != 0)
2556
+ {
2557
+ RContour contour;
2558
+ if(result.countContours()>0){
2559
+ contour = result.contours[0];
2560
+ }else{
2561
+ contour = new RContour();
2562
+ }
2563
+ //RPolygon poly = result ;
2564
+ if( num_contours > 0 )
2565
+ {
2566
+ contour = new RContour();
2567
+ //poly = createNewPoly( polyClass );
2568
+ }
2569
+ if( poly_node.proxy.hole )
2570
+ {
2571
+ contour.isHole = poly_node.proxy.hole;
2572
+ //poly.setIsHole( poly_node.proxy.hole );
2573
+ }
2574
+
2575
+ // ------------------------------------------------------------------------
2576
+ // --- This algorithm puts the verticies into the poly in reverse order ---
2577
+ // ------------------------------------------------------------------------
2578
+ for (VertexNode vtx = poly_node.proxy.v[LEFT]; (vtx != null) ; vtx = vtx.next )
2579
+ {
2580
+ contour.addPoint(vtx.x, vtx.y);
2581
+ //poly.add( vtx.x, vtx.y );
2582
+ }
2583
+ if( num_contours > 0 )
2584
+ {
2585
+ result.addContour(contour);
2586
+ //result.add( poly );
2587
+ }
2588
+ c++;
2589
+ }
2590
+ }
2591
+
2592
+ // -----------------------------------------
2593
+ // --- Sort holes to the end of the list ---
2594
+ // -----------------------------------------
2595
+ RPolygon orig = new RPolygon(result) ;
2596
+ result = new RPolygon();
2597
+ //result = createNewPoly( polyClass );
2598
+ for( int i = 0 ; i < orig.countContours() ; i++ )
2599
+ //for( int i = 0 ; i < orig.getNumInnerPoly() ; i++ )
2600
+ {
2601
+ RContour inner = orig.contours[i];
2602
+ //RPolygon inner = orig.getInnerPoly(i);
2603
+ if( !inner.isHole() )
2604
+ {
2605
+ result.addContour(inner);
2606
+ //result.add(inner);
2607
+ }
2608
+ }
2609
+
2610
+ for( int i = 0 ; i < orig.countContours() ; i++ )
2611
+ //for( int i = 0 ; i < orig.getNumInnerPoly() ; i++ )
2612
+ {
2613
+ RContour inner = orig.contours[i];
2614
+ //RPolygon inner = orig.getInnerPoly(i);
2615
+ if( inner.isHole() )
2616
+ {
2617
+ result.addContour(inner);
2618
+ }
2619
+ }
2620
+ }
2621
+ return result ;
2622
+ }
2623
+
2624
+ public void print()
2625
+ {
2626
+ System.out.println("---- out_poly ----");
2627
+ int c= 0;
2628
+ PolygonNode npoly_node = null ;
2629
+ for (PolygonNode poly_node= top_node; (poly_node != null); poly_node = npoly_node)
2630
+ {
2631
+ System.out.println("contour="+c+" active="+poly_node.active+" hole="+poly_node.proxy.hole);
2632
+ npoly_node = poly_node.next;
2633
+ if (poly_node.active != 0)
2634
+ {
2635
+ int v=0 ;
2636
+ for (VertexNode vtx = poly_node.proxy.v[LEFT]; (vtx != null) ; vtx = vtx.next )
2637
+ {
2638
+ System.out.println("v="+v+" vtx.x="+vtx.x+" vtx.y="+vtx.y);
2639
+ }
2640
+ c++;
2641
+ }
2642
+ }
2643
+ }
2644
+ }
2645
+
2646
+ private static class EdgeNode
2647
+ {
2648
+ RPoint vertex = new RPoint(); /* Piggy-backed contour vertex data */
2649
+ RPoint bot = new RPoint(); /* Edge lower (x, y) coordinate */
2650
+ RPoint top = new RPoint(); /* Edge upper (x, y) coordinate */
2651
+ float xb; /* Scanbeam bottom x coordinate */
2652
+ float xt; /* Scanbeam top x coordinate */
2653
+ float dx; /* Change in x for a unit y increase */
2654
+ int type; /* Clip / subject edge flag */
2655
+ int[][] bundle = new int[2][2]; /* Bundle edge flags */
2656
+ int[] bside = new int[2]; /* Bundle left / right indicators */
2657
+ BundleState[] bstate = new BundleState[2]; /* Edge bundle state */
2658
+ PolygonNode[] outp = new PolygonNode[2]; /* Output polygon / tristrip pointer */
2659
+ EdgeNode prev; /* Previous edge in the AET */
2660
+ EdgeNode next; /* Next edge in the AET */
2661
+ EdgeNode pred; /* Edge connected at the lower end */
2662
+ EdgeNode succ; /* Edge connected at the upper end */
2663
+ EdgeNode next_bound; /* Pointer to next bound in LMT */
2664
+ }
2665
+
2666
+ private static class AetTree
2667
+ {
2668
+ EdgeNode top_node ;
2669
+
2670
+ public void print()
2671
+ {
2672
+ System.out.println("");
2673
+ System.out.println("aet");
2674
+ for( EdgeNode edge = top_node ; (edge != null) ; edge = edge.next )
2675
+ {
2676
+ System.out.println("edge.vertex.x="+edge.vertex.x+" edge.vertex.y="+edge.vertex.y);
2677
+ }
2678
+ }
2679
+ }
2680
+
2681
+ private static class EdgeTable
2682
+ {
2683
+ private List<EdgeNode> m_List = new ArrayList<>();
2684
+
2685
+ public void addNode( float x, float y )
2686
+ {
2687
+ EdgeNode node = new EdgeNode();
2688
+ node.vertex.x = x ;
2689
+ node.vertex.y = y ;
2690
+ m_List.add( node );
2691
+ }
2692
+
2693
+ public EdgeNode getNode( int index )
2694
+ {
2695
+ return (EdgeNode)m_List.get(index);
2696
+ }
2697
+
2698
+ public boolean FWD_MIN( int i )
2699
+ {
2700
+ EdgeNode prev = (EdgeNode)m_List.get(PREV_INDEX(i, m_List.size()));
2701
+ EdgeNode next = (EdgeNode)m_List.get(NEXT_INDEX(i, m_List.size()));
2702
+ EdgeNode ith = (EdgeNode)m_List.get(i);
2703
+ return ((prev.vertex.getY() >= ith.vertex.getY()) &&
2704
+ (next.vertex.getY() > ith.vertex.getY()));
2705
+ }
2706
+
2707
+ public boolean NOT_FMAX( int i )
2708
+ {
2709
+ EdgeNode next = (EdgeNode)m_List.get(NEXT_INDEX(i, m_List.size()));
2710
+ EdgeNode ith = (EdgeNode)m_List.get(i);
2711
+ return(next.vertex.getY() > ith.vertex.getY());
2712
+ }
2713
+
2714
+ public boolean REV_MIN( int i )
2715
+ {
2716
+ EdgeNode prev = (EdgeNode)m_List.get(PREV_INDEX(i, m_List.size()));
2717
+ EdgeNode next = (EdgeNode)m_List.get(NEXT_INDEX(i, m_List.size()));
2718
+ EdgeNode ith = (EdgeNode)m_List.get(i);
2719
+ return ((prev.vertex.getY() > ith.vertex.getY()) &&
2720
+ (next.vertex.getY() >= ith.vertex.getY()));
2721
+ }
2722
+
2723
+ public boolean NOT_RMAX( int i )
2724
+ {
2725
+ EdgeNode prev = (EdgeNode)m_List.get(PREV_INDEX(i, m_List.size()));
2726
+ EdgeNode ith = (EdgeNode)m_List.get(i);
2727
+ return (prev.vertex.getY() > ith.vertex.getY()) ;
2728
+ }
2729
+ }
2730
+
2731
+ /**
2732
+ * Local minima table
2733
+ */
2734
+ private static class LmtNode
2735
+ {
2736
+ float y; /* Y coordinate at local minimum */
2737
+ EdgeNode first_bound; /* Pointer to bound list */
2738
+ LmtNode next; /* Pointer to next local minimum */
2739
+
2740
+ public LmtNode( float yvalue )
2741
+ {
2742
+ y = yvalue ;
2743
+ }
2744
+ }
2745
+
2746
+ private static class LmtTable
2747
+ {
2748
+ LmtNode top_node ;
2749
+
2750
+ public void print()
2751
+ {
2752
+ int n = 0 ;
2753
+ LmtNode lmt = top_node ;
2754
+ while( lmt != null )
2755
+ {
2756
+ System.out.println("lmt("+n+")");
2757
+ for( EdgeNode edge = lmt.first_bound ; (edge != null) ; edge = edge.next_bound )
2758
+ {
2759
+ System.out.println("edge.vertex.x="+edge.vertex.x+" edge.vertex.y="+edge.vertex.y);
2760
+ }
2761
+ n++ ;
2762
+ lmt = lmt.next ;
2763
+ }
2764
+ }
2765
+ }
2766
+
2767
+ /**
2768
+ * Scanbeam tree
2769
+ */
2770
+ private static class ScanBeamTree
2771
+ {
2772
+ float y; /* Scanbeam node y value */
2773
+ ScanBeamTree less; /* Pointer to nodes with lower y */
2774
+ ScanBeamTree more; /* Pointer to nodes with higher y */
2775
+
2776
+ public ScanBeamTree( float yvalue )
2777
+ {
2778
+ y = yvalue ;
2779
+ }
2780
+ }
2781
+
2782
+ /**
2783
+ *
2784
+ */
2785
+ private static class ScanBeamTreeEntries
2786
+ {
2787
+ int sbt_entries ;
2788
+ ScanBeamTree sb_tree ;
2789
+
2790
+ public float[] build_sbt()
2791
+ {
2792
+ float[] sbt = new float[sbt_entries] ;
2793
+
2794
+ int entries = 0 ;
2795
+ entries = inner_build_sbt( entries, sbt, sb_tree );
2796
+ if( entries != sbt_entries )
2797
+ {
2798
+ throw new IllegalStateException("Something went wrong buildign sbt from tree.");
2799
+ }
2800
+ return sbt ;
2801
+ }
2802
+
2803
+ private int inner_build_sbt( int entries, float[] sbt, ScanBeamTree sbt_node )
2804
+ {
2805
+ if( sbt_node.less != null )
2806
+ {
2807
+ entries = inner_build_sbt(entries, sbt, sbt_node.less);
2808
+ }
2809
+ sbt[entries]= sbt_node.y;
2810
+ entries++;
2811
+ if( sbt_node.more != null )
2812
+ {
2813
+ entries = inner_build_sbt(entries, sbt, sbt_node.more );
2814
+ }
2815
+ return entries ;
2816
+ }
2817
+ }
2818
+
2819
+ /**
2820
+ * Intersection table
2821
+ */
2822
+ private static class ItNode
2823
+ {
2824
+ EdgeNode[] ie = new EdgeNode[2]; /* Intersecting edge (bundle) pair */
2825
+ RPoint point = new RPoint(); /* Point of intersection */
2826
+ ItNode next; /* The next intersection table node */
2827
+
2828
+ public ItNode( EdgeNode edge0, EdgeNode edge1, float x, float y, ItNode next )
2829
+ {
2830
+ this.ie[0] = edge0 ;
2831
+ this.ie[1] = edge1 ;
2832
+ this.point.x = x ;
2833
+ this.point.y = y ;
2834
+ this.next = next ;
2835
+ }
2836
+ }
2837
+
2838
+ private static class ItNodeTable
2839
+ {
2840
+ ItNode top_node ;
2841
+
2842
+ public void build_intersection_table(AetTree aet, float dy)
2843
+ {
2844
+ StNode st = null ;
2845
+
2846
+ /* Process each AET edge */
2847
+ for (EdgeNode edge = aet.top_node ; (edge != null); edge = edge.next)
2848
+ {
2849
+ if( (edge.bstate[ABOVE] == BundleState.BUNDLE_HEAD) ||
2850
+ (edge.bundle[ABOVE][CLIP] != 0) ||
2851
+ (edge.bundle[ABOVE][SUBJ] != 0) )
2852
+ {
2853
+ st = add_st_edge(st, this, edge, dy);
2854
+ }
2855
+ }
2856
+ }
2857
+ }
2858
+
2859
+ /**
2860
+ * Sorted edge table
2861
+ */
2862
+ private static class StNode
2863
+ {
2864
+ EdgeNode edge; /* Pointer to AET edge */
2865
+ float xb; /* Scanbeam bottom x coordinate */
2866
+ float xt; /* Scanbeam top x coordinate */
2867
+ float dx; /* Change in x for a unit y increase */
2868
+ StNode prev; /* Previous edge in sorted list */
2869
+
2870
+ public StNode( EdgeNode edge, StNode prev )
2871
+ {
2872
+ this.edge = edge ;
2873
+ this.xb = edge.xb ;
2874
+ this.xt = edge.xt ;
2875
+ this.dx = edge.dx ;
2876
+ this.prev = prev ;
2877
+ }
2878
+ }
2879
+
2880
+ // -------------
2881
+ // --- DEBUG ---
2882
+ // -------------
2883
+ private static void print_sbt( float[] sbt )
2884
+ {
2885
+ System.out.println("");
2886
+ System.out.println("sbt.length="+sbt.length);
2887
+ for( int i = 0 ; i < sbt.length ; i++ )
2888
+ {
2889
+ System.out.println("sbt["+i+"]="+sbt[i]);
2890
+ }
2891
+ }
2892
+ }