/****************************************************************************
 *   gadt_polygon.h : header file for polygon ADT.
 *   
 *   Change Log :
 *		  06-12-1996 Initial version,  Liujian Qian
 *
 *   $Id: gadt_polygon.h,v 1.12 1998/12/10 00:11:29 qian Exp $
 ***************************************************************************/
 
#ifndef _GPOLYGON_H_
#define _GPOLYGON_H_

#include "gadt.h"
#include "gops.h"

/**
 *    The 2D polygon (with holes) ADT. 
 *
 *    A polygon is a bounded area defined by one or
 *    more rings. If there are more than one rings, then there is one
 *    outer boundary ring and the rest are interier rings (holes). The
 *    internal data layout is very similar to that of an ArcView shapefile
 *    Polygon record (without all the record headers etc).
 *
 *    The first ring is the outer boundary of the polygon by default.
 */
class GPolygon : public GSpatial
{
    GOps	ops;
    
    friend class GRect;
    friend class GCircle;
    
public:
    /**
     */
    GPolygon ();
    
    /**
     */
    GPolygon (const GPolygon& a);

    /**
     */
    GPolygon& operator= (const GPolygon& other);
    
    /**
     */
    virtual ~GPolygon ();

    virtual GType 	type() const { return _Polygon; }
    virtual uint32  	getPSize() const;
    virtual Result 	init(void);

    /**
     * User format: "n_rings, #_points_1, #_points_2, ... #_points_N,
     *		 x1 y1 x2 y2 ... xm ym"
     */
    virtual Result 	input     (const char* in);
    /**
     * generates a string with same format in input
     */
    virtual Result 	output    (char*& out);
    virtual Result	pack	  (DataPipe& p);
    virtual Result 	unpack    (DataPipe& p);

    /**
     * @short return the mbr of the out boundary ring.
     * @param box will be filled with the minimum bounding rectangle.
     *  	if returns GFail, then box is not set.
     */ 
    virtual Result  	mbr(GRect& box) const;
    virtual GADT* 	clone() const {return  new GPolygon; }
    /**
     * compares the area with the polygon 'a's area.  
     * Returns -1 if 'a' has larger area; or zero if they equal; otherwise 1
     */
    virtual int		cmp 	   (const GADT&) const {return UNDEFINED;}
    /**
     * this method accepts severl "parts" each of which are a series of 
     * ordered points. All existing data will be replaced by the new data.
     */
    virtual void	set(int n_parts, int n_pnts, 
			    const int* parts, const Coord* coord);
    
    virtual Result      scale      (double xf, double yf, double zf=1);
    virtual Result      translate  (double xf, double yf, double zf=1);
    virtual Result	rotate	   (double, bool);
    virtual Result	transform  (const GMatrix&);

    /**
     */
    int     numVertices(void) const { return ops.n_points; }

    /**
     * return number of rings
     */
    int	    numRings (void) const { return ops.n_parts; }

    /**
     * return 1 if the polygon has holes
     */
    bool    hasHole (void) const  { return ops.n_parts>1; };

    /**
     * add a ring to the owning polygon
     * @param n_vertices	number of vertices in the new ring
     * @param coords		the coordinates of the new ring
     */
    Result  addRing(int n_vertices, Coord* coords);
    /**
     * return the information about a particular ring
     * @param  nth		which ring to get
     * @param  coords		where the coordinates of the ring begin
     * @return the number of vertices in this ring.
     */
    int	    getRing(int nth, Coord*& coords);
    /**
     * set the MBR
     */
    void    setMbr(const GRect& b) {ops.setMbr(b);}
    /**
     * recalculate the MBR for this polygon
     * @param   r   is the newly calculated MBR
     */
    Result genMbr(GRect& r);

    //Result  addPoint(Coord x, Coord y, bool do_mbr=1);
    //Result  addPoint(const GPoint& pnt);
    /**
     */
    int     bearing  (const GADT& other) const;
    
    /**
     *  return distance between this polygon and another object.
     *
     *	if the argument is another polygon, we calculte the distance
     *	between the centroids of the two polygons' outer boundary ring
     *	only...  this may not really what we want since we don't take 
     *	into account any of the holes of either polygon.
     *
     *	@Return the distance.
     */
    double  distance (const GADT& other) const;

    /**
     * return the area (not including any holes)
     */
    double  area      () const;
    /**
     * calculate the signed area of a ring (simple polygon without holes).
     * @param   n_points	number of vertices in the ring
     * @param   coord		coordinates of the vertices.
     * Can be used to determine the ordering of vertices.
     */
    double  sarea     (int n_points, Coord* coord) const;
    /**
     * calculate the signed area of a polygon (assuming a  simple one).
     * the area of holes are subtracted from that of the outer boundary
     * ring.
     */
    double  sarea     () const;

    /**
     * return the perimeter (including those of the holes)
     */
    double  perimeter () const;
    /**
     * calculate the perimeter of a particular ring
     * @param nth	specifies the ring 
     */
    double  perimeter(int nth) const;
    /**
     *	Determine the class of the polygon according to its convexity.
     *  It calls some inlines that are useful routines in
     *	their own right.
     *
     *  Originally  by Peter Schorn & Frederick Fisher, In "Graphics
     *	Gems IV", Academic Press 1994.
     *
     *  @return the class of the polygon; for meaning of return values 
     *	see geomacro.h, they are GCONVEX_CW, GCONVEX_CCW, GNOT_CONVEX,
     *	GNOT_CONVEX_DEGENERATE, GCONEXT_DEGENERATE.
     */
    int	    classify  (int, Coord*) ;
    /**
     * handy version of the classify method.
     */
    int     classify  ();
    /**
     */
    static int 
    whichSide(GPoint& p, GPoint& q, GPoint& r);

    /**
     */
    int     isConvex  ();

    /**
     * return the centroid (of the outer boundary ring!)
     */
    double centroid  (GPoint& ctr) const;
    /**
     * calculate the centrod of a ring (simple polygon w/o holes).
     */
    double  centroid (int, Coord*, GPoint&) const;
    
    /**
     *	ADT-in-Polygon checking. It is a driver that calls 
     *	sub-routines according to the given type. for now it's only
     *	accepting point ADT.
     */
    virtual int covers (const GSpatial& ) const;

    /**
     *	check if this polygon intersects with other adt objects.
     * 	calls subroutines accordingly with given type of adt.
     */
    virtual int intersects (const GSpatial&) const;
    /**
     * check if this polygon intersects with a linear series of 
     * connected coordinates.
     */
    virtual int intersects(int n_point, Coord* coo) const;
    /**
     * check if the polygon intersects a set of 
     * ordered point series.
     */
    virtual int intersects(const GOps& ops) const;
    /**
     * check if this polygon is inside the given rectangle.
     * @return 1 if true, otherwise 0.
     */
    int    isInside     (const GRect& other) const;
    /**
     * check if this polygon is inside the given circle.
     * @return 1 if true, otherwise 0.
     */
    int    isInside     (const GCircle& other) const;
    
private:
    int    _covers (const GPoint& p) const;
    int    _covers (const GSegment& s) const;
    int    _covers (const GArc& s) const;
    int    _covers (const GPolygon& a) const;

    int    pCompare(GPoint& p, GPoint& q) const;
    int    getPoint(int total, int& cur, Coord* coo, GPoint& p) const;
    int    getDifferentPoint(int total, int& cur, Coord* coo,
			     GPoint& previous, GPoint& next) const;
    
    int    _intersects (const GSegment& seg) const; 	
    int    _intersects (const GArc& other) const;
    int    _intersects (const GPolygon& pgn)const ;
    int    _intersects (const GRect&  r) const;
    int    _intersects (const GCircle& c)const;
    
    // does triangulation
    int    _triangulate(GTrig*& result){result=0; return 0;};

    friend ostream& operator << (ostream& s, const GPolygon& p);
};



static class _GIPolygon
{
    static int cnt;
public:
    _GIPolygon() 
    {
	if(cnt++ ==0 ) 
	    GADTManager::registerADT(new GADTDef( _Polygon, "Polygon", 
						  0, 1, new GPolygon) );
    }
    ~_GIPolygon() 
    {
	if(--cnt==0)
	    GADTManager::removeADT(_Polygon);
    }
} gi_polygon;


//
// CheckTriple tests three consecutive points for change of direction
// and for orientation.
//
#define CheckTriple							\
	if ( (this_dir = pCompare(second, third)) == -cur_dir )		\
	    ++dir_changes;						\
	cur_dir = this_dir;						\
	if ( (this_sign = whichSide(first, second, third)) ) {		\
	    if ( angle_sign == -this_sign )				\
		return GNOT_CONVEX;					\
	    angle_sign = this_sign;					\
	}								\
	first = second; second = third;




#endif

Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999