1f220fa62Smrg/*
2f220fa62Smrg** License Applicability. Except to the extent portions of this file are
3f220fa62Smrg** made subject to an alternative license as permitted in the SGI Free
4f220fa62Smrg** Software License B, Version 1.1 (the "License"), the contents of this
5f220fa62Smrg** file are subject only to the provisions of the License. You may not use
6f220fa62Smrg** this file except in compliance with the License. You may obtain a copy
7f220fa62Smrg** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8f220fa62Smrg** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
9f220fa62Smrg**
10f220fa62Smrg** http://oss.sgi.com/projects/FreeB
11f220fa62Smrg**
12f220fa62Smrg** Note that, as provided in the License, the Software is distributed on an
13f220fa62Smrg** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14f220fa62Smrg** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15f220fa62Smrg** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16f220fa62Smrg** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
17f220fa62Smrg**
18f220fa62Smrg** Original Code. The Original Code is: OpenGL Sample Implementation,
19f220fa62Smrg** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20f220fa62Smrg** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21f220fa62Smrg** Copyright in any portions created by third parties is as indicated
22f220fa62Smrg** elsewhere herein. All Rights Reserved.
23f220fa62Smrg**
24f220fa62Smrg** Additional Notice Provisions: The application programming interfaces
25f220fa62Smrg** established by SGI in conjunction with the Original Code are The
26f220fa62Smrg** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27f220fa62Smrg** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28f220fa62Smrg** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29f220fa62Smrg** Window System(R) (Version 1.3), released October 19, 1998. This software
30f220fa62Smrg** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31f220fa62Smrg** published by SGI, but has not been independently verified as being
32f220fa62Smrg** compliant with the OpenGL(R) version 1.2.1 Specification.
33f220fa62Smrg*/
34f220fa62Smrg
35f220fa62Smrg/*
36f220fa62Smrg * subdivider.cxx
37f220fa62Smrg *
38f220fa62Smrg */
39f220fa62Smrg
40f220fa62Smrg#include "glimports.h"
41f220fa62Smrg#include "myassert.h"
42f220fa62Smrg#include "mystdio.h"
43f220fa62Smrg#include "subdivider.h"
44f220fa62Smrg#include "arc.h"
45f220fa62Smrg#include "bezierarc.h"
46f220fa62Smrg#include "bin.h"
47f220fa62Smrg#include "renderhints.h"
48f220fa62Smrg#include "backend.h"
49f220fa62Smrg#include "mapdesc.h"
50f220fa62Smrg#include "quilt.h"
51f220fa62Smrg#include "patchlist.h"
52f220fa62Smrg#include "patch.h"
53f220fa62Smrg#include "nurbsconsts.h"
54f220fa62Smrg#include "trimvertpool.h"
55f220fa62Smrg#include "simplemath.h"
56f220fa62Smrg
57f220fa62Smrg#include "polyUtil.h" //for function area()
58f220fa62Smrg
59f220fa62Smrg//#define  PARTITION_TEST
60f220fa62Smrg#ifdef PARTITION_TEST
61f220fa62Smrg#include "partitionY.h"
62f220fa62Smrg#include "monoTriangulation.h"
63f220fa62Smrg#include "dataTransform.h"
64f220fa62Smrg#include "monoChain.h"
65f220fa62Smrg
66f220fa62Smrg#endif
67f220fa62Smrg
68f220fa62Smrg
69f220fa62Smrg#define OPTIMIZE_UNTRIMED_CASE
70f220fa62Smrg
71f220fa62Smrg
72f220fa62SmrgBin*
73f220fa62SmrgSubdivider::makePatchBoundary( const REAL *from, const REAL *to )
74f220fa62Smrg{
75f220fa62Smrg    Bin* ret = new Bin();
76f220fa62Smrg    REAL smin = from[0];
77f220fa62Smrg    REAL smax = to[0];
78f220fa62Smrg    REAL tmin = from[1];
79f220fa62Smrg    REAL tmax = to[1];
80f220fa62Smrg
81f220fa62Smrg    pjarc = 0;
82f220fa62Smrg
83f220fa62Smrg    Arc_ptr jarc = new(arcpool) Arc( arc_bottom, 0 );
84f220fa62Smrg    arctessellator.bezier( jarc, smin, smax, tmin, tmin );
85f220fa62Smrg    ret->addarc( jarc  );
86f220fa62Smrg    pjarc = jarc->append( pjarc );
87f220fa62Smrg
88f220fa62Smrg    jarc = new(arcpool) Arc( arc_right, 0 );
89f220fa62Smrg    arctessellator.bezier( jarc, smax, smax, tmin, tmax );
90f220fa62Smrg    ret->addarc( jarc  );
91f220fa62Smrg    pjarc = jarc->append( pjarc );
92f220fa62Smrg
93f220fa62Smrg    jarc = new(arcpool) Arc( arc_top, 0 );
94f220fa62Smrg    arctessellator.bezier( jarc, smax, smin, tmax, tmax );
95f220fa62Smrg    ret->addarc( jarc  );
96f220fa62Smrg    pjarc = jarc->append( pjarc );
97f220fa62Smrg
98f220fa62Smrg    jarc = new(arcpool) Arc( arc_left, 0 );
99f220fa62Smrg    arctessellator.bezier( jarc, smin, smin, tmax, tmin );
100f220fa62Smrg    ret->addarc( jarc  );
101f220fa62Smrg    jarc->append( pjarc );
102f220fa62Smrg
103f220fa62Smrg    assert( jarc->check() != 0 );
104f220fa62Smrg    return ret;
105f220fa62Smrg}
106f220fa62Smrg
107f220fa62Smrg/*---------------------------------------------------------------------------
108f220fa62Smrg * Subdivider - construct a subdivider
109f220fa62Smrg *---------------------------------------------------------------------------
110f220fa62Smrg */
111f220fa62Smrg
112f220fa62SmrgSubdivider::Subdivider( Renderhints& r, Backend& b )
113f220fa62Smrg	: slicer( b ),
114f220fa62Smrg	  arctessellator( trimvertexpool, pwlarcpool ),
115f220fa62Smrg	  arcpool( sizeof( Arc), 1, "arcpool" ),
116f220fa62Smrg 	  bezierarcpool( sizeof( BezierArc ), 1, "Bezarcpool" ),
117f220fa62Smrg	  pwlarcpool( sizeof( PwlArc ), 1, "Pwlarcpool" ),
118f220fa62Smrg	  renderhints( r ),
119f220fa62Smrg	  backend( b )
120f220fa62Smrg{
121f220fa62Smrg}
122f220fa62Smrg
123f220fa62Smrgvoid
124f220fa62SmrgSubdivider::setJumpbuffer( JumpBuffer *j )
125f220fa62Smrg{
126f220fa62Smrg    jumpbuffer = j;
127f220fa62Smrg}
128f220fa62Smrg
129f220fa62Smrg/*---------------------------------------------------------------------------
130f220fa62Smrg * clear - reset all state after possible error condition
131f220fa62Smrg *---------------------------------------------------------------------------
132f220fa62Smrg */
133f220fa62Smrg
134f220fa62Smrgvoid
135f220fa62SmrgSubdivider::clear( void )
136f220fa62Smrg{
137f220fa62Smrg    trimvertexpool.clear();
138f220fa62Smrg    arcpool.clear();
139f220fa62Smrg    pwlarcpool.clear();
140f220fa62Smrg    bezierarcpool.clear();
141f220fa62Smrg}
142f220fa62Smrg
143f220fa62Smrg/*---------------------------------------------------------------------------
144f220fa62Smrg * ~Subdivider - destroy a subdivider
145f220fa62Smrg *---------------------------------------------------------------------------
146f220fa62Smrg */
147f220fa62Smrg
148f220fa62SmrgSubdivider::~Subdivider( void )
149f220fa62Smrg{
150f220fa62Smrg}
151f220fa62Smrg
152f220fa62Smrg/*---------------------------------------------------------------------------
153f220fa62Smrg * addArc - add a bezier arc to a trim loop and to a bin
154f220fa62Smrg *---------------------------------------------------------------------------
155f220fa62Smrg */
156f220fa62Smrgvoid
157f220fa62SmrgSubdivider::addArc( REAL *cpts, Quilt *quilt, long _nuid )
158f220fa62Smrg{
159f220fa62Smrg    BezierArc *bezierArc = new(bezierarcpool) BezierArc;
160f220fa62Smrg    Arc *jarc  		= new(arcpool) Arc( arc_none, _nuid );
161f220fa62Smrg    jarc->pwlArc	= 0;
162f220fa62Smrg    jarc->bezierArc	= bezierArc;
163f220fa62Smrg    bezierArc->order	= quilt->qspec->order;
164f220fa62Smrg    bezierArc->stride	= quilt->qspec->stride;
165f220fa62Smrg    bezierArc->mapdesc	= quilt->mapdesc;
166f220fa62Smrg    bezierArc->cpts	= cpts;
167f220fa62Smrg    initialbin.addarc( jarc );
168f220fa62Smrg    pjarc		= jarc->append( pjarc );
169f220fa62Smrg}
170f220fa62Smrg
171f220fa62Smrg/*---------------------------------------------------------------------------
172f220fa62Smrg * addArc - add a pwl arc to a trim loop and to a bin
173f220fa62Smrg *---------------------------------------------------------------------------
174f220fa62Smrg */
175f220fa62Smrg
176f220fa62Smrgvoid
177f220fa62SmrgSubdivider::addArc( int npts, TrimVertex *pts, long _nuid )
178f220fa62Smrg{
179f220fa62Smrg    Arc *jarc 		= new(arcpool) Arc( arc_none, _nuid );
180f220fa62Smrg    jarc->pwlArc	= new(pwlarcpool) PwlArc( npts, pts );
181f220fa62Smrg    initialbin.addarc( jarc  );
182f220fa62Smrg    pjarc		= jarc->append( pjarc );
183f220fa62Smrg}
184f220fa62Smrg
185f220fa62Smrgvoid
186f220fa62SmrgSubdivider::beginQuilts( void )
187f220fa62Smrg{
188f220fa62Smrg    qlist = 0;
189f220fa62Smrg}
190f220fa62Smrg
191f220fa62Smrgvoid
192f220fa62SmrgSubdivider::addQuilt( Quilt *quilt )
193f220fa62Smrg{
194f220fa62Smrg    quilt->next = qlist;
195f220fa62Smrg    qlist = quilt;
196f220fa62Smrg}
197f220fa62Smrg
198f220fa62Smrg/*---------------------------------------------------------------------------
199f220fa62Smrg * drawSurfaces - main entry point for surface tessellation
200f220fa62Smrg *---------------------------------------------------------------------------
201f220fa62Smrg */
202f220fa62Smrg
203f220fa62Smrgvoid
204f220fa62SmrgSubdivider::drawSurfaces( long nuid )
205f220fa62Smrg{
206f220fa62Smrg    renderhints.init( );
207f220fa62Smrg
208f220fa62Smrg    if (qlist == NULL)
209f220fa62Smrg      {
210f220fa62Smrg	//initialbin could be nonempty due to some errors
211f220fa62Smrg	freejarcs(initialbin);
212f220fa62Smrg	return;
213f220fa62Smrg      }
214f220fa62Smrg
215f220fa62Smrg    for( Quilt *q = qlist; q; q = q->next ) {
216f220fa62Smrg	if( q->isCulled( ) == CULL_TRIVIAL_REJECT ) {
217f220fa62Smrg	    freejarcs( initialbin );
218f220fa62Smrg	    return;
219f220fa62Smrg	}
220f220fa62Smrg    }
221f220fa62Smrg
222f220fa62Smrg
223f220fa62Smrg    REAL from[2], to[2];
224f220fa62Smrg    qlist->getRange( from, to, spbrkpts, tpbrkpts );
225f220fa62Smrg#ifdef OPTIMIZE_UNTRIMED_CASE
226f220fa62Smrg    //perform optimization only when the samplng method is
227f220fa62Smrg    //DOMAIN_DISTANCE and the display methdo is either
228f220fa62Smrg    //fill or outline_polygon.
229f220fa62Smrg    int optimize = (is_domain_distance_sampling && (renderhints.display_method != N_OUTLINE_PATCH));
230f220fa62Smrg#endif
231f220fa62Smrg
232f220fa62Smrg    if( ! initialbin.isnonempty() ) {
233f220fa62Smrg#ifdef OPTIMIZE_UNTRIMED_CASE
234f220fa62Smrg        if(! optimize )
235f220fa62Smrg	  {
236f220fa62Smrg
237f220fa62Smrg	  makeBorderTrim( from, to );
238f220fa62Smrg	  }
239f220fa62Smrg#else
240f220fa62Smrg	makeBorderTrim( from, to );
241f220fa62Smrg#endif
242f220fa62Smrg    } else {
243f220fa62Smrg	REAL rate[2];
244f220fa62Smrg	qlist->findRates( spbrkpts, tpbrkpts, rate );
245f220fa62Smrg
246f220fa62Smrg    	if( decompose( initialbin, min(rate[0], rate[1]) ) )
247f220fa62Smrg	    mylongjmp( jumpbuffer, 31 );
248f220fa62Smrg    }
249f220fa62Smrg
250f220fa62Smrg    backend.bgnsurf( renderhints.wiretris, renderhints.wirequads, nuid );
251f220fa62Smrg
252f220fa62Smrg#ifdef PARTITION_TEST
253f220fa62Smrg if(    initialbin.isnonempty() && spbrkpts.end-2 == spbrkpts.start &&
254f220fa62Smrg	tpbrkpts.end-2 == tpbrkpts.start)
255f220fa62Smrg{
256f220fa62Smrg    for(int i=spbrkpts.start; i<spbrkpts.end-1; i++){
257f220fa62Smrg      for(int j=tpbrkpts.start; j<tpbrkpts.end-1; j++){
258f220fa62Smrg	Real pta[2], ptb[2];
259f220fa62Smrg	pta[0] = spbrkpts.pts[i];
260f220fa62Smrg	ptb[0] = spbrkpts.pts[i+1];
261f220fa62Smrg	pta[1] = tpbrkpts.pts[j];
262f220fa62Smrg	ptb[1] = tpbrkpts.pts[j+1];
263f220fa62Smrg	qlist->downloadAll(pta, ptb, backend);
264f220fa62Smrg
265f220fa62Smrg	directedLine *poly;
266f220fa62Smrg
267f220fa62Smrg	  {
268f220fa62Smrg
269f220fa62Smrg	    poly = bin_to_DLineLoops(initialbin);
270f220fa62Smrg
271f220fa62Smrg	    poly=poly->deleteDegenerateLinesAllPolygons();
272f220fa62Smrg
273f220fa62Smrg    sampledLine* retSampledLines;
274f220fa62Smrg//printf("before MC_partition\n");
275f220fa62Smrg	    poly = MC_partitionY(poly, &retSampledLines);
276f220fa62Smrg//printf("after MC_partition\n");
277f220fa62Smrg
278f220fa62Smrg	  }
279f220fa62Smrg
280f220fa62Smrg
281f220fa62Smrg	{
282f220fa62Smrg	  primStream pStream(5000,5000);
283f220fa62Smrg	  directedLine* temp;
284f220fa62Smrg
285f220fa62Smrg	  for(temp=poly; temp != NULL; temp=temp->getNextPolygon())
286f220fa62Smrg
287f220fa62Smrg	    monoTriangulation(temp, &pStream);
288f220fa62Smrg
289f220fa62Smrg	  slicer.evalStream(&pStream);
290f220fa62Smrg
291f220fa62Smrg	}
292f220fa62Smrg	//need to clean up space
293f220fa62Smrg      }
294f220fa62Smrg    }
295f220fa62Smrg    freejarcs( initialbin );
296f220fa62Smrg    backend.endsurf();
297f220fa62Smrg    return;
298f220fa62Smrg
299f220fa62Smrg    /*
300f220fa62Smrg    printf("num_polygons=%i\n", poly->numPolygons());
301f220fa62Smrg    printf("num_edges=%i\n", poly->numEdgesAllPolygons());
302f220fa62Smrg    poly->writeAllPolygons("zloutputFile");
303f220fa62Smrg    return;
304f220fa62Smrg    {
305f220fa62Smrg      primStream pStream(20,20);
306f220fa62Smrg      for(directedLine* tempD = poly; tempD != NULL; tempD = tempD->getNextPolygon())
307f220fa62Smrg	monoTriangulation(tempD, &pStream);
308f220fa62Smrg    }
309f220fa62Smrg    return;
310f220fa62Smrg    */
311f220fa62Smrg}
312f220fa62Smrg#endif //PARTITION_TEST
313f220fa62Smrg
314f220fa62Smrg
315f220fa62Smrg#ifdef OPTIMIZE_UNTRIMED_CASE
316f220fa62Smrg    if( (!initialbin.isnonempty())  && optimize )
317f220fa62Smrg      {
318f220fa62Smrg	int i,j;
319f220fa62Smrg	int num_u_steps;
320f220fa62Smrg        int num_v_steps;
321f220fa62Smrg	for(i=spbrkpts.start; i<spbrkpts.end-1; i++){
322f220fa62Smrg	  for(j=tpbrkpts.start; j<tpbrkpts.end-1; j++){
323f220fa62Smrg	    Real pta[2], ptb[2];
324f220fa62Smrg	    pta[0] = spbrkpts.pts[i];
325f220fa62Smrg	    ptb[0] = spbrkpts.pts[i+1];
326f220fa62Smrg	    pta[1] = tpbrkpts.pts[j];
327f220fa62Smrg	    ptb[1] = tpbrkpts.pts[j+1];
328f220fa62Smrg	    qlist->downloadAll(pta, ptb, backend);
329f220fa62Smrg
330f220fa62Smrg            num_u_steps = (int) (domain_distance_u_rate * (ptb[0]-pta[0]));
331f220fa62Smrg            num_v_steps = (int) (domain_distance_v_rate * (ptb[1]-pta[1]));
332f220fa62Smrg
333f220fa62Smrg            if(num_u_steps <= 0) num_u_steps = 1;
334f220fa62Smrg            if(num_v_steps <= 0) num_v_steps = 1;
335f220fa62Smrg
336f220fa62Smrg	    backend.surfgrid(pta[0], ptb[0], num_u_steps,
337f220fa62Smrg			     ptb[1], pta[1], num_v_steps);
338f220fa62Smrg	    backend.surfmesh(0,0,num_u_steps,num_v_steps);
339f220fa62Smrg
340f220fa62Smrg
341f220fa62Smrg
342f220fa62Smrg	    continue;
343f220fa62Smrg	    /* the following is left for reference purpose, don't delete
344f220fa62Smrg	    {
345f220fa62Smrg	    Bin* tempSource;
346f220fa62Smrg	      Patchlist patchlist(qlist, pta, ptb);
347f220fa62Smrg	      patchlist.getstepsize();
348f220fa62Smrg
349f220fa62Smrg	      tempSource=makePatchBoundary(pta, ptb);
350f220fa62Smrg
351f220fa62Smrg	      tessellation(*tempSource, patchlist);
352f220fa62Smrg
353f220fa62Smrg	      render(*tempSource);
354f220fa62Smrg	      delete tempSource;
355f220fa62Smrg	    }
356f220fa62Smrg	    */
357f220fa62Smrg	  }
358f220fa62Smrg	}
359f220fa62Smrg      }
360f220fa62Smrg    else
361f220fa62Smrg      subdivideInS( initialbin );
362f220fa62Smrg#else
363f220fa62Smrg
364f220fa62Smrg    subdivideInS( initialbin );
365f220fa62Smrg#endif
366f220fa62Smrg
367f220fa62Smrg    backend.endsurf();
368f220fa62Smrg
369f220fa62Smrg}
370f220fa62Smrg
371f220fa62Smrgvoid
372f220fa62SmrgSubdivider::subdivideInS( Bin& source )
373f220fa62Smrg{
374f220fa62Smrg    if( renderhints.display_method == N_OUTLINE_PARAM ) {
375f220fa62Smrg	outline( source );
376f220fa62Smrg	freejarcs( source );
377f220fa62Smrg    } else {
378f220fa62Smrg	setArcTypeBezier();
379f220fa62Smrg	setNonDegenerate();
380f220fa62Smrg	splitInS( source, spbrkpts.start, spbrkpts.end );
381f220fa62Smrg    }
382f220fa62Smrg}
383f220fa62Smrg
384f220fa62Smrg
385f220fa62Smrg/*---------------------------------------------------------------------------
386f220fa62Smrg * splitInS - split a patch and a bin by an isoparametric line
387f220fa62Smrg *---------------------------------------------------------------------------
388f220fa62Smrg */
389f220fa62Smrg
390f220fa62Smrgvoid
391f220fa62SmrgSubdivider::splitInS( Bin& source, int start, int end )
392f220fa62Smrg{
393f220fa62Smrg    if( source.isnonempty() ) {
394f220fa62Smrg        if( start != end ) {
395f220fa62Smrg	    int	i = start + (end - start) / 2;
396f220fa62Smrg	    Bin left, right;
397f220fa62Smrg	    split( source, left, right, 0, spbrkpts.pts[i] );
398f220fa62Smrg	    splitInS( left, start, i );
399f220fa62Smrg	    splitInS( right, i+1, end );
400f220fa62Smrg        } else {
401f220fa62Smrg	    if( start == spbrkpts.start || start == spbrkpts.end ) {
402f220fa62Smrg		freejarcs( source );
403f220fa62Smrg	    } else if( renderhints.display_method == N_OUTLINE_PARAM_S ) {
404f220fa62Smrg		outline( source );
405f220fa62Smrg		freejarcs( source );
406f220fa62Smrg	    } else {
407f220fa62Smrg		setArcTypeBezier();
408f220fa62Smrg		setNonDegenerate();
409f220fa62Smrg		s_index = start;
410f220fa62Smrg		splitInT( source, tpbrkpts.start, tpbrkpts.end );
411f220fa62Smrg	    }
412f220fa62Smrg        }
413f220fa62Smrg    }
414f220fa62Smrg}
415f220fa62Smrg
416f220fa62Smrg/*---------------------------------------------------------------------------
417f220fa62Smrg * splitInT - split a patch and a bin by an isoparametric line
418f220fa62Smrg *---------------------------------------------------------------------------
419f220fa62Smrg */
420f220fa62Smrg
421f220fa62Smrgvoid
422f220fa62SmrgSubdivider::splitInT( Bin& source, int start, int end )
423f220fa62Smrg{
424f220fa62Smrg    if( source.isnonempty() ) {
425f220fa62Smrg        if( start != end ) {
426f220fa62Smrg	    int	i = start + (end - start) / 2;
427f220fa62Smrg	    Bin left, right;
428f220fa62Smrg	    split( source, left, right, 1, tpbrkpts.pts[i] );
429f220fa62Smrg	    splitInT( left, start, i );
430f220fa62Smrg	    splitInT( right, i+1, end );
431f220fa62Smrg        } else {
432f220fa62Smrg	    if( start == tpbrkpts.start || start == tpbrkpts.end ) {
433f220fa62Smrg		freejarcs( source );
434f220fa62Smrg	    } else if( renderhints.display_method == N_OUTLINE_PARAM_ST ) {
435f220fa62Smrg		outline( source );
436f220fa62Smrg		freejarcs( source );
437f220fa62Smrg	    } else {
438f220fa62Smrg		t_index = start;
439f220fa62Smrg		setArcTypeBezier();
440f220fa62Smrg		setDegenerate();
441f220fa62Smrg
442f220fa62Smrg		REAL pta[2], ptb[2];
443f220fa62Smrg		pta[0] = spbrkpts.pts[s_index-1];
444f220fa62Smrg		pta[1] = tpbrkpts.pts[t_index-1];
445f220fa62Smrg
446f220fa62Smrg		ptb[0] = spbrkpts.pts[s_index];
447f220fa62Smrg		ptb[1] = tpbrkpts.pts[t_index];
448f220fa62Smrg		qlist->downloadAll( pta, ptb, backend );
449f220fa62Smrg
450f220fa62Smrg		Patchlist patchlist( qlist, pta, ptb );
451f220fa62Smrg/*
452f220fa62Smrgprintf("-------samplingSplit-----\n");
453f220fa62Smrgsource.show("samplingSplit source");
454f220fa62Smrg*/
455f220fa62Smrg		samplingSplit( source, patchlist, renderhints.maxsubdivisions, 0 );
456f220fa62Smrg		setNonDegenerate();
457f220fa62Smrg		setArcTypeBezier();
458f220fa62Smrg	    }
459f220fa62Smrg        }
460f220fa62Smrg    }
461f220fa62Smrg}
462f220fa62Smrg
463f220fa62Smrg/*--------------------------------------------------------------------------
464f220fa62Smrg * samplingSplit - recursively subdivide patch, cull check each subpatch
465f220fa62Smrg *--------------------------------------------------------------------------
466f220fa62Smrg */
467f220fa62Smrg
468f220fa62Smrgvoid
469f220fa62SmrgSubdivider::samplingSplit(
470f220fa62Smrg    Bin& source,
471f220fa62Smrg    Patchlist& patchlist,
472f220fa62Smrg    int subdivisions,
473f220fa62Smrg    int param )
474f220fa62Smrg{
475f220fa62Smrg    if( ! source.isnonempty() ) return;
476f220fa62Smrg
477f220fa62Smrg    if( patchlist.cullCheck() == CULL_TRIVIAL_REJECT ) {
478f220fa62Smrg	freejarcs( source );
479f220fa62Smrg	return;
480f220fa62Smrg    }
481f220fa62Smrg
482f220fa62Smrg    patchlist.getstepsize();
483f220fa62Smrg
484f220fa62Smrg    if( renderhints.display_method == N_OUTLINE_PATCH ) {
485f220fa62Smrg        tessellation( source, patchlist );
486f220fa62Smrg	outline( source );
487f220fa62Smrg	freejarcs( source );
488f220fa62Smrg	return;
489f220fa62Smrg    }
490f220fa62Smrg
491f220fa62Smrg    //patchlist.clamp();
492f220fa62Smrg
493f220fa62Smrg    tessellation( source, patchlist );
494f220fa62Smrg
495f220fa62Smrg    if( patchlist.needsSamplingSubdivision() && (subdivisions > 0) ) {
496f220fa62Smrg	if( ! patchlist.needsSubdivision( 0 ) )
497f220fa62Smrg	    param = 1;
498f220fa62Smrg	else if( ! patchlist.needsSubdivision( 1 ) )
499f220fa62Smrg	    param = 0;
500f220fa62Smrg	else
501f220fa62Smrg	    param = 1 - param;
502f220fa62Smrg
503f220fa62Smrg	Bin left, right;
504f220fa62Smrg	REAL mid = ( patchlist.pspec[param].range[0] +
505f220fa62Smrg		     patchlist.pspec[param].range[1] ) * 0.5;
506f220fa62Smrg	split( source, left, right, param, mid );
507f220fa62Smrg	Patchlist subpatchlist( patchlist, param, mid );
508f220fa62Smrg	samplingSplit( left, subpatchlist, subdivisions-1, param );
509f220fa62Smrg	samplingSplit( right, patchlist, subdivisions-1, param );
510f220fa62Smrg    } else {
511f220fa62Smrg	setArcTypePwl();
512f220fa62Smrg	setDegenerate();
513f220fa62Smrg	nonSamplingSplit( source, patchlist, subdivisions, param );
514f220fa62Smrg	setDegenerate();
515f220fa62Smrg	setArcTypeBezier();
516f220fa62Smrg    }
517f220fa62Smrg}
518f220fa62Smrg
519f220fa62Smrgvoid
520f220fa62SmrgSubdivider::nonSamplingSplit(
521f220fa62Smrg    Bin& source,
522f220fa62Smrg    Patchlist& patchlist,
523f220fa62Smrg    int subdivisions,
524f220fa62Smrg    int param )
525f220fa62Smrg{
526f220fa62Smrg    if( patchlist.needsNonSamplingSubdivision() && (subdivisions > 0) ) {
527f220fa62Smrg	param = 1 - param;
528f220fa62Smrg
529f220fa62Smrg	Bin left, right;
530f220fa62Smrg	REAL mid = ( patchlist.pspec[param].range[0] +
531f220fa62Smrg		     patchlist.pspec[param].range[1] ) * 0.5;
532f220fa62Smrg	split( source, left, right, param, mid );
533f220fa62Smrg	Patchlist subpatchlist( patchlist, param, mid );
534f220fa62Smrg	if( left.isnonempty() ) {
535f220fa62Smrg	    if( subpatchlist.cullCheck() == CULL_TRIVIAL_REJECT )
536f220fa62Smrg		freejarcs( left );
537f220fa62Smrg	    else
538f220fa62Smrg	        nonSamplingSplit( left, subpatchlist, subdivisions-1, param );
539f220fa62Smrg	}
540f220fa62Smrg	if( right.isnonempty() ) {
541f220fa62Smrg	    if( patchlist.cullCheck() == CULL_TRIVIAL_REJECT )
542f220fa62Smrg		freejarcs( right );
543f220fa62Smrg	    else
544f220fa62Smrg	        nonSamplingSplit( right, patchlist, subdivisions-1, param );
545f220fa62Smrg	}
546f220fa62Smrg
547f220fa62Smrg    } else {
548f220fa62Smrg	// make bbox calls
549f220fa62Smrg	patchlist.bbox();
550f220fa62Smrg	backend.patch( patchlist.pspec[0].range[0], patchlist.pspec[0].range[1],
551f220fa62Smrg		       patchlist.pspec[1].range[0], patchlist.pspec[1].range[1] );
552f220fa62Smrg
553f220fa62Smrg	if( renderhints.display_method == N_OUTLINE_SUBDIV ) {
554f220fa62Smrg	    outline( source );
555f220fa62Smrg	    freejarcs( source );
556f220fa62Smrg	} else {
557f220fa62Smrg	    setArcTypePwl();
558f220fa62Smrg	    setDegenerate();
559f220fa62Smrg	    findIrregularS( source );
560f220fa62Smrg	    monosplitInS( source, smbrkpts.start, smbrkpts.end );
561f220fa62Smrg	}
562f220fa62Smrg    }
563f220fa62Smrg}
564f220fa62Smrg
565f220fa62Smrg/*--------------------------------------------------------------------------
566f220fa62Smrg * tessellation - set tessellation of interior and boundary of patch
567f220fa62Smrg *--------------------------------------------------------------------------
568f220fa62Smrg */
569f220fa62Smrg
570f220fa62Smrgvoid
571f220fa62SmrgSubdivider::tessellation( Bin& bin, Patchlist &patchlist )
572f220fa62Smrg{
573f220fa62Smrg    // tessellate unsampled trim curves
574f220fa62Smrg    tessellate( bin, patchlist.pspec[1].sidestep[1], patchlist.pspec[0].sidestep[1],
575f220fa62Smrg	 patchlist.pspec[1].sidestep[0], patchlist.pspec[0].sidestep[0] );
576f220fa62Smrg
577f220fa62Smrg    // set interior sampling rates
578f220fa62Smrg    slicer.setstriptessellation( patchlist.pspec[0].stepsize, patchlist.pspec[1].stepsize );
579f220fa62Smrg
580f220fa62Smrg    //added by zl: set the order which will be used in slicer.c++
581f220fa62Smrg    slicer.set_ulinear( (patchlist.get_uorder() == 2));
582f220fa62Smrg    slicer.set_vlinear( (patchlist.get_vorder() == 2));
583f220fa62Smrg
584f220fa62Smrg    // set boundary sampling rates
585f220fa62Smrg    stepsizes[0] = patchlist.pspec[1].stepsize;
586f220fa62Smrg    stepsizes[1] = patchlist.pspec[0].stepsize;
587f220fa62Smrg    stepsizes[2] = patchlist.pspec[1].stepsize;
588f220fa62Smrg    stepsizes[3] = patchlist.pspec[0].stepsize;
589f220fa62Smrg}
590f220fa62Smrg
591f220fa62Smrg/*---------------------------------------------------------------------------
592f220fa62Smrg * monosplitInS - split a patch and a bin by an isoparametric line
593f220fa62Smrg *---------------------------------------------------------------------------
594f220fa62Smrg */
595f220fa62Smrg
596f220fa62Smrgvoid
597f220fa62SmrgSubdivider::monosplitInS( Bin& source, int start, int end )
598f220fa62Smrg{
599f220fa62Smrg    if( source.isnonempty() ) {
600f220fa62Smrg        if( start != end ) {
601f220fa62Smrg	    int	i = start + (end - start) / 2;
602f220fa62Smrg	    Bin left, right;
603f220fa62Smrg	    split( source, left, right, 0, smbrkpts.pts[i] );
604f220fa62Smrg	    monosplitInS( left, start, i );
605f220fa62Smrg	    monosplitInS( right, i+1, end );
606f220fa62Smrg        } else {
607f220fa62Smrg	    if( renderhints.display_method == N_OUTLINE_SUBDIV_S ) {
608f220fa62Smrg		outline( source );
609f220fa62Smrg		freejarcs( source );
610f220fa62Smrg	    } else {
611f220fa62Smrg		setArcTypePwl();
612f220fa62Smrg		setDegenerate();
613f220fa62Smrg		findIrregularT( source );
614f220fa62Smrg		monosplitInT( source, tmbrkpts.start, tmbrkpts.end );
615f220fa62Smrg	    }
616f220fa62Smrg        }
617f220fa62Smrg    }
618f220fa62Smrg}
619f220fa62Smrg
620f220fa62Smrg/*---------------------------------------------------------------------------
621f220fa62Smrg * monosplitInT - split a patch and a bin by an isoparametric line
622f220fa62Smrg *---------------------------------------------------------------------------
623f220fa62Smrg */
624f220fa62Smrg
625f220fa62Smrgvoid
626f220fa62SmrgSubdivider::monosplitInT( Bin& source, int start, int end )
627f220fa62Smrg{
628f220fa62Smrg    if( source.isnonempty() ) {
629f220fa62Smrg        if( start != end ) {
630f220fa62Smrg	    int	i = start + (end - start) / 2;
631f220fa62Smrg	    Bin left, right;
632f220fa62Smrg	    split( source, left, right, 1, tmbrkpts.pts[i] );
633f220fa62Smrg	    monosplitInT( left, start, i );
634f220fa62Smrg	    monosplitInT( right, i+1, end );
635f220fa62Smrg        } else {
636f220fa62Smrg	    if( renderhints.display_method == N_OUTLINE_SUBDIV_ST ) {
637f220fa62Smrg		outline( source );
638f220fa62Smrg		freejarcs( source );
639f220fa62Smrg	    } else {
640f220fa62Smrg/*
641f220fa62Smrgprintf("*******render\n");
642f220fa62Smrgsource.show("source\n");
643f220fa62Smrg*/
644f220fa62Smrg		render( source );
645f220fa62Smrg		freejarcs( source );
646f220fa62Smrg	    }
647f220fa62Smrg        }
648f220fa62Smrg    }
649f220fa62Smrg}
650f220fa62Smrg
651f220fa62Smrg
652f220fa62Smrg/*----------------------------------------------------------------------------
653f220fa62Smrg * findIrregularS - determine points of non-monotonicity is s direction
654f220fa62Smrg *----------------------------------------------------------------------------
655f220fa62Smrg */
656f220fa62Smrg
657f220fa62Smrgvoid
658f220fa62SmrgSubdivider::findIrregularS( Bin& bin )
659f220fa62Smrg{
660f220fa62Smrg    assert( bin.firstarc()->check() != 0 );
661f220fa62Smrg
662f220fa62Smrg    smbrkpts.grow( bin.numarcs() );
663f220fa62Smrg
664f220fa62Smrg    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
665f220fa62Smrg	REAL *a = jarc->prev->tail();
666f220fa62Smrg	REAL *b = jarc->tail();
667f220fa62Smrg	REAL *c = jarc->head();
668f220fa62Smrg
669f220fa62Smrg	if( b[1] == a[1] && b[1] == c[1] ) continue;
670f220fa62Smrg
671f220fa62Smrg	//corrected code
672f220fa62Smrg	if((b[1]<=a[1] && b[1] <= c[1]) ||
673f220fa62Smrg	   (b[1]>=a[1] && b[1] >= c[1]))
674f220fa62Smrg	  {
675f220fa62Smrg	    //each arc (jarc, jarc->prev, jarc->next) is a
676f220fa62Smrg	    //monotone arc consisting of multiple line segements.
677f220fa62Smrg	    //it may happen that jarc->prev and jarc->next are the same,
678f220fa62Smrg	    //that is, jarc->prev and jarc form a closed loop.
679f220fa62Smrg	    //In such case, a and c will be the same.
680f220fa62Smrg            if(a[0]==c[0] && a[1] == c[1])
681f220fa62Smrg	      {
682f220fa62Smrg		if(jarc->pwlArc->npts >2)
683f220fa62Smrg		  {
684f220fa62Smrg		    c = jarc->pwlArc->pts[jarc->pwlArc->npts-2].param;
685f220fa62Smrg		  }
686f220fa62Smrg		else
687f220fa62Smrg		  {
688f220fa62Smrg		    assert(jarc->prev->pwlArc->npts>2);
689f220fa62Smrg		    a = jarc->prev->pwlArc->pts[jarc->prev->pwlArc->npts-2].param;
690f220fa62Smrg		  }
691f220fa62Smrg
692f220fa62Smrg	      }
693f220fa62Smrg	    if(area(a,b,c) < 0)
694f220fa62Smrg	      {
695f220fa62Smrg		smbrkpts.add(b[0]);
696f220fa62Smrg	      }
697f220fa62Smrg
698f220fa62Smrg	  }
699f220fa62Smrg
700f220fa62Smrg	/* old code,
701f220fa62Smrg	if( b[1] <= a[1] && b[1] <= c[1] ) {
702f220fa62Smrg	    if( ! ccwTurn_tr( jarc->prev, jarc ) )
703f220fa62Smrg                smbrkpts.add( b[0] );
704f220fa62Smrg	} else if( b[1] >= a[1] && b[1] >= c[1] ) {
705f220fa62Smrg	    if( ! ccwTurn_tl( jarc->prev, jarc ) )
706f220fa62Smrg                smbrkpts.add( b[0] );
707f220fa62Smrg        }
708f220fa62Smrg	*/
709f220fa62Smrg
710f220fa62Smrg    }
711f220fa62Smrg
712f220fa62Smrg    smbrkpts.filter();
713f220fa62Smrg}
714f220fa62Smrg
715f220fa62Smrg/*----------------------------------------------------------------------------
716f220fa62Smrg * findIrregularT - determine points of non-monotonicity in t direction
717f220fa62Smrg *		     where one arc is parallel to the s axis.
718f220fa62Smrg *----------------------------------------------------------------------------
719f220fa62Smrg */
720f220fa62Smrg
721f220fa62Smrgvoid
722f220fa62SmrgSubdivider::findIrregularT( Bin& bin )
723f220fa62Smrg{
724f220fa62Smrg    assert( bin.firstarc()->check() != 0 );
725f220fa62Smrg
726f220fa62Smrg    tmbrkpts.grow( bin.numarcs() );
727f220fa62Smrg
728f220fa62Smrg    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
729f220fa62Smrg	REAL *a = jarc->prev->tail();
730f220fa62Smrg	REAL *b = jarc->tail();
731f220fa62Smrg	REAL *c = jarc->head();
732f220fa62Smrg
733f220fa62Smrg	if( b[0] == a[0] && b[0] == c[0] ) continue;
734f220fa62Smrg
735f220fa62Smrg	if( b[0] <= a[0] && b[0] <= c[0] ) {
736f220fa62Smrg	    if( a[1] != b[1] && b[1] != c[1] ) continue;
737f220fa62Smrg	    if( ! ccwTurn_sr( jarc->prev, jarc ) )
738f220fa62Smrg                tmbrkpts.add( b[1] );
739f220fa62Smrg	} else if ( b[0] >= a[0] && b[0] >= c[0] ) {
740f220fa62Smrg	    if( a[1] != b[1] && b[1] != c[1] ) continue;
741f220fa62Smrg	    if( ! ccwTurn_sl( jarc->prev, jarc ) )
742f220fa62Smrg                tmbrkpts.add( b[1] );
743f220fa62Smrg	}
744f220fa62Smrg    }
745f220fa62Smrg    tmbrkpts.filter( );
746f220fa62Smrg}
747f220fa62Smrg
748f220fa62Smrg/*-----------------------------------------------------------------------------
749f220fa62Smrg * makeBorderTrim - if no user input trimming data then create
750f220fa62Smrg * a trimming curve around the boundaries of the Quilt.  The curve consists of
751f220fa62Smrg * four Jordan arcs, one for each side of the Quilt, connected, of course,
752f220fa62Smrg * head to tail.
753f220fa62Smrg *-----------------------------------------------------------------------------
754f220fa62Smrg */
755f220fa62Smrg
756f220fa62Smrgvoid
757f220fa62SmrgSubdivider::makeBorderTrim( const REAL *from, const REAL *to )
758f220fa62Smrg{
759f220fa62Smrg    REAL smin = from[0];
760f220fa62Smrg    REAL smax = to[0];
761f220fa62Smrg    REAL tmin = from[1];
762f220fa62Smrg    REAL tmax = to[1];
763f220fa62Smrg
764f220fa62Smrg    pjarc = 0;
765f220fa62Smrg
766f220fa62Smrg    Arc_ptr jarc = new(arcpool) Arc( arc_bottom, 0 );
767f220fa62Smrg    arctessellator.bezier( jarc, smin, smax, tmin, tmin );
768f220fa62Smrg    initialbin.addarc( jarc  );
769f220fa62Smrg    pjarc = jarc->append( pjarc );
770f220fa62Smrg
771f220fa62Smrg    jarc = new(arcpool) Arc( arc_right, 0 );
772f220fa62Smrg    arctessellator.bezier( jarc, smax, smax, tmin, tmax );
773f220fa62Smrg    initialbin.addarc( jarc  );
774f220fa62Smrg    pjarc = jarc->append( pjarc );
775f220fa62Smrg
776f220fa62Smrg    jarc = new(arcpool) Arc( arc_top, 0 );
777f220fa62Smrg    arctessellator.bezier( jarc, smax, smin, tmax, tmax );
778f220fa62Smrg    initialbin.addarc( jarc  );
779f220fa62Smrg    pjarc = jarc->append( pjarc );
780f220fa62Smrg
781f220fa62Smrg    jarc = new(arcpool) Arc( arc_left, 0 );
782f220fa62Smrg    arctessellator.bezier( jarc, smin, smin, tmax, tmin );
783f220fa62Smrg    initialbin.addarc( jarc  );
784f220fa62Smrg    jarc->append( pjarc );
785f220fa62Smrg
786f220fa62Smrg    assert( jarc->check() != 0 );
787f220fa62Smrg}
788f220fa62Smrg
789f220fa62Smrg/*----------------------------------------------------------------------------
790f220fa62Smrg * render - renders all monotone regions in a bin and frees the bin
791f220fa62Smrg *----------------------------------------------------------------------------
792f220fa62Smrg */
793f220fa62Smrg
794f220fa62Smrgvoid
795f220fa62SmrgSubdivider::render( Bin& bin )
796f220fa62Smrg{
797f220fa62Smrg    bin.markall();
798f220fa62Smrg
799f220fa62Smrg#ifdef N_ISOLINE_S
800f220fa62Smrg    slicer.setisolines( ( renderhints.display_method == N_ISOLINE_S ) ? 1 : 0 );
801f220fa62Smrg#else
802f220fa62Smrg    slicer.setisolines( 0 );
803f220fa62Smrg#endif
804f220fa62Smrg
805f220fa62Smrg    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
806f220fa62Smrg	if( jarc->ismarked() ) {
807f220fa62Smrg	    assert( jarc->check( ) != 0 );
808f220fa62Smrg	    Arc_ptr jarchead = jarc;
809f220fa62Smrg	    do {
810f220fa62Smrg		jarc->clearmark();
811f220fa62Smrg		jarc = jarc->next;
812f220fa62Smrg	    } while (jarc != jarchead);
813f220fa62Smrg	    slicer.slice( jarc );
814f220fa62Smrg	}
815f220fa62Smrg    }
816f220fa62Smrg}
817f220fa62Smrg
818f220fa62Smrg/*---------------------------------------------------------------------------
819f220fa62Smrg * outline - render the trimmed patch by outlining the boundary
820f220fa62Smrg *---------------------------------------------------------------------------
821f220fa62Smrg */
822f220fa62Smrg
823f220fa62Smrgvoid
824f220fa62SmrgSubdivider::outline( Bin& bin )
825f220fa62Smrg{
826f220fa62Smrg    bin.markall();
827f220fa62Smrg    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
828f220fa62Smrg	if( jarc->ismarked() ) {
829f220fa62Smrg	    assert( jarc->check( ) != 0 );
830f220fa62Smrg	    Arc_ptr jarchead = jarc;
831f220fa62Smrg	    do {
832f220fa62Smrg		slicer.outline( jarc );
833f220fa62Smrg		jarc->clearmark();
834f220fa62Smrg		jarc = jarc->prev;
835f220fa62Smrg	    } while (jarc != jarchead);
836f220fa62Smrg	}
837f220fa62Smrg    }
838f220fa62Smrg}
839f220fa62Smrg
840f220fa62Smrg/*---------------------------------------------------------------------------
841f220fa62Smrg * freejarcs - free all arcs in a bin
842f220fa62Smrg *---------------------------------------------------------------------------
843f220fa62Smrg */
844f220fa62Smrg
845f220fa62Smrgvoid
846f220fa62SmrgSubdivider::freejarcs( Bin& bin )
847f220fa62Smrg{
848f220fa62Smrg    bin.adopt();	/* XXX - should not be necessary */
849f220fa62Smrg
850f220fa62Smrg    Arc_ptr jarc;
851f220fa62Smrg    while( (jarc = bin.removearc()) != NULL ) {
852f220fa62Smrg	if( jarc->pwlArc ) jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
853f220fa62Smrg	if( jarc->bezierArc) jarc->bezierArc->deleteMe( bezierarcpool ); jarc->bezierArc = 0;
854f220fa62Smrg	jarc->deleteMe( arcpool );
855f220fa62Smrg    }
856f220fa62Smrg}
857f220fa62Smrg
858f220fa62Smrg/*----------------------------------------------------------------------------
859f220fa62Smrg * tessellate - tessellate all Bezier arcs in a bin
860f220fa62Smrg * 		   1) only accepts linear Bezier arcs as input
861f220fa62Smrg * 		   2) the Bezier arcs are stored in the pwlArc structure
862f220fa62Smrg * 		   3) only vertical or horizontal lines work
863f220fa62Smrg * 		-- should
864f220fa62Smrg * 		   1) represent Bezier arcs in BezierArc structure
865f220fa62Smrg * 		      (this requires a multitude of changes to the code)
866f220fa62Smrg * 		   2) accept high degree Bezier arcs (hard)
867f220fa62Smrg * 		   3) map the curve onto the surface to determine tessellation
868f220fa62Smrg * 		   4) work for curves of arbitrary geometry
869f220fa62Smrg *----------------------------------------------------------------------------
870f220fa62Smrg */
871f220fa62Smrg
872f220fa62Smrg
873f220fa62Smrgvoid
874f220fa62SmrgSubdivider::tessellate( Bin& bin, REAL rrate, REAL trate, REAL lrate, REAL brate )
875f220fa62Smrg{
876f220fa62Smrg    for( Arc_ptr jarc=bin.firstarc(); jarc; jarc=bin.nextarc() ) {
877f220fa62Smrg	if( jarc->isbezier( ) ) {
878f220fa62Smrg    	    assert( jarc->pwlArc->npts == 2 );
879f220fa62Smrg	    TrimVertex  *pts = jarc->pwlArc->pts;
880f220fa62Smrg    	    REAL s1 = pts[0].param[0];
881f220fa62Smrg    	    REAL t1 = pts[0].param[1];
882f220fa62Smrg    	    REAL s2 = pts[1].param[0];
883f220fa62Smrg    	    REAL t2 = pts[1].param[1];
884f220fa62Smrg
885f220fa62Smrg    	    jarc->pwlArc->deleteMe( pwlarcpool ); jarc->pwlArc = 0;
886f220fa62Smrg
887f220fa62Smrg	    switch( jarc->getside() ) {
888f220fa62Smrg		case arc_left:
889f220fa62Smrg		    assert( s1 == s2 );
890f220fa62Smrg		    arctessellator.pwl_left( jarc, s1, t1, t2, lrate );
891f220fa62Smrg		    break;
892f220fa62Smrg		case arc_right:
893f220fa62Smrg		    assert( s1 == s2 );
894f220fa62Smrg		    arctessellator.pwl_right( jarc, s1, t1, t2, rrate );
895f220fa62Smrg		    break;
896f220fa62Smrg		case arc_top:
897f220fa62Smrg		    assert( t1 == t2 );
898f220fa62Smrg		    arctessellator.pwl_top( jarc, t1, s1, s2, trate );
899f220fa62Smrg		    break;
900f220fa62Smrg		case arc_bottom:
901f220fa62Smrg		    assert( t1 == t2 );
902f220fa62Smrg		    arctessellator.pwl_bottom( jarc, t1, s1, s2, brate );
903f220fa62Smrg		    break;
904f220fa62Smrg		case arc_none:
905f220fa62Smrg		    (void) abort();
906f220fa62Smrg		    break;
907f220fa62Smrg	    }
908f220fa62Smrg	    assert( ! jarc->isbezier() );
909f220fa62Smrg    	    assert( jarc->check() != 0 );
910f220fa62Smrg	}
911f220fa62Smrg    }
912f220fa62Smrg}
913