geomerative 0.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/LICENSE +662 -0
- data/LICENSE.md +9 -0
- data/README.md +2 -0
- data/Rakefile +37 -0
- data/examples/README.md +7 -0
- data/examples/data/FreeSans.ttf +0 -0
- data/examples/data/ReplicaBold.ttf +0 -0
- data/examples/data/bot1.svg +160 -0
- data/examples/hello_svg_to_pdf.rb +26 -0
- data/examples/hello_world.rb +23 -0
- data/examples/physics_type.rb +77 -0
- data/examples/rotate_first_letter.rb +28 -0
- data/geomerative.gemspec +32 -0
- data/lib/geomerative.rb +12 -0
- data/lib/geomerative/version.rb +3 -0
- data/pom.xml +110 -0
- data/src/geomerative/FastRClip.java +2715 -0
- data/src/geomerative/RClip.java +2892 -0
- data/src/geomerative/RClosest.java +64 -0
- data/src/geomerative/RCommand.java +1941 -0
- data/src/geomerative/RContour.java +348 -0
- data/src/geomerative/RFont.java +583 -0
- data/src/geomerative/RG.java +753 -0
- data/src/geomerative/RGeomElem.java +1075 -0
- data/src/geomerative/RGroup.java +888 -0
- data/src/geomerative/RMatrix.java +401 -0
- data/src/geomerative/RMesh.java +420 -0
- data/src/geomerative/RPath.java +1095 -0
- data/src/geomerative/RPoint.java +419 -0
- data/src/geomerative/RPolygon.java +1110 -0
- data/src/geomerative/RRectangle.java +91 -0
- data/src/geomerative/RSVG.java +976 -0
- data/src/geomerative/RShape.java +2045 -0
- data/src/geomerative/RStrip.java +221 -0
- data/src/geomerative/RStyle.java +469 -0
- data/src/org/apache/batik/svggen/font/.SVGFont.java.swp +0 -0
- data/src/org/apache/batik/svggen/font/Font.java +188 -0
- data/src/org/apache/batik/svggen/font/Glyph.java +113 -0
- data/src/org/apache/batik/svggen/font/Messages.java.bak +72 -0
- data/src/org/apache/batik/svggen/font/Point.java +38 -0
- data/src/org/apache/batik/svggen/font/RandomAccessFileEmulator.java +15 -0
- data/src/org/apache/batik/svggen/font/table/ClassDef.java +42 -0
- data/src/org/apache/batik/svggen/font/table/ClassDefFormat1.java +55 -0
- data/src/org/apache/batik/svggen/font/table/ClassDefFormat2.java +49 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat.java +81 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat0.java +60 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat2.java +48 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat4.java +147 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat6.java +60 -0
- data/src/org/apache/batik/svggen/font/table/CmapIndexEntry.java +84 -0
- data/src/org/apache/batik/svggen/font/table/CmapTable.java +87 -0
- data/src/org/apache/batik/svggen/font/table/Coverage.java +50 -0
- data/src/org/apache/batik/svggen/font/table/CoverageFormat1.java +59 -0
- data/src/org/apache/batik/svggen/font/table/CoverageFormat2.java +56 -0
- data/src/org/apache/batik/svggen/font/table/CvtTable.java +48 -0
- data/src/org/apache/batik/svggen/font/table/Device.java +63 -0
- data/src/org/apache/batik/svggen/font/table/DirectoryEntry.java +73 -0
- data/src/org/apache/batik/svggen/font/table/Feature.java +56 -0
- data/src/org/apache/batik/svggen/font/table/FeatureList.java +70 -0
- data/src/org/apache/batik/svggen/font/table/FeatureRecord.java +52 -0
- data/src/org/apache/batik/svggen/font/table/FeatureTags.java +30 -0
- data/src/org/apache/batik/svggen/font/table/FpgmTable.java +38 -0
- data/src/org/apache/batik/svggen/font/table/GlyfCompositeComp.java +165 -0
- data/src/org/apache/batik/svggen/font/table/GlyfCompositeDescript.java +160 -0
- data/src/org/apache/batik/svggen/font/table/GlyfDescript.java +79 -0
- data/src/org/apache/batik/svggen/font/table/GlyfSimpleDescript.java +155 -0
- data/src/org/apache/batik/svggen/font/table/GlyfTable.java +111 -0
- data/src/org/apache/batik/svggen/font/table/GlyphDescription.java +39 -0
- data/src/org/apache/batik/svggen/font/table/GposTable.java +80 -0
- data/src/org/apache/batik/svggen/font/table/GsubTable.java +118 -0
- data/src/org/apache/batik/svggen/font/table/HeadTable.java +159 -0
- data/src/org/apache/batik/svggen/font/table/HheaTable.java +109 -0
- data/src/org/apache/batik/svggen/font/table/HmtxTable.java +99 -0
- data/src/org/apache/batik/svggen/font/table/KernSubtable.java +58 -0
- data/src/org/apache/batik/svggen/font/table/KernSubtableFormat0.java +65 -0
- data/src/org/apache/batik/svggen/font/table/KernSubtableFormat2.java +56 -0
- data/src/org/apache/batik/svggen/font/table/KernTable.java +64 -0
- data/src/org/apache/batik/svggen/font/table/KerningPair.java +53 -0
- data/src/org/apache/batik/svggen/font/table/LangSys.java +58 -0
- data/src/org/apache/batik/svggen/font/table/LangSysRecord.java +52 -0
- data/src/org/apache/batik/svggen/font/table/Ligature.java +57 -0
- data/src/org/apache/batik/svggen/font/table/LigatureSet.java +55 -0
- data/src/org/apache/batik/svggen/font/table/LigatureSubst.java +40 -0
- data/src/org/apache/batik/svggen/font/table/LigatureSubstFormat1.java +63 -0
- data/src/org/apache/batik/svggen/font/table/LocaTable.java +72 -0
- data/src/org/apache/batik/svggen/font/table/Lookup.java +77 -0
- data/src/org/apache/batik/svggen/font/table/LookupList.java +68 -0
- data/src/org/apache/batik/svggen/font/table/LookupSubtable.java +27 -0
- data/src/org/apache/batik/svggen/font/table/LookupSubtableFactory.java +31 -0
- data/src/org/apache/batik/svggen/font/table/MaxpTable.java +124 -0
- data/src/org/apache/batik/svggen/font/table/NameRecord.java +98 -0
- data/src/org/apache/batik/svggen/font/table/NameTable.java +67 -0
- data/src/org/apache/batik/svggen/font/table/Os2Table.java +232 -0
- data/src/org/apache/batik/svggen/font/table/Panose.java +108 -0
- data/src/org/apache/batik/svggen/font/table/PostTable.java +379 -0
- data/src/org/apache/batik/svggen/font/table/PrepTable.java +38 -0
- data/src/org/apache/batik/svggen/font/table/Program.java +49 -0
- data/src/org/apache/batik/svggen/font/table/RangeRecord.java +57 -0
- data/src/org/apache/batik/svggen/font/table/Script.java +72 -0
- data/src/org/apache/batik/svggen/font/table/ScriptList.java +78 -0
- data/src/org/apache/batik/svggen/font/table/ScriptRecord.java +52 -0
- data/src/org/apache/batik/svggen/font/table/ScriptTags.java +28 -0
- data/src/org/apache/batik/svggen/font/table/SingleSubst.java +47 -0
- data/src/org/apache/batik/svggen/font/table/SingleSubstFormat1.java +67 -0
- data/src/org/apache/batik/svggen/font/table/SingleSubstFormat2.java +67 -0
- data/src/org/apache/batik/svggen/font/table/Table.java +204 -0
- data/src/org/apache/batik/svggen/font/table/TableDirectory.java +94 -0
- data/src/org/apache/batik/svggen/font/table/TableFactory.java +121 -0
- 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
|
+
}
|