/*
*                 TeX Device Driver DVIOUT, DVIPRT で
*                書体倶楽部のアウトラインフォントを使う
*
*                               vdata.c
*
*                       "Vector Font ReadData"
*
*    "本プログラムは、向内さんの書かれた dvii という dvi ドライバの
*    アウトラインフォント展開アルゴリズムと、ソースコードの大部分を
*    使用しています。
*
*
*                         1992  by T.Minagawa
*
*        12 Nov 1992 : modified for JGfont(3D-Bezier) by Naochan!
*        27 Nov 1992 : slightly modified by Yakumo
*/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <dir.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#ifdef	CC_JPN
#include <jctype.h>
#else
unsigned short jistojms(unsigned short);
int jisl1(unsigned short);
int jisl2(unsigned short);

#endif

#include "dd.h"
#include "err.h"
#include "vfont.h"
#include "vraster.h"
#include "jgfont.h"

/* グローバル変数 */
Line *linebuf = NULL;	/* draw_fine用のバッファ */
int linecount;
int itemcount;

/* vfont.c */
extern int s_ratio[];
extern V_FONT *vfont[];

/* jgfont.c */
#ifdef BEZIERFONT
int get_twelve(VPARA_TBL *, GET_TEN_SW);
BEZ_LOCATE bez_emulate(VPARA_TBL *);

#endif

static void slsort(_Setflag *, int);
static int seek_to_vf_data(VPARA_TBL *);
static int get_ten(VPARA_TBL *, GET_TEN_SW);
static int get_ten_fep(VPARA_TBL *, GET_TEN_SW, LOCATE *);

#ifdef VFD
int get_ten_vfd();

#endif

#ifdef VFTOBM
static void size_adj(int *, int *, int, int);

#endif
static void arrange(int *, int *, int);
static void rotate(int *, int *, int);
int readdata(VPARA_TBL *, DRAW_MODE);
static void setline(int, int, int, int, int, DRAW_MODE);
static long get_cross_point(Line *, int);
static void setopenclose(int, int);
static long search_hpair(int, int, int);
static long search_vpair(int, int, int);

/* buffer.c */
char *marea(unsigned int);

/*************************************************************
*	seek_to_vf_data
*	vfn_file のデータ位置までシークする
**************************************************************/
int seek_to_vf_data(VPARA_TBL *tbl_ptr)
{
#ifdef BEZIERFONT
	int preamblesize, max, v_code;

#endif
	long pointer;

#ifdef BEZIERFONT
	if (tbl_ptr->font_type == ZS_FONT) {
#endif
		lseek(tbl_ptr->vfn_file, tbl_ptr->v_code * 4 + 2, SEEK_SET);
		if (read(tbl_ptr->vfn_file, &pointer, sizeof(pointer))
			!= sizeof(pointer)) {
			error(WARNING, "[vfont] read pointer error.(%#x) %s",
					tbl_ptr->char_code, tbl_ptr->v_font_name);
			return (FAILURE);
		}
		if (pointer == 0xffffffffl)
			return (FAILURE);

		lseek(tbl_ptr->vfn_file, pointer + 2 + (MAX_CODE + 1) * 4, SEEK_SET);
#ifdef BEZIERFONT
	}
	else {						/* JG_FONT */
		if (tbl_ptr->char_code < 0x3000)
			max = 1410;
		else if (tbl_ptr->char_code < 0x5000)
			max = 3008;
		else
			max = 3478;

		lseek(tbl_ptr->vfn_file, 8L, SEEK_SET);
		if (read(tbl_ptr->vfn_file, &preamblesize, 2)
			!= sizeof(preamblesize)) {
			error(WARNING, "[JGfont] preamble error.(%#x) %s",
					tbl_ptr->char_code, tbl_ptr->v_font_name);
			return (FAILURE);
		}
		lseek(tbl_ptr->vfn_file, 10L + preamblesize + tbl_ptr->v_code * 4,
			  SEEK_SET);
		if (read(tbl_ptr->vfn_file, &pointer, sizeof(pointer))
			!= sizeof(pointer)) {
			error(WARNING, "[JGfont] read pointer error.(%#x) %s",
					tbl_ptr->char_code, tbl_ptr->v_font_name);
			return (FAILURE);
		}
		if (pointer == 0xffffffffl)
			return (FAILURE);
		lseek(tbl_ptr->vfn_file,
			  10L + preamblesize + max * 4 + pointer, SEEK_SET);
	}
#endif
	return (TRUE);
}

/*************************************************************
*	get_ten
*	10bit の座標データを取得する
**************************************************************/
int get_ten(VPARA_TBL *tbl_ptr, GET_TEN_SW get_ten_sw)
{
	static short bufx[VF_BUF_SIZE];	/* データ先読みバッファ */
	static int remaining_bits;
	static int remaining_words;
	static int remaining_words_save;
	static int buf_pos;
	static union {
		short s[2];
		long l;
	}
	d;
	static int buffering = 0;

	if (get_ten_sw == GET_DATA) {
		if (remaining_bits < 10) {
			d.s[1] = d.s[0];
			if (remaining_words == 0) {
				remaining_words
					= (read(tbl_ptr->vfn_file, bufx, VF_BUF_SIZE * 2)) / 2;
				remaining_words_save = remaining_words;
				buffering++;
				if (remaining_words == 0) {
					error(WARNING,
							"[vfont] 10 bits data error.(%#x) %s",
							tbl_ptr->char_code, tbl_ptr->v_font_name);
					return (-1);
				}
				buf_pos = 0;
			}
			d.s[0] = bufx[buf_pos++];
			remaining_words--;
			remaining_bits += 16;
		}
		remaining_bits -= 10;
		return ((int)((d.l >> remaining_bits) & MAX_VALUE));
	}
	else if (get_ten_sw == KEEP_BUF && buffering == 1) {
		remaining_words = remaining_words_save;
		buf_pos = 0;
		buffering = 0;
		return (-1);
	}
	else {
		remaining_bits = 0;
		remaining_words = 0;
		buffering = 0;
		return (-1);
	}
}

/*************************************************************
*	get_ten_fep
*	get_tenやget_twelveへの橋渡し処理
**************************************************************/
int get_ten_fep(VPARA_TBL *tbl_ptr, GET_TEN_SW get_ten_sw, LOCATE * locate)
{
	BEZ_LOCATE bl;
	int tmp1, tmp2;

#ifdef BEZIERFONT
	if (tbl_ptr->font_type == JG_FONT) {
		if (get_ten_sw == GET_DATA) {
			bl = bez_emulate(tbl_ptr);
			switch (bl.type) {
			  case BEZ_LINE:
				  locate->x = bl.x;
				  locate->y = bl.y;
				  return 0;
			  case BEZ_STOP:
				  return MAX_VALUE;
			  default:
				  return -1;
			}
		}
		else {
			get_twelve(tbl_ptr, get_ten_sw);
			return 0;
		}
	}
	else
#endif
#ifdef VFD
	if (tbl_ptr->font_type == VFD_FONT) {
		if (get_ten_sw == GET_DATA) {
			tmp1 = get_ten_vfd();
			tmp2 = get_ten_vfd();
			if (tmp1 == MAX_VALUE) {
				return MAX_VALUE;
			}
			else {
				locate->x = tmp1;
				locate->y = tmp2;
				return 0;
			}
		}
		else
			return 0;
	}
	else
#endif
	{
		if (get_ten_sw == GET_DATA) {
			tmp1 = get_ten(tbl_ptr, GET_DATA);
			tmp2 = get_ten(tbl_ptr, GET_DATA);
			if (tmp1 == MAX_VALUE) {
				return MAX_VALUE;
			}
			else {
				locate->x = tmp1;
				locate->y = tmp2;
				return 0;
			}
		}
		else {
			get_ten(tbl_ptr, get_ten_sw);
			return 0;
		}
	}
}

#ifdef VFTOBM
/*************************************************************
*	size_adj
*	書体倶楽部のフォントの大きさを調整する
**************************************************************/
static void size_adj(int *xptr, int *yptr, int width_adj, int height_adj)
{
	int x, y;

	x = *xptr;
	y = *yptr;
	x = (int)((long)x * (MAX_VALUE + 1) * width_adj / 1000L);
	if (x > MAX_VALUE) {
		error(WARNING, "[vfont] expand error X. (%d)", x);
		x = MAX_VALUE;
	}
	y = (int)((long)y * (MAX_VALUE + 1) * height_adj / 1000L);
	if (y > MAX_VALUE) {
		error(WARNING, "[vfont] expand error Y. (%d)", y);
		y = MAX_VALUE;
	}
	*xptr = x;
	*yptr = y;
}

#endif /* end of ifdef VFTOBM */

/*************************************************************
*	arrange
*	フォントの変形を行なう
**************************************************************/
void arrange(int *xptr, int *yptr, int slant)
{
	int x, y, max_shift;

	x = *xptr;
	y = *yptr;

	max_shift = s_ratio[(slant - (int)'b') % 3];
	/* 斜体の処理 */
	if ((int)'b' <= slant && slant <= (int)'d') {
		x += (int)((long)(MAX_VALUE - y) * max_shift / (MAX_VALUE + 1));
	}
	else if ((int)'e' <= slant && slant <= (int)'g') {
		x += (int)((long)y * max_shift / (MAX_VALUE + 1));
	}
	else if ((int)'h' <= slant && slant <= (int)'j') {
		y += (int)(max_shift - (long)x * max_shift / (MAX_VALUE + 1));
	}
	else if ((int)'k' <= slant && slant <= (int)'m') {
		y += (int)(max_shift
				   - (long)(MAX_VALUE - x) * max_shift / (MAX_VALUE + 1));
	}
	*xptr = x;
	*yptr = y;
}

/*************************************************************
*	rotate
*	フォントを回転させる
**************************************************************/
static void rotate(int *xptr, int *yptr, int flag)
{
	int tmp;

	switch (flag) {
	  case 1:
		  tmp = *yptr;
		  *yptr = *xptr;
		  *xptr = MAX_VALUE - tmp;
		  break;
	  case 2:
		  *yptr = MAX_VALUE - *yptr;
		  *xptr = MAX_VALUE - *xptr;
		  break;
	  case 3:
		  tmp = *xptr;
		  *xptr = *yptr;
		  *yptr = MAX_VALUE - tmp;
		  break;
	}
}

#ifndef	NOTATEGAKI
/*************************************************************
*	疑似縦書き用のフォントを回転させる関数群
*   +-----> X
*   |
*   Y
***************************************************************/
void TateKanji_Miteigi(int *xptr, int *yptr)
{
	printf("縦漢字未定義\n");
}

void (*TateKanji) (int *, int *) = TateKanji_Miteigi;

void TateKanji_non(int *xptr, int *yptr)
{
};

void TateKanji_n(int *xptr, int *yptr)
{
	int x;

	x = *xptr;
	*xptr = *yptr;
	*yptr = MAX_VALUE - x;
}

void TateKanji_m(int *xptr, int *yptr)
{
	int x;

	x = *xptr;
	*xptr = *yptr - (MAX_VALUE * 11 / 20);
	*yptr = (MAX_VALUE - (MAX_VALUE * 12 / 20)) - x;
	if (*xptr < 0)
		*xptr = 0;				/* これが発生するようだったら*12/20を変更 */
	if (*yptr < 0)
		*yptr = 0;				/* すべきである */
}

void TateKanji_mr(int *xptr, int *yptr)
{
	int x;

	x = *xptr;
	*xptr = *yptr;
	*yptr = (MAX_VALUE - (MAX_VALUE * 3 / 20)) - x;
	if (*yptr < 0)
		*yptr = 0;
}

void TateKanji_r(int *xptr, int *yptr)
{

	*yptr = MAX_VALUE - *yptr;

}

extern int tategaki;

#ifdef VFD
extern BOOL tatevfd;

#endif

void TateKanji_type(unsigned int code)
{

#ifndef VFD
	if (!tategaki) {
#else
	if (!tategaki && !tatevfd) {
#endif
		TateKanji = TateKanji_non;
		return;
	}

	if (code >= 0x8141 && code <= 0x8142)	/*、,。*/
		TateKanji = TateKanji_m;
	else if (code >= 0x815b && code <= 0x815d)	/*ー , ‐*/
		TateKanji = TateKanji_r;
	else if (code == 0x8160)	/*〜*/
		TateKanji = TateKanji_r;
	else if ((code >= 0x8169 && code <= 0x817a)	/*（,】*/
			 ||(code >= 0x8163 && code <= 0x8164))	/* …,‥ */
		TateKanji = TateKanji_non;
	else if (code >= 0x829f && code <= 0x82ec) {	/*かな小文字*/
		switch (code - (unsigned)0x829f) {
		  case (0x9f) - (0x9f):
		  case (0xa1) - (0x9f):
		  case (0xa3) - (0x9f):
		  case (0xa5) - (0x9f):
		  case (0xa7) - (0x9f):
		  case (0xc1) - (0x9f):
		  case (0xe1) - (0x9f):
		  case (0xe3) - (0x9f):
		  case (0xe5) - (0x9f):
		  case (0xec) - (0x9f):
			  TateKanji = TateKanji_mr;
			  break;
		  default:
			  TateKanji = TateKanji_n;
		}
	}
	else if (code >= 0x8340 && code <= 0x8396) {	/*カナ小文字*/
		switch (code - (unsigned)0x8340) {
		  case (0x40) - (0x40):
		  case (0x42) - (0x40):
		  case (0x44) - (0x40):
		  case (0x46) - (0x40):
		  case (0x48) - (0x40):
		  case (0x62) - (0x40):
		  case (0x83) - (0x40):
		  case (0x85) - (0x40):
		  case (0x87) - (0x40):
		  case (0x8e) - (0x40):
		  case (0x95) - (0x40):
		  case (0x96) - (0x40):
			  TateKanji = TateKanji_mr;
			  break;
		  default:
			  TateKanji = TateKanji_n;
		}
	}
	else
		TateKanji = TateKanji_n;
}

#endif

/*************************************************************
*	get_yofs
*	v_table をもとに垂直方向のオフセットを求める
**************************************************************/
int get_yofs(VPARA_TBL *tbl_ptr)
{
	int i, j;

	linecount = itemcount = 0;
	if (readdata(tbl_ptr, FINE_MODE) == FAILURE)
		return (0);
	for (i = 0, j = -1; i < linecount; i++) {
		if (linebuf[i].yl > j) {
			j = linebuf[i].yl;
		}
	}
	return (0x400 - j - Y_BASE);
}

/*************************************************************
*	readdata
*	アウトラインデ−タを読み取り、linebuf[]に格納する
**************************************************************/
int readdata(VPARA_TBL *tbl_ptr, DRAW_MODE sw)
{
	int x, y, x0, y0, xl, yl, r;
	LOCATE z;

	if (tbl_ptr->char_code == 0x2121)
		return (TRUE);
	/* Get pointer to character data. */
#ifndef VFD
	if (seek_to_vf_data(tbl_ptr) == FAILURE)
#else
	if (tbl_ptr->font_type != VFD_FONT && seek_to_vf_data(tbl_ptr) == FAILURE)
#endif
		return (FAILURE);
	get_ten_fep(tbl_ptr, CLEAR_BUF, &z);
	while ((r = get_ten_fep(tbl_ptr, GET_DATA, &z)) != MAX_VALUE) {
		x = z.x;
		y = z.y;
		if (r == -1)
			return (FAILURE);
#ifndef	NOTATEGAKI
		(*TateKanji) (&x, &y);
#endif
#ifdef VFTOBM
		if (tbl_ptr->club_flag == TRUE) {
			size_adj(&x, &y, tbl_ptr->width_adj, tbl_ptr->height_adj);
		}
#endif
		if (tbl_ptr->rotation != 0)
			rotate(&x, &y, tbl_ptr->rotation);
		if (tbl_ptr->slant != (int)'a')
			arrange(&x, &y, tbl_ptr->slant);
		x0 = xl = x;
		y0 = yl = y;
		while ((r = get_ten_fep(tbl_ptr, GET_DATA, &z)) != MAX_VALUE) {
			x = z.x;
			y = z.y;
			if (r == -1)
				return (FAILURE);
#ifndef	NOTATEGAKI
			(*TateKanji) (&x, &y);
#endif
#ifdef VFTOBM
			if (tbl_ptr->club_flag == TRUE) {
				size_adj(&x, &y, tbl_ptr->width_adj, tbl_ptr->height_adj);
			}
#endif
			if (tbl_ptr->rotation != 0)
				rotate(&x, &y, tbl_ptr->rotation);
			if (tbl_ptr->slant != (int)'a')
				arrange(&x, &y, tbl_ptr->slant);
			setline(xl, yl, x, y, itemcount, sw);	/* 線分を記録 */
			xl = x;
			yl = y;
		}						/* 折れ線を閉じる */
		setline(xl, yl, x0, y0, itemcount, sw);	/* 線分を記録 */
		itemcount++;
	}
	return (TRUE);
}

/*************************************************************
*	setline
*	linebuf[]にデ−タを実際に格納する
**************************************************************/
static void setline
    (int x1, int y1, int x2, int y2, int no, DRAW_MODE sw) {
	int i, dx, dy;
	int tmp;
	static int line_bufsize;	/* バッファサイズ記憶用変数 */
	Line *tmp_line;

	/* Line 用のバッファエリアとして、Line * MIN_LINE ずつ確保していく */
	if (linebuf == NULL) {
		line_bufsize = MIN_LINE;
		linebuf = (Line *)marea(sizeof(Line) * line_bufsize);
	}
	if (linecount == line_bufsize) {
		/* データがバッファをオーバーフローしたら領域を追加確保 */
		line_bufsize += MIN_LINE;
		tmp_line = linebuf;
		linebuf = (Line *)marea(sizeof(Line) * line_bufsize);

		for (i = 0; i < line_bufsize - MIN_LINE; i++) {
			linebuf[i] = tmp_line[i];
			/* このコピーのオーバーヘッドは大きそう ^^;; */
		}
		free(tmp_line);
	}

	linebuf[linecount].flag = 0;
	linebuf[linecount].itemno = no;

	if (sw == FINE_MODE) {
		dx = x2 - x1;
		dy = y2 - y1;

		if (dx < 0) {
			dx = -dx;
			linebuf[linecount].flag |= XREV;
			linebuf[linecount].flag ^= XYREV;
			tmp = x1;
			x1 = x2;
			x2 = tmp;
		}
		if (dy < 0) {
			dy = -dy;
			linebuf[linecount].flag |= YREV;
			linebuf[linecount].flag ^= XYREV;
			tmp = y1;
			y1 = y2;
			y2 = tmp;
		}
		linebuf[linecount].xl = x1;
		linebuf[linecount].xr = x2;
		linebuf[linecount].yu = y1;
		linebuf[linecount].yl = y2;
		linebuf[linecount].dx = dx;
		linebuf[linecount].dy = dy;
	}
	else {
		linebuf[linecount].xl = x1;
		linebuf[linecount].yu = y1;
	}
	linecount++;
}

/*************************************************************
*	slsort
*	sl をソートするための関数（中身は挿入法）
**************************************************************/
static void slsort(_Setflag * sl, int n)
{
	int i, j, x;
	long y1, y2;
	_Setflag sltmp;

	for (i = 1; i < n; i++) {
		sltmp = sl[i];
		for (j = i - 1; j >= 0; j--) {
			if (sl[j].v < sltmp.v)
				break;
			else if (sl[j].v == sltmp.v) {
				x = max((sl[j].lp)->xl, (sltmp.lp)->xl);
				y1 = get_cross_point(sl[j].lp, x);
				y2 = get_cross_point(sltmp.lp, x);
				if (y1 < y2)
					break;
			}
			sl[j + 1] = sl[j];
		}
		sl[j + 1] = sltmp;
	}
}

/*************************************************************
*	get_cross_point
*	与えられた x座標に対応する y座標をTIMES倍して返す
**************************************************************/
long get_cross_point(Line *lbuf, int x)
{
	if (lbuf->dy == 0)
		return ((long)(lbuf->yu * TIMES));
	else if (lbuf->flag & XYREV)
		return (((long)(lbuf->xr - x) * lbuf->dy * TIMES) / lbuf->dx
				+ (long)lbuf->yu * TIMES);
	else
		return (((long)(x - lbuf->xl) * lbuf->dy * TIMES) / lbuf->dx
				+ (long)lbuf->yu * TIMES);
}

/*************************************************************
*	setopenclose
*	setflag から呼ばれて、実際に OPEN, CLOSE を linebufに
*	設定する
**************************************************************/
static void setopenclose(int itemno, int isanticlock)
{
	int i, dx, dy, flag;

	for (i = 0; i < linecount; i++) {
		if (linebuf[i].itemno == itemno) {
			dx = linebuf[i].dx;
			dy = linebuf[i].dy;
			flag = linebuf[i].flag;
			if (dx == 0) {
				linebuf[i].flag |= VERTLINE;
			}
			else if (flag & XREV) {
				linebuf[i].flag |= (isanticlock) ? VOPEN : VCLOSE;
			}
			else {
				linebuf[i].flag |= (isanticlock) ? VCLOSE : VOPEN;
			}

			if (dy == 0) {
				linebuf[i].flag |= HORILINE;
			}
			else if (flag & YREV) {
				linebuf[i].flag |= (isanticlock) ? HCLOSE : HOPEN;
			}
			else {
				linebuf[i].flag |= (isanticlock) ? HOPEN : HCLOSE;
			}
		}
	}
}

/*********************************************************
*	setflag
*	(1)OPEN, CLOSE のフラグを linebuf[] にセットする
*	(2)itemno を閉曲線の番号から部品の番号に付け換える
**********************************************************/
void setflag(VPARA_TBL *tbl_ptr, int itemflag)
{
	int i, j, k, v, it1, it2;
	int slcount;
	static int lcount_save = 0;	/* バッファサイズ記憶用変数 */
	static int icount_save = 0;	/* バッファサイズ記憶用変数 */

	static _Setflag *sl;
	static int *oc;

	if (linecount > lcount_save) {
		if (lcount_save)
			free(sl);
		sl = (_Setflag *) marea((sizeof(_Setflag)) * linecount);
		lcount_save = linecount;
	}
	if (itemcount > icount_save) {
		if (icount_save)
			free(oc);
		oc = (int *)marea(sizeof(int) * itemcount);

		icount_save = itemcount;
	}

	for (i = 0; i < itemcount; i++)
		oc[i] = FALSE;

	for (i = 0; i < linecount; i++) {
		if (linebuf[i].flag & FMASK) {
			continue;
		}
		v = CENTER(linebuf[i].xl, linebuf[i].xr);

		slcount = 0;
		for (j = 0; j < linecount; j++) {
			if (linebuf[j].xl < v && v <= linebuf[j].xr) {
				sl[slcount].v = get_cross_point(&linebuf[j], v);
				sl[slcount++].lp = &linebuf[j];
			}
		}
		if (slcount > 0) {
			slsort(sl, slcount);

			if (slcount % 2) {
				fprintf(stderr, "[vfont] data error. (%#x) %s\n",
						tbl_ptr->char_code, tbl_ptr->v_font_name);
				slcount &= ~1;
			}
			for (j = 0; j < slcount; j += 2) {
				if (!oc[sl[j].lp->itemno]) {
					oc[sl[j].lp->itemno] = TRUE;

					/*					if (sl[j].lp->dx == 0)
						it1 = (!(sl[j].lp->flag&YREV)) ? TRUE : FALSE;
					else
*/
					it1 = (sl[j].lp->flag & XREV) ? TRUE : FALSE;
					setopenclose(sl[j].lp->itemno, it1);
				}

				if (!oc[sl[j + 1].lp->itemno]) {
					oc[sl[j + 1].lp->itemno] = TRUE;

					/*					if (sl[j + 1].lp->dx == 0 )
						it1 = (sl[j + 1].lp->flag&YREV)? TRUE : FALSE;
					else
*/
					it1 = (!(sl[j + 1].lp->flag & XREV)) ? TRUE : FALSE;
					setopenclose(sl[j + 1].lp->itemno, it1);
				}

				if (sl[j].lp->itemno != sl[j + 1].lp->itemno) {
					if (sl[j].lp->itemno < sl[j + 1].lp->itemno) {
						it1 = sl[j].lp->itemno;
						it2 = sl[j + 1].lp->itemno;
					}
					else {
						it1 = sl[j + 1].lp->itemno;
						it2 = sl[j].lp->itemno;
					}
					for (k = 0; k < linecount; k++) {
						if (linebuf[k].itemno == it2) {
							linebuf[k].itemno = it1;
						}
					}
				}
			}
		}
	}

	if (itemflag) {
		for (i = 0; i < itemcount; i++) {
			oc[i] = FALSE;
		}
		for (i = 0; i < linecount; i++) {
			oc[linebuf[i].itemno] = TRUE;
		}
		for (i = it1 = 0; i < itemcount; i++) {
			if (oc[i]) {
				oc[i] = it1++;
			}
		}
		for (i = 0; i < linecount; i++) {
			linebuf[i].itemno = oc[linebuf[i].itemno];
		}
		itemcount = it1;
	}
	else {
		for (i = 0; i < linecount; i++) {
			linebuf[i].itemno = 0;
		}
		itemcount = 1;
	}
}

/*************************************************************
*	search_hpair
*	与えられた (x,y) の座標を通る線分とペアの線分を求めて、
*	2本の線分の距離を返す。
**************************************************************/
static long search_hpair(int x, int y, int flag)
{
	int i, itmp = 0, ftmp = 0;
	int dx, dy;
	long vy, vy0, ltmp, distance;

	distance = NOHV;
	vy0 = y * TIMES;
	if (flag & VOPEN) {
		for (i = 0; i < linecount; i++) {
			if (linebuf[i].xl < x && x <= linebuf[i].xr) {
				if (linebuf[i].flag & VCLOSE) {
					dx = linebuf[i].dx;
					dy = linebuf[i].dy;
					if (linebuf[i].flag & XYREV) {
						vy = ((long)(linebuf[i].xr - x) * dy * TIMES) / dx
							+ (long)linebuf[i].yu * TIMES;
					}
					else {
						vy = ((long)(x - linebuf[i].xl) * dy * TIMES) / dx
							+ (long)linebuf[i].yu * TIMES;
					}
					if (vy > vy0) {
						ltmp = vy - vy0;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = linebuf[i].flag;
							itmp = dx;
						}
					}
				}
			}
		}
	}
	else {
		for (i = 0; i < linecount; i++) {
			if (linebuf[i].xl < x && x <= linebuf[i].xr) {
				if (linebuf[i].flag & VOPEN) {
					dx = linebuf[i].dx;
					dy = linebuf[i].dy;
					if (linebuf[i].flag & XYREV) {
						vy = ((long)(linebuf[i].xr - x) * dy * TIMES) / dx
							+ (long)linebuf[i].yu * TIMES;
					}
					else {
						vy = ((long)(x - linebuf[i].xl) * dy * TIMES) / dx
							+ (long)linebuf[i].yu * TIMES;
					}
					if (vy < vy0) {
						ltmp = vy0 - vy;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = linebuf[i].flag;
							itmp = dx;
						}
					}
				}
			}
		}
	}
	return ((ftmp & HORILINE && itmp > XTHICKLINEWIDTHDOUBLE) ? distance : NOHV);
}

/*************************************************************
*	search_vpair
*	与えられた (x,y) の座標を通る線分とペアの線分を求めて、
*	2本の線分の距離を返す。
**************************************************************/
static long search_vpair(int x, int y, int flag)
{
	int i, itmp = 0, ftmp = 0;
	int dx, dy;
	long vx0, vx, ltmp, distance;

	distance = NOHV;
	vx0 = x * TIMES;
	if (flag & HOPEN) {
		for (i = 0; i < linecount; i++) {
			if (linebuf[i].yu < y && y <= linebuf[i].yl) {
				if (linebuf[i].flag & HCLOSE) {
					dx = linebuf[i].dx;
					dy = linebuf[i].dy;
					if (linebuf[i].flag & XYREV) {
						vx = ((long)(linebuf[i].yl - y) * dx * TIMES) / dy
							+ (long)linebuf[i].xl * TIMES;
					}
					else {
						vx = ((long)(y - linebuf[i].yu) * dx * TIMES) / dy
							+ (long)linebuf[i].xl * TIMES;
					}
					if (vx > vx0) {
						ltmp = vx - vx0;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = linebuf[i].flag;
							itmp = dy;
						}
					}
				}
			}
		}
	}
	else {
		for (i = 0; i < linecount; i++) {
			if (linebuf[i].yu < y && y <= linebuf[i].yl) {
				if (linebuf[i].flag & HOPEN) {
					dx = linebuf[i].dx;
					dy = linebuf[i].dy;
					if (linebuf[i].flag & XYREV) {
						vx = ((long)(linebuf[i].yl - y) * dx * TIMES) / dy
							+ (long)linebuf[i].xl * TIMES;
					}
					else {
						vx = ((long)(y - linebuf[i].yu) * dx * TIMES) / dy
							+ (long)linebuf[i].xl * TIMES;
					}
					if (vx < vx0) {
						ltmp = vx0 - vx;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = linebuf[i].flag;
							itmp = dy;
						}
					}
				}
			}
		}
	}
	return ((ftmp & VERTLINE && itmp > YTHICKLINEWIDTHDOUBLE) ? distance : NOHV);
}

/*************************************************************
*	getthinwidth
*	xthin, ythin を求める
**************************************************************/
void getthinwidth(int *xthin, int *ythin)
{
	int i, dx, dy, cx, cy, flag;
	long xt, yt, tmp1;

	xt = yt = NOHV;

	for (i = 0; i < linecount; i++) {
		flag = linebuf[i].flag;
		if (flag & HORILINE) {
			dx = linebuf[i].dx;
			if (dx > XTHICKLINEWIDTHDOUBLE) {
				cx = CENTER(linebuf[i].xl, linebuf[i].xr);
				tmp1 = search_hpair(cx, linebuf[i].yu, flag);
				if (yt > tmp1)
					yt = tmp1;
			}
		}
		else if (flag & VERTLINE) {
			dy = linebuf[i].dy;
			if (dy > YTHICKLINEWIDTHDOUBLE) {
				cy = CENTER(linebuf[i].yu, linebuf[i].yl);
				tmp1 = search_vpair(linebuf[i].xl, cy, flag);
				if (xt > tmp1)
					xt = tmp1;
			}
		}
	}
	if (xt < NOHV) {
		*xthin = (int)(xt / TIMES);
	}
	else {
		*xthin = 0;
	}

	if (yt < NOHV) {
		*ythin = (int)(yt / TIMES);
	}
	else {
		*ythin = 0;
	}
}

/* end of all */
