/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program 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.

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



#include	<math.h>
#include	<stdlib.h>
#include	"memory_debug.h"
#include	"pdb.h"
#include	"xl.h"
#include	"gbview.h"
#include	"xlerror.h"
#include	"gbs_trailer.h"

extern int lock_pdb_lock_p;

typedef struct scan_list {
	struct scan_list *	next;
	OBJ *			obj;
} SCAN_LIST;

typedef struct scan_work {
	SCAN_LIST * 		sl;
	RESOURCE * 		r;
} SCAN_WORK;


int
scan_func(AVT_NODE * a,SCAN_WORK * w)
{
POINT_LIST * pt,* pt2;
int lod;
SCAN_LIST * sl;
OBJ * o;
	o = a->data;
	if ( o->h.type != OT_POLYGON2D )
		return 0;
	for ( pt = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
		pt != (POINT_LIST*)&o->polygon2d.point_list;
		) {

		pt2 = R_NEXT(POINT_LIST*,&pt->h);
		lod = get_lod_of_position(w->r,pt->pt);
		if ( pt->lod_min <= lod &&
				lod <= pt->lod_max ) {
			pt = pt2;
			continue;
		}
		DELETE_RING(&pt->h);
		d_f_ree(pt);
		touch_obj_mem(-sizeof(*pt));
		pt = pt2;
	}
	if ( R_NEXT(RING_TYPE*,&o->polygon2d.point_list)
			== &o->polygon2d.point_list ) {
		sl = d_alloc(sizeof(*sl),25);
		sl->obj = o;
		sl->next = w->sl;
		w->sl = sl;
	}
	return 0;
}

void
scan_polygon2d(RESOURCE * r)
{
OBJ * o,* o1;
POINT_LIST * pt,* pt2;
int lod;
SCAN_LIST * sl2;
SCAN_WORK w;

	lock_pdb_lock(r,4);
	w.sl = 0;
	w.r = r;
	avt_trace_from_small(r->draw_gb.obj_code_tree,
		scan_func,&w);
	for ( ; w.sl ; ) {
		sl2 = w.sl->next;
		free_object(r,w.sl->obj);
		d_f_ree(w.sl);
		w.sl = sl2;
	}
	unlock_pdb_lock(r);
}


void
scan_dm_point_list(DRAW_MATRIX * dm)
{
POINT_LIST * p;
OBJ * obj;
printf("scan_dm_point\n");
	lock_pdb_lock(dm->r,5);
	for ( ; dm->dm_point_list ; ) {
		p = dm->dm_point_list;
		dm->dm_point_list = p->dm_next;

		DELETE_RING(&p->h);
		obj = p->obj;

		switch ( obj->h.type ) {
		case OT_POLYGON2D:
			if ( obj->polygon2d.point_list.next
					== &obj->polygon2d.point_list )
				free_object(dm->r,obj);
			break;
		default:
			er_panic("scan_dm_point_list(1)");
		}
		d_f_ree(p);
		touch_obj_mem(-sizeof(*p));
	}
	unlock_pdb_lock(dm->r);
printf("scan_dm_point end\n");
}


POINT_LIST *
lod_next(POINT_LIST * n,RING_TYPE * h,int lod,GB_RECT * tr)
{
POINT_LIST * stp;
	stp = n;
	n = R_NEXT(POINT_LIST*,&n->h);
	for ( ; stp != n ; n = R_NEXT(POINT_LIST*,&n->h) ) {
		if ( &n->h == h )
			return (POINT_LIST*)h;
		if ( n->lod_min <= lod &&
				lod <= n->lod_max )
			return n;
	}
	return n;
}

POINT_LIST *
lod_prev(POINT_LIST * n,RING_TYPE * h,int lod,GB_RECT * tr)
{
int l;
POINT_LIST * stp;
	stp = n;
	n = R_PREV(POINT_LIST*,&n->h);
	for ( ; stp != n ; n = R_PREV(POINT_LIST*,&n->h) ) {
		if ( &n->h == h )
			return (POINT_LIST*)h;
/*
		l = lod_select(lod_distance(tr,n->pt),lod,2);
*/
l = lod;
		if ( n->lod_min <= l &&
				l <= n->lod_max )
			return n;
	}
	return n;
}

unsigned long
put_color(unsigned long a,GB_COLOR_INT * col)
{
unsigned long c1[3],c2[3],c3,c4;
int i;
	if( a == C_TRANSPARENT )
		return col->c;
	if ( col->t >= 1 )
		return col->c;
	c1[0] = a&COL_MASK;
	c1[1] = a&(COL_MASK<<COL_BIT);
	c1[2] = a&(COL_MASK<<(COL_BIT*2));

	c2[0] = col->c&COL_MASK;
	c2[1] = col->c&(COL_MASK<<COL_BIT);
	c2[2] = col->c&(COL_MASK<<(COL_BIT*2));

	c4 = 0;
	for ( i = 0 ; i < 3 ; i ++ ) {
		c3 = c1[i]*col->rev_t + c2[i]*col->t;
		c4 |= c3&(COL_MASK<<(COL_BIT*i));
	}
	return c4;
}


XL_SEXP *
dgb_polygon2d(XLISP_ENV * e,XL_SEXP * s,
	XLISP_ENV * a,
	XL_SYM_FIELD * sf)
{
RESOURCE * r;
XLISP_ENV * ee;
L_CHAR * id;
unsigned int _id;
L_CHAR * depth;
L_CHAR * type;
int depth_int;
OBJ * obj;
XL_SEXP * ret;
int i;


	r = get_resource_ptr(&ret,e,s->h.file,s->h.line);
	if ( r == 0 )
		return ret;
	if ( r->h.type != RT_DRAW_GB )
		er_panic("dgb_polygon2d(2)");
	id = get_sf_attribute(sf,l_string(std_cm,"code"));
	if ( id == 0 )
		goto id_is_required;
	sscanf(n_string(std_cm,id),"%i",&_id);
	type = get_sf_attribute(sf,l_string(std_cm,"type"));

	lock_pdb_lock(r,6);
	obj = search_obj(r,_id);
	if ( obj == 0 ) {
		obj = new_object(r,OT_POLYGON2D,_id);
		INIT_RING(&obj->polygon2d.point_list);
	}

	if ( type == 0 )
		obj->polygon2d.type = PT_OPEN;
	else if ( l_strcmp(type,l_string(std_cm,"open")) == 0 )
		obj->polygon2d.type = PT_OPEN;
	else	obj->polygon2d.type = PT_CLOSE;
	r->draw_gb.flags |= DGF_POLY;
	unlock_pdb_lock(r);

	return 0;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"polygon2d"),
		List(n_get_string("type missmatch"),-1));
id_is_required:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_UNDEF_NAME,
		l_string(std_cm,"polygon2d"),
		List(n_get_string("id is required"),-1));
}


#define F_TOP_X		1
#define F_TOP_Y		2
#define F_BOT_X		4
#define F_BOT_Y		8
#define F_TARGET_X	(F_TOP_X|F_BOT_X)
#define F_TARGET_Y	(F_TOP_Y|F_BOT_Y)
#define F_SET_TOP	(F_TOP_X|F_TOP_Y)
#define F_SET_BOT	(F_BOT_X|F_BOT_Y)

int
reasion(
	int *	low_flag,
	int *	high_flag,
	int	target,
	REAL1 * low,
	REAL1 * high,
	REAL1 * low_pt,
	REAL1 * high_pt,
	int top,
	int bottom,
	REAL1 a,
	REAL1 b)
{
REAL1 d;
REAL1 ll,hh;
	if ( a == b ) {
		if ( (top-b)*(bottom-b) > 0 )
			return -1;
		return 0;
	}
	else {
		d = a-b;
		ll = (top-b)/d;
		hh = (bottom-b)/d;
		if ( ll < hh ) {
			if ( *low < ll ) {
				*low = ll;
				*low_pt = top;
				*low_flag |= target&F_SET_TOP;
				return 0;
			}
			if ( *high > hh ) {
				*high = hh;
				*high_pt = bottom;
				*high_flag |= target&F_SET_BOT;
				return 0;
			}
		}
		else {
			if ( *low < hh ) {
				*low = hh;
				*low_pt = bottom;
				*low_flag |= target&F_SET_BOT;
				return 0;
			}
			if ( *high > ll ) {
				*high = ll;
				*high_pt = top;
				*high_flag |= target&F_SET_TOP;
				return 0;
			}
		}
		return 0;
	}
}

void
line_to(
	long * buf,
	GB_POINT a,
	GB_POINT b,
	GB_COLOR_INT * col,
	int ix,
	int iy,
	int w,
	int h,
	int ww)
{
REAL1 low,high;
REAL1 ll,hh,d;
GB_POINT low_pt,high_pt;
int low_flag,high_flag;
int x,y;
int xe,ye;
REAL1 A,B;
REAL1 abs1,abs2;


	low = 0;
	high = 1;
	low_flag = 0;
	high_flag = 0;
	if ( reasion(
			&low_flag,
			&high_flag,
			F_TARGET_X,
			&low,
			&high,
			&low_pt.x,
			&high_pt.x,
			ix,
			ix+w,
			a.x,
			b.x) < 0 )
		return;
	if ( low > high )
		return;
	if ( reasion(
			&low_flag,
			&high_flag,
			F_TARGET_Y,
			&low,
			&high,
			&low_pt.y,
			&high_pt.y,
			iy,
			iy+h,
			a.y,
			b.y) < 0 )
		return;
	if ( low > high )
		return;
	if ( low == 0 ) {
		low_pt = b;
		goto next1;
	}
	if ( low_flag&F_TARGET_X )
		low_pt.y = (a.y-b.y)*low+b.y;
	if ( low_flag&F_TARGET_Y )
		low_pt.x = (a.x-b.x)*low+b.x;
next1:
	if ( high == 1 ) {
		high_pt = a;
		goto next2;
	}
	if ( high_flag&F_TARGET_X )
		high_pt.y = (a.y-b.y)*high+b.y;
	if ( high_flag&F_TARGET_Y )
		high_pt.x = (a.x-b.x)*high+b.x;
next2:
	abs1 = fabs(low_pt.x-high_pt.x);
	abs2 = fabs(low_pt.y-high_pt.y);
	if ( abs1 < 1 && abs2 < 1 ) {
		x = rint(low_pt.x);
		y = rint(low_pt.y);
		if ( x < ix || x >= ix+w )
			return;
		if ( y < iy || y >= iy+h )
			return;
		buf[(y-iy)*ww+(x-ix)] = 0x3ff;
	}
	else if ( abs1 < abs2 ) {
		if ( low_pt.y < high_pt.y ) {
			y = rint(low_pt.y);
			ye = rint(high_pt.y)+1;
		}
		else {
			y = rint(high_pt.y);
			ye = rint(low_pt.y)+1;
		}
		if ( y < iy )
			y = iy;
		if ( ye > iy+h )
			ye = iy+h;
		A = (low_pt.x-high_pt.x)/(low_pt.y-high_pt.y);
		B = -A*low_pt.y + low_pt.x;
		for ( ; y < ye ; y ++ ) {
		int index;
			x = rint(A*y+B);
			if ( x < ix || x >= ix+w )
				continue;
			index = (y-iy)*ww+(x-ix);
			buf[index] =
				put_color(buf[index],col);
		}
	}
	else {
		if ( low_pt.x < high_pt.x ) {
			x = rint(low_pt.x);
			xe = rint(high_pt.x)+1;
		}
		else {
			x = rint(high_pt.x);
			xe = rint(low_pt.x)+1;
		}
		if ( x < ix )
			x = ix;
		if ( xe > ix+w )
			xe = ix+w;
		A = (low_pt.y-high_pt.y)/(low_pt.x-high_pt.x);
		B = -A*low_pt.x + low_pt.y;
		for ( ; x < xe ; x ++ ) {
		int index;
			y = rint(A*x+B);
			if ( y < iy || y >= iy+h )
				continue;
			index = (y-iy)*ww+(x-ix);
			buf[index] =
				put_color(buf[index],col);
		}
	}
	return;
}

void
fill(char * fill_buf,GB_RECT * r2d,
	int w,int h,
	I_POINT p1,I_POINT p2,
	int fg1,int fg2)
{
int y,y_end;
int x,x_end;
I_POINT p3;
REAL1 a,b;
int st_x,st_y;
int i;
char aa;
int fg;
	if ( r2d->tl.y > p1.y &&
			r2d->tl.y > p2.y )
		return;
	if ( r2d->br.y < p1.y &&
			r2d->br.y < p2.y )
		return;
	if ( r2d->tl.x > p1.x &&
			r2d->tl.x > p2.x )
		return;
	st_x = r2d->tl.x;
	st_y = r2d->tl.y;
	if ( p1.y > p2.y ) {
		p3 = p2;
		p2 = p1;
		p1 = p3;

		fg = fg2;
		fg2 = fg1;
		fg1 = fg;
	}
	y = p1.y-st_y;
	if ( fg1 == 0 )
		y ++;
	y_end = p2.y-st_y;
	if ( fg2 == 0 )
		y_end --;
	if ( p1.y == p2.y ) {
		if ( y >= h )
			return;
		if ( p1.x > p2.x ) {
			x = p2.x-st_x;
			if ( fg2 == 0 )
				x ++;
			x_end = p1.x-st_x;
			if ( fg1 == 0 )
				x_end --;
		}
		else {
			x = p1.x-st_x;
			if ( fg1 == 0 )
				x ++;
			x_end = p2.x-st_x;
			if ( fg2 == 0 )
				x_end --;
		}
		if ( x < 0 )
			x = 0;
		if ( x_end >= w )
			x_end = w;
		if ( x != w ) {
			for ( i = x ; i < x_end ; i ++ )
				fill_buf[y*w + i] = 2;
		}
	}
	else {
		a = ((REAL1)(p1.x - p2.x))/(p1.y - p2.y);
		b = a*(st_y - p1.y) + p1.x - st_x;
		if ( y < 0 )
			y = 0;
		if ( y_end >= h )
			y_end = h-1;
		for ( ; y <= y_end ; y ++ ) {
			x = a*y + b;
			if ( x < 0 )
				continue;
			if ( x >= w )
				x = w;
			for ( i = 0 ; i < x ; i ++ ) {
				aa = fill_buf[y*w + i];
				if ( aa >= 2 )
					continue;
				fill_buf[y*w + i]
					= 1 - aa;
			}
			if ( x == w )
				continue;
			if ( fill_buf[y*w + x] == 0 )
				fill_buf[y*w + x] = 2;
		}
	}
}


I_POINT
gb2i_point(GB_POINT p)
{
I_POINT ret;
	ret.x = rint(p.x);
	ret.y = rint(p.y);
	return ret;
}

void
get_objrect(GB_RECT * r,OBJ * o,DRAW_WORK * dw)
{
POINT_LIST * p;
REAL1 er;
GB_POINT p2;

	p = lod_next((POINT_LIST*)&o->polygon2d.point_list,
		&o->polygon2d.point_list,
		dw->draw_lod,
		&dw->draw_rect);
	r->tl.x = r->tl.y = 0;
	r->br.x = r->br.y = -1;
	for ( ;
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = lod_next(p,&o->polygon2d.point_list,dw->draw_lod,
			&dw->draw_rect) ) {
		p2 = p->pt;
		er = 1;
		map_conv_forward(dw->map->map_file,&p2,&er,1);
		map_from_resource(dw->mh,&p2,&er,1);
		if ( er == -1 )
			continue;
		insert_rect(r,p2);
	}


}


int
padding(GB_POINT * indp,OBJ * o,DRAW_WORK * dw)
{
GB_POINT p1,p2;
I_POINT p1_i,p2_i,last_i;
POINT_LIST * p,* pp, * p_prev;
REAL1 er;
int w,h;
int i;
char * fill_buf;
int direct,start_d,end_d;
int fg,fg2;
GB_RECT minrect;
int ww,hh,xx,yy,x_ofs,y_ofs,x,y;
GB_POINT ind;
int ind_cnt;
	get_objrect(&minrect,o,dw);
	minrect.br.x ++;
	minrect.br.y ++;
	intersection_rect(&minrect,&minrect,dw->rectondisp);
	w = minrect.br.x - minrect.tl.x;
	h = minrect.br.y - minrect.tl.y;
	if ( w <= 0 || h <= 0 )
		return 0;
	minrect.br.x ++;
	minrect.br.y ++;
	w ++;
	h ++;

	p = lod_next((POINT_LIST*)&o->polygon2d.point_list,
		&o->polygon2d.point_list,
		dw->draw_lod,
		&dw->draw_rect);
	pp = lod_prev((POINT_LIST*)&o->polygon2d.point_list,
		&o->polygon2d.point_list,
		dw->draw_lod,
		&dw->draw_rect);
	if ( p == pp )
		return 0;
	if ( lod_next(p,&o->polygon2d.point_list,dw->draw_lod,
			&dw->draw_rect) == pp )
		return 0;
	p1 = p->pt;
	er = 1;
	map_conv_forward(dw->map->map_file,&p1,&er,1);
	map_from_resource(dw->mh,&p1,&er,1);
	if ( er < 0 )
		return -1;
	p1_i = gb2i_point(p1);
	fill_buf = d_alloc(w*h,45);
	for ( i = 0 ; i < w*h ; i ++ )
		fill_buf[i] = 0;

	last_i = p1_i;
	direct = 0;
	start_d = 0;
	p_prev = p;
	for ( p = lod_next(p,&o->polygon2d.point_list,dw->draw_lod,
			&dw->draw_rect);
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = lod_next(p,&o->polygon2d.point_list,dw->draw_lod,
			&dw->draw_rect) ) {

		p2 = p->pt;
		er = 1;
		map_conv_forward(dw->map->map_file,&p2,&er,1);
		map_from_resource(dw->mh,&p2,&er,1);
		if ( er == -1 ) {
			p2_i = p1_i;
			break;
		}
		p2_i = gb2i_point(p2);

		if ( p->no & PP_LMOVE ) {
			if ( (p2_i.y - p1_i.y) * direct > 0 )
				fg = 0;
			else	fg = 1;
			if ( p2_i.y - p1_i.y > 0 )
				end_d = 1;
			else if ( p2_i.y - p1_i.y < 0 )
				end_d = -1;
			if ( start_d * end_d < 0 )
				fg2 = 1;
			else	fg2 = 0;
			fill(fill_buf,&minrect,w,h,p1_i,p2_i,fg,fg2);

			p = lod_next(p,&o->polygon2d.point_list,
					dw->draw_lod,
					&dw->draw_rect);
			if ( p == (POINT_LIST*)
					&o->polygon2d.point_list )
				goto end;
			p1 = p->pt;
			er = 1;
			map_conv_forward(dw->map->map_file,&p1,&er,1);
			map_from_resource(dw->mh,&p1,&er,1);
			if ( er < 0 )
				return -1;
			p1_i = gb2i_point(p1);
			direct = 0;
			start_d = 0;
			p_prev = p;
		}
		else {
			if ( (p2_i.y - p1_i.y) * direct > 0 )
				fg = 0;
			else	fg = 1;
			fill(fill_buf,&minrect,w,h,p1_i,p2_i,fg,1);
			if ( p2_i.y - p1_i.y > 0 )
				direct = 1;
			else if ( p2_i.y - p1_i.y < 0 )
				direct = -1;
			if ( start_d == 0 )
				start_d = direct;
			if ( direct )
				end_d = direct;
			p1_i = p2_i;
			p_prev = p;
		}
	}
	if ( (last_i.y - p2_i.y) * direct > 0 )
		fg = 0;
	else	fg = 1;
	if ( last_i.y - p2_i.y > 0 )
		end_d = 1;
	else if ( last_i.y - p2_i.y < 0 )
		end_d = -1;
	if ( start_d * end_d < 0 )
		fg2 = 1;
	else	fg2 = 0;
	fill(fill_buf,&minrect,w,h,p2_i,last_i,fg,fg2);
end:

	ww = dw->rectondisp->br.x - dw->rectondisp->tl.x;
	hh = dw->rectondisp->br.y - dw->rectondisp->tl.y;
	x_ofs = minrect.tl.x - dw->rectondisp->tl.x;
	y_ofs = minrect.tl.y - dw->rectondisp->tl.y;
	ind.x = ind.y = 0;
	ind_cnt = 0;
	for ( xx = 0 ; xx < w ; xx ++ )
		for ( yy = 0 ; yy < h ; yy ++ ) {
			i = xx + yy*w;
			if ( fill_buf[i] == 0 )
				continue;
			x = xx + x_ofs;
			y = yy + y_ofs;
			if ( x >= ww )
				continue;
			if ( y >= hh )
				continue;
			dw->pixels[x + y*ww] = put_color(
				dw->pixels[x + y*ww],
				&o->h.palette.padding_color);
			ind_cnt ++;
			ind.x += x;
			ind.y += y;
		}
	d_f_ree(fill_buf);
	ind.x = ind.x/ind_cnt;
	ind.y = ind.y/ind_cnt;
	*indp = ind;
	if ( ind_cnt == 0 )
		return 0;
	else	return 1;
}



int
draw_polygon2d(
	OBJ * o,
	DRAW_WORK * dw)
{
GB_POINT p1,p2,last;
POINT_LIST * p,* pp, * p_prev;
REAL1 er;
GB_RECT mr;
int ind_cnt;
GB_POINT ind;
int inside_rect_flag;

int cnt;


dw->resource->draw_gb.pdb_lock_msg = 820;
	if ( dw->method == 0 )
		return 0; 

dw->resource->draw_gb.pdb_lock_msg = 821;

	if ( dw->pixels && o->polygon2d.type == PT_CLOSE &&
			o->h.palette.padding_color.t != 0 ) {
		padding(&ind,o,dw);
	}

dw->resource->draw_gb.pdb_lock_msg = 822;

	if ( o->h.palette.line_color.t == 0 )
		return 0;

dw->resource->draw_gb.pdb_lock_msg = 823;

	p = lod_next((POINT_LIST*)&o->polygon2d.point_list,
		&o->polygon2d.point_list,dw->draw_lod,&dw->draw_rect);
	if ( p == lod_prev((POINT_LIST*)&o->polygon2d.point_list,
		&o->polygon2d.point_list,dw->draw_lod,&dw->draw_rect) )
		return 0;

dw->resource->draw_gb.pdb_lock_msg = 824;

	p1 = p->pt;
	er = 1;
	map_conv_forward(dw->map->map_file,&p1,&er,1);
	map_from_resource(dw->mh,&p1,&er,1);
	mr.tl = mr.br = p1;
	if ( inside_rect(dw->rectondisp,p1) ) {
		ind = p1;
		ind_cnt = 1;
		inside_rect_flag = 1;
	}
	else {
		ind.x = ind.y = 0;
		ind_cnt = 0;
		inside_rect_flag = 0;
	}
	if ( er < 0 )
		return -1;

dw->resource->draw_gb.pdb_lock_msg = 825;

	if ( o->polygon2d.type == PT_CLOSE )
		last = p1;
	else {
		pp = lod_prev((POINT_LIST*)&o->polygon2d.point_list,
			&o->polygon2d.point_list,dw->draw_lod,&dw->draw_rect);
		er = 1;
		last = pp->pt;
		map_conv_forward(dw->map->map_file,&last,&er,1);
		map_from_resource(dw->mh,&last,&er,1);
		if ( er < 0 )
			return -1;
	}
dw->resource->draw_gb.pdb_lock_msg = 826;

	p_prev = p;
	for ( p = lod_next(p,&o->polygon2d.point_list,
			dw->draw_lod,&dw->draw_rect);
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = lod_next(p,&o->polygon2d.point_list,
			dw->draw_lod,&dw->draw_rect) ) {
dw->resource->draw_gb.pdb_lock_msg = 827;

		p2 = p->pt;
		er = 1;
		map_conv_forward(dw->map->map_file,&p2,&er,1);
		map_from_resource(dw->mh,&p2,&er,1);
		insert_rect(&mr,p2);
		if ( inside_rect(dw->rectondisp,p2) ) {
			ind = p_add(ind,p2);
			ind_cnt ++;
			if ( inside_rect_flag == 0 ) {
				ind = p_add(ind,p1);
				ind_cnt ++;
			}
			inside_rect_flag = 1;
		}
		else if ( inside_rect_flag ) {
			ind = p_add(ind,p2);
			ind_cnt ++;
			inside_rect_flag = 0;
		}
		else {
			inside_rect_flag = 0;
		}
dw->resource->draw_gb.pdb_lock_msg = 828;
		if ( er == -1 )
			return -1;
		if (  !(p_prev->no & PP_LMOVE) &&
			!(p->no & PP_LMOVE) && 
			fabs(p1.x-p2.x)+fabs(p1.y-p2.y) < 2 )
			continue;
		if ( dw->pixels && !(p_prev->no & PP_LMOVE)  )
			line_to(dw->pixels,p1,p2,
				&o->h.palette.line_color,
				dw->rectondisp->tl.x,dw->rectondisp->tl.y,
				dw->rectondisp->br.x-dw->rectondisp->tl.x,
				dw->rectondisp->br.y-dw->rectondisp->tl.y,
				dw->rectondisp->br.x-
					dw->rectondisp->tl.x);
		p1 = p2;
		p_prev = p;
dw->resource->draw_gb.pdb_lock_msg = 829;
	}
dw->resource->draw_gb.pdb_lock_msg = 830;
	if ( dw->pixels && (p2.x != last.x || p2.y != last.y) &&
		!(p_prev->no & PP_LMOVE) )
		line_to(dw->pixels,p2,last,
			&o->h.palette.line_color,
			dw->rectondisp->tl.x,dw->rectondisp->tl.y,
			dw->rectondisp->br.x-dw->rectondisp->tl.x,
			dw->rectondisp->br.y-dw->rectondisp->tl.y,
			dw->rectondisp->br.x-dw->rectondisp->tl.x);

dw->resource->draw_gb.pdb_lock_msg = 831;
	if ( ind_cnt ) {
	int size;
		ind.x = ind.x/ind_cnt;
		ind.y = ind.y/ind_cnt;
		size = mr.br.x - mr.tl.x + mr.br.y - mr.tl.y;
		if ( size > DEFAULT_ONMAP_INDICATE_SIZE ) {
			o->h.req_resolution = dw->surp.reso[4];
			if ( (o->h.flags & OF_INFO_STS) != OF_INFO_FETCH )
				o->h.flags |= OF_ONMAP_REQ;

			indicate_onmap(1,dw->wfid,dw->resource,o,ind);
		}
	}
dw->resource->draw_gb.pdb_lock_msg = 832;
	return 0;
}

int
check_ptr(GB_POINT p1,GB_POINT p2,int fg1,int fg2,GB_POINT pt)
{
GB_POINT p3;
int fg;
REAL1 a,b;
REAL1 x;
	if ( p1.y > p2.y ) {
		p3 = p1;
		p1 = p2;
		p2 = p3;

		fg = fg1;
		fg1 = fg2;
		fg2 = fg;
	}
	if ( p1.y == p2.y )
		return 0;
	if ( p1.y == pt.y ) {
		if ( fg1 == 0 )
			return 0;
		if ( p1.x <= pt.x )
			return 1;
		return 0;
	}
	else if ( pt.y < p1.y || pt.y > p2.y )
		return 0;
	if ( p2.y == pt.y ) {
		if ( fg2 == 0 )
			return 0;
		if ( p2.x <= pt.x )
			return 1;
		return 0;
	}
	a = (p1.x - p2.x)/(p1.y - p2.y);
	x = a*(pt.y - p1.y) + p1.x;
	if ( x <= pt.x )
		return 1;
	return 0;
}

int
get_point_polygon2d(
	RESOURCE * r,
	OBJ * o,
	GET_POINT_WORK * w)
{
GB_POINT p1,p2,last;
POINT_LIST * p;
GB_RECT mr;
int direct,start_d,end_d;
int cnt;
int fg,fg2,fg3;

	if ( o->polygon2d.type != PT_CLOSE )
		return 0;
	p = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
	p1 = p->pt;
	mr.tl = mr.br = p1;
	for ( p = R_NEXT(POINT_LIST*,&p->h) ;
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = R_NEXT(POINT_LIST*,&p->h) ) {
		p2 = p->pt;
		if ( mr.tl.x > p2.x )
			mr.tl.x = p2.x;
		if ( mr.tl.y > p2.y )
			mr.tl.y = p2.y;
		if ( mr.br.x < p2.x )
			mr.br.x = p2.x;
		if ( mr.br.y < p2.y )
			mr.br.y = p2.y;
	}
	if ( inside_rect(&mr,w->pt) == 0 )
		return 0;
	p = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
	p1 = p->pt;
	last = p1;
	direct = 0;
	start_d = 0;
	cnt = 0;
	for ( p = R_NEXT(POINT_LIST*,&p->h) ;
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = R_NEXT(POINT_LIST*,&p->h) ) {

		p2 = p->pt;
		if ( (p2.y - p1.y) * direct > 0 )
			fg = 0;
		else	fg = 1;
		cnt += check_ptr(p1,p2,fg,1,w->pt);
		if ( p2.y - p1.y > 0 )
			direct = 1;
		else if ( p2.y - p1.y < 0 )
			direct = -1;
		if ( start_d == 0 )
			start_d = direct;
		if ( direct )
			end_d = direct;
		p1 = p2;
	}
	if ( (last.y - p2.y) * direct > 0 )
		fg = 0;
	else	fg = 1;
	if ( last.y - p2.y > 0 )
		end_d = 1;
	else if ( last.y - p2.y < 0 )
		end_d = -1;
	if ( start_d * end_d < 0 )
		fg2 = 1;
	else	fg2 = 0;
	cnt += check_ptr(p2,last,fg,fg2,w->pt);
	if ( (cnt & 1) == 0  )
		return 0;
	if ( w->button == GPB_PRESS )
		indicate_info_card(r,o);
	return 1;
}


int
free_polygon2d(
	OBJ * o)
{
POINT_LIST * pl,* pl1;
	for ( pl = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
		pl != (POINT_LIST*)&o->polygon2d.point_list; ) {

		pl1 = R_NEXT(POINT_LIST*,&pl->h);
		d_f_ree(pl);
		touch_obj_mem(-sizeof(*pl));
		pl = pl1;
	}
	d_f_ree(o);
	touch_obj_mem(-sizeof(*o));
	return 0;
}



int
select_padding(OBJ * o,SELECT_WORK * sw,GB_RECT * minrect,GB_COLOR_INT * c)
{
GB_POINT p1,p2;
/*
GB_POINT last;
*/
I_POINT p1_i,p2_i,last_i;
POINT_LIST * p,* pp;
REAL1 er;
int w,h;
int i;
char * fill_buf;
int direct,start_d,end_d;
int fg,fg2;
	p = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
	p1 = p->pt;
	er = 1;
	map_conv_forward(sw->map->map_file,&p1,&er,1);
	map_from_resource(sw->mh,&p1,&er,1);
	if ( er < 0 )
		return -1;
	p1_i = gb2i_point(p1);
	w = minrect->br.x - minrect->tl.x;
	h = minrect->br.y - minrect->tl.y;
	fill_buf = d_alloc(w*h,46);
	for ( i = 0 ; i < w*h ; i ++ )
		fill_buf[i] = 0;
	last_i = p1_i;
	direct = 0;
	start_d = 0;
	for ( p = R_NEXT(POINT_LIST*,&p->h) ;
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = R_NEXT(POINT_LIST*,&p->h) ) {

		p2 = p->pt;
		er = 1;
		map_conv_forward(sw->map->map_file,&p2,&er,1);
		map_from_resource(sw->mh,&p2,&er,1);
		if ( er == -1 ) {
			p2_i = p1_i;
			break;
		}
		p2_i = gb2i_point(p2);
		if ( (p2_i.y - p1_i.y) * direct > 0 )
			fg = 0;
		else	fg = 1;
		fill(fill_buf,minrect,w,h,p1_i,p2_i,fg,1);
		if ( p2_i.y - p1_i.y > 0 )
			direct = 1;
		else if ( p2_i.y - p1_i.y < 0 )
			direct = -1;
		if ( start_d == 0 )
			start_d = direct;
		if ( direct )
			end_d = direct;
		p1_i = p2_i;
	}
	if ( (last_i.y - p2_i.y) * direct > 0 )
		fg = 0;
	else	fg = 1;
	if ( last_i.y - p2_i.y > 0 )
		end_d = 1;
	else if ( last_i.y - p2_i.y < 0 )
		end_d = -1;
	if ( start_d * end_d < 0 )
		fg2 = 1;
	else	fg2 = 0;
	fill(fill_buf,minrect,w,h,p2_i,last_i,fg,fg2);
	for ( i = 0 ; i < w*h ; i ++ ) {
		if ( fill_buf[i] == 0 )
			continue;
		sw->si->pixels[i] = put_color(
			sw->si->pixels[i],
			c);
	}
	d_f_ree(fill_buf);
	return 0;
}



int
select_polygon2d(
	OBJ * o,
	SELECT_WORK * sw)
{
GB_POINT p1,p2,last;
POINT_LIST * p,* pp;
REAL1 er;
GB_RECT minrect;
int w,h,i;

	if ( sw->select_obj != o )
		return 0;
	minrect.tl.x = 0;
	minrect.br.x = -1;
	p = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
	for ( ;
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = R_NEXT(POINT_LIST*,&p->h) ) {

		p2 = p->pt;
		er = 1;
		map_conv_forward(sw->map->map_file,&p2,&er,1);
		map_from_resource(sw->mh,&p2,&er,1);
		if ( minrect.tl.x > minrect.br.x ) {
			minrect.tl = p2;
			minrect.br = p2;
		}
		else {
			if ( minrect.tl.x > p2.x )
				minrect.tl.x = p2.x;
			if ( minrect.tl.y > p2.y )
				minrect.tl.y = p2.y;
			if ( minrect.br.x < p2.x )
				minrect.br.x = p2.x;
			if ( minrect.br.y < p2.y )
				minrect.br.y = p2.y;
		}
	}
	if ( minrect.tl.x < 0 )
		minrect.tl.x = 0;
	if ( minrect.tl.y < 0 )
		minrect.tl.y = 0;
	if ( minrect.br.x > sw->width)
		minrect.br.x = sw->width;
	if ( minrect.br.y > sw->height )
		minrect.br.y = sw->height;
	if ( minrect.tl.x >= minrect.br.x )
		return 1;
	if ( minrect.tl.y >= minrect.br.y )
		return 1;
	w = minrect.br.x - minrect.tl.x;
	h = minrect.br.y - minrect.tl.y;
	sw->si->pixels = d_alloc(sizeof(long)*w*h,47);
	for ( i = 0 ; i < w*h ; i ++ )
		sw->si->pixels[i] = C_TRANSPARENT;
	sw->si->x = minrect.tl.x;
	sw->si->y = minrect.tl.y;
	sw->si->w = w;
	sw->si->h = h;

	
	if ( o->polygon2d.type == PT_CLOSE &&
			o->h.palette.padding_color.t != 0 )
		select_padding(o,sw,&minrect,&sw->color);

	p = R_NEXT(POINT_LIST*,&o->polygon2d.point_list);
	p1 = p->pt;
	er = 1;
	map_conv_forward(sw->map->map_file,&p1,&er,1);
	map_from_resource(sw->mh,&p1,&er,1);
	if ( er < 0 )
		return 1;
	if ( o->polygon2d.type == PT_CLOSE )
		last = p1;
	else {
		pp = R_PREV(POINT_LIST *,&o->polygon2d.point_list);
		er = 1;
		last = pp->pt;
		map_conv_forward(sw->map->map_file,&last,&er,1);
		map_from_resource(sw->mh,&last,&er,1);
		if ( er < 0 )
			return 1;
	}
	for ( p = R_NEXT(POINT_LIST*,&p->h) ;
		p != (POINT_LIST*)&o->polygon2d.point_list;
		p = R_NEXT(POINT_LIST*,&p->h) ) {

		p2 = p->pt;
		er = 1;
		map_conv_forward(sw->map->map_file,&p2,&er,1);
		map_from_resource(sw->mh,&p2,&er,1);
		if ( er == -1 )
			return 1;
		if ( fabs(p1.x-p2.x)+fabs(p1.y-p2.y) < 2 )
			continue;
		if ( fabs(p2.x-last.x)+fabs(p2.y-last.y) < 2 )
			p2 = last;
		line_to(sw->si->pixels,p1,p2,
			&sw->color,
			minrect.tl.x,minrect.tl.y,
			minrect.br.x-minrect.tl.x,
			minrect.br.y-minrect.tl.y,
			minrect.br.x-minrect.tl.x);
		if ( p2.x == last.x && p2.y == last.y )
			break;
		p1 = p2;
	}
	if ( p2.x != last.x || p2.y != last.y )
		line_to(sw->si->pixels,p2,last,
			&sw->color,
			minrect.tl.x,minrect.tl.y,
			minrect.br.x-minrect.tl.x,
			minrect.br.y-minrect.tl.y,
			minrect.br.x-minrect.tl.x);
	return 1;
}


int
olist_polygon2d(OBJ * o,XL_SEXP ** ret)
{
XL_SEXP * header;
	header = get_object_header(o);
	if ( o->polygon2d.type == PT_OPEN ) {
		*ret = cons(get_symbol(l_string(std_cm,"polygon2d")),
			append(header,
				List(
				List(get_symbol(l_string(std_cm,"type")),
					n_get_string("open"),
					-1),
					-1)));
	}
	else {
		*ret = cons(get_symbol(l_string(std_cm,"polygon2d")),
			append(header,
				List(
				List(get_symbol(l_string(std_cm,"type")),
					n_get_string("close"),
					-1),
					-1)));
	}
	return 0;
}
