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