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