home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Utilities / AltPoly.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  18.0 KB  |  898 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        AltPoly.cpp
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Owned by:    Reggie Adkins
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     10/2/96    RA        1278220: AltPoly.cpp includes ODDebug.h
  13.                                     twice
  14.  
  15.     To Do:
  16. */
  17.  
  18. /*
  19.     File:        AltPoly.cpp
  20.  
  21.     Contains:    OpenDoc polygon: optional C++ savvy classes
  22.  
  23.     Owned by:    Jens Alfke
  24.  
  25.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  26.  
  27.     To Do:
  28.                   
  29.         Improve the equality tests for contours and polygons. See comments
  30.         in the two "operator==" methods for details.
  31.     
  32.     In Progress:
  33.         
  34. */
  35.  
  36.  
  37. #ifndef _ALTPOINT_
  38. #include "AltPoint.h"            // Use C++ savvy ODPoint and ODRect
  39. #endif
  40.  
  41. #ifndef _ALTPOLY_
  42. #include "AltPoly.h"
  43. #endif
  44.  
  45. #ifndef SOM_ODTransform_xh
  46. #include "Trnsform.xh"
  47. #endif
  48.  
  49. #ifndef _LINEOPS_
  50. #include "LineOps.h"
  51. #endif
  52.  
  53. #ifndef _ODMEMORY_
  54. #include "ODMemory.h"
  55. #endif
  56.  
  57. #ifndef _EXCEPT_
  58. #include "Except.h"
  59. #endif
  60.  
  61. #ifndef SOM_ODStorageUnit_xh
  62. #include "StorageU.xh"
  63. #endif
  64.  
  65. #ifndef _STDTYPES_
  66. #include "StdTypes.xh"
  67. #endif
  68.  
  69. #ifndef _EXCEPT_
  70. #include "Except.h"
  71. #endif
  72.  
  73. #ifndef _ODDEBUG_
  74. #include "ODDebug.h"
  75. #endif
  76.  
  77. #ifndef _STORUTIL_
  78. #include <StorUtil.h>
  79. #endif
  80.  
  81. #ifndef _STDTYPIO_
  82. #include <StdTypIO.h>
  83. #endif
  84.  
  85. #ifndef _UTILERRS_
  86. #include "UtilErrs.h"
  87. #endif
  88.  
  89. #ifdef _PLATFORM_MACINTOSH_
  90.     #ifndef __GXERRORS__
  91.     #include "GXErrors.h"
  92.     #endif
  93.     #ifndef __GXGRAPHICS__
  94.     #include "GXGraphics.h"
  95.     #endif
  96. #endif
  97.  
  98. #include <stddef.h>                    // Defines offsetof() macro
  99.  
  100.  
  101. const ODSLong kMaxLong    = 0x7FFFFFFF;
  102.  
  103. #pragma segment ODShape
  104.  
  105.  
  106. //==============================================================================
  107. // Destructos
  108. //==============================================================================
  109.  
  110.  
  111. ODTempPolygon::ODTempPolygon( )
  112. {
  113.     // This constructor doesn't do anything special, but if not declared it will
  114.     // be inlined at the call site, resulting in lots of extra code due to the
  115.     // multiple inheritance.
  116. }
  117.  
  118.  
  119. ODTempPolygon::~ODTempPolygon( )
  120. {
  121.     this->Clear();
  122. }
  123.  
  124.  
  125. ODTempPolygonPtr::ODTempPolygonPtr( )
  126.     :fPoly(kODNULL)
  127. {
  128. }
  129.  
  130.  
  131. ODTempPolygonPtr::ODTempPolygonPtr( ODPolygon *p )
  132.     :fPoly(p)
  133. {
  134. }
  135.  
  136.  
  137. ODTempPolygonPtr::~ODTempPolygonPtr( )
  138. {
  139.     delete fPoly;
  140.     fPoly = kODNULL;
  141. }
  142.  
  143.  
  144. TempGXShape::TempGXShape( )
  145.     :fShape(kODNULL)
  146. {
  147. }
  148.  
  149.  
  150. TempGXShape::TempGXShape( gxShape s )
  151.     :fShape(s)
  152. {
  153. }
  154.  
  155.  
  156. TempGXShape::~TempGXShape( )
  157. {
  158.     if( fShape ) {
  159.         GXDisposeShape(fShape);
  160.         fShape = kODNULL;
  161.     }
  162. }
  163.  
  164.  
  165. //==============================================================================
  166. // QuickDraw GX Utilities
  167. //==============================================================================
  168.  
  169.  
  170. #pragma segment QDGXShape
  171.  
  172.  
  173. static void
  174. ClearGXError( )
  175. {
  176.     GXGetGraphicsError(kODNULL);
  177.     // GX error status is cleared after asking for errors.
  178. }
  179.  
  180.  
  181. static void
  182. ThrowIfGXError( )
  183. {
  184.     gxGraphicsError err = GXGetGraphicsError(kODNULL);    // Get latest graphics error
  185.     if( err )
  186.         THROW(err,"QuickDraw GX error");
  187. }
  188.  
  189.  
  190. static void
  191. ThrowIfFirstGXError( )
  192. {
  193.     gxGraphicsError err;
  194.     (void) GXGetGraphicsError(&err);            // Get first error, not last
  195.     if( err )
  196.         THROW(err,"QuickDraw GX error");
  197. }
  198.  
  199.  
  200. /******************************************************************************/
  201. //**    ALLOCATION
  202. /******************************************************************************/
  203.  
  204.  
  205. ODPolygon::ODPolygon( )
  206.     :_maximum(0),
  207.      _length(0),
  208.      _buf(kODNULL)
  209. {
  210. }
  211.  
  212.  
  213. #if ODDebug
  214. ODPolygon::~ODPolygon( )
  215. {
  216.     // To help catch double-deletes of ODPolygon structures!
  217.     _buf = (ODPolygonData*)0xDDDDDDDD;
  218.     _length = _maximum = 0xDDDDDDDD;
  219. }
  220. #endif
  221.  
  222.  
  223. void
  224. ODPolygon::Delete( )
  225. {
  226.     ODDisposePtr(_buf);
  227.     delete this;
  228. }
  229.  
  230.  
  231. void
  232. ODPolygon::Clear( )
  233. {
  234.     ODDisposePtr(_buf);
  235.     _buf = kODNULL;
  236.     _length = _maximum = 0;
  237. }
  238.  
  239.  
  240. static ODULong
  241. CalcDataSize( ODSLong nVertices )
  242. {
  243.     if( nVertices==0 )
  244.         return 0;
  245.     else
  246.         return offsetof(ODPolygonData,firstContour.vertex[nVertices]);
  247. }
  248.  
  249.  
  250. void
  251. ODPolygon::Realloc( ODULong dataSize )
  252. {
  253.     if( _buf!=kODNULL && dataSize>=_length && dataSize<=_maximum )
  254.         _length = dataSize;
  255.     else {
  256.         ODPtr newData;
  257.         if( dataSize!=0 )
  258.             newData = ODNewPtr(dataSize, kDefaultHeapID);
  259.         ODDisposePtr(_buf);
  260.         if( dataSize!=0 )
  261.             _buf = (ODPolygonData*)newData;
  262.         else
  263.             _buf = kODNULL;
  264.         _length = _maximum = dataSize;
  265.     }
  266. }
  267.  
  268.  
  269. void
  270. ODPolygon::SetData( const ODPolygonData *data )
  271. {
  272.     _length = sizeof(ODULong) * (1+data->nContours);
  273.     const ODContour *c = &data->firstContour;
  274.     for( ODULong i=data->nContours; i!=0; i-- ) {
  275.         _length += c->nVertices * sizeof(ODPoint);
  276.         c = c->NextContour();
  277.     }
  278.     
  279.     ODDisposePtr(_buf);
  280.     _buf = (ODPolygonData*)data;
  281.     _maximum = _length;
  282. }
  283.  
  284.  
  285. ODPolygon*
  286. ODPolygon::SetNVertices( ODSLong nVertices )
  287. {
  288.     ASSERT(nVertices>=0,kODErrValueOutOfRange);
  289.     
  290.     this->Realloc(CalcDataSize(nVertices));
  291.     if( nVertices>0 ) {
  292.         _buf->nContours = 1;
  293.         _buf->firstContour.nVertices = nVertices;
  294.     }
  295.     return this;
  296. }
  297.  
  298.  
  299. ODPolygon*
  300. ODPolygon::SetVertices( ODSLong nVertices, const ODPoint *vertices )
  301. {
  302.     ASSERT(nVertices>=0,kODErrValueOutOfRange);
  303.     ASSERT(vertices!=kODNULL,kODErrIllegalNullInput);
  304.     
  305.     this->SetNVertices(nVertices);
  306.     if( nVertices>0 )
  307.         ODBlockMove( (void *) vertices, _buf->firstContour.vertex, nVertices*sizeof(ODPoint) );
  308.     return this;
  309. }
  310.  
  311.  
  312. ODPolygon*
  313. ODPolygon::SetContours( ODSLong nContours, const ODSLong *contourVertices )
  314. {
  315.     ASSERT(nContours>=0,kODErrValueOutOfRange);
  316.     if( nContours==0 )
  317.         return this->SetNVertices(0);
  318.     else {
  319.         ASSERT(contourVertices!=kODNULL,kODErrIllegalNullInput);
  320.         ODULong totalVertices = 0;
  321.         ODSLong i;
  322.         for( i=nContours-1; i>=0; i-- )
  323.             totalVertices += contourVertices[i];
  324.         this->Realloc( offsetof(ODPolygonData,firstContour)
  325.                      + offsetof(ODContour,vertex[0]) * nContours
  326.                      + sizeof(ODPoint)*totalVertices );
  327.         _buf->nContours = nContours;
  328.         ODContour *cont = this->FirstContour();
  329.         for( i=0; i<nContours; i++ ) {
  330.             cont->nVertices = contourVertices[i];
  331.             cont = cont->NextContour();
  332.         }
  333.         return this;
  334.     }
  335. }
  336.  
  337.  
  338. ODPolygon*
  339. ODPolygon::SetRect( const ODRect &r )
  340. {
  341.     if( r.IsEmpty() )
  342.         return this->SetNVertices(0);
  343.     else {
  344.         this->SetNVertices(4);
  345.         _buf->firstContour.vertex[0] = r.TopLeft();
  346.         _buf->firstContour.vertex[1].Set(r.right,r.top);
  347.         _buf->firstContour.vertex[2] = r.BotRight();
  348.         _buf->firstContour.vertex[3].Set(r.left,r.bottom);
  349.     }
  350.     return this;
  351. }
  352.  
  353.  
  354. ODPolygon*
  355. ODPolygon::CopyFrom( const ODPolygon &poly )
  356. {
  357.     if( poly._buf != _buf ) {
  358.         ODULong size = poly.GetDataSize();
  359.         this->Realloc(size);
  360.         ODBlockMove(poly.GetData(),_buf,size);
  361.     }
  362.     return this;
  363. }
  364.  
  365.  
  366. ODPolygon*
  367. ODPolygon::MoveFrom( ODPolygon &poly )
  368. {
  369.     if( poly._buf != _buf ) {
  370.         ODDisposePtr(_buf);
  371.         _buf = poly._buf;
  372.         _length = poly._length;
  373.         _maximum = poly._maximum;
  374.     }
  375.     if( &poly._buf != &_buf ) {            // Don't clear poly if it's myself!
  376.         poly._buf = kODNULL;
  377.         poly._length = poly._maximum = 0;
  378.     }
  379.     return this;
  380. }
  381.  
  382.  
  383.  
  384. #ifdef _PLATFORM_MACINTOSH_
  385. #pragma segment ODGXShape
  386.  
  387. ODPolygon*
  388. ODPolygon::CopyFrom( gxShape shape )
  389. {
  390.     ClearGXError();
  391.     TempGXShape copiedShape = GXCopyToShape(kODNULL,shape);
  392.     GXPrimitiveShape(copiedShape);
  393.     GXSimplifyShape(copiedShape);
  394.     GXSetShapeType(copiedShape,gxPolygonType);
  395.     ThrowIfFirstGXError();
  396.     
  397.     ODULong size = GXGetPolygonParts(copiedShape, 1,gxSelectToEnd, kODNULL);
  398.     ThrowIfGXError();
  399.     this->Realloc(size);
  400.     GXGetPolygonParts(copiedShape, 1,gxSelectToEnd, (gxPolygons*)_buf);
  401.     ThrowIfGXError();
  402.     
  403.     return this;
  404. }
  405. #pragma segment ODShape
  406. #endif
  407.  
  408.  
  409. ODPolygon*
  410. ODPolygon::ReadFrom( Environment *ev, ODStorageUnit *su )
  411. {
  412.  
  413.     if( !su->Exists(ev,kODNULL,kODPolygon,kODPosUndefined) ) {
  414.         this->Clear();
  415.     } else {
  416.         ODPropertyName propName = su->GetProperty(ev);
  417.         ODGetPolygonProp(ev, su, propName, kODPolygon, this);
  418.         ODDisposePtr((ODPtr) propName);
  419.     }
  420.  
  421.     return this;
  422. }
  423.  
  424.  
  425. ODPolygon*
  426. ODPolygon::WriteTo( Environment *ev, ODStorageUnit *su )  const
  427. {
  428.     ODPropertyName propName = su->GetProperty(ev);
  429.     ODSetPolygonProp(ev, su, propName, kODPolygon, this);
  430.     ODDisposePtr((ODPtr) propName);
  431.     
  432.     return (ODPolygon*)this;
  433. }
  434.  
  435.  
  436. /******************************************************************************/
  437. //**    POLYGON STUFF
  438. /******************************************************************************/
  439.  
  440.  
  441. ODSLong
  442. ODPolygon::GetNContours( )  const
  443. {
  444.     return _length>0 ?_buf->nContours :0;
  445. }
  446.  
  447.  
  448. const ODContour*
  449. ODPolygon::FirstContour( )  const
  450. {
  451.     return _length>0 ?&_buf->firstContour :kODNULL;
  452. }
  453.  
  454.  
  455. ODContour*
  456. ODPolygon::FirstContour( )
  457. {
  458.     return _length>0 ?&_buf->firstContour :kODNULL;
  459. }
  460.  
  461.  
  462. ODPolygon*
  463. ODPolygon::Copy( ) const
  464. {
  465.     ODTempPolygonPtr poly = new ODPolygon;
  466.     poly->CopyFrom(*this);
  467.     return poly.DontDelete();
  468. }
  469.  
  470.  
  471. void
  472. ODPolygon::ComputeBoundingBox( ODRect *bbox ) const
  473. {
  474.     ASSERT(bbox!=kODNULL,kODErrIllegalNullInput);
  475.     
  476.     if( _buf==kODNULL || _buf->nContours <= 0 ) {
  477.         bbox->Clear();
  478.         return;
  479.     }
  480.     
  481.     // Start bbox out as maximally empty:
  482.     bbox->left    = bbox->top        =  kMaxLong;
  483.     bbox->right = bbox->bottom    = -kMaxLong;
  484.     
  485.     const ODContour *c = this->FirstContour();
  486.     for( ODSLong i=this->GetNContours(); i>0; i-- ) {
  487.         ODPoint *pt = (ODPoint*)c->vertex;
  488.         for( ODSLong v=c->nVertices; v>0; v--,pt++ ) {
  489.             if( pt->x < bbox->left )    bbox->left    = pt->x;
  490.             if( pt->x > bbox->right )    bbox->right    = pt->x;
  491.             if( pt->y < bbox->top )        bbox->top    = pt->y;
  492.             if( pt->y > bbox->bottom )    bbox->bottom= pt->y;
  493.         }
  494.         if( i>1 )
  495.             c = c->NextContour();
  496.     }
  497. }
  498.  
  499.  
  500. ODBoolean
  501. ODContour::operator== ( const ODContour &cont ) const
  502. {
  503.     /*    This test is complicated by the fact that the two contours might have the
  504.         same points, but out of phase. Therefore we have to compare the points
  505.         in sequence, once per possible phase difference.  */
  506.     
  507.     ODSLong nv = this->nVertices;
  508.     if( nv != cont.nVertices )
  509.         return kODFalse;
  510.     
  511.     for( ODSLong phase=0; phase<nv; phase++ ) {
  512.         const ODPoint *p0 = &this->vertex[0];
  513.         const ODPoint *p1 = &cont.vertex[phase];
  514.         ODSLong i;
  515.         for( i=nVertices; i>0; i-- ) {
  516.             if( i==phase )
  517.                 p1 = &cont.vertex[0];
  518.             if( ! (p0++)->ApproxEquals(*p1++) )        // Coords may differ very slightly
  519.                 break;
  520.         }
  521.         if( i==0 )
  522.             return kODTrue;
  523.     }
  524.     return kODFalse;
  525. }
  526.  
  527.  
  528. Boolean
  529. ODPolygon::operator== ( ODPolygon &poly ) const
  530. {
  531.     /*    This test is complicated by the fact that the two polygons may not have their
  532.         contours in the same order. Our approach is to step through my contours in
  533.         order, trying to match each to a unique contour in the target. To ensure
  534.         uniqueness, the sign of the nVertices field in a target contour is flipped
  535.         after it's matched.  */
  536.     
  537.     if( this->GetNContours() != poly.GetNContours() )
  538.         return kODFalse;
  539.     if( &poly == this )
  540.         return kODTrue;
  541.     
  542.     ODBoolean result = kODTrue;
  543.     const ODContour * c = this->FirstContour();
  544.     ODContour *pc;
  545.     
  546.     ODSLong i;
  547.     for( i=this->GetNContours(); i>0; i-- ) {
  548.         pc = poly.FirstContour();
  549.         ODSLong j;
  550.         for( j=poly.GetNContours(); j>0; j-- ) {
  551.             if( pc->nVertices>0 && *c==*pc ) {        // Compare contours!
  552.                 pc->nVertices = -pc->nVertices;        // Use sign bit as a flag (yech)
  553.                 break;
  554.             }
  555.             if( j>1 )
  556.                 pc = pc->NextContour();
  557.         }
  558.         if( j<=0 ) {
  559.             result = kODFalse;                    // No match for contour
  560.             break;
  561.         }
  562.  
  563.         if( i>1 )
  564.             c = c->NextContour();
  565.     }
  566.  
  567.     // Now that we know, clear all the sign bits:
  568.     pc = poly.FirstContour();
  569.     for( i=poly.GetNContours(); i>0; i-- ) {
  570.         if( pc->nVertices<0 )
  571.             pc->nVertices = -pc->nVertices;
  572.         pc = pc->NextContour();
  573.     }
  574.     return result;
  575. }
  576.  
  577.  
  578. Boolean
  579. ODPolygon::IsEmpty( ) const
  580. {
  581.     // FIX: This is not very smart. It will probably be necessary to compute the area
  582.     // of each contour...
  583.     
  584.     return _buf==kODNULL || _buf->nContours==0;
  585. }
  586.  
  587.  
  588. Boolean
  589. ODPolygon::IsRectangular( ) const
  590. {
  591.     return _buf==kODNULL || _buf->nContours==0 ||
  592.             (_buf->nContours==1  && _buf->firstContour.IsRectangular());
  593. }
  594.  
  595.  
  596. Boolean
  597. ODPolygon::AsRectangle( ODRect *r ) const
  598. {
  599.     if( _buf==kODNULL || _buf->nContours==0 ) {
  600.         r->Clear();
  601.         return kODTrue;
  602.     } else if( _buf->nContours==1 )
  603.         return _buf->firstContour.AsRectangle(r);
  604.     else
  605.         return kODFalse;
  606. }
  607.  
  608.  
  609. Boolean
  610. ODContour::IsRectangular( ) const
  611. {
  612.     if( nVertices != 4 )
  613.         return kODFalse;
  614.     else if( vertex[0].x == vertex[1].x )            // 1st edge is vertical
  615.         return vertex[1].y==vertex[2].y
  616.             && vertex[2].x==vertex[3].x
  617.             && vertex[3].y==vertex[0].y;
  618.     else if( vertex[0].y == vertex[1].y )            // 1st edge is horizontal
  619.         return vertex[1].x==vertex[2].x
  620.             && vertex[2].y==vertex[3].y
  621.             && vertex[3].x==vertex[0].x;
  622.     else
  623.         return kODFalse;
  624. }
  625.  
  626.  
  627. Boolean
  628. ODContour::AsRectangle( ODRect *r ) const
  629. {
  630.     ASSERT(r!=kODNULL,kODErrIllegalNullInput);
  631.     
  632.     if( this->IsRectangular() ) {
  633.         ODRect r2(vertex[0],vertex[2]);            // C'tor properly orders the coords
  634.         *r = r2;
  635.         return kODTrue;
  636.     } else
  637.         return kODFalse;
  638. }
  639.  
  640.  
  641. /******************************************************************************/
  642. //**    REGION CONVERSION
  643. /******************************************************************************/
  644.  
  645.  
  646. ODBoolean
  647. ODContour::HasExactRegion( ) const
  648. {
  649.     const ODPoint *b = &vertex[0];
  650.     for( ODSLong i=nVertices; i>=0; i-- ) {
  651.         const ODPoint *a = &vertex[i];
  652.         if( (a->x & 0xFFFF) || (a->y & 0xFFFF) )
  653.             return kODFalse;                        // Non-integer coordinates
  654.         if( a->x!=b->x && a->y!=b->y )
  655.             return kODFalse;                        // Diagonal line
  656.         b = a;
  657.     }
  658.     return kODTrue;
  659. }
  660.  
  661.  
  662. ODBoolean
  663. ODPolygon::HasExactRegion( ) const
  664. {
  665.     const ODContour *c = this->FirstContour();
  666.     for( long i=this->GetNContours(); i>0; i-- ) {
  667.         if( !c->HasExactRegion() )
  668.             return kODFalse;
  669.         if( i>1 )
  670.             c = c->NextContour();
  671.     }
  672.     return kODTrue;
  673. }
  674.  
  675.  
  676. #ifdef _PLATFORM_MACINTOSH_
  677. PolyHandle
  678. ODContour::AsQDPolygon( ) const
  679. {
  680.     ODSLong size = (sizeof(short)+sizeof(Rect)+sizeof(Point)) + nVertices*sizeof(Point);
  681.     if( size > 32767 )
  682.         THROW(kODErrShapeTooComplex);
  683.     PolyHandle p = (PolyHandle) ODNewHandle(size);
  684.     (**p).polySize = (short)size;
  685.     Rect &bbox = (**p).polyBBox;
  686.     SetRect(&bbox,32767,32767,-32767,-32767);
  687.     
  688.     const ODPoint *src = &vertex[0];
  689.     Point *dst = &(**p).polyPoints[0];
  690.     for( ODSLong i=nVertices; i>0; i-- ) {
  691.         *dst = src->AsQDPoint();
  692.         if( dst->h < bbox.left  )    bbox.left  = dst->h;
  693.         if( dst->v < bbox.top   )    bbox.top   = dst->v;
  694.         if( dst->h > bbox.right )    bbox.right = dst->h;
  695.         if( dst->v > bbox.bottom)    bbox.bottom= dst->v;
  696.         src++;
  697.         dst++;
  698.     }
  699.     *dst = vertex[0].AsQDPoint();    // QD makes us repeat the 1st pt at the end
  700.     
  701.     return p;
  702. }
  703. #endif
  704.  
  705.  
  706. #ifdef _PLATFORM_MACINTOSH_
  707. RgnHandle
  708. ODPolygon::AsQDRegion( ) const
  709. {
  710.     // NOTE: This method will not work properly for self-intersecting polygons!
  711.     // QuickDraw uses even-odd filling, while OpenDoc uses winding-number.
  712.     
  713.     if( !this->HasData() )
  714.         return ODNewRgn();
  715.  
  716.     GrafPtr port, myPort;
  717.  
  718.     // Make sure we have a real port to work with:
  719.     GetPort(&port);
  720.     if( FrontWindow() ) {
  721.         SetPort(FrontWindow());
  722.         myPort = kODNULL;
  723.     } else {
  724.         myPort = new GrafPort;
  725.         OpenPort(myPort);
  726.     }
  727.     
  728.     RgnHandle rgn = ODNewRgn();
  729.     
  730.     OpenRgn();
  731.     TRY{
  732.         PolyHandle poly;
  733.         const ODContour *cont = this->FirstContour();
  734.         for( ODSLong i=_buf->nContours; i>0; i-- ) {
  735.             poly = cont->AsQDPolygon();
  736.             FramePoly(poly);
  737.             KillPoly(poly);
  738.             cont = cont->NextContour();
  739.         }
  740.     }CATCH_ALL{
  741.         CloseRgn(rgn);
  742.         DisposeRgn(rgn);
  743.         SetPort(port);
  744.         if( myPort ) {
  745.             ClosePort(myPort);
  746.             delete myPort;
  747.         }
  748.         RERAISE;
  749.     }ENDTRY
  750.     
  751.     CloseRgn(rgn);
  752.     
  753.     SetPort(port);
  754.     if( myPort ) {
  755.         ClosePort(myPort);
  756.         delete myPort;
  757.     }
  758.     return rgn;
  759. }
  760. #endif
  761.  
  762.  
  763. #ifdef _PLATFORM_MACINTOSH_
  764. gxShape
  765. ODPolygon::AsGXShape( ) const
  766. {
  767.     gxShape shape;
  768.     if( this->HasData() ) {
  769.         shape = GXNewPolygons( (gxPolygons*)this->GetData() );
  770.         GXSetShapeFill(shape,gxWindingFill);
  771.     } else
  772.         shape = GXNewShape(gxEmptyType);
  773.     
  774.     ThrowIfFirstGXError();
  775.     return shape;
  776. }
  777. #endif
  778.  
  779.  
  780. void
  781. ODPolygon::Transform( Environment *ev, ODTransform *xform )
  782. {
  783.     if( this->HasData() ) {
  784.         ODContour *c = &_buf->firstContour;
  785.         for( ODSLong i=_buf->nContours; i>0; i-- ) {
  786.             ODPoint *pt = c->vertex;
  787.             for( ODSLong v=c->nVertices; v>0; v--, pt++ )
  788.                 xform->TransformPoint(ev,pt);
  789.             if( i>1 )
  790.                 c = c->NextContour();
  791.         }
  792.     }
  793. }
  794.  
  795.  
  796. /******************************************************************************/
  797. //**    CONTAINMENT TEST
  798. /******************************************************************************/
  799.  
  800.  
  801. //------------------------------------------------------------------------------
  802. // ODPolygon::Contains
  803. //
  804. // Does a polygon contain a point?
  805. // We determine this by drawing a ray from the point to the right towards
  806. // infinity, and finding the polygon edges that intersect this ray. For each
  807. // such edge, count it as 1 if its y value is increasing, -1 if decreasing.
  808. // The sum of these values is 0 if the point is outside the polygon.
  809. //------------------------------------------------------------------------------
  810.  
  811. ODSLong
  812. ODPolygon::Contains( ODPoint point ) const
  813. {
  814.     if( !this->HasData() )
  815.         return kODFalse;
  816.  
  817.     ODSLong count = 0;
  818.     const ODPoint *pp1, *pp2;
  819.     ODPoint p1, p2;
  820.     ODPoint ray = point;
  821.     
  822.     for( PolyEdgeIterator polyIter (this); polyIter.IsNotComplete(); polyIter.Next() ) {
  823.         polyIter.CurrentEdge(pp1,pp2);
  824.         p1 = *pp1;
  825.         p2 = *pp2;
  826.         
  827.         if( p1.y==p2.y ) {                                            // Horizontal line: ignore
  828.             if( p1.y==point.y && InRange(point.x, p1.x,p2.x) ) {    // unless point is on it
  829.                 return 0;
  830.             }
  831.         } else {
  832.             ray.x = Max(p1.x,p2.x);
  833.             ODPoint sect;
  834.             if( ray.x >= point.x )
  835.                 if( IntersectSegments(p1,p2, point,ray, §) ) {
  836.                     if( WithinEpsilon(point.x,sect.x) && WithinEpsilon(point.y,sect.y) ) {
  837.                         return 0;
  838.                     }
  839.                     if( p2.y > p1.y )
  840.                         count++;
  841.                     else
  842.                         count--;
  843.                 }
  844.         }
  845.     }
  846.     
  847.     return count;
  848. }
  849.  
  850.  
  851. /******************************************************************************/
  852. //**    POLYGON EDGE ITERATOR
  853. /******************************************************************************/
  854.  
  855.  
  856. PolyEdgeIterator::PolyEdgeIterator( const ODPolygon *poly )
  857.     :fPoly (poly)
  858. {
  859.     fCurContour = poly->FirstContour();
  860.     fCurContourIndex = 0;
  861.     fCurVertex = 0;
  862. }
  863.  
  864.  
  865. void
  866. PolyEdgeIterator::CurrentEdge( const ODPoint* &v1, const ODPoint* &v2 )
  867. {
  868.     v1 = &fCurContour->vertex[fCurVertex];
  869.     if( fCurVertex+1 < fCurContour->nVertices )
  870.         v2 = v1+1;
  871.     else
  872.         v2 = &fCurContour->vertex[0];
  873. }
  874.  
  875.  
  876. Boolean
  877. PolyEdgeIterator::Next( )
  878. {
  879.     if( !fCurContour )                                    // Was already finished
  880.         return false;
  881.     if( ++fCurVertex >= fCurContour->nVertices )        // Next vertex; if past contour:
  882.         if( ++fCurContourIndex >= fPoly->GetNContours() ) {        // Next contour; if past end:
  883.             fCurContour = kODNULL;
  884.             return false;                                        //...we're done.
  885.         } else {
  886.             fCurContour = fCurContour->NextContour();            // Else go to start of contour
  887.             fCurVertex = 0;
  888.         }
  889.     return kODTrue;
  890. }
  891.  
  892.  
  893. Boolean
  894. PolyEdgeIterator::IsNotComplete( )
  895. {
  896.     return fCurContour!=kODNULL;
  897. }
  898.