Home | History | Annotate | Line # | Download | only in internals
      1 /*
      2 ** License Applicability. Except to the extent portions of this file are
      3 ** made subject to an alternative license as permitted in the SGI Free
      4 ** Software License B, Version 1.1 (the "License"), the contents of this
      5 ** file are subject only to the provisions of the License. You may not use
      6 ** this file except in compliance with the License. You may obtain a copy
      7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
      8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
      9 **
     10 ** http://oss.sgi.com/projects/FreeB
     11 **
     12 ** Note that, as provided in the License, the Software is distributed on an
     13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
     14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
     15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
     16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
     17 **
     18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
     19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
     20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
     21 ** Copyright in any portions created by third parties is as indicated
     22 ** elsewhere herein. All Rights Reserved.
     23 **
     24 ** Additional Notice Provisions: The application programming interfaces
     25 ** established by SGI in conjunction with the Original Code are The
     26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
     27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
     28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
     29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
     30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
     31 ** published by SGI, but has not been independently verified as being
     32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
     33 */
     34 
     35 /*
     36  * intersect.c++
     37  *
     38  */
     39 
     40 #include "glimports.h"
     41 #include "myassert.h"
     42 #include "mystdio.h"
     43 #include "subdivider.h"
     44 #include "arc.h"
     45 #include "bin.h"
     46 #include "backend.h"
     47 #include "trimvertpool.h"
     48 
     49 /*#define NOTDEF*/
     50 
     51 enum i_result { INTERSECT_VERTEX, INTERSECT_EDGE };
     52 
     53 /* local functions */
     54 #ifndef NDEBUG  // for asserts only
     55 static int		arc_classify( Arc_ptr, int, REAL );
     56 #endif
     57 static enum i_result	pwlarc_intersect( PwlArc *, int, REAL, int, int[3] );
     58 
     59 
     60 void
     61 Subdivider::partition( Bin & bin, Bin & left, Bin & intersections,
     62 	        Bin & right, Bin & unknown, int param, REAL value )
     63 {
     64     Bin	headonleft, headonright, tailonleft, tailonright;
     65 
     66     for( Arc_ptr jarc = bin.removearc(); jarc; jarc = bin.removearc() ) {
     67 
     68 	REAL tdiff = jarc->tail()[param] - value;
     69 	REAL hdiff = jarc->head()[param] - value;
     70 
     71 	if( tdiff > 0.0 ) {
     72 	    if( hdiff > 0.0 ) {
     73 		right.addarc( jarc  );
     74 	    } else if( hdiff == 0.0 ) {
     75 		tailonright.addarc( jarc  );
     76 	    } else {
     77 	        Arc_ptr	jtemp;
     78 		switch( arc_split(jarc, param, value, 0) ) {
     79 		    case 2:
     80 			tailonright.addarc( jarc  );
     81 			headonleft.addarc( jarc->next  );
     82 			break;
     83 		    case 31:
     84 			assert( jarc->head()[param] > value );
     85 			right.addarc( jarc  );
     86 			tailonright.addarc( jtemp = jarc->next  );
     87 			headonleft.addarc( jtemp->next  );
     88 		        break;
     89 		    case 32:
     90 			assert( jarc->head()[param] <= value );
     91 			tailonright .addarc( jarc  );
     92 			headonleft.addarc( jtemp = jarc->next  );
     93 			left.addarc( jtemp->next  );
     94 			break;
     95 		    case 4:
     96 			right.addarc( jarc  );
     97 			tailonright.addarc( jtemp = jarc->next  );
     98 			headonleft.addarc( jtemp = jtemp->next  );
     99 			left.addarc( jtemp->next  );
    100 		}
    101 	    }
    102 	} else if( tdiff == 0.0 ) {
    103 	    if( hdiff > 0.0 ) {
    104 		headonright.addarc( jarc  );
    105 	    } else if( hdiff == 0.0 ) {
    106 		unknown.addarc( jarc  );
    107 	    } else {
    108 		headonleft.addarc( jarc  );
    109 	    }
    110 	} else {
    111 	    if( hdiff > 0.0 ) {
    112 	        Arc_ptr	jtemp;
    113 		switch( arc_split(jarc, param, value, 1) ) {
    114 		    case 2:
    115 			tailonleft.addarc( jarc  );
    116 			headonright.addarc( jarc->next  );
    117 			break;
    118 		    case 31:
    119 			assert( jarc->head()[param] < value );
    120 			left.addarc( jarc  );
    121 			tailonleft.addarc( jtemp = jarc->next  );
    122 			headonright.addarc( jtemp->next  );
    123 			break;
    124 		    case 32:
    125 			assert( jarc->head()[param] >= value );
    126 			tailonleft.addarc( jarc  );
    127 			headonright.addarc( jtemp = jarc->next  );
    128 			right.addarc( jtemp->next  );
    129 			break;
    130 		    case 4:
    131 			left.addarc( jarc  );
    132 			tailonleft.addarc( jtemp = jarc->next  );
    133 			headonright.addarc( jtemp = jtemp->next  );
    134 			right.addarc( jtemp->next  );
    135 		}
    136 	    } else if( hdiff == 0.0 ) {
    137 		tailonleft.addarc( jarc  );
    138 	    } else {
    139 		left.addarc( jarc  );
    140 	    }
    141 	}
    142     }
    143     if( param == 0 ) {
    144 	classify_headonleft_s( headonleft, intersections, left, value );
    145 	classify_tailonleft_s( tailonleft, intersections, left, value );
    146 	classify_headonright_s( headonright, intersections, right, value );
    147 	classify_tailonright_s( tailonright, intersections, right, value );
    148     } else {
    149 	classify_headonleft_t( headonleft, intersections, left, value );
    150 	classify_tailonleft_t( tailonleft, intersections, left, value );
    151 	classify_headonright_t( headonright, intersections, right, value );
    152 	classify_tailonright_t( tailonright, intersections, right, value );
    153     }
    154 }
    155 
    156 inline static void
    157 vert_interp( TrimVertex *n, TrimVertex *l, TrimVertex *r, int p, REAL val )
    158 {
    159     assert( val > l->param[p]);
    160     assert( val < r->param[p]);
    161 
    162     n->nuid = l->nuid;
    163 
    164     n->param[p] = val;
    165     if( l->param[1-p] != r->param[1-p]  ) {
    166 	REAL ratio = (val - l->param[p]) / (r->param[p] - l->param[p]);
    167 	n->param[1-p] = l->param[1-p] +
    168 		        ratio * (r->param[1-p] - l->param[1-p]);
    169     } else {
    170 	n->param[1-p] = l->param[1-p];
    171     }
    172 }
    173 
    174 int
    175 Subdivider::arc_split( Arc_ptr jarc, int param, REAL value, int dir )
    176 {
    177     int		maxvertex = jarc->pwlArc->npts;
    178     Arc_ptr	jarc1;
    179     TrimVertex* v = jarc->pwlArc->pts;
    180 
    181     int		loc[3];
    182     switch( pwlarc_intersect( jarc->pwlArc, param, value, dir, loc ) ) {
    183 
    184 		// When the parameter value lands on a vertex, life is sweet
    185     case INTERSECT_VERTEX: {
    186 	    jarc1 = new(arcpool) Arc( jarc, new( pwlarcpool) PwlArc( maxvertex-loc[1], &v[loc[1]] ) );
    187 	    jarc->pwlArc->npts = loc[1] + 1;
    188 	    jarc1->next = jarc->next;
    189 	    jarc1->next->prev = jarc1;
    190 	    jarc->next = jarc1;
    191 	    jarc1->prev = jarc;
    192 	    assert(jarc->check() != 0);
    193 	    return 2;
    194 	}
    195 
    196 		// When the parameter value intersects an edge, we have to
    197 		// interpolate a new vertex.  There are special cases
    198 		// if the new vertex is adjacent to one or both of the
    199 		// endpoints of the arc.
    200     case INTERSECT_EDGE: {
    201 	    int i, j;
    202 	    if( dir == 0 ) {
    203 		i = loc[0];
    204 		j = loc[2];
    205 	    } else {
    206 		i = loc[2];
    207 		j = loc[0];
    208 	    }
    209 
    210 #ifndef NOTDEF
    211 	    // The split is between vertices at index j and i, in that
    212 	    // order (j < i)
    213 
    214 	    // JEB:  This code is my idea of how to do the split without
    215 	    // increasing the number of links.  I'm doing this so that
    216 	    // the is_rect routine can recognize rectangles created by
    217 	    // subdivision.  In exchange for simplifying the curve list,
    218       	    // however, it costs in allocated space and vertex copies.
    219 
    220 	    TrimVertex *newjunk = trimvertexpool.get(maxvertex -i+1 /*-j*/);
    221 	    int k;
    222 	    for(k=0; k<maxvertex-i; k++)
    223 	      {
    224 		newjunk[k+1] = v[i+k];
    225 		newjunk[k+1].nuid = jarc->nuid;
    226 	      }
    227 
    228 	    TrimVertex *vcopy = trimvertexpool.get(maxvertex);
    229 	    for(k=0; k<maxvertex; k++)
    230 	      {
    231 		vcopy[k].param[0] = v[k].param[0];
    232 		vcopy[k].param[1] = v[k].param[1];
    233 	      }
    234 	    jarc->pwlArc->pts=vcopy;
    235 
    236 	    v[i].nuid = jarc->nuid;
    237 	    v[j].nuid = jarc->nuid;
    238 	    vert_interp( &newjunk[0], &v[loc[0]], &v[loc[2]], param, value );
    239 
    240 	    if( showingDegenerate() )
    241 		backend.triangle( &v[i], &newjunk[0], &v[j] );
    242 
    243             vcopy[j+1].param[0]=newjunk[0].param[0];
    244             vcopy[j+1].param[1]=newjunk[0].param[1];
    245 
    246 
    247 	    jarc1 = new(arcpool) Arc( jarc,
    248 			new(pwlarcpool) PwlArc(maxvertex-i+1 , newjunk ) );
    249 
    250 	    jarc->pwlArc->npts = j+2;
    251 	    jarc1->next = jarc->next;
    252 	    jarc1->next->prev = jarc1;
    253 	    jarc->next = jarc1;
    254 	    jarc1->prev = jarc;
    255 	    assert(jarc->check() != 0);
    256 
    257 	    return 2;
    258 #endif //not NOTDEF
    259 		// JEB: This is the original version:
    260 #ifdef NOTDEF
    261             Arc_ptr    jarc2, jarc3;
    262 
    263 	    TrimVertex *newjunk = trimvertexpool.get(3);
    264 	    v[i].nuid = jarc->nuid;
    265 	    v[j].nuid = jarc->nuid;
    266 	    newjunk[0] = v[j];
    267 	    newjunk[2] = v[i];
    268 	    vert_interp( &newjunk[1], &v[loc[0]], &v[loc[2]], param, value );
    269 
    270 	    if( showingDegenerate() )
    271 		backend.triangle( &newjunk[2], &newjunk[1], &newjunk[0] );
    272 
    273 		// New vertex adjacent to both endpoints
    274 	    if (maxvertex == 2) {
    275 		jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
    276 		jarc->pwlArc->npts = 2;
    277 		jarc->pwlArc->pts = newjunk;
    278 		jarc1->next = jarc->next;
    279 		jarc1->next->prev = jarc1;
    280 		jarc->next = jarc1;
    281 		jarc1->prev = jarc;
    282 		assert(jarc->check() != 0);
    283 
    284 		return 2;
    285 
    286 		// New vertex adjacent to ending point of arc
    287 	    } else if (maxvertex - j == 2) {
    288 		jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk ) );
    289 		jarc2 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
    290 		jarc->pwlArc->npts = maxvertex-1;
    291 		jarc2->next = jarc->next;
    292 		jarc2->next->prev = jarc2;
    293 		jarc->next = jarc1;
    294 		jarc1->prev = jarc;
    295 		jarc1->next = jarc2;
    296 		jarc2->prev = jarc1;
    297 		assert(jarc->check() != 0);
    298 		return 31;
    299 
    300 		// New vertex adjacent to starting point of arc
    301 	    } else if (i == 1) {
    302 		jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
    303 		jarc2 = new(arcpool) Arc( jarc,
    304 			new(pwlarcpool) PwlArc( maxvertex-1, &jarc->pwlArc->pts[1] ) );
    305 		jarc->pwlArc->npts = 2;
    306 		jarc->pwlArc->pts = newjunk;
    307 		jarc2->next = jarc->next;
    308 		jarc2->next->prev = jarc2;
    309 		jarc->next = jarc1;
    310 		jarc1->prev = jarc;
    311 		jarc1->next = jarc2;
    312 		jarc2->prev = jarc1;
    313 		assert(jarc->check() != 0);
    314 		return 32;
    315 
    316 		// It's somewhere in the middle
    317 	    } else {
    318 		jarc1 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk ) );
    319 		jarc2 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( 2, newjunk+1 ) );
    320 		jarc3 = new(arcpool) Arc( jarc, new(pwlarcpool) PwlArc( maxvertex-i, v+i ) );
    321 		jarc->pwlArc->npts = j + 1;
    322 		jarc3->next = jarc->next;
    323 		jarc3->next->prev = jarc3;
    324 		jarc->next = jarc1;
    325 		jarc1->prev = jarc;
    326 		jarc1->next = jarc2;
    327 		jarc2->prev = jarc1;
    328 		jarc2->next = jarc3;
    329 		jarc3->prev = jarc2;
    330 		assert(jarc->check() != 0);
    331 		return 4;
    332 	    }
    333 #endif // NOTDEF
    334 	}
    335 	default:
    336 	return -1; //picked -1 since it's not used
    337     }
    338 }
    339 
    340 /*----------------------------------------------------------------------------
    341  * pwlarc_intersect -  find intersection of pwlArc and isoparametric line
    342  *----------------------------------------------------------------------------
    343  */
    344 
    345 static enum i_result
    346 pwlarc_intersect(
    347     PwlArc *pwlArc,
    348     int param,
    349     REAL value,
    350     int dir,
    351     int loc[3] )
    352 {
    353     assert( pwlArc->npts > 0 );
    354 
    355     if( dir ) {
    356 	TrimVertex *v = pwlArc->pts;
    357 	int imin = 0;
    358 	int imax = pwlArc->npts - 1;
    359 	assert( value > v[imin].param[param] );
    360 	assert( value < v[imax].param[param] );
    361 	while( (imax - imin) > 1 ) {
    362 	    int imid = (imax + imin)/2;
    363 	    if( v[imid].param[param] > value )
    364 		imax = imid;
    365 	    else if( v[imid].param[param] < value )
    366 		imin = imid;
    367 	    else {
    368 		loc[1] = imid;
    369 		return INTERSECT_VERTEX;
    370 	    }
    371 	}
    372 	loc[0] = imin;
    373 	loc[2] = imax;
    374 	return INTERSECT_EDGE;
    375     } else {
    376 	TrimVertex *v = pwlArc->pts;
    377 	int imax = 0;
    378 	int imin = pwlArc->npts - 1;
    379 	assert( value > v[imin].param[param] );
    380 	assert( value < v[imax].param[param] );
    381 	while( (imin - imax) > 1 ) {
    382 	    int imid = (imax + imin)/2;
    383 	    if( v[imid].param[param] > value )
    384 		imax = imid;
    385 	    else if( v[imid].param[param] < value )
    386 		imin = imid;
    387 	    else {
    388 		loc[1] = imid;
    389 		return INTERSECT_VERTEX;
    390 	    }
    391 	}
    392 	loc[0] = imin;
    393 	loc[2] = imax;
    394 	return INTERSECT_EDGE;
    395     }
    396 }
    397 
    398 /*----------------------------------------------------------------------------
    399  * arc_classify - determine which side of a line a jarc lies
    400  *----------------------------------------------------------------------------
    401  */
    402 
    403 #ifndef NDEBUG  // for asserts only
    404 static int
    405 arc_classify( Arc_ptr jarc, int param, REAL value )
    406 {
    407     REAL tdiff, hdiff;
    408     if( param == 0 ) {
    409 	tdiff = jarc->tail()[0] - value;
    410 	hdiff = jarc->head()[0] - value;
    411     } else {
    412 	tdiff = jarc->tail()[1] - value;
    413 	hdiff = jarc->head()[1] - value;
    414     }
    415 
    416     if( tdiff > 0.0 ) {
    417 	if( hdiff > 0.0 ) {
    418 	    return 0x11;
    419 	} else if( hdiff == 0.0 ) {
    420 	    return 0x12;
    421 	} else {
    422 	    return 0x10;
    423 	}
    424     } else if( tdiff == 0.0 ) {
    425 	if( hdiff > 0.0 ) {
    426 	    return 0x21;
    427 	} else if( hdiff == 0.0 ) {
    428 	    return 0x22;
    429 	} else {
    430 	    return 0x20;
    431 	}
    432     } else {
    433 	if( hdiff > 0.0 ) {
    434 	    return 0x01;
    435 	} else if( hdiff == 0.0 ) {
    436 	    return 0x02;
    437 	} else {
    438 	    return 0;
    439 	}
    440     }
    441 }
    442 #endif
    443 
    444 void
    445 Subdivider::classify_tailonleft_s( Bin& bin, Bin& in, Bin& out, REAL val )
    446 {
    447     /* tail at left, head on line */
    448     Arc_ptr j;
    449 
    450     while( (j = bin.removearc()) != NULL ) {
    451 	assert( arc_classify( j, 0, val ) == 0x02 );
    452 	j->clearitail();
    453 
    454 	REAL diff = j->next->head()[0] - val;
    455 	if( diff > 0.0 ) {
    456 	    in.addarc( j );
    457 	} else if( diff < 0.0 ) {
    458 	    if( ccwTurn_sl( j, j->next ) )
    459 		out.addarc( j );
    460 	    else
    461 		in.addarc( j );
    462 	} else {
    463 	    if( j->next->tail()[1] > j->next->head()[1] )
    464 		in.addarc(j);
    465 	    else
    466 		out.addarc(j);
    467 	}
    468     }
    469 }
    470 
    471 void
    472 Subdivider::classify_tailonleft_t( Bin& bin, Bin& in, Bin& out, REAL val )
    473 {
    474     /* tail at left, head on line */
    475     Arc_ptr j;
    476 
    477     while( (j = bin.removearc()) != NULL ) {
    478 	assert( arc_classify( j, 1, val ) == 0x02 );
    479 	j->clearitail();
    480 
    481         REAL diff = j->next->head()[1] - val;
    482 	if( diff > 0.0 ) {
    483 	    in.addarc( j );
    484 	} else if( diff < 0.0 ) {
    485 	    if( ccwTurn_tl( j, j->next ) )
    486 		out.addarc( j );
    487 	    else
    488 		in.addarc( j );
    489 	} else {
    490 	    if (j->next->tail()[0] > j->next->head()[0] )
    491 		out.addarc( j );
    492 	    else
    493 		in.addarc( j );
    494 	}
    495     }
    496 }
    497 
    498 void
    499 Subdivider::classify_headonleft_s( Bin& bin, Bin& in, Bin& out, REAL val )
    500 {
    501     /* tail on line, head at left */
    502     Arc_ptr j;
    503 
    504     while( (j = bin.removearc()) != NULL ) {
    505 	assert( arc_classify( j, 0, val ) == 0x20 );
    506 
    507 	j->setitail();
    508 
    509 	REAL diff = j->prev->tail()[0] - val;
    510 	if( diff > 0.0 ) {
    511 	    out.addarc( j );
    512 	} else if( diff < 0.0 ) {
    513 	    if( ccwTurn_sl( j->prev, j ) )
    514 		out.addarc( j );
    515 	    else
    516 		in.addarc( j );
    517 	} else {
    518 	    if( j->prev->tail()[1] > j->prev->head()[1] )
    519 		in.addarc( j );
    520 	    else
    521 		out.addarc( j );
    522 	}
    523     }
    524 }
    525 
    526 void
    527 Subdivider::classify_headonleft_t( Bin& bin, Bin& in, Bin& out, REAL val )
    528 {
    529     /* tail on line, head at left */
    530     Arc_ptr j;
    531 
    532     while( (j = bin.removearc()) != NULL ) {
    533 	assert( arc_classify( j, 1, val ) == 0x20 );
    534 	j->setitail();
    535 
    536 	REAL diff = j->prev->tail()[1] - val;
    537 	if( diff > 0.0 ) {
    538 	    out.addarc( j );
    539 	} else if( diff < 0.0 ) {
    540 	    if( ccwTurn_tl( j->prev, j ) )
    541 		out.addarc( j );
    542 	    else
    543 		in.addarc( j );
    544 	} else {
    545 	    if( j->prev->tail()[0] > j->prev->head()[0] )
    546 		out.addarc( j );
    547 	    else
    548 		in.addarc( j );
    549 	}
    550     }
    551 }
    552 
    553 
    554 void
    555 Subdivider::classify_tailonright_s( Bin& bin, Bin& in, Bin& out, REAL val )
    556 {
    557     /* tail at right, head on line */
    558     Arc_ptr j;
    559 
    560     while( (j = bin.removearc()) != NULL ) {
    561 	assert( arc_classify( j, 0, val ) == 0x12);
    562 
    563 	j->clearitail();
    564 
    565         REAL diff = j->next->head()[0] - val;
    566 	if( diff > 0.0 ) {
    567 	    if( ccwTurn_sr( j, j->next ) )
    568 		out.addarc( j );
    569 	    else
    570 		in.addarc( j );
    571 	} else if( diff < 0.0 ) {
    572 	    in.addarc( j );
    573 	} else {
    574 	    if( j->next->tail()[1] > j->next->head()[1] )
    575 		out.addarc( j );
    576 	    else
    577 		in.addarc( j );
    578 	}
    579     }
    580 }
    581 
    582 void
    583 Subdivider::classify_tailonright_t( Bin& bin, Bin& in, Bin& out, REAL val )
    584 {
    585     /* tail at right, head on line */
    586     Arc_ptr j;
    587 
    588     while( (j = bin.removearc()) != NULL ) {
    589 	assert( arc_classify( j, 1, val ) == 0x12);
    590 
    591 	j->clearitail();
    592 
    593 	REAL diff =  j->next->head()[1] - val;
    594 	if( diff > 0.0 ) {
    595 	    if( ccwTurn_tr( j, j->next ) )
    596 		out.addarc( j );
    597 	    else
    598 		in.addarc( j );
    599 	} else if( diff < 0.0 ) {
    600 	    in.addarc( j );
    601 	} else {
    602 	    if( j->next->tail()[0] > j->next->head()[0] )
    603 		in.addarc( j );
    604 	    else
    605 		out.addarc( j );
    606 	}
    607     }
    608 }
    609 
    610 void
    611 Subdivider::classify_headonright_s( Bin& bin, Bin& in, Bin& out, REAL val )
    612 {
    613     /* tail on line, head at right */
    614     Arc_ptr j;
    615 
    616     while( (j = bin.removearc()) != NULL ) {
    617 	assert( arc_classify( j, 0, val ) == 0x21 );
    618 
    619 	j->setitail();
    620 
    621         REAL diff = j->prev->tail()[0] - val;
    622 	if( diff > 0.0 ) {
    623 	    if( ccwTurn_sr( j->prev, j ) )
    624 		out.addarc( j );
    625 	    else
    626 		in.addarc( j );
    627 	} else if( diff < 0.0 ) {
    628 	    out.addarc( j );
    629 	} else {
    630 	    if( j->prev->tail()[1] > j->prev->head()[1] )
    631 		out.addarc( j );
    632 	    else
    633 		in.addarc( j );
    634 	}
    635     }
    636 }
    637 
    638 void
    639 Subdivider::classify_headonright_t( Bin& bin, Bin& in, Bin& out, REAL val )
    640 {
    641     /* tail on line, head at right */
    642     Arc_ptr j;
    643 
    644     while( (j = bin.removearc()) != NULL ) {
    645 	assert( arc_classify( j, 1, val ) == 0x21 );
    646 
    647 	j->setitail();
    648 
    649         REAL diff = j->prev->tail()[1] - val;
    650 	if( diff > 0.0 ) {
    651 	    if( ccwTurn_tr( j->prev, j ) )
    652 		out.addarc( j );
    653 	    else
    654 		in.addarc( j );
    655 	} else if( diff < 0.0 ) {
    656 	    out.addarc( j );
    657 	} else {
    658 	    if( j->prev->tail()[0] > j->prev->head()[0] )
    659 		in.addarc( j );
    660 	    else
    661 		out.addarc( j );
    662 	}
    663     }
    664 }
    665 
    666