/*

    This file is part of the extensible drawing editor Ipe.
    Copyright (C) 1993-2004  Otfried Cheong

    Ipe is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    As a special exception, you have permission to link Ipe with the
    CGAL library and distribute executables, as long as you follow the
    requirements of the Gnu General Public License in regard to all of
    the software in the executable aside from CGAL.

    Ipe is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Ipe; if not, you can find it at
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
/*  -*-C++-*-
 *
 *  plageo.h
 *
 *  This is a slightly modified version of the Plageo header file,
 *  with some changes to make it compile on other machines
 *    --- templates eliminated by using "ireray.h" instead of "reray.h"
 *    --- using C's "stdio.h" instead of C++'s "iostream.h"
 *    --- replaced <math++.h> by <imath.h> to use only ANSI functions
 *    --- inserted a few missing types in this file and in `pl_onedim.C'
 *
 * $Modified: Monday, September 19, 1994 by otfried $
 */

/*

NOTICE

This software is public domain. It may be freely copied and used in
non-commercial products, assuming proper credit to the author is given, but it
should not be resold. If you want to use the software for commercial products,
contact the author.
This software is provided `as is' without warranty of any kind, either
expressed or implied. The entire risk as to the quality and performance of the
software is with you. Should the software prove defective, you assume the cost
of all necessary servicing, repair or correction.

Please send any comments to Geert-Jan Giezeman (geert@cs.ruu.nl).
  --- but beware that I may have introduced bugs! (otfried@cs.ruu.nl)
*/

// set a flag for a few fixes necessary for Ipe
#define FOR_IPE

#ifndef PLAGEOH
#define PLAGEOH

#include <stdlib.h>
#ifdef FOR_IPE
#include <ipestream.h>
#include <imath.h>
#include <ireray.h>
#else
#include <iostream.h>
#include <math++.h>
#include <reray.h>
// replaces the old definition in this header file
#define DeclareReray(Trr, T) typedef reray<T> Trr;
#endif


/*******************************
 *
 * basic types (classes) for planar geometry
 *
 * angles
 * vectors
 * bounding boxes
 *
 *******************************/


/*
enum pl_types { PL_NOTYPE=100, S_COORD=101, RERAY=102,
                PL_COORD=111, PL_VEC=112, PL_UNITVEC=113, PL_BOUNDINGBOX=114,
                PL_ROTRA=115,
                PL_VERTEX=121, PL_LINE=122, PL_RAY=123, PL_EDGE=124, PL_POLYGON=12,
                PL_DISC=126, PL_ARC=127 };
*/

#ifdef sgi
typedef float s_coord;		// for single coordinate
#else
typedef double s_coord;		// for single coordinate
#endif


class pl_angle {
public:
		pl_angle()				{}
		pl_angle(s_coord v)			{_a = v;}
    void	normalise(s_coord lowlimit = -M_PI);
    void	normalize(s_coord lowlimit = -M_PI)	{ normalise(lowlimit);}
    int		lies_between(pl_angle small, pl_angle large) const;
    s_coord	value() const				{ return _a; }
    s_coord	degrees() const			    { return (180/M_PI)*_a; }
    s_coord	normalised_value(s_coord lowlimit = -M_PI) const;
    s_coord	normalized_value(s_coord lowlimit = -M_PI) const
					{ return normalised_value(lowlimit); }
		operator s_coord() const		{ return _a; }
protected:
    s_coord	_a;
};

DeclareReray(s_coordreray, s_coord);
DeclareReray(intreray, int);

inline int increasing_angle_order(pl_angle small, pl_angle theta, pl_angle large)
{ return theta.lies_between(small, large); }
// returns true if, travelling over the unit circle counterclockwise, you will
// encounter the angles small, theta and large in that order.
// returns false if you would encounter them in the order large, theta, small.

inline int decreasing_angle_order(pl_angle large, pl_angle theta, pl_angle small)
{ return theta.lies_between(small, large); }
// opposite of increasing_angle_order


// vectors


class pl_fixedvec {
public:
		    pl_fixedvec()	{}
		    pl_fixedvec(s_coord x, s_coord y)  { c[0]=x; c[1]=y;}
    const s_coord   &x() const			    {return c[0];}
    const s_coord   &y() const			    {return c[1];}
    s_coord	    length() const	{ return sqrt_pp(c[0]*c[0] + c[1]*c[1]); }
    s_coord	    sqlength() const	{ return c[0]*c[0] + c[1]*c[1]; }

protected:
    s_coord c[2];
private:
  // Ipe: somehow, the HP compiler cannot cope with these assignments
#ifdef sgi
    void	    operator=(pl_fixedvec) ;	// not implemented.
#endif
};

inline int operator< (const pl_fixedvec &a, const pl_fixedvec &b)
{
    int result;
    if (a.x() == b.x()) result = (a.y() < b.y());
    else result = (a.x() < b.x());
    return result;
}

inline int operator> (const pl_fixedvec &a, const pl_fixedvec &b)
{
    int result;
    if (a.x() == b.x()) result = (a.y() > b.y());
    else result = (a.x() > b.x());
    return result;
}

inline int operator<= (const pl_fixedvec &a, const pl_fixedvec &b)
{
    int result;
    if (a.x() == b.x()) result = (a.y() <= b.y());
    else result = (a.x() < b.x());
    return result;
}

inline int operator>= (const pl_fixedvec &a, const pl_fixedvec &b)
{
    int result;
    if (a.x() == b.x()) result = (a.y() >= b.y());
    else result = (a.x() > b.x());
    return result;
}

extern int compare(const pl_fixedvec &a, const pl_fixedvec &b);

class pl_vec: public pl_fixedvec {
public:
		pl_vec()						    {}
		pl_vec(const pl_fixedvec &vec)		: pl_fixedvec(vec) {}
		pl_vec(const s_coord x, const s_coord y) : pl_fixedvec(x, y) {}
    void	normalise()		{s_coord l=1/length();c[0]*=l;c[1]*=l;}
    void	normalize()		{ normalise();}
    void        set_x(s_coord x)				{ c[0] = x;}
    void        set_y(s_coord y)				{ c[1] = y;}
#ifdef sgi
    void	operator=(const pl_fixedvec &vec)
			    { c[0] = vec.x(); c[1] = vec.y(); }
#endif
    void	operator*=(s_coord f)		{ c[0] *= f; c[1] *= f;}
    void	operator+=(const pl_fixedvec &vec)
		    {c[0] += vec.x(); c[1] += vec.y(); }
    void	operator-=(const pl_fixedvec &vec)
		    {c[0] -= vec.x(); c[1] -= vec.y(); }
};


class pl_unitvec: public pl_fixedvec {
// assert: length == 1
public:
		    pl_unitvec(): pl_fixedvec(1.0, 0.0)	{}
		    pl_unitvec(pl_angle angle) ;
    pl_unitvec	    operator-() const	{ return pl_unitvec(-x(), -y()); }
    pl_unitvec	    normal() const	    { return pl_unitvec(-y(), x());}
friend pl_unitvec   normalised(const pl_fixedvec &vec)	;
friend s_coord	    factorise(pl_unitvec &uv,const pl_fixedvec &vec);
#ifdef sgi
    void	    operator=(const pl_unitvec &uvec)
				    { c[0]=uvec.x(); c[1]=uvec.y(); }
#endif
protected:
		pl_unitvec(const s_coord a, const s_coord b): pl_fixedvec(a, b){}
		pl_unitvec(const pl_fixedvec &vec): pl_fixedvec(vec) {}
};

inline pl_unitvec normalized(const pl_fixedvec &vec)
{ return normalised(vec); }

inline s_coord factorize(pl_unitvec &uvec,const pl_fixedvec &vec)
{ return factorise(uvec, vec); }

const pl_vec pl_origin(0, 0);
extern const pl_unitvec pl_xdir;
extern const pl_unitvec pl_ydir;

extern pl_angle angle_of(const pl_fixedvec &vec);

pl_vec to_polar(const pl_fixedvec &);

pl_vec from_polar(const pl_fixedvec &);

extern pl_angle angle_between(const pl_unitvec &, const pl_unitvec &);


inline pl_vec operator- (const pl_fixedvec &vec)
{
    return pl_vec(-vec.x(), -vec.y());
}

inline pl_vec operator*(s_coord f, const pl_fixedvec &v)
{
    return pl_vec(f*v.x(), f*v.y());
}

inline pl_vec operator+ (const pl_fixedvec &v1, const pl_fixedvec &v2)
{
    return pl_vec(v1.x()+v2.x(), v1.y()+v2.y());
}

inline pl_vec operator- (const pl_fixedvec &v1, const pl_fixedvec &v2)
{
    return pl_vec(v1.x()-v2.x(), v1.y()-v2.y());
}


inline s_coord dot(const pl_fixedvec &v1, const pl_fixedvec &v2)
{
    return v1.x()*v2.x() + v1.y()*v2.y();
}

inline s_coord cross(const pl_fixedvec &v1, const pl_fixedvec &v2)
{
    return v1.x()*v2.y() - v1.y()*v2.x();
}

class pl_boundingbox {
public:
		pl_boundingbox()	{}
		pl_boundingbox(pl_fixedvec c) :
			min(c),max(c){}
    int		is_empty() const	{return min.x() > max.x();}
    s_coord 	xmax() const		{return max.x();}
    s_coord 	xmin() const		{return min.x();}
    s_coord 	ymax() const		{return max.y();}
    s_coord 	ymin() const		{return min.y();}
    void	make_empty()		{min.set_x(1); max.set_x(-1);}
    s_coord	area() const		;
    void	translate(const pl_fixedvec &disp);
    void	scale(s_coord fac);
    void	add_point(const pl_fixedvec &c);
    void	add_first_point(const pl_fixedvec &c) {min = c; max = c; }
    void	add_non_first_point(const pl_fixedvec &c) ;
    void	operator+=(const pl_boundingbox &);
    friend pl_boundingbox
		intersect(pl_boundingbox const &, pl_boundingbox const &);
    friend pl_boundingbox
		operator+(const pl_boundingbox &, const pl_boundingbox &);
protected:
    pl_vec    min;
    pl_vec    max;
};

typedef pl_boundingbox pl_box;

extern int lies_inside(const pl_box &innerbb, const pl_box &outerbb);

class pl_transform {
public:
    virtual pl_vec	operator*(const pl_vec &) const =0;
    virtual pl_unitvec	operator*(const pl_unitvec &) const =0;
    virtual s_coord	operator*(s_coord) const =0;
    virtual pl_angle	operator*(pl_angle) const = 0;
};

enum pl_object_type {PL_POINT=1, PL_LINE, PL_RAY, PL_EDGE,
		    PL_POLYGON, PL_DISC, PL_ARC};

class pl_object {
public:
    virtual	    ~pl_object() ;
    virtual pl_box  bbox() const  = 0;
    virtual void    transform(const pl_transform &tfm) = 0;
    virtual void    rotate(pl_angle) ;
    virtual void    translate(const pl_fixedvec &) ;
    virtual void    scale(s_coord) ;
    virtual pl_object_type type() const = 0;
};

class pl_point: public pl_object {
public:
		pl_point()						{}
		pl_point(const pl_fixedvec& v)			:_vec(v) {}
		pl_point(s_coord a, s_coord b) : _vec(a, b) {}
    pl_object_type type() const;
    pl_box	bbox() const ;
const pl_vec	&vec() const					{return _vec;}
    void	transform(const pl_transform &tfm);
    void	translate(const pl_fixedvec &disp) ;
    void	scale(s_coord fac);
protected:
    pl_vec	_vec;
};

DeclareReray(uvecreray, pl_unitvec);
DeclareReray(pl_vecreray, pl_vec);

/**** flags8 ****
 *
 * flags8 supplies 8 flags.
 * initially the flags are not set.
 * one or more flags can be queried by means of is_set(char x).
 * this funtion returns true iff all flags denoted by x are true.
 * the flags denoted by x are those bits of x that are 1, so
 * isvalid(0x2c) (0010 1100) inspects 3 flags.
 * the other routines set, unset or toggle one or more bits.
 *
 ********************/


class flags8 {
    char	flags;			// internally: bit 0:set, 1:not set
public:
		flags8()		{ flags = all_flags; }
    int		is_set(char x) const	{ return ((x & flags) == 0); }
    void	set(char x)		{ flags &= ~x; }
    void	unset(char x)		{ flags |= x; }
    void	toggle(char x)		{ flags ^= x; }
    enum flags { flag0 = 0x01,
		 flag1 = 0x02,
		 flag2 = 0x04,
		 flag3 = 0x08,
		 flag4 = 0x10,
		 flag5 = 0x20,
		 flag6 = 0x40,
		 flag7 = 0x80,
		 all_flags = 0xff };
};

typedef unsigned short ushort;

class flags16 {
    ushort  flags;			// internally: bit 0:set, 1:not set
public:
		flags16()		{ flags = all_flags; }
    int		is_set(ushort x) const	{ return ((x & flags) == 0); }
    void	set(ushort x)		{ flags &= ~x; }
    void	unset(ushort x)		{ flags |= x; }
    void	toggle(ushort x)	{ flags ^= x; }
    enum flags { flag0 = 0x01,
		 flag1 = 0x02,
		 flag2 = 0x04,
		 flag3 = 0x08,
		 flag4 = 0x10,
		 flag5 = 0x20,
		 flag6 = 0x40,
		 flag7 = 0x80,
		 flag8 = 0x100,
		 flag9 = 0x200,
		 flag10 = 0x400,
		 flag11 = 0x800,
		 flag12 = 0x1000,
		 flag13 = 0x2000,
		 flag14 = 0x4000,
		 flag15 = 0x8000,
		 all_flags = 0xffff };
};

#ifndef FOR_IPE
// the HP C++ compiler complains about long enum's

typedef unsigned long ulong;

class flags32 {
    ulong  flags;			// internally: bit 0:set, 1:not set
public:
		flags32()		{ flags = all_flags; }
    int		is_set(ulong x) const	{ return ((x & flags) == 0); }
    void	set(ulong x)		{ flags &= ~x; }
    void	unset(ulong x)		{ flags |= x; }
    void	toggle(ulong x)	{ flags ^= x; }
    enum flags { flag0 =         0x1,
		 flag1 =         0x2,
		 flag2 =         0x4,
		 flag3 =         0x8,
		 flag4 =        0x10,
		 flag5 =        0x20,
		 flag6 =        0x40,
		 flag7 =        0x80,
		 flag8 =       0x100,
		 flag9 =       0x200,
		 flag10 =      0x400,
		 flag11 =      0x800,
		 flag12 =     0x1000,
		 flag13 =     0x2000,
		 flag14 =     0x4000,
		 flag15 =     0x8000,
		 flag16 =    0x10000,
		 flag17 =    0x20000,
		 flag18 =    0x40000,
		 flag19 =    0x80000,
		 flag20 =   0x100000,
		 flag21 =   0x200000,
		 flag22 =   0x400000,
		 flag23 =   0x800000,
		 flag24 =  0x1000000,
		 flag25 =  0x2000000,
		 flag26 =  0x4000000,
		 flag27 =  0x8000000,
		 flag28 = 0x10000000,
		 flag29 = 0x20000000,
		 flag30 = 0x40000000,
		 flag31 = 0x80000000,
		 all_flags = 0xffffffff };
};

#endif

class pl_unit_tfm : public pl_transform{
public:
    virtual pl_vec	operator*(const pl_vec &) const =0;
    virtual pl_unitvec	operator*(const pl_unitvec &) const =0;
    virtual pl_angle	operator*(pl_angle) const = 0;
    s_coord	operator*(s_coord) const;
};


class pl_uniscale: public pl_transform {
public:
		pl_uniscale()				: _scale(1) {}
		pl_uniscale(s_coord f)			: _scale(f) {}
    pl_vec	operator*(const pl_vec &) const ;
    pl_unitvec	operator*(const pl_unitvec &) const ;
    pl_angle	operator*(pl_angle) const;
    s_coord	operator*(s_coord) const ;
    s_coord	factor() const				{ return _scale;}
protected:
    s_coord	_scale;
};

class pl_translation: public pl_unit_tfm {
public:
		pl_translation()			: _trans(0, 0) {}
		pl_translation(const pl_fixedvec &v)		:_trans(v) {}
    pl_vec	operator*(const pl_vec &) const ;
    s_coord	operator*(s_coord) const ;
    pl_unitvec	operator*(const pl_unitvec &) const ;
    pl_angle	operator*(pl_angle) const;
    pl_vec	vec() const				    { return _trans;}
protected:
    pl_vec	_trans;
};

class pl_rotation: public pl_unit_tfm {
public:
		pl_rotation() : _angle(0) {_rot[0]=1; _rot[1]=0;}
		pl_rotation(pl_angle theta) ;
    pl_vec	operator*(const pl_vec &) const ;
    s_coord	operator*(s_coord) const ;
    pl_unitvec	operator*(const pl_unitvec &) const ;
    pl_angle	operator*(pl_angle) const;
    pl_angle	angle() const ;
protected:
    s_coord	_rot[2];
    pl_angle	_angle;
};

class pl_rotra: public pl_unit_tfm {
public:
		pl_rotra()  : _trans(0, 0), _angle(0) {_rot[0]=1;_rot[1]=0;}
		pl_rotra(pl_angle theta, const pl_fixedvec &vec) ;
		pl_rotra(pl_angle theta) ;
		pl_rotra(const pl_fixedvec &vec) ;
    pl_rotra	inverse() const;
    pl_vec	operator*(const pl_vec &) const ;
    s_coord	operator*(s_coord) const ;
    pl_unitvec	operator*(const pl_unitvec &) const ;
    pl_angle	operator*(pl_angle) const;
    pl_rotra	operator*(const pl_rotra &) const;
    void	get_params(pl_angle &theta, pl_vec &vec) const;
    int		operator==(const pl_rotra &) const;
    void	set_x(s_coord x)			{ _trans.set_x(x); }
    s_coord	x() const				{ return _trans.x();}
    s_coord	get_x() const				{ return _trans.x();}
    void	set_y(s_coord y)			{ _trans.set_y(y); }
    s_coord	y() const				{ return _trans.y();}
    s_coord	get_y() const				{ return _trans.y();}
    void	set_angle(pl_angle theta) ;
    pl_angle	get_angle() const ;
protected:
    pl_angle	_angle;
    s_coord	_rot[2];
    pl_vec	_trans;
};

class pl_ortho_tfm: public pl_transform {
public:
		pl_ortho_tfm() : _angle(0), _scale(1), _trans(0, 0) {_tfm[0]=1; _tfm[1]=0;}
		pl_ortho_tfm(pl_angle, s_coord, const pl_fixedvec &) ;
    pl_vec	operator*(const pl_vec &) const ;
    pl_unitvec	operator*(const pl_unitvec &) const ;
    pl_angle	operator*(pl_angle) const;
    s_coord	operator*(s_coord) const ;
    pl_ortho_tfm	operator*(const pl_ortho_tfm &) const;
    int		operator==(const pl_ortho_tfm &) const;
    void	get_params(pl_angle &theta, s_coord &scale, pl_vec &trans) ;
protected:
    pl_angle	_angle;
    s_coord	_scale;
    s_coord	_tfm[2];    // transformation matrix (top row),
    pl_vec	_trans;
};

class intervals {
public:
    int		starts_at_min_infinity;	// boolean
    s_coordreray	boundaries;	// sorted reray of boundaries of intervals
		intervals() : starts_at_min_infinity(0) {}
    void	toggle();
    void	toggle_after(s_coord x);
    int		is_empty() const;
    int		lies_in(s_coord) const;
    int		find_index_after(s_coord x) const;
    int		is_interval_endpoint(int index) const;
};

extern intervals operator&(const intervals &,
				const intervals &);

extern intervals operator|(const intervals &,
				const intervals &);

extern intervals operator^(const intervals &,
				const intervals &);

// shortest gap gives the shortest distance between an interval in a to
// an interval in b. It will be zero if a&b is not empty.
extern s_coord shortest_gap(const intervals &a, const intervals &b);




/*******************************
 *
 * one dimensional types (classes) for planar geometry
 *
 * -lines
 * -rays
 * -edges
 *
 *******************************/





class pl_line: public pl_object {
public:
		    pl_line()		{};
		    pl_line(const pl_fixedvec &v1, const pl_fixedvec &v2)
				    : _vt(v1), _d(normalized(v2-v1)) {}
		    pl_line(const pl_fixedvec &vt, const pl_unitvec &uv)
					    : _vt(vt), _d(uv) {}
    pl_object_type  type() const;
    pl_box	    bbox() const ;
const pl_vec &	    ref_vt() const		{ return _vt; }
const pl_unitvec &  direction() const	{ return _d; }
    pl_unitvec	    normal() const		{ return _d.normal(); }
    s_coord	    placeproject(const pl_fixedvec &vec) const ;
    s_coord	    dirproject(const pl_fixedvec &vec) const ;
    pl_vec	    placevec(s_coord co) const	{return _vt + co*_d;}
    pl_vec	    dirvec(s_coord co) const		{return co*_d;}
    void	    transform(const pl_transform &tfm) ;
    void	    translate(const pl_fixedvec &disp) ;
    void	    scale(s_coord fac);
protected:
    pl_vec	    _vt;
    pl_unitvec	    _d;
};


class pl_ray: public pl_object {
public:
		    pl_ray()                {}
		    pl_ray(const pl_fixedvec &vt, const pl_unitvec &vec)
			    : _begin_vt(vt), _d(vec) {}
    pl_object_type  type() const;
    pl_box	    bbox() const ;
const pl_vec &	    begin_vt() const			    {return _begin_vt;}
const pl_unitvec &  direction() const				{ return _d;}
    pl_line	    supporting_line() const { return pl_line(_begin_vt, _d); }
    void	    transform(const pl_transform &tfm) ;
    void	    translate(const pl_fixedvec &disp) ;
    void	    scale(s_coord fac);
protected:
    pl_vec	    _begin_vt;
    pl_unitvec	    _d;      // direction
};


class pl_edge: public pl_object {
public:
		    pl_edge()			{}
		    pl_edge(const pl_fixedvec &v1, const pl_fixedvec &v2)
			    : _begin_vt(v1), _end_vt(v2)	{}
    pl_object_type  type() const;
    pl_box	    bbox() const;
const pl_vec &	    begin_vt() const			{ return _begin_vt;}
const pl_vec &	    end_vt() const			{ return _end_vt;}
    pl_line	    supporting_line() const {return pl_line(_begin_vt,_end_vt);}
    s_coord	    length() const	{return (_end_vt-_begin_vt).length();}
    pl_unitvec	    direction() const	{return normalized(_end_vt-_begin_vt); }
    void	    transform(const pl_transform &tfm) ;
    void	    translate(const pl_fixedvec &disp) ;
    void	    scale(s_coord fac);
protected:
    pl_vec	    _begin_vt, _end_vt;
};

extern pl_vec placeproject(const pl_fixedvec &vt, const pl_line &l);
extern pl_vec dirproject(const pl_fixedvec &vt, const pl_line &l);


inline pl_unitvec normal(const pl_edge &e)
{
    return e.supporting_line().normal();
}


// zeer voorlopig class design
class pl_dotted_line {
public:
    intervals fiv;
    pl_vec reference_vertex;
    pl_unitvec dir;
    pl_unitvec	direction() const	{return dir;}
    pl_vec	ref_vt() const	{return reference_vertex;}
protected:
};

DeclareReray(pl_edgereray, pl_edge);

int is_to_the_left(const pl_fixedvec &, const pl_line &);

int is_to_the_right(const pl_fixedvec &, const pl_line &);

int is_above(const pl_fixedvec &, const pl_line &);

int is_below(const pl_fixedvec &, const pl_line &);



typedef unsigned short ushort;
DeclareReray(ushortreray, ushort);


class pl_pgn: public pl_object {
public:
		    pl_pgn():_vertices(),_el(),_ord(),_direction()	{}
		    pl_pgn(const pl_vecreray &vl): _vertices(vl) {}
    int		    element(int i) const    {validate(sortflag); return _el[i];}
const pl_vec &	    velement(int i) const   {validate(sortflag); return vertex(_el[i]);}
    int		    order(int i) const	{validate(sortflag); return _ord[i];}
const pl_unitvec &  direction(int i) const {validate(directionflag); return _direction[i];}

    int		    is_ok()	const
		      {validate(simpleflag); return _flags.is_set(is_simplef);}
    pl_object_type  type() const;
    pl_box	    bbox() const ;
    int		    is_clockwise() const
		{validate(clockwiseflag); return _flags.is_set(is_clockwisef);}
    void	    invert_orientation();
    int		    is_convex() const
		    { validate(convexflag); return _flags.is_set(is_convexf);}
    int		    size() const		{ return _vertices.size(); }
const pl_vec &	    vertex(int i) const			{return _vertices[i];}
const pl_vec &	    vertex_mod(int i) const ;
const pl_vecreray & all_vertices() const {return _vertices;}
    void	    all_vertices(pl_vecreray &result) const {result= _vertices;}
    pl_edge	    edge(int i) const	;   // edge from vertex(i) to vertex(i+1)
    pl_edge	    edge_mod(int i) const	;   // edge from vertex(i) to vertex(i+1)
    void	    all_edges(pl_edgereray &result)	const;
    s_coord	    area() const		{validate(areaflag); return _area;}
    void	    translate(const pl_fixedvec &vec) ;
    void	    scale(s_coord);
    void	    transform(const pl_transform &);
protected:
    flags16	    _flags;
    pl_vecreray	    _vertices;
    ushortreray	    _el;		// als i<j dan vl[el[i]]<=vl[el[j]]
    ushortreray	    _ord;		// ord[j]==i <-> el[i]==j
    uvecreray	    _direction;	// direction of edges
    pl_box	    _bb;
    s_coord	_area;
    enum pgnflags{
		    bbflag = flags16::flag0,
		    sortflag = flags16::flag1,
		    simpleflag = flags16::flag2,
		    clockwiseflag = flags16::flag3,
		    convexflag = flags16::flag4,
		    is_convexf = flags16::flag5,
		    is_clockwisef = flags16::flag6,
		    is_simplef = flags16::flag7,
		    directionflag = flags16::flag8,
		    areaflag = flags16::flag9
    };
    void	    validate(short x) const	{if (!_flags.is_set(x)) validate_work(x);}
    void	    validate_work(short x) const;	// casts away const
    void	    makebbox();
    void	    compute_area();
    void	    compute_directions();
    void	    sort();
    int		    insertion_check(int, int, int)	const;
    int		    transition_check(int, int, int)	const;
    int		    deletion_check(int) const;
    int		    check_event(int)    const;
    void	    check_simple();
    void	    check_clockwise();
    void	    check_convex();
};

typedef pl_pgn pl_polygon;

DeclareReray(pl_pgnreray, pl_pgn);

typedef pl_pgnreray pl_polygonreray;


class pl_disc: public pl_object {
public:
		    pl_disc(const pl_fixedvec &vt, s_coord radius) {
					_center = vt;
					// assert (radius >= 0)
					_radius = radius; }
		    pl_disc()				{}
    pl_object_type  type() const;
    pl_box	    bbox() const;
    pl_vec	    center() const			{ return _center; }
    s_coord	    radius() const			{ return _radius; }
    s_coord	    area() const		;
    void	    set_center(const pl_fixedvec &vt)	{ _center = vt; }
    void	    set_radius(s_coord radius)		{ _radius = radius; }
    void	    transform(const pl_transform &tfm);
    void	    translate(const pl_fixedvec &disp) ;
    void	    scale(s_coord fac);
    void	    outer_approximation_d(pl_vecreray &result, s_coord epsilon) const;
    void	    outer_approximation_n(pl_vecreray &result, int n) const;
    void	    inner_approximation_d(pl_vecreray &result, s_coord epsilon) const;
    void	    inner_approximation_n(pl_vecreray &result, int n) const;
protected:
    pl_vec	    _center;
    s_coord	    _radius;
};

class pl_arc: public pl_object {
public:
		    pl_arc(const pl_fixedvec &vt, s_coord radius, pl_angle startangle,
			pl_angle enclosed_angle) ;
		    pl_arc(const pl_disc &c, pl_angle angle, pl_angle diffangle) ;
		    pl_arc()			{}
    pl_object_type  type() const;
    pl_box	    bbox() const ;
    pl_vec	    center() const		    { return _disc.center(); }
    s_coord	    radius() const		    { return _disc.radius(); }
    pl_vec	    begin_vt() const;
    pl_vec	    end_vt() const;
    pl_vec	    small_vt() const;
    pl_vec	    big_vt() const;
    pl_angle	    begin_angle() const			{ return _startangle; }
    pl_angle	    end_angle() const		{ return _startangle + _angle;}
    pl_angle	    enclosed_angle() const		    { return _angle; }
    pl_angle	    small_angle() const;
    pl_angle	    big_angle() const;
    s_coord	    length() const	    {return fabs_pp(radius()*_angle);}
const pl_disc&	    supporting_disc() const	    { return _disc; }
    void	    set_center(const pl_fixedvec &vt) { _disc.set_center(vt); }
    void	    set_radius(s_coord radius)	  { _disc.set_radius(radius); }
    void	    set_angles(pl_angle angle, pl_angle diffangle) ;
    void	    transform(const pl_transform &tfm);
    void	    translate(const pl_fixedvec &disp) ;
    void	    scale(s_coord fac);
    void	    outer_approximation_d(pl_vecreray &result, s_coord epsilon) const;
    void	    outer_approximation_n(pl_vecreray &result, int n) const;
    void	    inner_approximation_d(pl_vecreray &result, s_coord epsilon) const;
    void	    inner_approximation_n(pl_vecreray &result, int n) const;
protected:
    pl_disc	    _disc;
    pl_angle	    _startangle;
    pl_angle	    _angle;
    pl_box	    _bbox;
    void	    make_bbox();
};

// *********** Axis Centered Ellipse : for internal use
class pl_ACE {
public:
		pl_ACE() {}
		pl_ACE(s_coord x, s_coord y)	{_x=x; _y=y;}
    s_coord	x() const			{return _x;}
    s_coord	y() const			{return _y;}
protected:
    s_coord _x, _y;
};

extern s_coord wn_clearance(pl_vec &wn, const pl_fixedvec &, const pl_ACE &);
extern s_coord wn_clearance(pl_vec &wn, const pl_fixedvec &,
	const pl_ACE &, s_coord bound);
extern s_coord wn_open_clearance(pl_vec &wn,const pl_fixedvec &,const pl_ACE&);
extern s_coord wn_open_clearance(pl_vec &wn, const pl_fixedvec &,
	const pl_ACE &, s_coord bound);
extern s_coord open_clearance(const pl_fixedvec &, const pl_ACE &, s_coord);
extern s_coord clearance(const pl_fixedvec &, const pl_ACE &, s_coord);

// ***********

#ifdef FOR_IPE

// for portability reasons, Ipe uses the C stdio library with a C++
// interface defined in "ipestream.h". Ipe doesn't use pl_io.C,
// but this one function here is used in pl_pgn.C (and in Ipe).

inline ostream & operator<<(ostream &fh, const pl_fixedvec &vec) {
  return (fh << vec.x() << " " << vec.y()); }

#else

extern ostream & operator<<(ostream &ofile, const pl_angle &);
extern istream & operator>>(istream &ifile, pl_angle &);


extern ostream & operator<<(ostream &ofile, const pl_fixedvec &vec);
extern istream & operator>>(istream &ifile, pl_vec &vec);
extern istream & operator>>(istream &ifile, pl_unitvec &uvec);

inline ostream & operator<<(ostream &ofile, const pl_point &vt)
{ return ofile<<vt.vec(); }
extern istream & operator>>(istream &ifile, pl_point &pt);


extern ostream & operator<<(ostream &ofile, const pl_edge &edge);
extern istream & operator>>(istream &ifile, pl_edge &edge);

extern ostream & operator<<(ostream &ofile, const pl_ray &ray);
extern istream & operator>>(istream &ifile, pl_ray &ray);

extern ostream & operator<<(ostream &ofile, const pl_line &line);
extern istream & operator>>(istream &ifile, pl_line &line);

extern ostream & operator<<(ostream &ofile, const pl_arc &arc);
extern istream & operator>>(istream &ifile, pl_arc &arc);

extern ostream & operator<<(ostream &ofile, const pl_box &box);
extern istream & operator>>(istream &ifile, pl_box &box);

extern ostream & operator<<(ostream &ofile, const pl_polygon &pgn);
extern istream & operator>>(istream &ifile, pl_polygon &pgn);

extern ostream & operator<<(ostream &ofile, const pl_disc &disc);
extern istream & operator>>(istream &ifile, pl_disc &disc);

extern ostream & operator<<(ostream &ofile, const pl_vecreray &);
extern istream & operator>>(istream &ifile, pl_vecreray &);

extern ostream & operator<<(ostream &ofile, const pl_edgereray &);
extern istream & operator>>(istream &ifile, pl_edgereray &);

extern ostream & operator<<(ostream &ofile, const pl_polygonreray &);
extern istream & operator>>(istream &ifile, pl_polygonreray &);

#endif

//  ******** ROUTINES DELIVERING A WITNESS OF AN INTERSECTION ********

// witnesses of intersections between one dimensional objects
// edge, ray, line, arc and disc (taken as circle)

extern int intersect(pl_vec &, const pl_line &, const pl_line &);

extern int intersect(pl_vec &, const pl_ray &, const pl_line &);

inline int intersect(pl_vec &wn, const pl_line &l, const pl_ray &r)
{ return intersect(wn, r, l); }

extern int intersect(pl_vec &, const pl_edge &, const pl_line &);

inline int intersect(pl_vec &wn, const pl_line &l, const pl_edge &e)
{ return intersect(wn, e, l); }

extern int intersect(pl_vec &, const pl_ray&, const pl_ray&);

extern int intersect(pl_vec & ,const pl_edge&, const pl_ray&);

inline int intersect(pl_vec &wn, const pl_ray &r, const pl_edge &e)
{ return intersect(wn, e, r); }

extern int intersect(pl_vec &, const pl_edge&, const pl_edge&);

extern intervals intersect(const pl_pgn &, const pl_line &);

inline intervals intersect(const pl_line &l, const pl_pgn &pgn)
{ return intersect(pgn,  l); }

extern intervals intersect(const pl_pgn &, const pl_ray &);

inline intervals intersect(const pl_ray &ray, const pl_pgn &pgn)
{ return intersect(pgn,  ray); }

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_disc &disc, const pl_edge &edge);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_edge &edge, const pl_disc &disc)
{ return intersect(wn1, wn2, disc, edge); }

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_disc &disc, const pl_ray &ray);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_ray &ray, const pl_disc &disc)
{ return intersect(wn1, wn2, disc, ray); }

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_disc &disc, const pl_line &line);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_line &line, const pl_disc &disc)
{ return intersect(wn1, wn2, disc, line); }


extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_edge &edge, const pl_arc &arc);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_arc &arc, const pl_edge &edge)
{ return intersect(wn1, wn2, edge, arc); }

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_ray &ray, const pl_arc &arc);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_arc &arc, const pl_ray &ray)
{ return intersect(wn1, wn2, ray, arc); }

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_line &line, const pl_arc &arc);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_arc &arc, const pl_line &line)
{ return intersect(wn1, wn2, line, arc); }


extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_disc &disc1, const pl_disc &disc2);

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_disc &disc, const pl_arc &arc);

inline int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_arc &arc, const pl_disc &disc)
{ return intersect(wn1, wn2, disc, arc); }

extern int intersect(pl_vec &wn1, pl_vec &wn2,
		const pl_arc &, const pl_arc &);









//  ******** INTERSECTION DECISION ROUTINES********

// ******   OBJECT *****

extern int do_cross(const pl_object &, const pl_fixedvec &);

extern int do_cross(const pl_object &, const pl_point &);

extern int do_cross(const pl_object &, const pl_line &);

extern int do_cross(const pl_object &, const pl_ray &);

extern int do_cross(const pl_object &, const pl_edge &);

extern int do_cross(const pl_object &, const pl_arc &);

extern int do_cross(const pl_object &, const pl_box &);

extern int do_cross(const pl_object &, const pl_pgn &);

extern int do_cross(const pl_object &, const pl_disc &);

extern int do_cross(const pl_object &, const pl_object &);


extern int do_overlap(const pl_object &, const pl_fixedvec &);

extern int do_overlap(const pl_object &, const pl_point &);

extern int do_overlap(const pl_object &, const pl_line &);

extern int do_overlap(const pl_object &, const pl_ray &);

extern int do_overlap(const pl_object &, const pl_edge &);

extern int do_overlap(const pl_object &, const pl_arc &);

extern int do_overlap(const pl_object &, const pl_box &);

extern int do_overlap(const pl_object &, const pl_pgn &);

extern int do_overlap(const pl_object &, const pl_disc &);

extern int do_overlap(const pl_object &, const pl_object &);


// ******   VEC   ******

inline int do_cross(const pl_fixedvec &vec, const pl_object &obj)
{ return do_cross(obj, vec); }

inline int do_cross(const pl_fixedvec &vec, const pl_fixedvec &vec2)
{ if (vec.x()==vec2.x());  return 0; }

inline int do_cross(const pl_fixedvec &vec, const pl_box &box)
{ if (vec.x()==box.xmax());  return 0; }


extern int lies_inside(const pl_fixedvec &, const pl_box &);

extern int lies_inside(const pl_fixedvec &, const pl_pgn &);

extern int lies_inside(const pl_fixedvec &, const pl_disc &);

inline do_overlap(const pl_fixedvec &vec, const pl_box &box)
{ return lies_inside(vec, box); }

inline do_overlap(const pl_fixedvec &vec, const pl_pgn &pgn)
{ return lies_inside(vec, pgn); }

inline do_overlap(const pl_fixedvec &vec, const pl_disc &disc)
{ return lies_inside(vec, disc); }

inline do_overlap(const pl_fixedvec &vec, const pl_object &obj)
{ return do_overlap(obj, vec); }

// ******   POINT   ******

inline int do_cross(const pl_point &vt, const pl_object &obj)
{ return do_cross(obj, vt.vec()); }

inline int do_cross(const pl_point &vt, const pl_fixedvec &vec2)
{ if (vt.vec().x()==vec2.x());  return 0; }

inline int do_cross(const pl_point &vt, const pl_box &box)
{ if (vt.vec().x()==box.xmax());  return 0; }


inline int lies_inside(const pl_point &pt, const pl_box &box)
{ return lies_inside(pt.vec(), box); }

inline int lies_inside(const pl_point &pt, const pl_pgn &pgn)
{ return lies_inside(pt.vec(), pgn); }

inline int lies_inside(const pl_point &pt, const pl_disc &disc)
{ return lies_inside(pt.vec(), disc); }

// Ipe bug fix: the type was missing in the next few declarations
inline int do_overlap(const pl_point &vt, const pl_box &box)
{ return lies_inside(vt.vec(), box); }

inline int do_overlap(const pl_point &vt, const pl_pgn &pgn)
{ return lies_inside(vt.vec(), pgn); }

inline int do_overlap(const pl_point &vt, const pl_disc &disc)
{ return lies_inside(vt.vec(), disc); }

inline int do_overlap(const pl_point &vt, const pl_object &obj)
{ return do_overlap(obj, vt.vec()); }


// ******   EDGE   ******

extern int do_intersect(const pl_edge &e1, const pl_edge &e2);

extern int do_intersect(const pl_edge &e1, const pl_ray &e2);

extern int do_intersect(const pl_edge &e, const pl_line &l);

inline int do_intersect(const pl_edge &edge, const pl_arc &arc)
{
    pl_vec dummy1, dummy2;
    return intersect(dummy1, dummy2, arc, edge);
}

inline int do_cross(const pl_edge &edge, const pl_fixedvec &vec)
{ if (edge.begin_vt().x()==vec.x()); return 0; }

inline int do_cross(const pl_edge &edge, const pl_point &vt)
{ if (edge.begin_vt().x()==vt.vec().x()); return 0; }

inline int do_cross(const pl_edge &edge1, const pl_edge &edge2)
{ return do_intersect(edge1, edge2); }

inline int do_cross(const pl_edge &edge, const pl_ray &ray)
{ return do_intersect(edge, ray); }

inline int do_cross(const pl_edge &edge, const pl_line &line)
{ return do_intersect(edge, line); }

inline int do_cross(const pl_edge &edge, const pl_arc &arc)
{ return do_intersect(edge, arc); }

extern int do_cross(const pl_edge &, const pl_box &);

extern int do_cross(const pl_edge &, const pl_pgn &);

extern int do_cross(const pl_edge &, const pl_disc &);


inline int do_overlap(const pl_edge &edge, const pl_fixedvec &vec)
{ if (edge.begin_vt().x()==vec.x()); return 0; }

inline int do_overlap(const pl_edge &edge, const pl_point &vt)
{ if (edge.begin_vt().x()==vt.vec().x()); return 0; }

inline int do_overlap(const pl_edge &edge1, const pl_edge &edge2)
{ return do_intersect(edge1, edge2); }

inline int do_overlap(const pl_edge &edge, const pl_ray &ray)
{ return do_intersect(edge, ray); }

inline int do_overlap(const pl_edge &edge, const pl_line &line)
{ return do_intersect(edge, line); }

inline int do_overlap(const pl_edge &edge, const pl_arc &arc)
{ return do_intersect(edge, arc); }

extern int do_overlap(const pl_edge &, const pl_box &);
extern int do_overlap(const pl_edge &, const pl_pgn &);
extern int do_overlap(const pl_edge &, const pl_disc &);

// ******   RAY   ******

inline int do_intersect(const pl_ray &ray, const pl_edge &edge)
{ return do_intersect(edge, ray); }

extern int do_intersect(const pl_ray &, const pl_ray &);

extern int do_intersect(const pl_ray &, const pl_line &);

extern int do_intersect(const pl_ray &ray, const pl_arc &arc);



inline int do_cross(const pl_ray &ray, const pl_fixedvec &vec)
{ if (ray.begin_vt().x()==vec.x()); return 0; }

inline int do_cross(const pl_ray &ray, const pl_point &vt)
{ if (ray.begin_vt().x()==vt.vec().x()); return 0; }

inline int do_cross(const pl_ray &ray, const pl_edge &edge)
{ return do_intersect(ray, edge); }

inline int do_cross(const pl_ray &ray1, const pl_ray &ray)
{ return do_intersect(ray1, ray); }

inline int do_cross(const pl_ray &ray, const pl_line &line)
{ return do_intersect(ray, line); }

inline int do_cross(const pl_ray &ray, const pl_arc &arc)
{ return do_intersect(ray, arc); }

extern int do_cross(const pl_ray &, const pl_box &);

extern int do_cross(const pl_ray &, const pl_pgn &);

extern int do_cross(const pl_ray &, const pl_disc &);


inline int do_overlap(const pl_ray &ray, const pl_fixedvec &vec)
{ if (ray.begin_vt().x()==vec.x()); return 0; }

inline int do_overlap(const pl_ray &ray, const pl_point &vt)
{ if (ray.begin_vt().x()==vt.vec().x()); return 0; }

inline int do_overlap(const pl_ray &ray, const pl_edge &edge)
{ return do_intersect(ray, edge); }

inline int do_overlap(const pl_ray &ray1, const pl_ray &ray)
{ return do_intersect(ray1, ray); }

inline int do_overlap(const pl_ray &ray, const pl_line &line)
{ return do_intersect(ray, line); }

inline int do_overlap(const pl_ray &ray, const pl_arc &arc)
{ return do_intersect(ray, arc); }

extern int do_overlap(const pl_ray &, const pl_box &);
extern int do_overlap(const pl_ray &, const pl_pgn &);
extern int do_overlap(const pl_ray &, const pl_disc &);



// ******   LINE   ******


inline int do_intersect(const pl_line &line, const pl_edge &edge)
{ return do_intersect(edge, line); }

inline int do_intersect(const pl_line &line, const pl_ray &ray)
{ return do_intersect(ray, line); }

inline int do_intersect(const pl_line &l1, const pl_line &l2)
{
    if (l1.ref_vt().x()==l2.ref_vt().x());
    return 1;
//    pl_vec dummy;
//    return intersect(dummy, l1, l2);
}

extern int do_intersect(const pl_line &line, const pl_arc &arc);


inline int do_cross(const pl_line &line, const pl_fixedvec &vec)
{ if (line.ref_vt().x()==vec.x()); return 0; }

inline int do_cross(const pl_line &line, const pl_point &vt)
{ if (line.ref_vt().x()==vt.vec().x()); return 0; }

inline int do_cross(const pl_line &line, const pl_edge &edge)
{ return do_intersect(line, edge); }

inline int do_cross(const pl_line &line1, const pl_ray &ray)
{ return do_intersect(line1, ray); }

inline int do_cross(const pl_line &line1, const pl_line &line)
{ if (line1.ref_vt().x()==line.ref_vt().x()); return 1; }

inline int do_cross(const pl_line &line, const pl_arc &arc)
{ return do_intersect(line, arc); }

extern int do_cross(const pl_line &, const pl_box &);

extern int do_cross(const pl_line &, const pl_pgn &);

extern int do_cross(const pl_line &, const pl_disc &);


inline int do_overlap(const pl_line &line, const pl_fixedvec &vec)
{ if (line.ref_vt().x()==vec.x()); return 0; }

inline int do_overlap(const pl_line &line, const pl_point &vt)
{ if (line.ref_vt().x()==vt.vec().x()); return 0; }

inline int do_overlap(const pl_line &line, const pl_edge &edge)
{ return do_intersect(line, edge); }

inline int do_overlap(const pl_line &line1, const pl_ray &ray)
{ return do_intersect(line1, ray); }

inline int do_overlap(const pl_line &line1, const pl_line &line)
{ if (line1.ref_vt().x()==line.ref_vt().x()); return 1; }

inline int do_overlap(const pl_line &line, const pl_arc &arc)
{ return do_intersect(line, arc); }

extern int do_overlap(const pl_line &, const pl_box &);
extern int do_overlap(const pl_line &, const pl_pgn &);
extern int do_overlap(const pl_line &, const pl_disc &);


// ******   ARC   ******

inline int do_intersect(const pl_arc &arc, const pl_edge &edge)
{
    pl_vec dummy1, dummy2;
    return intersect(dummy1, dummy2, arc, edge);
}

inline int do_intersect(const pl_arc &arc, const pl_ray &ray)
{ return do_intersect(ray, arc); }

inline int do_intersect(const pl_arc &arc, const pl_line &line)
{ return do_intersect(line, arc); }

extern int do_intersect(const pl_arc &, const pl_arc &);


inline int do_cross(const pl_arc &arc, const pl_fixedvec &vec)
{ if (arc.begin_vt().x()==vec.x()); return 0; }

inline int do_cross(const pl_arc &arc, const pl_point &vt)
{ if (arc.begin_vt().x()==vt.vec().x()); return 0; }

inline int do_cross(const pl_arc &arc, const pl_edge &edge)
{ return do_intersect(arc, edge); }

inline int do_cross(const pl_arc &arc1, const pl_ray &ray)
{ return do_intersect(arc1, ray); }

inline int do_cross(const pl_arc &arc, const pl_line &line)
{ if (arc.begin_vt().x()==line.ref_vt().x()); return 1; }

inline int do_cross(const pl_arc &arc1, const pl_arc &arc)
{ return do_intersect(arc1, arc); }

extern int do_cross(const pl_arc &, const pl_box &);

extern int do_cross(const pl_arc &, const pl_pgn &);

extern int do_cross(const pl_arc &arc, const pl_disc &disc);


inline int do_overlap(const pl_arc &arc, const pl_fixedvec &vec)
{ if (arc.begin_vt().x()==vec.x()); return 0; }

inline int do_overlap(const pl_arc &arc, const pl_point &vt)
{ if (arc.begin_vt().x()==vt.vec().x()); return 0; }

inline int do_overlap(const pl_arc &arc, const pl_edge &edge)
{ return do_intersect(arc, edge); }

inline int do_overlap(const pl_arc &arc1, const pl_ray &ray)
{ return do_intersect(arc1, ray); }

inline int do_overlap(const pl_arc &arc, const pl_line &line)
{ if (arc.begin_vt().x()==line.ref_vt().x()); return 1; }

inline int do_overlap(const pl_arc &arc1, const pl_arc &arc)
{ return do_intersect(arc1, arc); }

extern int do_overlap(const pl_arc &, const pl_box &);
extern int do_overlap(const pl_arc &, const pl_pgn &);
extern int do_overlap(const pl_arc &, const pl_disc &);



// ******   BOX   ******

inline int do_cross(const pl_box &box, const pl_fixedvec &vec)
{ if (vec.x()==box.xmax());  return 0;}

inline int do_cross(const pl_box &box, const pl_point &vt)
{ if (vt.vec().x()==box.xmax());  return 0;}

inline int do_cross( const pl_box &box, const pl_edge &edge)
{ return do_cross(edge, box); }

inline int do_cross(const pl_box &box, const pl_ray &ray)
{ return do_cross(ray, box); }

inline int do_cross(const pl_box &box, const pl_line &line)
{ return do_cross(line, box); }

inline int do_cross(const pl_box &box, const pl_arc &arc)
{ return do_cross(arc, box); }

extern int do_cross(const pl_box &, const pl_box &);

extern int do_cross(const pl_box &, const pl_pgn &);

extern int do_cross(const pl_box &, const pl_disc &);


inline int do_overlap(const pl_box &box, const pl_fixedvec &vec)
{ return lies_inside(vec, box);}

inline int do_overlap(const pl_box &box, const pl_point &vt)
{ return lies_inside(vt, box);}

inline int do_overlap( const pl_box &box, const pl_edge &edge)
{ return do_overlap(edge, box); }

inline int do_overlap(const pl_box &box, const pl_ray &ray)
{ return do_overlap(ray, box); }

inline int do_overlap(const pl_box &box, const pl_line &line)
{ return do_overlap(line, box); }

inline int do_overlap(const pl_box &box, const pl_arc &arc)
{ return do_overlap(arc, box); }

extern int do_overlap(const pl_box & , const pl_box &);
extern int do_overlap(const pl_box & , const pl_pgn & );
extern int do_overlap(const pl_box & , const pl_disc & );


// ******   POLYGON   ******

inline int do_cross(const pl_pgn &pgn, const pl_fixedvec &vec)
{ if (vec.x()==0||pgn.size());  return 0;}  // dummy conditional

inline int do_cross(const pl_pgn &pgn, const pl_point &vt)
{ if (vt.vec().x()==0||pgn.size());  return 0;}	// dummy conditional

inline int do_cross( const pl_pgn &pgn, const pl_edge &edge)
{ return do_cross(edge, pgn); }

inline int do_cross(const pl_pgn &pgn, const pl_ray &ray)
{ return do_cross(ray, pgn); }

inline int do_cross(const pl_pgn &pgn, const pl_line &line)
{ return do_cross(line, pgn); }

inline int do_cross(const pl_pgn &pgn, const pl_arc &arc)
{ return do_cross(arc, pgn); }

inline int do_cross(const pl_pgn &pgn, const pl_box &box)
{ return do_cross(box, pgn); }

extern int do_cross(const pl_pgn &, const pl_pgn &);

extern int do_cross(const pl_pgn &, const pl_disc &);


inline int do_overlap(const pl_pgn &pgn, const pl_fixedvec &vec)
{ return lies_inside(vec, pgn);}

inline int do_overlap(const pl_pgn &pgn, const pl_point &vt)
{ return lies_inside(vt, pgn);}

inline int do_overlap( const pl_pgn &pgn, const pl_edge &edge)
{ return do_overlap(edge, pgn); }

inline int do_overlap(const pl_pgn &pgn, const pl_ray &ray)
{ return do_overlap(ray, pgn); }

inline int do_overlap(const pl_pgn &pgn, const pl_line &line)
{ return do_overlap(line, pgn); }

inline int do_overlap(const pl_pgn &pgn, const pl_arc &arc)
{ return do_overlap(arc, pgn); }

inline int do_overlap(const pl_pgn &pgn, const pl_box &box)
{ return do_overlap(box, pgn); }

extern int do_overlap(const pl_pgn & , const pl_pgn & );
extern int do_overlap(const pl_pgn & , const pl_disc & );


// ******   DISC   ******

inline int do_cross(const pl_disc &disc, const pl_fixedvec &vec)
{ if (vec.x()==disc.center().x());  return 0;}	// dummy conditional

inline int do_cross(const pl_disc &disc, const pl_point &vt)
{ if (vt.vec().x()==disc.center().x());  return 0;} // dummy conditional

inline int do_cross( const pl_disc &disc, const pl_edge &edge)
{ return do_cross(edge, disc); }

inline int do_cross(const pl_disc &disc, const pl_ray &ray)
{ return do_cross(ray, disc); }

inline int do_cross(const pl_disc &disc, const pl_line &line)
{ return do_cross(line, disc); }

inline int do_cross(const pl_disc &disc, const pl_arc &arc)
{ return do_cross(arc, disc); }

inline int do_cross(const pl_disc &disc, const pl_box &box)
{ return do_cross(box, disc); }

inline int do_cross(const pl_disc &disc, const pl_pgn &pgn)
{ return do_cross(pgn, disc); }

extern int do_cross(const pl_disc &, const pl_disc &);


inline int do_overlap(const pl_disc &disc, const pl_fixedvec &vec)
{ return lies_inside(vec, disc);}

inline int do_overlap(const pl_disc &disc, const pl_point &vt)
{ return lies_inside(vt, disc);}

inline int do_overlap( const pl_disc &disc, const pl_edge &edge)
{ return do_overlap(edge, disc); }

inline int do_overlap(const pl_disc &disc, const pl_ray &ray)
{ return do_overlap(ray, disc); }

inline int do_overlap(const pl_disc &disc, const pl_line &line)
{ return do_overlap(line, disc); }

inline int do_overlap(const pl_disc &disc, const pl_arc &arc)
{ return do_overlap(arc, disc); }

inline int do_overlap(const pl_disc &disc, const pl_box &box)
{ return do_overlap(box, disc); }

inline int do_overlap(const pl_disc &disc, const pl_pgn &pgn)
{ return do_overlap(pgn, disc); }

extern int do_overlap(const pl_disc & , const pl_disc & );






// ******** OTHER ROUTINES (internal use) ********

extern int pl__ontbind2(s_coord fac[], const pl_vec &e0, const pl_vec &e1,
                 const pl_vec &v);

inline s_coord sqclearance(const pl_fixedvec &vt1, const pl_fixedvec & vt2)
{
    return (vt2-vt1).sqlength();
}

// checks the clearance between a fixedvec and a box
extern int certain_clearance(const pl_fixedvec &, const pl_boundingbox &, s_coord);

// checks the square of the clearance between a fixedvec and a box
extern int certain_sqclearance(const pl_fixedvec &, const pl_boundingbox &,
	    s_coord sqbound);

// checks the square of clearance between two boxes
extern int certain_sqclearance(const pl_boundingbox &, const pl_boundingbox &,
	    s_coord sqbound);

// returns true if clearance between two boxes is certainly bigger than bound.
// if false is returned, the clearance may still be bigger
extern int certain_clearance(const pl_boundingbox &, const pl_boundingbox &,
	    s_coord bound);

extern s_coord sqclearance(const pl_fixedvec &, const pl_line &);

extern s_coord sqclearance(const pl_fixedvec &, const pl_edge &);

// *****


// ******   VEC   ******

inline s_coord clearance(const pl_fixedvec &vt1, const pl_fixedvec & vt2)
{ return (vt2-vt1).length(); }
extern s_coord clearance(const pl_fixedvec &, const pl_fixedvec &, s_coord );

inline s_coord clearance(const pl_fixedvec &vt1, const pl_point & vt2)
{ return (vt2.vec()-vt1).length(); }
inline s_coord clearance(const pl_fixedvec &pt1, const pl_point &pt2, s_coord bound)
{ return clearance(pt1, pt2.vec(), bound); }

extern s_coord clearance(const pl_fixedvec &, const pl_edge &);
extern s_coord clearance(const pl_fixedvec &, const pl_edge &, s_coord bound);

extern s_coord clearance(const pl_fixedvec &, const pl_ray &);
extern s_coord clearance(const pl_fixedvec &, const pl_ray &, s_coord bound);

extern s_coord clearance(const pl_fixedvec &, const pl_line &);
extern s_coord clearance(const pl_fixedvec &, const pl_line &, s_coord bound);

extern s_coord clearance(const pl_fixedvec &, const pl_arc &);
extern s_coord clearance(const pl_fixedvec &, const pl_arc &, s_coord bound);


extern s_coord clearance(const pl_fixedvec &, const pl_box &);
extern s_coord clearance(const pl_fixedvec &, const pl_box &, s_coord bound);

extern s_coord clearance(const pl_fixedvec &, const pl_pgn &);
extern s_coord clearance(const pl_fixedvec &, const pl_pgn &, s_coord bound);

extern s_coord clearance(const pl_fixedvec &, const pl_disc &);
extern s_coord clearance(const pl_fixedvec &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_fixedvec &, const pl_object &);
extern s_coord clearance(const pl_fixedvec &, const pl_object &, s_coord bound);



// ******   POINT   ******

inline s_coord clearance(const pl_point &vt1, const pl_fixedvec & vt2)
{ return (vt2-vt1.vec()).length(); }
inline s_coord clearance(const pl_point &pt1, const pl_fixedvec &pt2, s_coord bound)
{ return clearance(pt1.vec(), pt2, bound); }

inline s_coord clearance(const pl_point &vt1, const pl_point & vt2)
{ return (vt2.vec()-vt1.vec()).length(); }
inline s_coord clearance(const pl_point &pt1, const pl_point &pt2, s_coord bound)
{ return clearance(pt1.vec(), pt2.vec(), bound); }

inline s_coord clearance(const pl_point &pt, const pl_edge &edge)
{ return clearance(pt.vec(), edge); }
inline s_coord clearance(const pl_point &pt, const pl_edge &edge, s_coord bound)
{ return clearance(pt.vec(), edge, bound); }

inline s_coord clearance(const pl_point &pt, const pl_ray &ray)
{ return clearance(pt.vec(), ray); }
inline s_coord clearance(const pl_point &pt, const pl_ray &ray, s_coord bound)
{ return clearance(pt.vec(), ray, bound); }

inline s_coord clearance(const pl_point &pt, const pl_line &line)
{ return clearance(pt.vec(), line); }
inline s_coord clearance(const pl_point &pt, const pl_line &line, s_coord bound)
{ return clearance(pt.vec(), line, bound); }

inline s_coord clearance(const pl_point &pt, const pl_arc &arc)
{ return clearance(pt.vec(), arc); }
inline s_coord clearance(const pl_point &pt, const pl_arc &arc, s_coord bound)
{ return clearance(pt.vec(), arc, bound); }


inline s_coord clearance(const pl_point &pt, const pl_box &box)
{ return clearance(pt.vec(), box); }
inline s_coord clearance(const pl_point &pt, const pl_box &box, s_coord bound)
{ return clearance(pt.vec(), box, bound); }

inline s_coord clearance(const pl_point &pt, const pl_pgn &pgn)
{ return clearance(pt.vec(), pgn); }
inline s_coord clearance(const pl_point &pt, const pl_pgn &pgn, s_coord bound)
{ return clearance(pt.vec(), pgn, bound); }

inline s_coord clearance(const pl_point &pt, const pl_disc &disc)
{ return clearance(pt.vec(), disc); }
inline s_coord clearance(const pl_point &pt, const pl_disc &disc, s_coord bound)
{ return clearance(pt.vec(), disc, bound); }


inline s_coord clearance(const pl_point &pt, const pl_object &obj)
{ return clearance(pt.vec(), obj); }
inline s_coord clearance(const pl_point &pt, const pl_object &obj, s_coord bound)
{ return clearance(pt.vec(), obj, bound); }


// ******   EDGE   ******

inline s_coord clearance(const pl_edge &edge, const pl_fixedvec &vt)
{ return clearance(vt, edge); }
inline s_coord clearance(const pl_edge &edge, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, edge, bound); }

inline s_coord clearance(const pl_edge &edge, const pl_point &vt)
{ return clearance(vt.vec(), edge); }
inline s_coord clearance(const pl_edge &edge, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), edge, bound); }

extern s_coord clearance(const pl_edge &, const pl_edge &);
extern s_coord clearance(const pl_edge &, const pl_edge &, s_coord bound);

extern s_coord clearance(const pl_edge &, const pl_ray &);
extern s_coord clearance(const pl_edge &, const pl_ray &, s_coord bound);

extern s_coord clearance(const pl_edge &, const pl_line &);
extern s_coord clearance(const pl_edge &, const pl_line &, s_coord bound);

extern s_coord clearance(const pl_edge &, const pl_arc &);
extern s_coord clearance(const pl_edge &, const pl_arc &, s_coord bound);


extern s_coord clearance(const pl_edge &, const pl_box &);
extern s_coord clearance(const pl_edge &, const pl_box &, s_coord bound);

extern s_coord clearance(const pl_edge &, const pl_pgn &);
extern s_coord clearance(const pl_edge &, const pl_pgn &, s_coord bound);

extern s_coord clearance(const pl_edge &, const pl_disc &);
extern s_coord clearance(const pl_edge &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_edge &, const pl_object &);
extern s_coord clearance(const pl_edge &, const pl_object &, s_coord bound);

// ******   RAY   ******

inline s_coord clearance(const pl_ray &ray, const pl_fixedvec &vt)
{ return clearance(vt, ray); }
inline s_coord clearance(const pl_ray &ray, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, ray, bound); }

inline s_coord clearance(const pl_ray &ray, const pl_point &vt)
{ return clearance(vt.vec(), ray); }
inline s_coord clearance(const pl_ray &ray, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), ray, bound); }

inline s_coord clearance(const pl_ray &r, const pl_edge &e)
{ return clearance(e,r); }
inline s_coord clearance(const pl_ray &r, const pl_edge &e, s_coord bound)
{ return clearance(e,r, bound); }

extern s_coord clearance(const pl_ray &, const pl_ray &);
extern s_coord clearance(const pl_ray &, const pl_ray &, s_coord bound);

extern s_coord clearance(const pl_ray &, const pl_line &);
extern s_coord clearance(const pl_ray &, const pl_line &, s_coord bound);

extern s_coord clearance(const pl_ray &, const pl_arc &);
extern s_coord clearance(const pl_ray &, const pl_arc &, s_coord bound);


extern s_coord clearance(const pl_ray &, const pl_box &);
extern s_coord clearance(const pl_ray &, const pl_box &, s_coord bound);

extern s_coord clearance(const pl_ray &, const pl_pgn &);
extern s_coord clearance(const pl_ray &, const pl_pgn &, s_coord bound);

extern s_coord clearance(const pl_ray &, const pl_disc &);
extern s_coord clearance(const pl_ray &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_ray &, const pl_object &);
extern s_coord clearance(const pl_ray &, const pl_object &, s_coord bound);


// ******   LINE   ******

inline s_coord clearance(const pl_line &l, const pl_fixedvec &vt)
{ return clearance(vt, l);}
inline s_coord clearance(const pl_line &l, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, l, bound);}

inline s_coord clearance(const pl_line &l, const pl_point &vt)
{ return clearance(vt.vec(), l);}
inline s_coord clearance(const pl_line &l, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), l, bound);}

inline s_coord clearance(const pl_line &l, const pl_edge &e)
{ return clearance(e,l); }
inline s_coord clearance(const pl_line &l, const pl_edge &e, s_coord bound)
{ return clearance(e,l, bound); }

inline s_coord clearance(const pl_line &l, const pl_ray &r)
{ return clearance(r,l); }
inline s_coord clearance(const pl_line &l, const pl_ray &r, s_coord bound)
{ return clearance(r,l, bound); }

extern s_coord clearance(const pl_line &, const pl_arc &);
extern s_coord clearance(const pl_line &, const pl_arc &, s_coord bound);


extern s_coord clearance(const pl_line &line, const pl_boundingbox &bb);
extern s_coord clearance(const pl_line &, const pl_boundingbox &, s_coord bound);

extern s_coord clearance(const pl_line &, const pl_pgn &);
extern s_coord clearance(const pl_line &, const pl_pgn &, s_coord bound);

extern s_coord clearance(const pl_line &, const pl_disc &);
extern s_coord clearance(const pl_line &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_line &, const pl_object &);
extern s_coord clearance(const pl_line &, const pl_object &, s_coord bound);


// ******   ARC   ******

inline s_coord clearance(const pl_arc &c, const pl_fixedvec &vt)
{ return clearance(vt, c); }
inline s_coord clearance(const pl_arc &c, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, c, bound); }

inline s_coord clearance(const pl_arc &c, const pl_point &vt)
{ return clearance(vt.vec(), c); }
inline s_coord clearance(const pl_arc &c, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), c, bound); }

inline s_coord clearance(const pl_arc &c, const pl_edge &edge)
{ return clearance(edge, c); }
inline s_coord clearance(const pl_arc &c, const pl_edge &edge, s_coord bound)
{ return clearance(edge, c, bound); }

inline s_coord clearance(const pl_arc &c, const pl_ray &ray)
{ return clearance(ray, c); }
inline s_coord clearance(const pl_arc &c, const pl_ray &ray, s_coord bound)
{ return clearance(ray, c, bound); }

inline s_coord clearance(const pl_arc &c, const pl_line &line)
{ return clearance(line, c); }
inline s_coord clearance(const pl_arc &c, const pl_line &line, s_coord bound)
{ return clearance(line, c, bound); }

extern s_coord clearance(const pl_arc &, const pl_arc &);
extern s_coord clearance(const pl_arc &, const pl_arc &, s_coord bound);


extern s_coord clearance(const pl_arc &, const pl_box &);
extern s_coord clearance(const pl_arc &, const pl_box &, s_coord bound);

extern s_coord clearance(const pl_arc &, const pl_pgn &);
extern s_coord clearance(const pl_arc &, const pl_pgn &, s_coord bound);

extern s_coord clearance(const pl_arc &, const pl_disc &);
extern s_coord clearance(const pl_arc &, const pl_disc &, s_coord bound);

extern s_coord open_clearance(const pl_arc &, const pl_disc &);
extern s_coord open_clearance(const pl_arc &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_arc &, const pl_object &);
extern s_coord clearance(const pl_arc &, const pl_object &, s_coord bound);



// ******   BOX   ******

inline s_coord clearance(const pl_box &box, const pl_fixedvec &vt)
{ return clearance(vt, box); }
inline s_coord clearance(const pl_box &box, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, box, bound); }

inline s_coord clearance(const pl_box &box, const pl_point &vt)
{ return clearance(vt.vec(), box); }
inline s_coord clearance(const pl_box &box, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), box, bound); }

inline s_coord clearance(const pl_box &bb, const pl_edge &edge)
{ return clearance(edge, bb); }
inline s_coord clearance(const pl_box &bb, const pl_edge &edge, s_coord bound)
{ return clearance(edge, bb, bound); }

inline s_coord clearance(const pl_box &bb, const pl_ray &ray)
{ return clearance(ray, bb); }
inline s_coord clearance(const pl_box &bb, const pl_ray &ray, s_coord bound)
{ return clearance(ray, bb, bound); }

inline s_coord clearance(const pl_box &bb, const pl_line &line)
{ return clearance(line, bb); }
inline s_coord clearance(const pl_box &bb, const pl_line &line, s_coord bound)
{ return clearance(line, bb, bound); }

inline s_coord clearance(const pl_box &bb, const pl_arc &arc)
{ return clearance(arc, bb); }
inline s_coord clearance(const pl_box &bb, const pl_arc &arc, s_coord bound)
{ return clearance(arc, bb, bound); }

extern s_coord clearance(const pl_box &, const pl_box &);
extern s_coord clearance(const pl_box &, const pl_box &, s_coord bound);

extern s_coord clearance(const pl_box &, const pl_pgn &);
extern s_coord clearance(const pl_box &, const pl_pgn &, s_coord bound);

extern s_coord clearance(const pl_box &, const pl_disc &);
extern s_coord clearance(const pl_box &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_box &, const pl_object &);
extern s_coord clearance(const pl_box &, const pl_object &, s_coord bound);


// ******   POLYGON   ******


inline s_coord clearance(const pl_pgn &pgn, const pl_fixedvec &vt)
{return clearance(vt, pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_fixedvec &vt, s_coord bound)
{return clearance(vt, pgn, bound); }

inline s_coord clearance(const pl_pgn &pgn, const pl_point &vt)
{return clearance(vt.vec(), pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_point &vt, s_coord bound)
{return clearance(vt.vec(), pgn, bound); }

inline s_coord clearance(const pl_pgn &pgn, const pl_edge &edge)
{ return clearance(edge, pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_edge &edge, s_coord bound)
{ return clearance(edge, pgn, bound); }

inline s_coord clearance(const pl_pgn &pgn, const pl_ray &ray)
{ return clearance(ray, pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_ray &ray, s_coord bound)
{ return clearance(ray, pgn, bound); }

inline s_coord clearance(const pl_pgn &pgn, const pl_line &line)
{ return clearance(line, pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_line &line, s_coord bound)
{ return clearance(line, pgn, bound); }

inline s_coord clearance(const pl_pgn &pgn, const pl_arc &arc)
{ return clearance(arc, pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_arc &arc, s_coord bound)
{ return clearance(arc, pgn, bound); }


inline s_coord clearance(const pl_pgn &pgn, const pl_box &box)
{ return clearance(box, pgn); }
inline s_coord clearance(const pl_pgn &pgn, const pl_box &box, s_coord bound)
{ return clearance(box, pgn, bound); }

extern s_coord clearance(const pl_pgn &, const pl_pgn &);
extern s_coord clearance(const pl_pgn &, const pl_pgn &, s_coord bound);

extern s_coord open_clearance(const pl_pgn &pgn1, const pl_pgn &pgn2);
extern s_coord open_clearance(const pl_pgn &pgn1, const pl_pgn &pgn2, s_coord bound);

extern s_coord clearance(const pl_pgn &, const pl_disc &);
extern s_coord clearance(const pl_pgn &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_pgn &, const pl_object &);
extern s_coord clearance(const pl_pgn &, const pl_object &, s_coord bound);


// ******   DISC   ******

inline s_coord clearance(const pl_disc &c, const pl_fixedvec &vt)
{ return clearance(vt, c); }
inline s_coord clearance(const pl_disc &c, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, c, bound); }

inline s_coord clearance(const pl_disc &c, const pl_point &vt)
{ return clearance(vt.vec(), c); }
inline s_coord clearance(const pl_disc &c, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), c, bound); }

inline s_coord clearance(const pl_disc &c, const pl_edge &edge)
{ return clearance(edge, c); }
inline s_coord clearance(const pl_disc &c, const pl_edge &edge, s_coord bound)
{ return clearance(edge, c, bound); }

inline s_coord clearance(const pl_disc &c, const pl_ray &ray)
{ return clearance(ray, c); }
inline s_coord clearance(const pl_disc &c, const pl_ray &ray, s_coord bound)
{ return clearance(ray, c, bound); }

inline s_coord clearance(const pl_disc &c, const pl_line &line)
{ return clearance(line, c); }
inline s_coord clearance(const pl_disc &c, const pl_line &line, s_coord bound)
{ return clearance(line, c, bound); }

inline s_coord clearance(const pl_disc &disc, const pl_arc &arc)
{ return clearance(arc, disc); }
inline s_coord clearance(const pl_disc &disc, const pl_arc &arc, s_coord bound)
{ return clearance(arc, disc, bound); }

inline s_coord open_clearance(const pl_disc &disc, const pl_arc &arc)
{ return open_clearance(arc, disc); }
inline s_coord open_clearance(const pl_disc &disc, const pl_arc &arc, s_coord bound)
{ return open_clearance(arc, disc, bound); }

inline s_coord clearance(const pl_disc &c, const pl_box &box)
{ return clearance(box, c); }
inline s_coord clearance(const pl_disc &c, const pl_box &box, s_coord bound)
{ return clearance(box, c, bound); }

inline s_coord clearance(const pl_disc &c, const pl_pgn &pgn)
{ return clearance(pgn, c); }
inline s_coord clearance(const pl_disc &c, const pl_pgn &pgn, s_coord bound)
{ return clearance(pgn, c, bound); }

extern s_coord clearance(const pl_disc &, const pl_disc &);
extern s_coord clearance(const pl_disc &, const pl_disc &, s_coord bound);

extern s_coord clearance(const pl_disc &, const pl_object &);
extern s_coord clearance(const pl_disc &, const pl_object &, s_coord bound);


// ******   OBJECT   ******


inline s_coord clearance(const pl_object &c, const pl_fixedvec &vt)
{ return clearance(vt, c); }
inline s_coord clearance(const pl_object &c, const pl_fixedvec &vt, s_coord bound)
{ return clearance(vt, c, bound); }

inline s_coord clearance(const pl_object &c, const pl_point &vt)
{ return clearance(vt.vec(), c); }
inline s_coord clearance(const pl_object &c, const pl_point &vt, s_coord bound)
{ return clearance(vt.vec(), c, bound); }

inline s_coord clearance(const pl_object &c, const pl_edge &edge)
{ return clearance(edge, c); }
inline s_coord clearance(const pl_object &c, const pl_edge &edge, s_coord bound)
{ return clearance(edge, c, bound); }

inline s_coord clearance(const pl_object &c, const pl_ray &ray)
{ return clearance(ray, c); }
inline s_coord clearance(const pl_object &c, const pl_ray &ray, s_coord bound)
{ return clearance(ray, c, bound); }

inline s_coord clearance(const pl_object &c, const pl_line &line)
{ return clearance(line, c); }
inline s_coord clearance(const pl_object &c, const pl_line &line, s_coord bound)
{ return clearance(line, c, bound); }

inline s_coord clearance(const pl_object &disc, const pl_arc &arc)
{ return clearance(arc, disc); }
inline s_coord clearance(const pl_object &disc, const pl_arc &arc, s_coord bound)
{ return clearance(arc, disc, bound); }

inline s_coord clearance(const pl_object &c, const pl_box &box)
{ return clearance(box, c); }
inline s_coord clearance(const pl_object &c, const pl_box &box, s_coord bound)
{ return clearance(box, c, bound); }

inline s_coord clearance(const pl_object &c, const pl_pgn &pgn)
{ return clearance(pgn, c); }
inline s_coord clearance(const pl_object &c, const pl_pgn &pgn, s_coord bound)
{ return clearance(pgn, c, bound); }

inline s_coord clearance(const pl_object &c, const pl_disc &disc)
{ return clearance(disc, c); }
inline s_coord clearance(const pl_object &c, const pl_disc &disc, s_coord bound)
{ return clearance(disc, c, bound); }

extern s_coord clearance(const pl_object &, const pl_object &);
extern s_coord clearance(const pl_object &, const pl_object &, s_coord bound);

// ******   OTHERS   ******

extern s_coord clearance(const pl_dotted_line &,
			    const pl_dotted_line &);



// ***


extern s_coord sqclearance(const pl_pgn &, const pl_pgn &, s_coord sqbound);


const int PL_COLORCOUNT = 256;

extern void pl_color_components(int &red, int &green, int &blue, int col);

class pl_drawarea {
public:
    enum vertexshapes {DOT=0, CROSS=1, SQUARE=2, BOX=3};
    enum areafills {NOFILL=0, FILL=1, OUTLINE=2, FILLOUT=3};
    virtual	    ~pl_drawarea();
    virtual void    pageready()=0;
    virtual void    clear()=0;
    virtual void    draw(const pl_fixedvec &)=0;
    void	    draw(const pl_point &);
    virtual void    draw(const pl_edge &)=0;
    void	    draw(const pl_ray &);
    void	    draw(const pl_line &);
    virtual void    draw(const pl_arc &)=0;
    void	    draw(const pl_box &);
    virtual void    draw(const pl_polygon &)=0;
    virtual void    draw(const pl_disc &)=0;
    void	    draw(const pl_object &);
    virtual void    draw_text(const pl_fixedvec&, const char*);
    void	    set_viewingarea(float x, float y, float xsize, float ysize);
    void	    set_viewingarea(float x, float y, float size);
    void	    get_viewingarea(float &x, float &y, float &xsize, float &ysize);
    int		    set_backcol(int c);
    int		    set_textcol(int c);
    int		    set_linecol(int c);
    int		    set_areacol(int c);
    int		    set_areafill(int);
    int		    set_vertexshape(int);
    float	    set_vertexsize(float);
    float	    set_textsize(float);
protected:
    int	    _backcol;
    int	    _linecol;
    int	    _areacol;
    int	    _textcol;
    int	    _areafill;
    int	    _vertexshape;
    float   _vertexsize;
    float   _viewing_x;
    float   _viewing_y;
    float   _viewing_xsize;
    float   _viewing_ysize;
    int	    _viewing_changed;
    float   _textsize;
    void    init_values();
};


class pl_psfile: public pl_drawarea {
public:
	    pl_psfile(ostream &os) ;
	    pl_psfile(ostream &os, int xoffset, int yoffset, int xsize, int ysize) ;
	    ~pl_psfile();
    void    pageready();
    void    clear();
    void    draw(const pl_fixedvec &);
    void    draw(const pl_edge &);
    void    draw(const pl_ray &ray)	    { pl_drawarea::draw(ray); }
    void    draw(const pl_line &line)	    { pl_drawarea::draw(line); }
    void    draw(const pl_arc &);
    void    draw(const pl_box &box)	    { pl_drawarea::draw(box); }
    void    draw(const pl_polygon &);
    void    draw(const pl_disc &);
    void    draw_text(const pl_fixedvec&, const char*) ;
protected:
    void    ps_init();
    void    page_init();
    void    setcol(int col);
    ostream &out;
    int	    _newpage;	// 1 if page is not initialised, 0 otherwise.
    int	    _image_xsize;
    int	    _image_ysize;
    int	    _x_offset;
    int	    _y_offset;
    int	    _pagenumber;
    char    _marked[PL_COLORCOUNT];
};

//extern void pl_draw(const pl_fixedvec &vt, int how, s_coord radius);
//extern void pl_draw(const pl_edge &e);
extern void pl_draw(const pl_polygon &pgn, int how);
// 0:outline;  1:inside;

class pl_glwindow: public pl_drawarea {
public:
		pl_glwindow() ;
		pl_glwindow(int dx, int dy) ;
		pl_glwindow(int x, int y, int dx, int dy) ;
		~pl_glwindow();
    int		set_directshow(int);
    void	pageready();
    void	clear();
    void	hide();
    void	draw(const pl_fixedvec &);
    void	draw(const pl_edge &);
    void	draw(const pl_ray &ray)	    { pl_drawarea::draw(ray); }
    void	draw(const pl_line &line)   { pl_drawarea::draw(line); }
    void	draw(const pl_arc &);
    void    	draw(const pl_box &box)	    { pl_drawarea::draw(box); }
    void    	draw(const pl_polygon &);
    void	draw(const pl_disc &);
    void	draw_text(const pl_fixedvec&, const char*) ;
    long	identifier() const ;
    pl_vec	get_mouseposition() ;
    int		get_mousestatus(int) ;
    void	set_name(const char *name) ;
protected:
    long	winid;
    int		_ds;
    int		_background_dirty;
    long	_winx, _winy, _windx, _windy;
    char	*_name;
    void	win_init();
    class active_win {
    public:
	active_win(long winid) ;
	~active_win();
    protected:
	long    _keepwin;
	long    _curwin;
    };
};


class pl_ipefile: public pl_drawarea {
public:
		pl_ipefile(ostream &os) ;
		~pl_ipefile();
    void	pageready();
    void	clear();
    void	draw(const pl_fixedvec &);
    void	draw(const pl_edge &);
    void	draw(const pl_ray &ray)	    { pl_drawarea::draw(ray); }
    void	draw(const pl_line &line)	    { pl_drawarea::draw(line); }
    void	draw(const pl_arc &);
    void	draw(const pl_box &box)	    { pl_drawarea::draw(box); }
    void	draw(const pl_polygon &);
    void	draw(const pl_disc &);
    void	draw_text(const pl_fixedvec&, const char*) ;
protected:
    void	ipe_init();
    void	page_init();
    pl_vec	to_ipe_coord(const pl_fixedvec &vt) const;
    s_coord	to_ipe_size(s_coord) const;
    pl_box	viewing_box() const;
    ostream	&out;
    int		_newpage;	// 1 if page is not initialised, 0 otherwise.
};

class pl_glsubwin: public pl_drawarea {
public:
		pl_glsubwin() ;
		pl_glsubwin(int x, int y, int dx, int dy) ;
		~pl_glsubwin();
    void	pageready();
    void	clear();
    void	draw(const pl_fixedvec &);
    void	draw(const pl_edge &);
    void	draw(const pl_ray &ray)	    { pl_drawarea::draw(ray); }
    void	draw(const pl_line &line)   { pl_drawarea::draw(line); }
    void	draw(const pl_arc &);
    void    	draw(const pl_box &box)	    { pl_drawarea::draw(box); }
    void    	draw(const pl_polygon &);
    void	draw(const pl_disc &);
    void	draw_text(const pl_fixedvec&, const char*) ;
    void	set_renderarea(int x, int y, int dx, int dy) ;
    void	set_colorfunc(void (*cf)(int) ) {_colorfunc = cf; }
protected:
    int		_cleanpage;
    short	_winx, _winy, _windx, _windy;
    void (*_colorfunc) (int) ;
    float	_savemat[4][4];
    long	_prevmode;
    void	init_page();
};

extern void pl_use_colormap(int col);

extern void pl_use_rgbcolor(int col);

extern void pl_use_autocolor(int col);


#endif
