aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/games/jogl/impl/nurbs/internals/Subdivider.java
diff options
context:
space:
mode:
authorKenneth Russel <[email protected]>2004-12-20 20:04:27 +0000
committerKenneth Russel <[email protected]>2004-12-20 20:04:27 +0000
commit167641d406619ba710e2d50005b6886d2874a251 (patch)
treed080e059fa1d034f63946ae68937dd3f97f6943c /src/net/java/games/jogl/impl/nurbs/internals/Subdivider.java
parent494740e563ead19828cc44a03230eb066bf84a02 (diff)
Initial incomplete GLU NURBS port under net.java.games.jogl.impl.nurbs
and a small README about the procedures being used during the port git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@180 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/net/java/games/jogl/impl/nurbs/internals/Subdivider.java')
-rwxr-xr-xsrc/net/java/games/jogl/impl/nurbs/internals/Subdivider.java1781
1 files changed, 1781 insertions, 0 deletions
diff --git a/src/net/java/games/jogl/impl/nurbs/internals/Subdivider.java b/src/net/java/games/jogl/impl/nurbs/internals/Subdivider.java
new file mode 100755
index 000000000..155b6b7ac
--- /dev/null
+++ b/src/net/java/games/jogl/impl/nurbs/internals/Subdivider.java
@@ -0,0 +1,1781 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+public class Subdivider {
+
+ /**
+ * Constructs a subdivider.
+ */
+ public Subdivider(RenderHints hints, Backend b) {
+ renderhints = hints;
+ arctessellator = new ArcTesselator();
+ backend = b;
+ slicer = new Slicer(b);
+ }
+
+ /**
+ * Resets all state after possible error condition.
+ */
+ public void clear() {
+ // FIXME: looks like nothing to do given that we have no object pools
+ }
+ public void beginTrims() {}
+ public void beginLoop() {
+ pjarc = 0;
+ }
+
+ /**
+ * Adds a bezier arc to a trim loop and to a bin.
+ */
+ public void addArc(float[] cpts, Quilt quilt, long _nuid) {
+ BezierArc bezierArc = new BezierArc();
+ Arc jarc = new Arc(Arc.SIDE_NONE, _nuid);
+ jarc.bezierArc = bezierArc;
+ bezierArc.order = quilt.qspec.order;
+ bezierArc.stride = quilt.qspec.stride;
+ bezierArc.mapdesc = quilt.mapdesc;
+ bezierArc.cpts = cpts;
+ initialbin.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+ }
+
+ /**
+ * Adds a pwl arc to a trim loop and to a bin.
+ */
+ public void addArc(int npts, TrimVertex[] pts, long _nuid) {
+ Arc jarc = new Arc( Arc.SIDE_NONE, _nuid );
+ jarc.pwlArc = new PwlArc( npts, pts );
+ initialbin.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+ }
+ public void endLoop() {}
+ public void endTrims() {}
+
+ public void beginQuilts() {
+ qlist = null;
+ }
+ public void addQuilt( Quilt quilt ) {
+ quilt.next = qlist;
+ qlist = quilt;
+ }
+ public void endQuilts() {}
+
+ /**
+ * Main curve rendering entry point
+ */
+ public void drawCurves() {
+ float[] from = new float[1];
+ float[] to = new float[1];
+ Flist bpts = new Flist();
+ qlist.getRange( from, to, bpts );
+
+ renderhints.init( );
+
+ backend.bgncurv();
+ float[] pta = new float[0];
+ float[] ptb = new float[1];
+ for( int i=bpts.start; i<bpts.end-1; i++ ) {
+ pta[0] = bpts.pts[i];
+ ptb[0] = bpts.pts[i+1];
+
+ qlist.downloadAll( pta, ptb, backend );
+
+ Curvelist curvelist = new Curvelist( qlist, pta, ptb );
+ samplingSplit( curvelist, renderhints.maxsubdivisions );
+ }
+ backend.endcurv();
+ }
+ public void drawSurfaces(long nuid) {
+ renderhints.init( );
+
+ if (qlist == null) {
+ //initialbin could be nonempty due to some errors
+ freejarcs(initialbin);
+ return;
+ }
+
+ for( Quilt q = qlist; q != null; q = q.next ) {
+ if( q.isCulled( ) == Defines.CULL_TRIVIAL_REJECT ) {
+ freejarcs( initialbin );
+ return;
+ }
+ }
+
+
+ float[] from = new float[2];
+ float[] to = new float[2];
+ qlist.getRange( from, to, spbrkpts, tpbrkpts );
+ //perform optimization only when the samplng method is
+ //DOMAIN_DISTANCE and the display methdo is either
+ //fill or outline_polygon.
+ bool optimize = (is_domain_distance_sampling && (renderhints.display_method != N_OUTLINE_PATCH));
+
+ if( ! initialbin.isnonempty() ) {
+ if(! optimize )
+ {
+ makeBorderTrim( from, to );
+ }
+ } else {
+ float[] rate = new float[2];
+ qlist.findRates( spbrkpts, tpbrkpts, rate );
+
+ if( decompose( initialbin, Math.min(rate[0], rate[1]) ) )
+ throw new NurbsException( 31 );
+ }
+
+ backend.bgnsurf( renderhints.wiretris, renderhints.wirequads, nuid );
+
+ if( (!initialbin.isnonempty()) && optimize )
+ {
+ int i,j;
+ int num_u_steps;
+ int num_v_steps;
+ for(i=spbrkpts.start; i<spbrkpts.end-1; i++){
+ for(j=tpbrkpts.start; j<tpbrkpts.end-1; j++){
+ float[] pta = new float[2];
+ float[] ptb = new float[2];
+ pta[0] = spbrkpts.pts[i];
+ ptb[0] = spbrkpts.pts[i+1];
+ pta[1] = tpbrkpts.pts[j];
+ ptb[1] = tpbrkpts.pts[j+1];
+ qlist.downloadAll(pta, ptb, backend);
+
+ num_u_steps = (int) (domain_distance_u_rate * (ptb[0]-pta[0]));
+ num_v_steps = (int) (domain_distance_v_rate * (ptb[1]-pta[1]));
+
+ if(num_u_steps <= 0) num_u_steps = 1;
+ if(num_v_steps <= 0) num_v_steps = 1;
+
+ backend.surfgrid(pta[0], ptb[0], num_u_steps,
+ ptb[1], pta[1], num_v_steps);
+ backend.surfmesh(0,0,num_u_steps,num_v_steps);
+
+ continue;
+ }
+ }
+ }
+ else
+ subdivideInS( initialbin );
+
+ backend.endsurf();
+ }
+
+ public int ccwTurn_sl(Arc j1, Arc j2 ) {
+ int v1i = j1.pwlArc.npts-1;
+ int v1lasti = 0;
+ int v2i = 0;
+ int v2lasti = j2.pwlArc.npts-1;
+ int v1nexti = v1i-1;
+ int v2nexti = v2i+1;
+ TrimVertex v1 = j1.pwlArc.pts[v1i];
+ TrimVertex v1last = j1.pwlArc.pts[v1lasti];
+ TrimVertex v2 = j2.pwlArc.pts[v2i];
+ TrimVertex v2last = j2.pwlArc.pts[v2lasti];
+ TrimVertex v1next = j1.pwlArc.pts[v1nexti];
+ TrimVertex v2next = j2.pwlArc.pts[v2nexti];
+ int sgn;
+
+ assert( v1 != v1last );
+ assert( v2 != v2last );
+
+ // the arcs lie on the line (0 == v1.param[0])
+ if( v1.param[0] == v1next.param[0] && v2.param[0] == v2next.param[0] )
+ return 0;
+
+ if( v2next.param[0] > v2.param[0] || v1next.param[0] > v1.param[0] )
+ throw new NurbsException(28);
+
+ if( v1.param[1] < v2.param[1] )
+ return 1;
+ else if( v1.param[1] > v2.param[1] )
+ return 0;
+
+ while( true ) {
+ if( v1next.param[0] > v2next.param[0] ) {
+ assert( v1.param[0] >= v1next.param[0] );
+ assert( v2.param[0] >= v1next.param[0] );
+ switch( bbox( v2next, v2, v1next, 1 ) ) {
+ case -1:
+ return 1;
+ case 0:
+ sgn = ccw( v1next, v2, v2next );
+ if( sgn != -1 )
+ return sgn;
+ else {
+ v1i = v1nexti--;
+ v1 = j1.pwlArc.pts[v1i];
+ v1next = j1.pwlArc.pts[v1nexti];
+ if( v1 == v1last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 0;
+ }
+ } else if( v1next.param[0] < v2next.param[0] ) {
+ assert( v1.param[0] >= v2next.param[0] );
+ assert( v2.param[0] >= v2next.param[0] );
+ switch( bbox( v1next, v1, v2next, 1 ) ) {
+ case -1:
+ return 0;
+ case 0:
+ sgn = ccw( v1next, v1, v2next );
+ if( sgn != -1 )
+ return sgn;
+ else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 1;
+ }
+ } else {
+ if( v1next.param[1] < v2next.param[1] )
+ return 1;
+ else if( v1next.param[1] > v2next.param[1] )
+ return 0;
+ else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ }
+ }
+ }
+
+ public int ccwTurn_sr(Arc j1, Arc j2 ) {
+ // dir = 1
+ int v1i = j1.pwlArc.npts-1;
+ int v1lasti = 0;
+ int v2i = 0;
+ int v2lasti = j2.pwlArc.npts-1;
+ int v1nexti = v1i-1;
+ int v2nexti = v2i+1;
+ TrimVertex v1 = j1.pwlArc.pts[v1i];
+ TrimVertex v1last = j1.pwlArc.pts[v1lasti];
+ TrimVertex v2 = j2.pwlArc.pts[v2i];
+ TrimVertex v2last = j2.pwlArc.pts[v2lasti];
+ TrimVertex v1next = j1.pwlArc.pts[v1nexti];
+ TrimVertex v2next = j2.pwlArc.pts[v2nexti];
+ int sgn;
+
+ assert( v1 != v1last );
+ assert( v2 != v2last );
+
+ // the arcs lie on the line (0 == v1.param[0])
+ if( v1.param[0] == v1next.param[0] && v2.param[0] == v2next.param[0] )
+ return 0;
+
+ if( v2next.param[0] < v2.param[0] || v1next.param[0] < v1.param[0] )
+ throw new NurbsException(28);
+
+ if( v1.param[1] < v2.param[1] )
+ return 0;
+ else if( v1.param[1] > v2.param[1] )
+ return 1;
+
+ while( true ) {
+ if( v1next.param[0] < v2next.param[0] ) {
+ assert( v1.param[0] <= v1next.param[0] );
+ assert( v2.param[0] <= v1next.param[0] );
+ switch( bbox( v2, v2next, v1next, 1 ) ) {
+ case -1:
+ return 0;
+ case 0:
+ sgn = ccw( v1next, v2, v2next );
+ if( sgn != -1 ) {
+ return sgn;
+ } else {
+ v1i = v1nexti--;
+ v1 = j1.pwlArc.pts[v1i];
+ v1next = j1.pwlArc.pts[v1nexti];
+ if( v1 == v1last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 1;
+ }
+ } else if( v1next.param[0] > v2next.param[0] ) {
+ assert( v1.param[0] <= v2next.param[0] );
+ assert( v2.param[0] <= v2next.param[0] );
+ switch( bbox( v1, v1next, v2next, 1 ) ) {
+ case -1:
+ return 1;
+ case 0:
+ sgn = ccw( v1next, v1, v2next );
+ if( sgn != -1 ) {
+ return sgn;
+ } else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 0;
+ }
+ } else {
+ if( v1next.param[1] < v2next.param[1] )
+ return 0;
+ else if( v1next.param[1] > v2next.param[1] )
+ return 1;
+ else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ }
+ }
+ }
+
+ public int ccwTurn_tl(Arc j1, Arc j2 ) {
+ int v1i = j1.pwlArc.npts-1;
+ int v1lasti = 0;
+ int v2i = 0;
+ int v2lasti = j2.pwlArc.npts-1;
+ int v1nexti = v1i-1;
+ int v2nexti = v2i+1;
+ TrimVertex v1 = j1.pwlArc.pts[v1i];
+ TrimVertex v1last = j1.pwlArc.pts[v1lasti];
+ TrimVertex v2 = j2.pwlArc.pts[v2i];
+ TrimVertex v2last = j2.pwlArc.pts[v2lasti];
+ TrimVertex v1next = j1.pwlArc.pts[v1nexti];
+ TrimVertex v2next = j2.pwlArc.pts[v2nexti];
+ int sgn;
+
+ assert( v1 != v1last );
+ assert( v2 != v2last );
+
+ // the arcs lie on the line (1 == v1.param[1])
+ if( v1.param[1] == v1next.param[1] && v2.param[1] == v2next.param[1] )
+ return 0;
+
+ if( v2next.param[1] > v2.param[1] || v1next.param[1] > v1.param[1] )
+ throw new NurbsException(28 );
+
+ if( v1.param[0] < v2.param[0] )
+ return 0;
+ else if( v1.param[0] > v2.param[0] )
+ return 1;
+
+ while( true ) {
+ if( v1next.param[1] > v2next.param[1] ) {
+ assert( v1.param[1] >= v1next.param[1] );
+ assert( v2.param[1] >= v1next.param[1] );
+ switch( bbox( v2next, v2, v1next, 0 ) ) {
+ case -1:
+ return 0;
+ case 0:
+ sgn = ccw( v1next, v2, v2next );
+ if( sgn != -1 )
+ return sgn;
+ else {
+ v1i = v1nexti--;
+ v1 = j1.pwlArc.pts[v1i];
+ v1next = j1.pwlArc.pts[v1nexti];
+ if( v1 == v1last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 1;
+ }
+ } else if( v1next.param[1] < v2next.param[1] ) {
+ switch( bbox( v1next, v1, v2next, 0 ) ) {
+ case -1:
+ return 1;
+ case 0:
+ sgn = ccw( v1next, v1, v2next );
+ if( sgn != -1 )
+ return sgn;
+ else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 0;
+ }
+ } else {
+ if( v1next.param[0] < v2next.param[0] )
+ return 0;
+ else if( v1next.param[0] > v2next.param[0] )
+ return 1;
+ else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ }
+ }
+ }
+
+ public int ccwTurn_tr(Arc j1, Arc j2) {
+ int v1i = j1.pwlArc.npts-1;
+ int v1lasti = 0;
+ int v2i = 0;
+ int v2lasti = j2.pwlArc.npts-1;
+ int v1nexti = v1i-1;
+ int v2nexti = v2i+1;
+ TrimVertex v1 = j1.pwlArc.pts[v1i];
+ TrimVertex v1last = j1.pwlArc.pts[v1lasti];
+ TrimVertex v2 = j2.pwlArc.pts[v2i];
+ TrimVertex v2last = j2.pwlArc.pts[v2lasti];
+ TrimVertex v1next = j1.pwlArc.pts[v1nexti];
+ TrimVertex v2next = j2.pwlArc.pts[v2nexti];
+ int sgn;
+
+ assert( v1 != v1last );
+ assert( v2 != v2last );
+
+ // the arcs lie on the line (1 == v1.param[1])
+ if( v1.param[1] == v1next.param[1] && v2.param[1] == v2next.param[1] )
+ return 0;
+
+ if( v2next.param[1] < v2.param[1] || v1next.param[1] < v1.param[1] )
+ throw new NurbsException( 28 );
+
+ if( v1.param[0] < v2.param[0] )
+ return 1;
+ else if( v1.param[0] > v2.param[0] )
+ return 0;
+
+ while( 1 ) {
+ if( v1next.param[1] < v2next.param[1] ) {
+ assert( v1.param[1] <= v1next.param[1] );
+ assert( v2.param[1] <= v1next.param[1] );
+ switch( bbox( v2, v2next, v1next, 0 ) ) {
+ case -1:
+ return 1;
+ case 0:
+ sgn = ccw( v1next, v2, v2next );
+ if( sgn != -1 ) {
+ return sgn;
+ } else {
+ v1i = v1nexti--;
+ v1 = j1.pwlArc.pts[v1i];
+ v1next = j1.pwlArc.pts[v1nexti];
+ if( v1 == v1last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 0;
+ }
+ } else if( v1next.param[1] > v2next.param[1] ) {
+ assert( v1.param[1] <= v2next.param[1] );
+ assert( v2.param[1] <= v2next.param[1] );
+ switch( bbox( v1, v1next, v2next, 0 ) ) {
+ case -1:
+ return 0;
+ case 0:
+ sgn = ccw( v1next, v1, v2next );
+ if( sgn != -1 ) {
+ return sgn;
+ } else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ break;
+ case 1:
+ return 1;
+ }
+ } else {
+ if( v1next.param[0] < v2next.param[0] )
+ return 1;
+ else if( v1next.param[0] > v2next.param[0] )
+ return 0;
+ else {
+ v2i = v2nexti++;
+ v2 = j2.pwlArc.pts[v2i];
+ v2next = j2.pwlArc.pts[v2nexti];
+ if( v2 == v2last ) {
+ return 0; // ill-conditioned, guess answer
+ }
+ }
+ }
+ }
+ }
+
+ public void set_domain_distance_u_rate(float u_rate) {
+ domain_distance_u_rate = u_rate;
+ }
+
+ public void set_domain_distance_v_rate(float v_rate) {
+ domain_distance_v_rate = v_rate;
+ }
+
+ public void set_is_domain_distance_sampling(int flag) {
+ is_domain_distance_sampling = flag;
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ /**
+ * Determine which side of a line a jarc lies (for debugging only)
+ */
+ private int arc_classify( Arc jarc, int param, float value )
+ {
+ float tdiff, hdiff;
+ if( param == 0 ) {
+ tdiff = jarc.tail()[0] - value;
+ hdiff = jarc.head()[0] - value;
+ } else {
+ tdiff = jarc.tail()[1] - value;
+ hdiff = jarc.head()[1] - value;
+ }
+
+ if( tdiff > 0.0 ) {
+ if( hdiff > 0.0 ) {
+ return 0x11;
+ } else if( hdiff == 0.0 ) {
+ return 0x12;
+ } else {
+ return 0x10;
+ }
+ } else if( tdiff == 0.0 ) {
+ if( hdiff > 0.0 ) {
+ return 0x21;
+ } else if( hdiff == 0.0 ) {
+ return 0x22;
+ } else {
+ return 0x20;
+ }
+ } else {
+ if( hdiff > 0.0 ) {
+ return 0x01;
+ } else if( hdiff == 0.0 ) {
+ return 0x02;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ private void classify_headonleft_s( Bin bin, Bin in, Bin out, float val ) {
+ /* tail on line, head at left */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 0, val ) == 0x20 );
+
+ j.setitail();
+
+ float diff = j.prev.tail()[0] - val;
+ if( diff > 0.0 ) {
+ out.addarc( j );
+ } else if( diff < 0.0 ) {
+ if( ccwTurn_sl( j.prev, j ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else {
+ if( j.prev.tail()[1] > j.prev.head()[1] )
+ in.addarc( j );
+ else
+ out.addarc( j );
+ }
+ }
+ }
+
+ private void classify_tailonleft_s( Bin bin, Bin in, Bin out, float val ) {
+ /* tail at left, head on line */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 1, val ) == 0x02 );
+ j.clearitail();
+
+ float diff = j.next.head()[1] - val;
+ if( diff > 0.0 ) {
+ in.addarc( j );
+ } else if( diff < 0.0 ) {
+ if( ccwTurn_tl( j, j.next ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else {
+ if (j.next.tail()[0] > j.next.head()[0] )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ }
+ }
+ }
+
+ private void classify_headonright_s( Bin bin, Bin in, Bin out, float val ) {
+ /* tail on line, head at right */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 0, val ) == 0x21 );
+
+ j.setitail();
+
+ float diff = j.prev.tail()[0] - val;
+ if( diff > 0.0 ) {
+ if( ccwTurn_sr( j.prev, j ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else if( diff < 0.0 ) {
+ out.addarc( j );
+ } else {
+ if( j.prev.tail()[1] > j.prev.head()[1] )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ }
+ }
+ }
+
+ private void classify_tailonright_s( Bin bin, Bin in, Bin out, float val ) {
+ /* tail at right, head on line */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 0, val ) == 0x12);
+
+ j.clearitail();
+
+ float diff = j.next.head()[0] - val;
+ if( diff > 0.0 ) {
+ if( ccwTurn_sr( j, j.next ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else if( diff < 0.0 ) {
+ in.addarc( j );
+ } else {
+ if( j.next.tail()[1] > j.next.head()[1] )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ }
+ }
+ }
+
+ private void classify_headonleft_t( Bin bin, Bin in, Bin out, float val ) {
+ /* tail on line, head at left */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 1, val ) == 0x20 );
+ j.setitail();
+
+ float diff = j.prev.tail()[1] - val;
+ if( diff > 0.0 ) {
+ out.addarc( j );
+ } else if( diff < 0.0 ) {
+ if( ccwTurn_tl( j.prev, j ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else {
+ if( j.prev.tail()[0] > j.prev.head()[0] )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ }
+ }
+ }
+
+ private void classify_tailonleft_t( Bin bin, Bin in, Bin out, float val ) {
+ /* tail at left, head on line */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 1, val ) == 0x02 );
+ j.clearitail();
+
+ float diff = j.next.head()[1] - val;
+ if( diff > 0.0 ) {
+ in.addarc( j );
+ } else if( diff < 0.0 ) {
+ if( ccwTurn_tl( j, j.next ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else {
+ if (j.next.tail()[0] > j.next.head()[0] )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ }
+ }
+ }
+
+ private void classify_headonright_t( Bin bin, Bin in, Bin out, float val ) {
+ /* tail on line, head at right */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 1, val ) == 0x21 );
+
+ j.setitail();
+
+ float diff = j.prev.tail()[1] - val;
+ if( diff > 0.0 ) {
+ if( ccwTurn_tr( j.prev, j ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else if( diff < 0.0 ) {
+ out.addarc( j );
+ } else {
+ if( j.prev.tail()[0] > j.prev.head()[0] )
+ in.addarc( j );
+ else
+ out.addarc( j );
+ }
+ }
+ }
+
+ private void classify_tailonright_t( Bin bin, Bin in, Bin out, float val ) {
+ /* tail at right, head on line */
+ Arc j;
+
+ while( (j = bin.removearc()) != null ) {
+ assert( arc_classify( j, 1, val ) == 0x12);
+
+ j.clearitail();
+
+ float diff = j.next.head()[1] - val;
+ if( diff > 0.0 ) {
+ if( ccwTurn_tr( j, j.next ) != 0 )
+ out.addarc( j );
+ else
+ in.addarc( j );
+ } else if( diff < 0.0 ) {
+ in.addarc( j );
+ } else {
+ if( j.next.tail()[0] > j.next.head()[0] )
+ in.addarc( j );
+ else
+ out.addarc( j );
+ }
+ }
+ }
+
+ private int DIR_DOWN = 0;
+ private int DIR_SAME = 1;
+ private int DIR_UP = 2;
+ private int DIR_NONE = 3;
+
+ private void tessellate( Arc_ptr, float );
+ private void monotonize( Arc_ptr , Bin & );
+ private int isMonotone( Arc_ptr );
+ private int decompose( Bin &, float );
+
+
+ private Slicer slicer;
+ private ArcTessellator arctessellator;
+ // private Pool arcpool;
+ // private Pool bezierarcpool;
+ // private Pool pwlarcpool;
+ // private TrimVertexPool trimvertexpool;
+
+ private JumpBuffer* jumpbuffer;
+ private Renderhints& renderhints;
+ private Backend& backend;
+
+ private Bin initialbin;
+ private Arc pjarc;
+ private int s_index;
+ private int t_index;
+ private Quilt *qlist;
+ private Flist spbrkpts;
+ private Flist tpbrkpts;
+ private Flist smbrkpts;
+ private Flist tmbrkpts;
+ private float stepsizes[4];
+ private int showDegenerate;
+ private int isArcTypeBezier;
+
+ // FIXME: NOT FINISHED
+ private void samplingSplit( Curvelist&, int );
+
+ private void subdivideInS( Bin source ) {
+ if( renderhints.display_method == N_OUTLINE_PARAM ) {
+ outline( source );
+ freejarcs( source );
+ } else {
+ setArcTypeBezier();
+ setNonDegenerate();
+ splitInS( source, spbrkpts.start, spbrkpts.end );
+ }
+ }
+
+ /**
+ * Splits a patch and a bin by an isoparametric line.
+ */
+ private void splitInS( Bin source, int start, int end ) {
+ if( source.isnonempty() ) {
+ if( start != end ) {
+ int i = start + (end - start) / 2;
+ Bin left = new Bin();
+ Bin right = new Bin();
+ split( source, left, right, 0, spbrkpts.pts[i] );
+ splitInS( left, start, i );
+ splitInS( right, i+1, end );
+ } else {
+ if( start == spbrkpts.start || start == spbrkpts.end ) {
+ freejarcs( source );
+ } else if( renderhints.display_method == NurbsConsts.N_OUTLINE_PARAM_S ) {
+ outline( source );
+ freejarcs( source );
+ } else {
+ setArcTypeBezier();
+ setNonDegenerate();
+ s_index = start;
+ splitInT( source, tpbrkpts.start, tpbrkpts.end );
+ }
+ }
+ }
+ }
+
+ /**
+ * Splits a patch and a bin by an isoparametric line.
+ */
+ private void splitInT( Bin source, int start, int end ) {
+ if( source.isnonempty() ) {
+ if( start != end ) {
+ int i = start + (end - start) / 2;
+ Bin left = new Bin();
+ Bin right = new Bin();
+ split( source, left, right, 1, tpbrkpts.pts[i] );
+ splitInT( left, start, i );
+ splitInT( right, i+1, end );
+ } else {
+ if( start == tpbrkpts.start || start == tpbrkpts.end ) {
+ freejarcs( source );
+ } else if( renderhints.display_method == NurbsConsts.N_OUTLINE_PARAM_ST ) {
+ outline( source );
+ freejarcs( source );
+ } else {
+ t_index = start;
+ setArcTypeBezier();
+ setDegenerate();
+
+ float[] pta = new float[2];
+ float[] ptb = new float[2];
+ pta[0] = spbrkpts.pts[s_index-1];
+ pta[1] = tpbrkpts.pts[t_index-1];
+
+ ptb[0] = spbrkpts.pts[s_index];
+ ptb[1] = tpbrkpts.pts[t_index];
+ qlist.downloadAll( pta, ptb, backend );
+
+ Patchlist patchlist = new Patchlist( qlist, pta, ptb );
+ /*
+ printf("-------samplingSplit-----\n");
+ source.show("samplingSplit source");
+ */
+ samplingSplit( source, patchlist, renderhints.maxsubdivisions, 0 );
+ setNonDegenerate();
+ setArcTypeBezier();
+ }
+ }
+ }
+ }
+
+ /**
+ * Recursively subdivides patch, cull checks each subpatch
+ */
+ private void samplingSplit( Bin source, Patchlist patchlist, int subdivisions, int param ) {
+ if( ! source.isnonempty() ) return;
+
+ if( patchlist.cullCheck() == Defines.CULL_TRIVIAL_REJECT ) {
+ freejarcs( source );
+ return;
+ }
+
+ patchlist.getstepsize();
+
+ if( renderhints.display_method == NurbsConsts.N_OUTLINE_PATCH ) {
+ tessellation( source, patchlist );
+ outline( source );
+ freejarcs( source );
+ return;
+ }
+
+ //patchlist.clamp();
+
+ tessellation( source, patchlist );
+
+ if( patchlist.needsSamplingSubdivision() && (subdivisions > 0) ) {
+ if( ! patchlist.needsSubdivision( 0 ) )
+ param = 1;
+ else if( ! patchlist.needsSubdivision( 1 ) )
+ param = 0;
+ else
+ param = 1 - param;
+
+ Bin left = new Bin();
+ Bin right = new Bin();
+ float mid = ( patchlist.pspec[param].range[0] +
+ patchlist.pspec[param].range[1] ) * 0.5;
+ split( source, left, right, param, mid );
+ Patchlist subpatchlist = new Patchlist( patchlist, param, mid );
+ samplingSplit( left, subpatchlist, subdivisions-1, param );
+ samplingSplit( right, patchlist, subdivisions-1, param );
+ } else {
+ setArcTypePwl();
+ setDegenerate();
+ nonSamplingSplit( source, patchlist, subdivisions, param );
+ setDegenerate();
+ setArcTypeBezier();
+ }
+ }
+
+ private void nonSamplingSplit( Bin source, Patchlist patchlist, int subdivisions, int param ) {
+ if( patchlist.needsNonSamplingSubdivision() && (subdivisions > 0) ) {
+ param = 1 - param;
+
+ Bin left = new Bin();
+ Bin right = new Bin();
+ float mid = ( patchlist.pspec[param].range[0] +
+ patchlist.pspec[param].range[1] ) * 0.5;
+ split( source, left, right, param, mid );
+ Patchlist subpatchlist = new Patchlist( patchlist, param, mid );
+ if( left.isnonempty() )
+ if( subpatchlist.cullCheck() == Defines.CULL_TRIVIAL_REJECT )
+ freejarcs( left );
+ else
+ nonSamplingSplit( left, subpatchlist, subdivisions-1, param );
+ if( right.isnonempty() )
+ if( patchlist.cullCheck() == Defines.CULL_TRIVIAL_REJECT )
+ freejarcs( right );
+ else
+ nonSamplingSplit( right, patchlist, subdivisions-1, param );
+
+ } else {
+ // make bbox calls
+ patchlist.bbox();
+ backend.patch( patchlist.pspec[0].range[0], patchlist.pspec[0].range[1],
+ patchlist.pspec[1].range[0], patchlist.pspec[1].range[1] );
+
+ if( renderhints.display_method == NurbsConsts.N_OUTLINE_SUBDIV ) {
+ outline( source );
+ freejarcs( source );
+ } else {
+ setArcTypePwl();
+ setDegenerate();
+ findIrregularS( source );
+ monosplitInS( source, smbrkpts.start, smbrkpts.end );
+ }
+ }
+ }
+
+ /**
+ * Sets tessellation of interior and boundary of patch.
+ */
+ private void tessellation( Bin bin, Patchlist patchlist ) {
+ // tessellate unsampled trim curves
+ tessellate( bin, patchlist.pspec[1].sidestep[1], patchlist.pspec[0].sidestep[1],
+ patchlist.pspec[1].sidestep[0], patchlist.pspec[0].sidestep[0] );
+
+ // set interior sampling rates
+ slicer.setstriptessellation( patchlist.pspec[0].stepsize, patchlist.pspec[1].stepsize );
+
+ //added by zl: set the order which will be used in slicer.c++
+ slicer.set_ulinear( (patchlist.get_uorder() == 2));
+ slicer.set_vlinear( (patchlist.get_vorder() == 2));
+
+ // set boundary sampling rates
+ stepsizes[0] = patchlist.pspec[1].stepsize;
+ stepsizes[1] = patchlist.pspec[0].stepsize;
+ stepsizes[2] = patchlist.pspec[1].stepsize;
+ stepsizes[3] = patchlist.pspec[0].stepsize;
+ }
+
+ /**
+ * Splits a patch and a bin by an isoparametric line.
+ */
+ private void monosplitInS( Bin source, int start, int end ) {
+ if( source.isnonempty() ) {
+ if( start != end ) {
+ int i = start + (end - start) / 2;
+ Bin left = new Bin();
+ Bin right = new Bin();
+ split( source, left, right, 0, smbrkpts.pts[i] );
+ monosplitInS( left, start, i );
+ monosplitInS( right, i+1, end );
+ } else {
+ if( renderhints.display_method == NurbsConsts.N_OUTLINE_SUBDIV_S ) {
+ outline( source );
+ freejarcs( source );
+ } else {
+ setArcTypePwl();
+ setDegenerate();
+ findIrregularT( source );
+ monosplitInT( source, tmbrkpts.start, tmbrkpts.end );
+ }
+ }
+ }
+ }
+
+ /**
+ * Splits a patch and a bin by an isoparametric line.
+ */
+ private void monosplitInT( Bin source, int start, int end ) {
+ if( source.isnonempty() ) {
+ if( start != end ) {
+ int i = start + (end - start) / 2;
+ Bin left = new Bin();
+ Bin right = new Bin();
+ split( source, left, right, 1, tmbrkpts.pts[i] );
+ monosplitInT( left, start, i );
+ monosplitInT( right, i+1, end );
+ } else {
+ if( renderhints.display_method == NurbsConsts.N_OUTLINE_SUBDIV_ST ) {
+ outline( source );
+ freejarcs( source );
+ } else {
+ /*
+ printf("*******render\n");
+ source.show("source\n");
+ */
+ render( source );
+ freejarcs( source );
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the trimmed patch by outlining the boundary .
+ */
+ private void outline( Bin bin ) {
+ bin.markall();
+ for( Arc jarc=bin.firstarc(); jarc != null; jarc=bin.nextarc() ) {
+ if( jarc.ismarked() ) {
+ assert( jarc.check( ) );
+ Arc jarchead = jarc;
+ do {
+ slicer.outline( jarc );
+ jarc.clearmark();
+ jarc = jarc.prev;
+ } while (jarc != jarchead);
+ }
+ }
+ }
+
+ /**
+ * Frees all arcs in a bin.
+ */
+ private void freejarcs( Bin & ) {
+ bin.adopt(); /* XXX - should not be necessary */
+
+ Arc jarc;
+ while( (jarc = bin.removearc()) != null ) {
+ if( jarc.pwlArc != null ) jarc.pwlArc.deleteMe( ); jarc.pwlArc = null;
+ if( jarc.bezierArc != null) jarc.bezierArc.deleteMe( ); jarc.bezierArc = null;
+ jarc.deleteMe( );
+ }
+ }
+
+ /**
+ * Renders all monotone regions in a bin and frees the bin.
+ */
+ private void render( Bin bin ) {
+ bin.markall();
+
+ slicer.setisolines( ( renderhints.display_method == N_ISOLINE_S ) ? 1 : 0 );
+
+ for( Arc jarc=bin.firstarc(); jarc != null; jarc=bin.nextarc() ) {
+ if( jarc.ismarked() ) {
+ assert( jarc.check( ) != 0 );
+ Arc jarchead = jarc;
+ do {
+ jarc.clearmark();
+ jarc = jarc.next;
+ } while (jarc != jarchead);
+ slicer.slice( jarc );
+ }
+ }
+ }
+
+ private void split( Bin &, Bin &, Bin &, int, float );
+
+ /**
+ * Tessellates all Bezier arcs in a bin.
+ * <ol>
+ * <li> only accepts linear Bezier arcs as input
+ * <li> the Bezier arcs are stored in the pwlArc structure
+ * <li> only vertical or horizontal lines work
+ * </ol>
+ * should:
+ * <ol>
+ * <li> represent Bezier arcs in BezierArc structure
+ * (this requires a multitude of changes to the code)
+ * <li> accept high degree Bezier arcs (hard)
+ * <il> map the curve onto the surface to determine tessellation
+ * <li> work for curves of arbitrary geometry
+ * </ol>
+ *----------------------------------------------------------------------------
+ */
+ private void tessellate( Bin bin, float rrate, float trate, float lrate, float brate ) {
+ for( Arc jarc=bin.firstarc(); jarc != null; jarc=bin.nextarc() ) {
+ if( jarc.isbezier( ) ) {
+ assert( jarc.pwlArc.npts == 2 );
+ TrimVertex[] pts = jarc.pwlArc.pts;
+ float s1 = pts[0].param[0];
+ float t1 = pts[0].param[1];
+ float s2 = pts[1].param[0];
+ float t2 = pts[1].param[1];
+
+ jarc.pwlArc.deleteMe( );
+ jarc.pwlArc = null;
+
+ switch( jarc.getside() ) {
+ case Arc.SIDE_LEFT:
+ assert( s1 == s2 );
+ arctessellator.pwl_left( jarc, s1, t1, t2, lrate );
+ break;
+ case Arc.SIDE_RIGHT:
+ assert( s1 == s2 );
+ arctessellator.pwl_right( jarc, s1, t1, t2, rrate );
+ break;
+ case Arc.SIDE_TOP:
+ assert( t1 == t2 );
+ arctessellator.pwl_top( jarc, t1, s1, s2, trate );
+ break;
+ case Arc.SIDE_BOTTOM:
+ assert( t1 == t2 );
+ arctessellator.pwl_bottom( jarc, t1, s1, s2, brate );
+ break;
+ case Arc.SIDE_NONE:
+ throw new InternalError("Incorrect tesselation state");
+ break;
+ }
+ assert( ! jarc.isbezier() );
+ assert( jarc.check() != 0 );
+ }
+ }
+ }
+
+ private inline void setDegenerate( void ) { showDegenerate = 1; }
+ private inline void setNonDegenerate( void ) { showDegenerate = 0; }
+ private inline int showingDegenerate( void ) { return showDegenerate; }
+ private inline void setArcTypeBezier( void ) { isArcTypeBezier = 1; }
+ private inline void setArcTypePwl( void ) { isArcTypeBezier = 0; }
+ private inline int isBezierArcType( void ) { return isArcTypeBezier; }
+
+ /**
+ * If no user input trimming data, then create a trimming curve
+ * around the boundaries of the Quilt. The curve consists of four
+ * Jordan arcs, one for each side of the Quilt, connected, of
+ * course, head to tail.
+ */
+ private void makeBorderTrim( float[] from, float[] to ) {
+ float smin = from[0];
+ float smax = to[0];
+ float tmin = from[1];
+ float tmax = to[1];
+
+ pjarc = null;
+
+ Arc jarc = new Arc( Arc.SIDE_BOTTOM, 0 );
+ arctessellator.bezier( jarc, smin, smax, tmin, tmin );
+ initialbin.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+
+ jarc = new Arc( Arc.SIDE_RIGHT, 0 );
+ arctessellator.bezier( jarc, smax, smax, tmin, tmax );
+ initialbin.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+
+ jarc = new Arc( Arc.SIDE_TOP, 0 );
+ arctessellator.bezier( jarc, smax, smin, tmax, tmax );
+ initialbin.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+
+ jarc = new Arc( Arc.SIDE_LEFT, 0 );
+ arctessellator.bezier( jarc, smin, smin, tmax, tmin );
+ initialbin.addarc( jarc );
+ jarc.append( pjarc );
+
+ assert( jarc.check() );
+ }
+
+ private void split( Bin &, int, const float *, int, int );
+ private void partition( Bin bin, Bin left, Bin intersections, Bin right, Bin unknown, int param, float value ) {
+ Bin headonleft = new Bin();
+ Bin headonright = new Bin();
+ Bin tailonleft = new Bin();
+ Bin tailonright = new Bin();
+
+ for( Arc jarc = bin.removearc(); jarc != null; jarc = bin.removearc() ) {
+
+ float tdiff = jarc.tail()[param] - value;
+ float hdiff = jarc.head()[param] - value;
+
+ if( tdiff > 0.0 ) {
+ if( hdiff > 0.0 ) {
+ right.addarc( jarc );
+ } else if( hdiff == 0.0 ) {
+ tailonright.addarc( jarc );
+ } else {
+ Arc jtemp;
+ switch( arc_split(jarc, param, value, 0) ) {
+ case 2:
+ tailonright.addarc( jarc );
+ headonleft.addarc( jarc.next );
+ break;
+ case 31:
+ assert( jarc.head()[param] > value );
+ right.addarc( jarc );
+ tailonright.addarc( jtemp = jarc.next );
+ headonleft.addarc( jtemp.next );
+ break;
+ case 32:
+ assert( jarc.head()[param] <= value );
+ tailonright .addarc( jarc );
+ headonleft.addarc( jtemp = jarc.next );
+ left.addarc( jtemp.next );
+ break;
+ case 4:
+ right.addarc( jarc );
+ tailonright.addarc( jtemp = jarc.next );
+ headonleft.addarc( jtemp = jtemp.next );
+ left.addarc( jtemp.next );
+ }
+ }
+ } else if( tdiff == 0.0 ) {
+ if( hdiff > 0.0 ) {
+ headonright.addarc( jarc );
+ } else if( hdiff == 0.0 ) {
+ unknown.addarc( jarc );
+ } else {
+ headonleft.addarc( jarc );
+ }
+ } else {
+ if( hdiff > 0.0 ) {
+ Arc jtemp;
+ switch( arc_split(jarc, param, value, 1) ) {
+ case 2:
+ tailonleft.addarc( jarc );
+ headonright.addarc( jarc.next );
+ break;
+ case 31:
+ assert( jarc.head()[param] < value );
+ left.addarc( jarc );
+ tailonleft.addarc( jtemp = jarc.next );
+ headonright.addarc( jtemp.next );
+ break;
+ case 32:
+ assert( jarc.head()[param] >= value );
+ tailonleft.addarc( jarc );
+ headonright.addarc( jtemp = jarc.next );
+ right.addarc( jtemp.next );
+ break;
+ case 4:
+ left.addarc( jarc );
+ tailonleft.addarc( jtemp = jarc.next );
+ headonright.addarc( jtemp = jtemp.next );
+ right.addarc( jtemp.next );
+ }
+ } else if( hdiff == 0.0 ) {
+ tailonleft.addarc( jarc );
+ } else {
+ left.addarc( jarc );
+ }
+ }
+ }
+ if( param == 0 ) {
+ classify_headonleft_s( headonleft, intersections, left, value );
+ classify_tailonleft_s( tailonleft, intersections, left, value );
+ classify_headonright_s( headonright, intersections, right, value );
+ classify_tailonright_s( tailonright, intersections, right, value );
+ } else {
+ classify_headonleft_t( headonleft, intersections, left, value );
+ classify_tailonleft_t( tailonleft, intersections, left, value );
+ classify_headonright_t( headonright, intersections, right, value );
+ classify_tailonright_t( tailonright, intersections, right, value );
+ }
+ }
+
+ /**
+ * Determine points of non-monotonicity in s direction.
+ */
+ private void findIrregularS( Bin bin ) {
+ assert( bin.firstarc() == null || bin.firstarc().check() );
+
+ smbrkpts.grow( bin.numarcs() );
+
+ for( Arc jarc=bin.firstarc(); jarc != null; jarc=bin.nextarc() ) {
+ float[] a = jarc.prev.tail();
+ float[] b = jarc.tail();
+ float[] c = jarc.head();
+
+ if( b[1] == a[1] && b[1] == c[1] ) continue;
+
+ //corrected code
+ if((b[1]<=a[1] && b[1] <= c[1]) ||
+ (b[1]>=a[1] && b[1] >= c[1]))
+ {
+ //each arc (jarc, jarc.prev, jarc.next) is a
+ //monotone arc consisting of multiple line segements.
+ //it may happen that jarc.prev and jarc.next are the same,
+ //that is, jarc.prev and jarc form a closed loop.
+ //In such case, a and c will be the same.
+ if(a[0]==c[0] && a[1] == c[1])
+ {
+ if(jarc.pwlArc.npts >2)
+ {
+ c = jarc.pwlArc.pts[jarc.pwlArc.npts-2].param;
+ }
+ else
+ {
+ assert(jarc.prev.pwlArc.npts>2);
+ a = jarc.prev.pwlArc.pts[jarc.prev.pwlArc.npts-2].param;
+ }
+
+ }
+ if(area(a,b,c) < 0)
+ {
+ smbrkpts.add(b[0]);
+ }
+
+ }
+
+ /* old code,
+ if( b[1] <= a[1] && b[1] <= c[1] ) {
+ if( ! ccwTurn_tr( jarc.prev, jarc ) )
+ smbrkpts.add( b[0] );
+ } else if( b[1] >= a[1] && b[1] >= c[1] ) {
+ if( ! ccwTurn_tl( jarc.prev, jarc ) )
+ smbrkpts.add( b[0] );
+ }
+ */
+
+ }
+
+ smbrkpts.filter();
+ }
+
+ /**
+ * Determines points of non-monotonicity in t direction where one
+ * arc is parallel to the s axis.
+ */
+ private void findIrregularT( Bin bin ) {
+ assert( bin.firstarc() == null || bin.firstarc().check() );
+
+ tmbrkpts.grow( bin.numarcs() );
+
+ for( Arc jarc=bin.firstarc(); jarc != null; jarc=bin.nextarc() ) {
+ float[] a = jarc.prev.tail();
+ float[] b = jarc.tail();
+ float[] c = jarc.head();
+
+ if( b[0] == a[0] && b[0] == c[0] ) continue;
+
+ if( b[0] <= a[0] && b[0] <= c[0] ) {
+ if( a[1] != b[1] && b[1] != c[1] ) continue;
+ if( ccwTurn_sr( jarc.prev, jarc ) == 0)
+ tmbrkpts.add( b[1] );
+ } else if ( b[0] >= a[0] && b[0] >= c[0] ) {
+ if( a[1] != b[1] && b[1] != c[1] ) continue;
+ if( ccwTurn_sl( jarc.prev, jarc ) == 0)
+ tmbrkpts.add( b[1] );
+ }
+ }
+ tmbrkpts.filter( );
+ }
+
+
+ private int bbox( TrimVertex a, TrimVertex b, TrimVertex c, int p ) {
+ return bbox( a.param[p], b.param[p], c.param[p],
+ a.param[1-p], b.param[1-p], c.param[1-p] );
+ }
+
+ private static int bbox( float sa, float sb, float sc, float ta, float tb, float tc ) {
+ assert( tc >= ta );
+ assert( tc <= tb );
+
+ if( sa < sb ) {
+ if( sc <= sa ) {
+ return -1;
+ } else if( sb <= sc ) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if( sa > sb ) {
+ if( sc >= sa ) {
+ return 1;
+ } else if( sb >= sc ) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } else {
+ if( sc > sa ) {
+ return 1;
+ } else if( sb > sc ) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ /**
+ * Determines how three points are oriented by computing their
+ * determinant.
+ *
+ * @return 1 if the vertices are ccw oriented, 0 if they are cw
+ * oriented, or -1 if the computation is ill-conditioned.
+ */
+ private static int ccw( TrimVertex a, TrimVertex b, TrimVertex c ) {
+ float d = TrimVertex.det3( a, b, c );
+ if( Math.abs(d) < 0.0001 ) return -1;
+ return (d < 0.0) ? 0 : 1;
+ }
+ private void join_s( Bin &, Bin &, Arc_ptr, Arc_ptr );
+ private void join_t( Bin &, Bin &, Arc_ptr , Arc_ptr );
+
+ private static void vert_interp( TrimVertex n, TrimVertex l, TrimVertex r, int p, float val ) {
+ assert( val > l.param[p]);
+ assert( val < r.param[p]);
+
+ n.nuid = l.nuid;
+
+ n.param[p] = val;
+ if( l.param[1-p] != r.param[1-p] ) {
+ float ratio = (val - l.param[p]) / (r.param[p] - l.param[p]);
+ n.param[1-p] = l.param[1-p] +
+ ratio * (r.param[1-p] - l.param[1-p]);
+ } else {
+ n.param[1-p] = l.param[1-p];
+ }
+ }
+
+ private static final int INTERSECT_VERTEX = 1;
+ private static final int INTERSECT_EDGE = 2;
+
+ /**
+ * Finds intersection of pwlArc and isoparametric line.
+ */
+ private static int pwlarc_intersect( PwlArc pwlArc, int param, float value, int dir, int[] loc ) {
+ assert( pwlArc.npts > 0 );
+
+ if( dir != 0 ) {
+ TrimVertex[] v = pwlArc.pts;
+ int imin = 0;
+ int imax = pwlArc.npts - 1;
+ assert( value > v[imin].param[param] );
+ assert( value < v[imax].param[param] );
+ while( (imax - imin) > 1 ) {
+ int imid = (imax + imin)/2;
+ if( v[imid].param[param] > value )
+ imax = imid;
+ else if( v[imid].param[param] < value )
+ imin = imid;
+ else {
+ loc[1] = imid;
+ return INTERSECT_VERTEX;
+ }
+ }
+ loc[0] = imin;
+ loc[2] = imax;
+ return INTERSECT_EDGE;
+ } else {
+ TrimVertex[] v = pwlArc.pts;
+ int imax = 0;
+ int imin = pwlArc.npts - 1;
+ assert( value > v[imin].param[param] );
+ assert( value < v[imax].param[param] );
+ while( (imin - imax) > 1 ) {
+ int imid = (imax + imin)/2;
+ if( v[imid].param[param] > value )
+ imax = imid;
+ else if( v[imid].param[param] < value )
+ imin = imid;
+ else {
+ loc[1] = imid;
+ return INTERSECT_VERTEX;
+ }
+ }
+ loc[0] = imin;
+ loc[2] = imax;
+ return INTERSECT_EDGE;
+ }
+ }
+
+ private int arc_split( Arc jarc , int param, float value, int dir ) {
+ int maxvertex = jarc.pwlArc.npts;
+ Arc jarc1, jarc2, jarc3;
+ TrimVertex v = jarc.pwlArc.pts;
+
+ int[] loc = new int[3];
+ switch( pwlarc_intersect( jarc.pwlArc, param, value, dir, loc ) ) {
+
+ // When the parameter value lands on a vertex, life is sweet
+ case INTERSECT_VERTEX: {
+ jarc1 = new Arc( jarc, new PwlArc( maxvertex-loc[1], /* &v[loc[1]] */ v, loc[1] ) );
+ jarc.pwlArc.npts = loc[1] + 1;
+ jarc1.next = jarc.next;
+ jarc1.next.prev = jarc1;
+ jarc.next = jarc1;
+ jarc1.prev = jarc;
+ assert(jarc.check());
+ return 2;
+ }
+
+ // When the parameter value intersects an edge, we have to
+ // interpolate a new vertex. There are special cases
+ // if the new vertex is adjacent to one or both of the
+ // endpoints of the arc.
+ case INTERSECT_EDGE: {
+ int i, j;
+ if( dir == 0 ) {
+ i = loc[0];
+ j = loc[2];
+ } else {
+ i = loc[2];
+ j = loc[0];
+ }
+
+ // The split is between vertices at index j and i, in that
+ // order (j < i)
+
+ // JEB: This code is my idea of how to do the split without
+ // increasing the number of links. I'm doing this so that
+ // the is_rect routine can recognize rectangles created by
+ // subdivision. In exchange for simplifying the curve list,
+ // however, it costs in allocated space and vertex copies.
+
+ TrimVertex[] newjunk = TrimVertex.allocate(maxvertex -i+1 /*-j*/);
+ int k;
+ for(k=0; k<maxvertex-i; k++)
+ {
+ newjunk[k+1] = v[i+k];
+ newjunk[k+1].nuid = jarc.nuid;
+ }
+
+ TrimVertex[] vcopy = TrimVertex.allocate(maxvertex);
+ for(k=0; k<maxvertex; k++)
+ {
+ vcopy[k].param[0] = v[k].param[0];
+ vcopy[k].param[1] = v[k].param[1];
+ }
+ jarc.pwlArc.pts=vcopy;
+
+ v[i].nuid = jarc.nuid;
+ v[j].nuid = jarc.nuid;
+ vert_interp( newjunk[0], v[loc[0]], v[loc[2]], param, value );
+
+ if( showingDegenerate() )
+ backend.triangle( v[i], newjunk[0], v[j] );
+
+ vcopy[j+1].param[0]=newjunk[0].param[0];
+ vcopy[j+1].param[1]=newjunk[0].param[1];
+
+
+ jarc1 = new Arc( jarc,
+ new PwlArc(maxvertex-i+1 , newjunk ) );
+
+ jarc.pwlArc.npts = j+2;
+ jarc1.next = jarc.next;
+ jarc1.next.prev = jarc1;
+ jarc.next = jarc1;
+ jarc1.prev = jarc;
+ assert(jarc.check());
+
+ return 2;
+
+ /***
+ // JEB: This is the original version:
+
+ TrimVertex[] newjunk = TrimVertex.allocate(3);
+ v[i].nuid = jarc.nuid;
+ v[j].nuid = jarc.nuid;
+ newjunk[0] = v[j];
+ newjunk[2] = v[i];
+ vert_interp( &newjunk[1], &v[loc[0]], &v[loc[2]], param, value );
+
+ if( showingDegenerate() )
+ backend.triangle( &newjunk[2], &newjunk[1], &newjunk[0] );
+
+ // New vertex adjacent to both endpoints
+ if (maxvertex == 2) {
+ jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+ jarc.pwlArc.npts = 2;
+ jarc.pwlArc.pts = newjunk;
+ jarc1.next = jarc.next;
+ jarc1.next.prev = jarc1;
+ jarc.next = jarc1;
+ jarc1.prev = jarc;
+ assert(jarc.check() != 0);
+
+ return 2;
+
+ // New vertex adjacent to ending point of arc
+ } else if (maxvertex - j == 2) {
+ jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk ) );
+ jarc2 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+ jarc.pwlArc.npts = maxvertex-1;
+ jarc2.next = jarc.next;
+ jarc2.next.prev = jarc2;
+ jarc.next = jarc1;
+ jarc1.prev = jarc;
+ jarc1.next = jarc2;
+ jarc2.prev = jarc1;
+ assert(jarc.check() != 0);
+ return 31;
+
+ // New vertex adjacent to starting point of arc
+ } else if (i == 1) {
+ jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+ jarc2 = new(arcpool) Arc( jarc,
+ new(pwlarcpool) PwlArc( maxvertex-1, &jarc.pwlArc.pts[1] ) );
+ jarc.pwlArc.npts = 2;
+ jarc.pwlArc.pts = newjunk;
+ jarc2.next = jarc.next;
+ jarc2.next.prev = jarc2;
+ jarc.next = jarc1;
+ jarc1.prev = jarc;
+ jarc1.next = jarc2;
+ jarc2.prev = jarc1;
+ assert(jarc.check() != 0);
+ return 32;
+
+ // It's somewhere in the middle
+ } else {
+ jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk ) );
+ jarc2 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
+ jarc3 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( maxvertex-i, v+i ) );
+ jarc.pwlArc.npts = j + 1;
+ jarc3.next = jarc.next;
+ jarc3.next.prev = jarc3;
+ jarc.next = jarc1;
+ jarc1.prev = jarc;
+ jarc1.next = jarc2;
+ jarc2.prev = jarc1;
+ jarc2.next = jarc3;
+ jarc3.prev = jarc2;
+ assert(jarc.check() != 0);
+ return 4;
+ }
+ ***/
+ }
+ default:
+ return -1; //picked -1 since it's not used
+ }
+ }
+
+ private void check_s( Arc_ptr , Arc_ptr );
+ private void check_t( Arc_ptr , Arc_ptr );
+ private inline void link( Arc_ptr , Arc_ptr , Arc_ptr , Arc_ptr );
+ private inline void simple_link( Arc_ptr , Arc_ptr );
+
+ private Bin makePatchBoundary( const float[] from, const float[] to ) {
+ Bin ret = new Bin();
+ float smin = from[0];
+ float smax = to[0];
+ float tmin = from[1];
+ float tmax = to[1];
+
+ pjarc = 0;
+
+ Arc jarc = new Arc( arc_bottom, 0 );
+ arctessellator.bezier( jarc, smin, smax, tmin, tmin );
+ ret.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+
+ jarc = new(arcpool) Arc( arc_right, 0 );
+ arctessellator.bezier( jarc, smax, smax, tmin, tmax );
+ ret.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+
+ jarc = new(arcpool) Arc( arc_top, 0 );
+ arctessellator.bezier( jarc, smax, smin, tmax, tmax );
+ ret.addarc( jarc );
+ pjarc = jarc.append( pjarc );
+
+ jarc = new(arcpool) Arc( arc_left, 0 );
+ arctessellator.bezier( jarc, smin, smin, tmax, tmin );
+ ret.addarc( jarc );
+ jarc.append( pjarc );
+
+ assert( jarc.check() != 0 );
+ return ret;
+ }
+
+ /*in domain distance method, the tessellation is controled by two numbers:
+ *GLU_U_STEP: number of u-segments per unit u length of domain
+ *GLU_V_STEP: number of v-segments per unit v length of domain
+ *These two numbers are normally stored in mapdesc.maxs(t)rate.
+ *I (ZL) put these two numbers here so that I can optimize the untrimmed
+ *case in the case of domain distance sampling.
+ *These two numbers are set by set_domain_distance_u_rate() and ..._v_..().
+ */
+ private float domain_distance_u_rate;
+ private float domain_distance_v_rate;
+ private int is_domain_distance_sampling;
+
+}