Edit

IABSD.fr/xenocara/lib/libGLU/src/libnurbs/internals/subdivider.cc

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2013-09-01 03:51:12
    Hash : 729f7da4
    Message : Update to GLU 9.0.0, GLU was previously part of Mesa but is now seperate. tested in a ports bulk build by landry@, ok matthieu@

  • lib/libGLU/src/libnurbs/internals/subdivider.cc
  • /*
    ** 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.
    */
    
    /*
     * subdivider.cxx
     *
     */
    
    #include "glimports.h"
    #include "myassert.h"
    #include "mystdio.h"
    #include "subdivider.h"
    #include "arc.h"
    #include "bezierarc.h"
    #include "bin.h"
    #include "renderhints.h"
    #include "backend.h"
    #include "mapdesc.h"
    #include "quilt.h"
    #include "patchlist.h"
    #include "patch.h"
    #include "nurbsconsts.h"
    #include "trimvertpool.h"
    #include "simplemath.h"
    
    #include "polyUtil.h" //for function area()
    
    //#define  PARTITION_TEST
    #ifdef PARTITION_TEST
    #include "partitionY.h"
    #include "monoTriangulation.h"
    #include "dataTransform.h"
    #include "monoChain.h"
    
    #endif
    
    
    #define OPTIMIZE_UNTRIMED_CASE
    
    
    Bin*
    Subdivider::makePatchBoundary( const REAL *from, const REAL *to )
    { 
        Bin* ret = new Bin();
        REAL smin = from[0];
        REAL smax = to[0];
        REAL tmin = from[1];
        REAL tmax = to[1];
    
        pjarc = 0;
    
        Arc_ptr jarc = new(arcpool) 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;
    }
    
    /*---------------------------------------------------------------------------
     * Subdivider - construct a subdivider
     *---------------------------------------------------------------------------
     */
    
    Subdivider::Subdivider( Renderhints& r, Backend& b ) 
    	: slicer( b ),
    	  arctessellator( trimvertexpool, pwlarcpool ), 
    	  arcpool( sizeof( Arc), 1, "arcpool" ),
     	  bezierarcpool( sizeof( BezierArc ), 1, "Bezarcpool" ),
    	  pwlarcpool( sizeof( PwlArc ), 1, "Pwlarcpool" ),
    	  renderhints( r ),
    	  backend( b )
    {
    }
    
    void
    Subdivider::setJumpbuffer( JumpBuffer *j )
    {
        jumpbuffer = j;
    }
    
    /*---------------------------------------------------------------------------
     * clear - reset all state after possible error condition
     *---------------------------------------------------------------------------
     */
    
    void		
    Subdivider::clear( void )
    {
        trimvertexpool.clear();     
        arcpool.clear();
        pwlarcpool.clear();
        bezierarcpool.clear();
    }
    
    /*---------------------------------------------------------------------------
     * ~Subdivider - destroy a subdivider
     *---------------------------------------------------------------------------
     */
    
    Subdivider::~Subdivider( void )
    {
    }
    
    /*---------------------------------------------------------------------------
     * addArc - add a bezier arc to a trim loop and to a bin
     *---------------------------------------------------------------------------
     */
    void
    Subdivider::addArc( REAL *cpts, Quilt *quilt, long _nuid )
    {
        BezierArc *bezierArc = new(bezierarcpool) BezierArc;
        Arc *jarc  		= new(arcpool) Arc( arc_none, _nuid );
        jarc->pwlArc	= 0;
        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 );
    }
    
    /*---------------------------------------------------------------------------
     * addArc - add a pwl arc to a trim loop and to a bin
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::addArc( int npts, TrimVertex *pts, long _nuid ) 
    {
        Arc *jarc 		= new(arcpool) Arc( arc_none, _nuid );
        jarc->pwlArc	= new(pwlarcpool) PwlArc( npts, pts );        
        initialbin.addarc( jarc  );
        pjarc		= jarc->append( pjarc );
    }
    
    void
    Subdivider::beginQuilts( void )
    {
        qlist = 0;
    }
    
    void
    Subdivider::addQuilt( Quilt *quilt )
    {
        quilt->next = qlist;
        qlist = quilt;
    }
    
    /*---------------------------------------------------------------------------
     * drawSurfaces - main entry point for surface tessellation
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::drawSurfaces( long nuid )
    {
        renderhints.init( );
    
        if (qlist == NULL) 
          {
    	//initialbin could be nonempty due to some errors
    	freejarcs(initialbin);
    	return;
          }
    
        for( Quilt *q = qlist; q; q = q->next ) {
    	if( q->isCulled( ) == CULL_TRIVIAL_REJECT ) {
    	    freejarcs( initialbin );
    	    return;
    	}
        }
    
    
        REAL from[2], to[2];
        qlist->getRange( from, to, spbrkpts, tpbrkpts );
    #ifdef OPTIMIZE_UNTRIMED_CASE
        //perform optimization only when the samplng method is 
        //DOMAIN_DISTANCE and the display methdo is either 
        //fill or outline_polygon.
        int optimize = (is_domain_distance_sampling && (renderhints.display_method != N_OUTLINE_PATCH));
    #endif
    
        if( ! initialbin.isnonempty() ) {
    #ifdef OPTIMIZE_UNTRIMED_CASE
            if(! optimize )
    	  {	
    
    	  makeBorderTrim( from, to );
    	  }
    #else
    	makeBorderTrim( from, to );
    #endif
        } else {
    	REAL rate[2];
    	qlist->findRates( spbrkpts, tpbrkpts, rate );
    
        	if( decompose( initialbin, min(rate[0], rate[1]) ) ) 
    	    mylongjmp( jumpbuffer, 31 );
        }
    
        backend.bgnsurf( renderhints.wiretris, renderhints.wirequads, nuid );
    
    #ifdef PARTITION_TEST
     if(    initialbin.isnonempty() && spbrkpts.end-2 == spbrkpts.start && 
    	tpbrkpts.end-2 == tpbrkpts.start)
    {
        for(int i=spbrkpts.start; i<spbrkpts.end-1; i++){
          for(int j=tpbrkpts.start; j<tpbrkpts.end-1; j++){
    	Real pta[2], ptb[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);
    
    	directedLine *poly;
    
    	  {
    
    	    poly = bin_to_DLineLoops(initialbin);
    	    
    	    poly=poly->deleteDegenerateLinesAllPolygons();	    	
    
        sampledLine* retSampledLines;
    //printf("before MC_partition\n");	    
    	    poly = MC_partitionY(poly, &retSampledLines);
    //printf("after MC_partition\n");	    
    
    	  }
    
    
    	{
    	  primStream pStream(5000,5000);
    	  directedLine* temp;
    
    	  for(temp=poly; temp != NULL; temp=temp->getNextPolygon())
    
    	    monoTriangulation(temp, &pStream);
    
    	  slicer.evalStream(&pStream);
    
    	}
    	//need to clean up space
          }
        }
        freejarcs( initialbin );
        backend.endsurf();
        return;
    
        /*
        printf("num_polygons=%i\n", poly->numPolygons());
        printf("num_edges=%i\n", poly->numEdgesAllPolygons());
        poly->writeAllPolygons("zloutputFile");
        return;
        {
          primStream pStream(20,20);
          for(directedLine* tempD = poly; tempD != NULL; tempD = tempD->getNextPolygon())
    	monoTriangulation(tempD, &pStream);
        }
        return;
        */
    }
    #endif //PARTITION_TEST
    
    
    #ifdef OPTIMIZE_UNTRIMED_CASE
        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++){
    	    Real pta[2], ptb[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;
    	    /* the following is left for reference purpose, don't delete
    	    {
    	    Bin* tempSource;	
    	      Patchlist patchlist(qlist, pta, ptb);
    	      patchlist.getstepsize();
    
    	      tempSource=makePatchBoundary(pta, ptb);
    
    	      tessellation(*tempSource, patchlist);
    
    	      render(*tempSource);
    	      delete tempSource;
    	    }
    	    */
    	  }
    	}
          }
        else
          subdivideInS( initialbin );
    #else
    
        subdivideInS( initialbin );
    #endif
    
        backend.endsurf();
    
    }
    
    void
    Subdivider::subdivideInS( Bin& source )
    {
        if( renderhints.display_method == N_OUTLINE_PARAM ) {
    	outline( source );
    	freejarcs( source );
        } else {
    	setArcTypeBezier();
    	setNonDegenerate();
    	splitInS( source, spbrkpts.start, spbrkpts.end );
        }
    }
    
    
    /*---------------------------------------------------------------------------
     * splitInS - split a patch and a bin by an isoparametric line
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::splitInS( Bin& source, int start, int end )
    {
        if( source.isnonempty() ) {
            if( start != end ) {
    	    int	i = start + (end - start) / 2;
    	    Bin left, right;
    	    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 == N_OUTLINE_PARAM_S ) {
    		outline( source );
    		freejarcs( source );
    	    } else {
    		setArcTypeBezier();
    		setNonDegenerate();
    		s_index = start;
    		splitInT( source, tpbrkpts.start, tpbrkpts.end );
    	    }
            }
        } 
    }
    
    /*---------------------------------------------------------------------------
     * splitInT - split a patch and a bin by an isoparametric line
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::splitInT( Bin& source, int start, int end )
    {
        if( source.isnonempty() ) {
            if( start != end ) {
    	    int	i = start + (end - start) / 2;
    	    Bin left, right;
    	    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 == N_OUTLINE_PARAM_ST ) {
    		outline( source );
    		freejarcs( source );
    	    } else {
    		t_index = start;
    		setArcTypeBezier();
    		setDegenerate();
    
    		REAL pta[2], ptb[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( qlist, pta, ptb );
    /*
    printf("-------samplingSplit-----\n");
    source.show("samplingSplit source");
    */
    		samplingSplit( source, patchlist, renderhints.maxsubdivisions, 0 );
    		setNonDegenerate();
    		setArcTypeBezier();
    	    }
            }
        } 
    }
    
    /*--------------------------------------------------------------------------
     * samplingSplit - recursively subdivide patch, cull check each subpatch  
     *--------------------------------------------------------------------------
     */
    
    void
    Subdivider::samplingSplit( 
        Bin& source, 
        Patchlist& patchlist, 
        int subdivisions, 
        int param )
    {
        if( ! source.isnonempty() ) return;
    
        if( patchlist.cullCheck() == CULL_TRIVIAL_REJECT ) {
    	freejarcs( source );
    	return;
        }
    
        patchlist.getstepsize();
    
        if( renderhints.display_method == 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, right;
    	REAL mid = ( patchlist.pspec[param].range[0] +
    		     patchlist.pspec[param].range[1] ) * 0.5;
    	split( source, left, right, param, mid );
    	Patchlist subpatchlist( 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();
        }
    }
    
    void
    Subdivider::nonSamplingSplit( 
        Bin& source, 
        Patchlist& patchlist, 
        int subdivisions, 
        int param )
    {
        if( patchlist.needsNonSamplingSubdivision() && (subdivisions > 0) ) {
    	param = 1 - param;
    
    	Bin left, right;
    	REAL mid = ( patchlist.pspec[param].range[0] +
    		     patchlist.pspec[param].range[1] ) * 0.5;
    	split( source, left, right, param, mid );
    	Patchlist subpatchlist( patchlist, param, mid );
    	if( left.isnonempty() ) {
    	    if( subpatchlist.cullCheck() == CULL_TRIVIAL_REJECT ) 
    		freejarcs( left );
    	    else
    	        nonSamplingSplit( left, subpatchlist, subdivisions-1, param );
    	}
    	if( right.isnonempty() ) {
    	    if( patchlist.cullCheck() == 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 == N_OUTLINE_SUBDIV ) {
    	    outline( source );
    	    freejarcs( source );
    	} else {
    	    setArcTypePwl();
    	    setDegenerate();
    	    findIrregularS( source );
    	    monosplitInS( source, smbrkpts.start, smbrkpts.end );
    	}
        }
    }
    
    /*--------------------------------------------------------------------------
     * tessellation - set tessellation of interior and boundary of patch
     *--------------------------------------------------------------------------
     */
    
    void
    Subdivider::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;
    }
    
    /*---------------------------------------------------------------------------
     * monosplitInS - split a patch and a bin by an isoparametric line
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::monosplitInS( Bin& source, int start, int end )
    {
        if( source.isnonempty() ) {
            if( start != end ) {
    	    int	i = start + (end - start) / 2;
    	    Bin left, right;
    	    split( source, left, right, 0, smbrkpts.pts[i] );
    	    monosplitInS( left, start, i );
    	    monosplitInS( right, i+1, end );
            } else {
    	    if( renderhints.display_method == N_OUTLINE_SUBDIV_S ) {
    		outline( source );
    		freejarcs( source );
    	    } else {
    		setArcTypePwl();
    		setDegenerate();
    		findIrregularT( source );
    		monosplitInT( source, tmbrkpts.start, tmbrkpts.end );
    	    }
            }
        } 
    }
    
    /*---------------------------------------------------------------------------
     * monosplitInT - split a patch and a bin by an isoparametric line
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::monosplitInT( Bin& source, int start, int end )
    {
        if( source.isnonempty() ) {
            if( start != end ) {
    	    int	i = start + (end - start) / 2;
    	    Bin left, right;
    	    split( source, left, right, 1, tmbrkpts.pts[i] );
    	    monosplitInT( left, start, i );
    	    monosplitInT( right, i+1, end );
            } else {
    	    if( renderhints.display_method == N_OUTLINE_SUBDIV_ST ) {
    		outline( source );
    		freejarcs( source );
    	    } else {
    /*
    printf("*******render\n");
    source.show("source\n");
    */
    		render( source );
    		freejarcs( source );
    	    }
            }
        } 
    }
    
    
    /*----------------------------------------------------------------------------
     * findIrregularS - determine points of non-monotonicity is s direction
     *----------------------------------------------------------------------------
     */
    
    void
    Subdivider::findIrregularS( Bin& bin )
    {
        assert( bin.firstarc()->check() != 0 );
    
        smbrkpts.grow( bin.numarcs() );
    
        for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
    	REAL *a = jarc->prev->tail();
    	REAL *b = jarc->tail();
    	REAL *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();
    } 
    
    /*----------------------------------------------------------------------------
     * findIrregularT - determine points of non-monotonicity in t direction
     *		     where one arc is parallel to the s axis.
     *----------------------------------------------------------------------------
     */
    
    void
    Subdivider::findIrregularT( Bin& bin )
    {
        assert( bin.firstarc()->check() != 0 );
    
        tmbrkpts.grow( bin.numarcs() );
    
        for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
    	REAL *a = jarc->prev->tail();
    	REAL *b = jarc->tail();
    	REAL *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 ) )
                    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 ) )
                    tmbrkpts.add( b[1] );
    	}
        }
        tmbrkpts.filter( );
    }
    
    /*-----------------------------------------------------------------------------
     * makeBorderTrim - 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. 
     *-----------------------------------------------------------------------------
     */
    
    void
    Subdivider::makeBorderTrim( const REAL *from, const REAL *to )
    { 
        REAL smin = from[0];
        REAL smax = to[0];
        REAL tmin = from[1];
        REAL tmax = to[1];
    
        pjarc = 0;
    
        Arc_ptr jarc = new(arcpool) Arc( arc_bottom, 0 );
        arctessellator.bezier( jarc, smin, smax, tmin, tmin );
        initialbin.addarc( jarc  );
        pjarc = jarc->append( pjarc );
    
        jarc = new(arcpool) Arc( arc_right, 0 );
        arctessellator.bezier( jarc, smax, smax, tmin, tmax );
        initialbin.addarc( jarc  );
        pjarc = jarc->append( pjarc );
    
        jarc = new(arcpool) Arc( arc_top, 0 );
        arctessellator.bezier( jarc, smax, smin, tmax, tmax );
        initialbin.addarc( jarc  );
        pjarc = jarc->append( pjarc );
    
        jarc = new(arcpool) Arc( arc_left, 0 );
        arctessellator.bezier( jarc, smin, smin, tmax, tmin );
        initialbin.addarc( jarc  );
        jarc->append( pjarc );
    
        assert( jarc->check() != 0 );
    }
    
    /*----------------------------------------------------------------------------
     * render - renders all monotone regions in a bin and frees the bin
     *----------------------------------------------------------------------------
     */
    
    void
    Subdivider::render( Bin& bin )
    {
        bin.markall();
    
    #ifdef N_ISOLINE_S
        slicer.setisolines( ( renderhints.display_method == N_ISOLINE_S ) ? 1 : 0 );
    #else
        slicer.setisolines( 0 );
    #endif
    
        for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
    	if( jarc->ismarked() ) {
    	    assert( jarc->check( ) != 0 );
    	    Arc_ptr jarchead = jarc;
    	    do {
    		jarc->clearmark();
    		jarc = jarc->next;
    	    } while (jarc != jarchead);
    	    slicer.slice( jarc );
    	}
        }
    }
    
    /*---------------------------------------------------------------------------
     * outline - render the trimmed patch by outlining the boundary 
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::outline( Bin& bin )
    {
        bin.markall();
        for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
    	if( jarc->ismarked() ) {
    	    assert( jarc->check( ) != 0 );
    	    Arc_ptr jarchead = jarc;
    	    do {
    		slicer.outline( jarc );
    		jarc->clearmark();
    		jarc = jarc->prev;
    	    } while (jarc != jarchead);
    	}
        }
    }
    
    /*---------------------------------------------------------------------------
     * freejarcs - free all arcs in a bin
     *---------------------------------------------------------------------------
     */
    
    void
    Subdivider::freejarcs( Bin& bin )
    {
        bin.adopt();	/* XXX - should not be necessary */
    
        Arc_ptr jarc;
        while( (jarc = bin.removearc()) != NULL ) {
    	if( jarc->pwlArc ) jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
    	if( jarc->bezierArc) jarc->bezierArc->deleteMe( bezierarcpool ); jarc->bezierArc = 0;
    	jarc->deleteMe( arcpool );
        }
    }
    
    /*----------------------------------------------------------------------------
     * tessellate - tessellate all Bezier arcs in a bin
     * 		   1) only accepts linear Bezier arcs as input 
     * 		   2) the Bezier arcs are stored in the pwlArc structure
     * 		   3) only vertical or horizontal lines work
     * 		-- should 
     * 		   1) represent Bezier arcs in BezierArc structure
     * 		      (this requires a multitude of changes to the code)
     * 		   2) accept high degree Bezier arcs (hard)
     * 		   3) map the curve onto the surface to determine tessellation
     * 		   4) work for curves of arbitrary geometry
     *----------------------------------------------------------------------------
     */
    
    
    void
    Subdivider::tessellate( Bin& bin, REAL rrate, REAL trate, REAL lrate, REAL brate )
    {
        for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
    	if( jarc->isbezier( ) ) {
        	    assert( jarc->pwlArc->npts == 2 );	
    	    TrimVertex  *pts = jarc->pwlArc->pts;
        	    REAL s1 = pts[0].param[0];
        	    REAL t1 = pts[0].param[1];
        	    REAL s2 = pts[1].param[0];
        	    REAL t2 = pts[1].param[1];
    	    
        	    jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
    	    
    	    switch( jarc->getside() ) {
    		case arc_left:
    		    assert( s1 == s2 );
    		    arctessellator.pwl_left( jarc, s1, t1, t2, lrate );
    		    break;
    		case arc_right:
    		    assert( s1 == s2 );
    		    arctessellator.pwl_right( jarc, s1, t1, t2, rrate );
    		    break;
    		case arc_top:
    		    assert( t1 == t2 );
    		    arctessellator.pwl_top( jarc, t1, s1, s2, trate );
    		    break;
    		case arc_bottom:
    		    assert( t1 == t2 );
    		    arctessellator.pwl_bottom( jarc, t1, s1, s2, brate );
    		    break;
    		case arc_none:
    		    (void) abort();
    		    break;
    	    }
    	    assert( ! jarc->isbezier() );
        	    assert( jarc->check() != 0 );
    	}
        }
    }