/* ---------------------------------------------------------------------------- * This file was automatically generated by SWIG (http://www.swig.org). * Version 1.3.14u-20020903-0949 * * This file is not intended to be easily readable and contains a number of * coding conventions designed to improve portability and efficiency. Do not make * changes to this file unless you know what you are doing--modify the SWIG * interface file instead. * ----------------------------------------------------------------------------- */ /*********************************************************************** * common.swg * * This file contains generic SWIG runtime support for pointer * type checking as well as a few commonly used macros to control * external linkage. * * Author : David Beazley (beazley@cs.uchicago.edu) * * Copyright (c) 1999-2000, The University of Chicago * * This file may be freely redistributed without license or fee provided * this copyright message remains intact. ************************************************************************/ #include #if defined(_WIN32) || defined(__WIN32__) # if defined(_MSC_VER) # if defined(STATIC_LINKED) # define SWIGEXPORT(a) a # define SWIGIMPORT(a) extern a # else # define SWIGEXPORT(a) __declspec(dllexport) a # define SWIGIMPORT(a) extern a # endif # else # if defined(__BORLANDC__) # define SWIGEXPORT(a) a _export # define SWIGIMPORT(a) a _export # else # define SWIGEXPORT(a) a # define SWIGIMPORT(a) a # endif # endif #else # define SWIGEXPORT(a) a # define SWIGIMPORT(a) a #endif #ifdef SWIG_GLOBAL #define SWIGRUNTIME(a) SWIGEXPORT(a) #else #define SWIGRUNTIME(a) static a #endif #ifdef __cplusplus extern "C" { #endif typedef void *(*swig_converter_func)(void *); typedef struct swig_type_info *(*swig_dycast_func)(void **); typedef struct swig_type_info { const char *name; swig_converter_func converter; const char *str; void *clientdata; swig_dycast_func dcast; struct swig_type_info *next; struct swig_type_info *prev; } swig_type_info; #ifdef SWIG_NOINCLUDE SWIGIMPORT(swig_type_info *) SWIG_TypeRegister(swig_type_info *); SWIGIMPORT(swig_type_info *) SWIG_TypeCheck(char *c, swig_type_info *); SWIGIMPORT(void *) SWIG_TypeCast(swig_type_info *, void *); SWIGIMPORT(swig_type_info *) SWIG_TypeDynamicCast(swig_type_info *, void **); SWIGIMPORT(swig_type_info *) SWIG_TypeQuery(const char *); SWIGIMPORT(void) SWIG_TypeClientData(swig_type_info *, void *); #else static swig_type_info *swig_type_list = 0; /* Register a type mapping with the type-checking */ SWIGRUNTIME(swig_type_info *) SWIG_TypeRegister(swig_type_info *ti) { swig_type_info *tc, *head, *ret, *next; /* Check to see if this type has already been registered */ tc = swig_type_list; while (tc) { if (strcmp(tc->name, ti->name) == 0) { /* Already exists in the table. Just add additional types to the list */ if (tc->clientdata) ti->clientdata = tc->clientdata; head = tc; next = tc->next; goto l1; } tc = tc->prev; } head = ti; next = 0; /* Place in list */ ti->prev = swig_type_list; swig_type_list = ti; /* Build linked lists */ l1: ret = head; tc = ti + 1; /* Patch up the rest of the links */ while (tc->name) { head->next = tc; tc->prev = head; head = tc; tc++; } head->next = next; return ret; } /* Check the typename */ SWIGRUNTIME(swig_type_info *) SWIG_TypeCheck(char *c, swig_type_info *ty) { swig_type_info *s; if (!ty) return 0; /* Void pointer */ s = ty->next; /* First element always just a name */ do { if (strcmp(s->name,c) == 0) { if (s == ty->next) return s; /* Move s to the top of the linked list */ s->prev->next = s->next; if (s->next) { s->next->prev = s->prev; } /* Insert s as second element in the list */ s->next = ty->next; if (ty->next) ty->next->prev = s; ty->next = s; return s; } s = s->next; } while (s && (s != ty->next)); return 0; } /* Cast a pointer up an inheritance hierarchy */ SWIGRUNTIME(void *) SWIG_TypeCast(swig_type_info *ty, void *ptr) { if ((!ty) || (!ty->converter)) return ptr; return (*ty->converter)(ptr); } /* Dynamic pointer casting. Down an inheritance hierarchy */ SWIGRUNTIME(swig_type_info *) SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { swig_type_info *lastty = ty; if (!ty || !ty->dcast) return ty; while (ty && (ty->dcast)) { ty = (*ty->dcast)(ptr); if (ty) lastty = ty; } return lastty; } /* Search for a swig_type_info structure */ SWIGRUNTIME(swig_type_info *) SWIG_TypeQuery(const char *name) { swig_type_info *ty = swig_type_list; while (ty) { if (ty->str && (strcmp(name,ty->str) == 0)) return ty; if (ty->name && (strcmp(name,ty->name) == 0)) return ty; ty = ty->prev; } return 0; } /* Set the clientdata field for a type */ SWIGRUNTIME(void) SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { swig_type_info *tc, *equiv; if (ti->clientdata) return; ti->clientdata = clientdata; equiv = ti->next; while (equiv) { if (!equiv->converter) { tc = swig_type_list; while (tc) { if ((strcmp(tc->name, equiv->name) == 0)) SWIG_TypeClientData(tc,clientdata); tc = tc->prev; } } equiv = equiv->next; } } #endif #ifdef __cplusplus } #endif /* ----------------------------------------------------------------------------- * perl5.swg * * Perl5 runtime library * $Header: /cvs/projects/SWIG/Lib/perl5/Attic/perlrun.swg,v 1.1.2.8 2002/07/05 03:50:31 beazley Exp $ * ----------------------------------------------------------------------------- */ #define SWIGPERL #define SWIGPERL5 #ifdef __cplusplus /* Needed on some windows machines---since MS plays funny games with the header files under C++ */ #include #include extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" /* Get rid of free and malloc defined by perl */ #undef free #undef malloc #ifndef pTHX_ #define pTHX_ #endif #include #ifdef __cplusplus } #endif /* Macro to call an XS function */ #ifdef PERL_OBJECT #define SWIG_CALLXS(_name) _name(cv,pPerl) #else #define SWIG_CALLXS(_name) _name(cv) #endif /* Note: SwigMagicFuncHack is a typedef used to get the C++ compiler to just shut up already */ #ifdef PERL_OBJECT #define MAGIC_PPERL CPerlObj *pPerl = (CPerlObj *) this; typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *); #ifdef __cplusplus extern "C" { #endif typedef int (CPerlObj::*SwigMagicFuncHack)(SV *, MAGIC *); #ifdef __cplusplus } #endif #define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) #define SWIGCLASS_STATIC #else #define MAGIC_PPERL #define SWIGCLASS_STATIC static #ifndef MULTIPLICITY #define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) typedef int (*SwigMagicFunc)(SV *, MAGIC *); #ifdef __cplusplus extern "C" { #endif typedef int (*SwigMagicFuncHack)(SV *, MAGIC *); #ifdef __cplusplus } #endif #else #define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b) typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *); #ifdef __cplusplus extern "C" { #endif typedef int (*SwigMagicFuncHack)(struct interpreter *, SV *, MAGIC *); #ifdef __cplusplus } #endif #endif #endif #if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE) #define PerlIO_exportFILE(fh,fl) (FILE*)(fh) #endif /* Modifications for newer Perl 5.005 releases */ #if !defined(PERL_REVISION) || ((PERL_REVISION >= 5) && ((PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION < 50)))) #ifndef PL_sv_yes #define PL_sv_yes sv_yes #endif #ifndef PL_sv_undef #define PL_sv_undef sv_undef #endif #ifndef PL_na #define PL_na na #endif #endif #include #ifdef __cplusplus extern "C" { #endif #ifdef SWIG_NOINCLUDE #ifndef PERL_OBJECT extern int SWIG_ConvertPtr(SV *, void **, swig_type_info *, int flags); extern void SWIG_MakePtr(SV *, void *, swig_type_info *, int flags); #else extern int _SWIG_ConvertPtr(CPerlObj *, SV *, void **, swig_type_info *,int flags); extern void _SWIG_MakePtr(CPerlObj *, SV *, void *, swig_type_info *, int flags); #define SWIG_ConvertPtr(a,b,c,d) _SWIG_ConvertPtr(pPerl,a,b,c,d) #define SWIG_MakePtr(a,b,c,d) _SWIG_MakePtr(pPerl,a,b,c,d) #endif #else /* Function for getting a pointer value */ #ifndef PERL_OBJECT SWIGRUNTIME(int) SWIG_ConvertPtr(SV *sv, void **ptr, swig_type_info *_t, int flags) #else #define SWIG_ConvertPtr(a,b,c,d) _SWIG_ConvertPtr(pPerl,a,b,c,d) SWIGRUNTIME(int) _SWIG_ConvertPtr(CPerlObj *pPerl, SV *sv, void **ptr, swig_type_info *_t, int flags) #endif { char *_c; swig_type_info *tc; IV tmp; /* If magical, apply more magic */ if (SvGMAGICAL(sv)) mg_get(sv); /* Check to see if this is an object */ if (sv_isobject(sv)) { SV *tsv = (SV*) SvRV(sv); if ((SvTYPE(tsv) == SVt_PVHV)) { MAGIC *mg; if (SvMAGICAL(tsv)) { mg = mg_find(tsv,'P'); if (mg) { SV *rsv = mg->mg_obj; if (sv_isobject(rsv)) { tmp = SvIV((SV*)SvRV(rsv)); } } } else { return -1; } } else { tmp = SvIV((SV*)SvRV(sv)); } if (!_t) { *(ptr) = (void *) tmp; return 0; } } else if (! SvOK(sv)) { /* Check for undef */ *(ptr) = (void *) 0; return 0; } else if (SvTYPE(sv) == SVt_RV) { /* Check for NULL pointer */ *(ptr) = (void *) 0; if (!SvROK(sv)) return 0; else return -1; } else { /* Don't know what it is */ *(ptr) = (void *) 0; return -1; } if (_t) { /* Now see if the types match */ _c = HvNAME(SvSTASH(SvRV(sv))); tc = SWIG_TypeCheck(_c,_t); if (!tc) { *ptr = (void *) tmp; return -1; } *ptr = SWIG_TypeCast(tc,(void *)tmp); return 0; } *ptr = (void *) tmp; return 0; } #ifndef PERL_OBJECT SWIGRUNTIME(void) SWIG_MakePtr(SV *sv, void *ptr, swig_type_info *t,int flags) #else #define SWIG_MakePtr(a,b,c,d) _SWIG_MakePtr(pPerl,a,b,c,d) SWIGRUNTIME(void) _SWIG_MakePtr(CPerlObj *pPerl, SV *sv, void *ptr, swig_type_info *t, int flags) #endif { sv_setref_pv(sv, (char *) t->name, ptr); } #endif typedef XS(SwigPerlWrapper); typedef SwigPerlWrapper *SwigPerlWrapperPtr; /* Structure for command table */ typedef struct { const char *name; SwigPerlWrapperPtr wrapper; } swig_command_info; /* Information for constant table */ #define SWIG_INT 1 #define SWIG_FLOAT 2 #define SWIG_STRING 3 #define SWIG_POINTER 4 #define SWIG_BINARY 5 /* Constant information structure */ typedef struct swig_constant_info { int type; const char *name; long lvalue; double dvalue; void *pvalue; swig_type_info **ptype; } swig_constant_info; #ifdef __cplusplus } #endif /* Structure for variable table */ typedef struct { const char *name; SwigMagicFunc set; SwigMagicFunc get; swig_type_info **type; } swig_variable_info; /* Magic variable code */ #ifndef PERL_OBJECT #define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c) #ifndef MULTIPLICITY static void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int \ (*get)(SV *,MAGIC *)) { #else static void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*,\ SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) { #endif #else #define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c) static void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) { #endif MAGIC *mg; sv_magic(sv,sv,'U',(char *) name,strlen(name)); mg = mg_find(sv,'U'); mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL)); mg->mg_virtual->svt_get = (SwigMagicFuncHack) get; mg->mg_virtual->svt_set = (SwigMagicFuncHack) set; mg->mg_virtual->svt_len = 0; mg->mg_virtual->svt_clear = 0; mg->mg_virtual->svt_free = 0; } /* -------- TYPES TABLE (BEGIN) -------- */ #define SWIGTYPE_p_FILE swig_types[0] #define SWIGTYPE_p_gpc_polygon swig_types[1] #define SWIGTYPE_p_gpc_vertex swig_types[2] #define SWIGTYPE_p_gpc_tristrip swig_types[3] #define SWIGTYPE_p_int swig_types[4] #define SWIGTYPE_p_gpc_vertex_list swig_types[5] static swig_type_info *swig_types[7]; /* -------- TYPES TABLE (END) -------- */ #define SWIG_init boot_Math__Geometry__Planar__GPC #define SWIG_name "Math::Geometry::GPC::boot_Math__Geometry__Planar__GPC" #define SWIG_prefix "Math::Geometry::Planar::GPC::" #ifdef __cplusplus extern "C" #endif #ifndef PERL_OBJECT #ifndef MULTIPLICITY SWIGEXPORT(void) SWIG_init (CV* cv); #else SWIGEXPORT(void) SWIG_init (pTHXo_ CV* cv); #endif #else SWIGEXPORT(void) SWIG_init (CV *cv, CPerlObj *); #endif #include "GPC.h" int *int_array(int size) { return (int *) malloc(sizeof(int)*size); } void int_destroy(int *a) { free(a); } void int_set(int *a, int i, int val) { a[i] = val; } int int_get(int *a, int i) { return a[i]; } gpc_vertex *gpc_vertex_array(int size) { return (gpc_vertex *) malloc(sizeof(gpc_vertex)*size); } void gpc_vertex_destroy(gpc_vertex *a) { free(a); } void gpc_vertex_set(gpc_vertex *a, int i, gpc_vertex val) { a[i] = val; } gpc_vertex gpc_vertex_get(gpc_vertex *a, int i) { return a[i]; } gpc_vertex_list *gpc_vertex_list_array(int size) { return (gpc_vertex_list *) malloc(sizeof(gpc_vertex_list)*size); } void gpc_vertex_list_destroy(gpc_vertex_list *a) { free(a); } void gpc_vertex_list_set(gpc_vertex_list *a, int i, gpc_vertex_list val) { a[i] = val; } gpc_vertex_list gpc_vertex_list_get(gpc_vertex_list *a, int i) { return a[i]; } #ifdef PERL_OBJECT #define MAGIC_CLASS _wrap_GPC_var:: class _wrap_GPC_var : public CPerlObj { public: #else #define MAGIC_CLASS #endif SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *sv, MAGIC *mg) { MAGIC_PPERL sv = sv; mg = mg; croak("Value is read-only."); return 0; } #ifdef PERL_OBJECT }; #endif #ifdef __cplusplus extern "C" { #endif XS(_wrap_fopen) { char *arg1 ; char *arg2 ; FILE *result; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: fopen(name,mode);"); } if (!SvOK((SV*) ST(0))) arg1 = 0; else arg1 = (char *) SvPV(ST(0), PL_na); if (!SvOK((SV*) ST(1))) arg2 = 0; else arg2 = (char *) SvPV(ST(1), PL_na); result = (FILE *)fopen(arg1,arg2); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_FILE,0); XSRETURN(argvi); } XS(_wrap_fclose) { FILE *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: fclose(FILE *);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_FILE,0) < 0) { croak("Type error in argument 1 of fclose. Expected %s", SWIGTYPE_p_FILE->name); } } fclose(arg1); XSRETURN(argvi); } XS(_wrap_int_array) { int arg1 ; int *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: int_array(size);"); } arg1 = (int) SvIV(ST(0)); result = (int *)int_array(arg1); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_int,0); XSRETURN(argvi); } XS(_wrap_int_destroy) { int *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: int_destroy(a);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_int,0) < 0) { croak("Type error in argument 1 of int_destroy. Expected %s", SWIGTYPE_p_int->name); } } int_destroy(arg1); XSRETURN(argvi); } XS(_wrap_int_set) { int *arg1 ; int arg2 ; int arg3 ; int argvi = 0; dXSARGS; if ((items < 3) || (items > 3)) { croak("Usage: int_set(a,i,val);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_int,0) < 0) { croak("Type error in argument 1 of int_set. Expected %s", SWIGTYPE_p_int->name); } } arg2 = (int) SvIV(ST(1)); arg3 = (int) SvIV(ST(2)); int_set(arg1,arg2,arg3); XSRETURN(argvi); } XS(_wrap_int_get) { int *arg1 ; int arg2 ; int result; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: int_get(a,i);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_int,0) < 0) { croak("Type error in argument 1 of int_get. Expected %s", SWIGTYPE_p_int->name); } } arg2 = (int) SvIV(ST(1)); result = (int)int_get(arg1,arg2); ST(argvi) = sv_newmortal(); sv_setiv(ST(argvi++), (IV) result); XSRETURN(argvi); } XS(_wrap_gpc_vertex_array) { int arg1 ; gpc_vertex *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_array(size);"); } arg1 = (int) SvIV(ST(0)); result = (gpc_vertex *)gpc_vertex_array(arg1); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex,0); XSRETURN(argvi); } XS(_wrap_gpc_vertex_destroy) { gpc_vertex *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_destroy(a);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_destroy. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } gpc_vertex_destroy(arg1); XSRETURN(argvi); } XS(_wrap_gpc_vertex_set) { gpc_vertex *arg1 ; int arg2 ; gpc_vertex arg3 ; int argvi = 0; dXSARGS; if ((items < 3) || (items > 3)) { croak("Usage: gpc_vertex_set(a,i,val);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_set. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } arg2 = (int) SvIV(ST(1)); { gpc_vertex * argp; if (SWIG_ConvertPtr(ST(2),(void **) &argp, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 3 of gpc_vertex_set. Expected %s", SWIGTYPE_p_gpc_vertex->name); } arg3 = *argp; } gpc_vertex_set(arg1,arg2,arg3); XSRETURN(argvi); } XS(_wrap_gpc_vertex_get) { gpc_vertex *arg1 ; int arg2 ; gpc_vertex result; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_vertex_get(a,i);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_get. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } arg2 = (int) SvIV(ST(1)); result = gpc_vertex_get(arg1,arg2); { gpc_vertex * resultobj = (gpc_vertex *) malloc(sizeof(gpc_vertex)); memmove(resultobj, &result, sizeof(gpc_vertex)); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) resultobj, SWIGTYPE_p_gpc_vertex,0); } XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_array) { int arg1 ; gpc_vertex_list *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_list_array(size);"); } arg1 = (int) SvIV(ST(0)); result = (gpc_vertex_list *)gpc_vertex_list_array(arg1); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex_list,0); XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_destroy) { gpc_vertex_list *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_list_destroy(a);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_destroy. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } gpc_vertex_list_destroy(arg1); XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_set) { gpc_vertex_list *arg1 ; int arg2 ; gpc_vertex_list arg3 ; int argvi = 0; dXSARGS; if ((items < 3) || (items > 3)) { croak("Usage: gpc_vertex_list_set(a,i,val);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_set. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } arg2 = (int) SvIV(ST(1)); { gpc_vertex_list * argp; if (SWIG_ConvertPtr(ST(2),(void **) &argp, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 3 of gpc_vertex_list_set. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } arg3 = *argp; } gpc_vertex_list_set(arg1,arg2,arg3); XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_get) { gpc_vertex_list *arg1 ; int arg2 ; gpc_vertex_list result; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_vertex_list_get(a,i);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_get. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } arg2 = (int) SvIV(ST(1)); result = gpc_vertex_list_get(arg1,arg2); { gpc_vertex_list * resultobj = (gpc_vertex_list *) malloc(sizeof(gpc_vertex_list)); memmove(resultobj, &result, sizeof(gpc_vertex_list)); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) resultobj, SWIGTYPE_p_gpc_vertex_list,0); } XSRETURN(argvi); } XS(_wrap_gpc_vertex_x_set) { gpc_vertex *arg1 ; double arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_vertex_x_set(self,x);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_x_set. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } arg2 = (double) SvNV(ST(1)); if (arg1) (arg1)->x = arg2; XSRETURN(argvi); } XS(_wrap_gpc_vertex_x_get) { gpc_vertex *arg1 ; double result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_x_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_x_get. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } result = (double) ((arg1)->x); ST(argvi) = sv_newmortal(); sv_setnv(ST(argvi++), (double) result); XSRETURN(argvi); } XS(_wrap_gpc_vertex_y_set) { gpc_vertex *arg1 ; double arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_vertex_y_set(self,y);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_y_set. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } arg2 = (double) SvNV(ST(1)); if (arg1) (arg1)->y = arg2; XSRETURN(argvi); } XS(_wrap_gpc_vertex_y_get) { gpc_vertex *arg1 ; double result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_y_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of gpc_vertex_y_get. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } result = (double) ((arg1)->y); ST(argvi) = sv_newmortal(); sv_setnv(ST(argvi++), (double) result); XSRETURN(argvi); } XS(_wrap_new_gpc_vertex) { gpc_vertex *result; int argvi = 0; dXSARGS; if ((items < 0) || (items > 0)) { croak("Usage: new_gpc_vertex();"); } result = (gpc_vertex *)(gpc_vertex *) calloc(1, sizeof(gpc_vertex)); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex,0); XSRETURN(argvi); } XS(_wrap_delete_gpc_vertex) { gpc_vertex *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: delete_gpc_vertex(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 1 of delete_gpc_vertex. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } free((char *) arg1); XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_num_vertices_set) { gpc_vertex_list *arg1 ; int arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_vertex_list_num_vertices_set(self,num_vertices);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_num_vertices_set. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } arg2 = (int) SvIV(ST(1)); if (arg1) (arg1)->num_vertices = arg2; XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_num_vertices_get) { gpc_vertex_list *arg1 ; int result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_list_num_vertices_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_num_vertices_get. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } result = (int) ((arg1)->num_vertices); ST(argvi) = sv_newmortal(); sv_setiv(ST(argvi++), (IV) result); XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_vertex_set) { gpc_vertex_list *arg1 ; gpc_vertex *arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_vertex_list_vertex_set(self,vertex);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_vertex_set. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_vertex,0) < 0) { croak("Type error in argument 2 of gpc_vertex_list_vertex_set. Expected %s", SWIGTYPE_p_gpc_vertex->name); } } if (arg1) (arg1)->vertex = arg2; XSRETURN(argvi); } XS(_wrap_gpc_vertex_list_vertex_get) { gpc_vertex_list *arg1 ; gpc_vertex *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_vertex_list_vertex_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of gpc_vertex_list_vertex_get. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } result = (gpc_vertex *) ((arg1)->vertex); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex,0); XSRETURN(argvi); } XS(_wrap_new_gpc_vertex_list) { gpc_vertex_list *result; int argvi = 0; dXSARGS; if ((items < 0) || (items > 0)) { croak("Usage: new_gpc_vertex_list();"); } result = (gpc_vertex_list *)(gpc_vertex_list *) calloc(1, sizeof(gpc_vertex_list)); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex_list,0); XSRETURN(argvi); } XS(_wrap_delete_gpc_vertex_list) { gpc_vertex_list *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: delete_gpc_vertex_list(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 1 of delete_gpc_vertex_list. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } free((char *) arg1); XSRETURN(argvi); } XS(_wrap_gpc_polygon_num_contours_set) { gpc_polygon *arg1 ; int arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_polygon_num_contours_set(self,num_contours);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_num_contours_set. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } arg2 = (int) SvIV(ST(1)); if (arg1) (arg1)->num_contours = arg2; XSRETURN(argvi); } XS(_wrap_gpc_polygon_num_contours_get) { gpc_polygon *arg1 ; int result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_polygon_num_contours_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_num_contours_get. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } result = (int) ((arg1)->num_contours); ST(argvi) = sv_newmortal(); sv_setiv(ST(argvi++), (IV) result); XSRETURN(argvi); } XS(_wrap_gpc_polygon_hole_set) { gpc_polygon *arg1 ; int *arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_polygon_hole_set(self,hole);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_hole_set. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_int,0) < 0) { croak("Type error in argument 2 of gpc_polygon_hole_set. Expected %s", SWIGTYPE_p_int->name); } } if (arg1) (arg1)->hole = arg2; XSRETURN(argvi); } XS(_wrap_gpc_polygon_hole_get) { gpc_polygon *arg1 ; int *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_polygon_hole_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_hole_get. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } result = (int *) ((arg1)->hole); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_int,0); XSRETURN(argvi); } XS(_wrap_gpc_polygon_contour_set) { gpc_polygon *arg1 ; gpc_vertex_list *arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_polygon_contour_set(self,contour);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_contour_set. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 2 of gpc_polygon_contour_set. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } if (arg1) (arg1)->contour = arg2; XSRETURN(argvi); } XS(_wrap_gpc_polygon_contour_get) { gpc_polygon *arg1 ; gpc_vertex_list *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_polygon_contour_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_contour_get. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } result = (gpc_vertex_list *) ((arg1)->contour); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex_list,0); XSRETURN(argvi); } XS(_wrap_new_gpc_polygon) { gpc_polygon *result; int argvi = 0; dXSARGS; if ((items < 0) || (items > 0)) { croak("Usage: new_gpc_polygon();"); } result = (gpc_polygon *)(gpc_polygon *) calloc(1, sizeof(gpc_polygon)); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_polygon,0); XSRETURN(argvi); } XS(_wrap_delete_gpc_polygon) { gpc_polygon *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: delete_gpc_polygon(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of delete_gpc_polygon. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } free((char *) arg1); XSRETURN(argvi); } XS(_wrap_gpc_tristrip_num_strips_set) { gpc_tristrip *arg1 ; int arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_tristrip_num_strips_set(self,num_strips);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 1 of gpc_tristrip_num_strips_set. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } arg2 = (int) SvIV(ST(1)); if (arg1) (arg1)->num_strips = arg2; XSRETURN(argvi); } XS(_wrap_gpc_tristrip_num_strips_get) { gpc_tristrip *arg1 ; int result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_tristrip_num_strips_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 1 of gpc_tristrip_num_strips_get. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } result = (int) ((arg1)->num_strips); ST(argvi) = sv_newmortal(); sv_setiv(ST(argvi++), (IV) result); XSRETURN(argvi); } XS(_wrap_gpc_tristrip_strip_set) { gpc_tristrip *arg1 ; gpc_vertex_list *arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_tristrip_strip_set(self,strip);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 1 of gpc_tristrip_strip_set. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 2 of gpc_tristrip_strip_set. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } if (arg1) (arg1)->strip = arg2; XSRETURN(argvi); } XS(_wrap_gpc_tristrip_strip_get) { gpc_tristrip *arg1 ; gpc_vertex_list *result; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_tristrip_strip_get(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 1 of gpc_tristrip_strip_get. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } result = (gpc_vertex_list *) ((arg1)->strip); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_vertex_list,0); XSRETURN(argvi); } XS(_wrap_new_gpc_tristrip) { gpc_tristrip *result; int argvi = 0; dXSARGS; if ((items < 0) || (items > 0)) { croak("Usage: new_gpc_tristrip();"); } result = (gpc_tristrip *)(gpc_tristrip *) calloc(1, sizeof(gpc_tristrip)); ST(argvi) = sv_newmortal(); SWIG_MakePtr(ST(argvi++), (void *) result, SWIGTYPE_p_gpc_tristrip,0); XSRETURN(argvi); } XS(_wrap_delete_gpc_tristrip) { gpc_tristrip *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: delete_gpc_tristrip(self);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 1 of delete_gpc_tristrip. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } free((char *) arg1); XSRETURN(argvi); } XS(_wrap_gpc_read_polygon) { FILE *arg1 ; int arg2 ; gpc_polygon *arg3 ; int argvi = 0; dXSARGS; if ((items < 3) || (items > 3)) { croak("Usage: gpc_read_polygon(infile_ptr,read_hole_flags,polygon);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_FILE,0) < 0) { croak("Type error in argument 1 of gpc_read_polygon. Expected %s", SWIGTYPE_p_FILE->name); } } arg2 = (int) SvIV(ST(1)); { if (SWIG_ConvertPtr(ST(2), (void **) &arg3, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 3 of gpc_read_polygon. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } gpc_read_polygon(arg1,arg2,arg3); XSRETURN(argvi); } XS(_wrap_gpc_write_polygon) { FILE *arg1 ; int arg2 ; gpc_polygon *arg3 ; int argvi = 0; dXSARGS; if ((items < 3) || (items > 3)) { croak("Usage: gpc_write_polygon(outfile_ptr,write_hole_flags,polygon);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_FILE,0) < 0) { croak("Type error in argument 1 of gpc_write_polygon. Expected %s", SWIGTYPE_p_FILE->name); } } arg2 = (int) SvIV(ST(1)); { if (SWIG_ConvertPtr(ST(2), (void **) &arg3, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 3 of gpc_write_polygon. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } gpc_write_polygon(arg1,arg2,arg3); XSRETURN(argvi); } XS(_wrap_gpc_add_contour) { gpc_polygon *arg1 ; gpc_vertex_list *arg2 ; int arg3 ; int argvi = 0; dXSARGS; if ((items < 3) || (items > 3)) { croak("Usage: gpc_add_contour(polygon,contour,hole);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_add_contour. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_vertex_list,0) < 0) { croak("Type error in argument 2 of gpc_add_contour. Expected %s", SWIGTYPE_p_gpc_vertex_list->name); } } arg3 = (int) SvIV(ST(2)); gpc_add_contour(arg1,arg2,arg3); XSRETURN(argvi); } XS(_wrap_gpc_polygon_clip) { int arg1 ; gpc_polygon *arg2 ; gpc_polygon *arg3 ; gpc_polygon *arg4 ; int argvi = 0; dXSARGS; if ((items < 4) || (items > 4)) { croak("Usage: gpc_polygon_clip(set_operation,subject_polygon,clip_polygon,result_polygon);"); } arg1 = (int) SvIV(ST(0)); { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 2 of gpc_polygon_clip. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(2), (void **) &arg3, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 3 of gpc_polygon_clip. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(3), (void **) &arg4, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 4 of gpc_polygon_clip. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } gpc_polygon_clip((gpc_op )arg1,arg2,arg3,arg4); XSRETURN(argvi); } XS(_wrap_gpc_tristrip_clip) { int arg1 ; gpc_polygon *arg2 ; gpc_polygon *arg3 ; gpc_tristrip *arg4 ; int argvi = 0; dXSARGS; if ((items < 4) || (items > 4)) { croak("Usage: gpc_tristrip_clip(set_operation,subject_polygon,clip_polygon,result_tristrip);"); } arg1 = (int) SvIV(ST(0)); { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 2 of gpc_tristrip_clip. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(2), (void **) &arg3, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 3 of gpc_tristrip_clip. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(3), (void **) &arg4, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 4 of gpc_tristrip_clip. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } gpc_tristrip_clip((gpc_op )arg1,arg2,arg3,arg4); XSRETURN(argvi); } XS(_wrap_gpc_polygon_to_tristrip) { gpc_polygon *arg1 ; gpc_tristrip *arg2 ; int argvi = 0; dXSARGS; if ((items < 2) || (items > 2)) { croak("Usage: gpc_polygon_to_tristrip(polygon,tristrip);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_polygon_to_tristrip. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } { if (SWIG_ConvertPtr(ST(1), (void **) &arg2, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 2 of gpc_polygon_to_tristrip. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } gpc_polygon_to_tristrip(arg1,arg2); XSRETURN(argvi); } XS(_wrap_gpc_free_polygon) { gpc_polygon *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_free_polygon(polygon);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_polygon,0) < 0) { croak("Type error in argument 1 of gpc_free_polygon. Expected %s", SWIGTYPE_p_gpc_polygon->name); } } gpc_free_polygon(arg1); XSRETURN(argvi); } XS(_wrap_gpc_free_tristrip) { gpc_tristrip *arg1 ; int argvi = 0; dXSARGS; if ((items < 1) || (items > 1)) { croak("Usage: gpc_free_tristrip(tristrip);"); } { if (SWIG_ConvertPtr(ST(0), (void **) &arg1, SWIGTYPE_p_gpc_tristrip,0) < 0) { croak("Type error in argument 1 of gpc_free_tristrip. Expected %s", SWIGTYPE_p_gpc_tristrip->name); } } gpc_free_tristrip(arg1); XSRETURN(argvi); } /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ static swig_type_info _swigt__p_FILE[] = {{"_p_FILE", 0, "FILE *", 0},{"_p_FILE"},{0}}; static swig_type_info _swigt__p_gpc_polygon[] = {{"_p_gpc_polygon", 0, "gpc_polygon *", 0},{"_p_gpc_polygon"},{0}}; static swig_type_info _swigt__p_gpc_vertex[] = {{"_p_gpc_vertex", 0, "gpc_vertex *", 0},{"_p_gpc_vertex"},{0}}; static swig_type_info _swigt__p_gpc_tristrip[] = {{"_p_gpc_tristrip", 0, "gpc_tristrip *", 0},{"_p_gpc_tristrip"},{0}}; static swig_type_info _swigt__p_int[] = {{"_p_int", 0, "int *", 0},{"_p_int"},{0}}; static swig_type_info _swigt__p_gpc_vertex_list[] = {{"_p_gpc_vertex_list", 0, "gpc_vertex_list *", 0},{"_p_gpc_vertex_list"},{0}}; static swig_type_info *swig_types_initial[] = { _swigt__p_FILE, _swigt__p_gpc_polygon, _swigt__p_gpc_vertex, _swigt__p_gpc_tristrip, _swigt__p_int, _swigt__p_gpc_vertex_list, 0 }; /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ static swig_constant_info swig_constants[] = { { SWIG_STRING, (char *) SWIG_prefix "GPC_VERSION", 0, 0, (void *)"2.31", 0}, { SWIG_INT, (char *) SWIG_prefix "GPC_DIFF", (long) GPC_DIFF, 0, 0, 0}, { SWIG_INT, (char *) SWIG_prefix "GPC_INT", (long) GPC_INT, 0, 0, 0}, { SWIG_INT, (char *) SWIG_prefix "GPC_XOR", (long) GPC_XOR, 0, 0, 0}, { SWIG_INT, (char *) SWIG_prefix "GPC_UNION", (long) GPC_UNION, 0, 0, 0}, {0} }; #ifdef __cplusplus } #endif static swig_variable_info swig_variables[] = { {0} }; static swig_command_info swig_commands[] = { {"Math::Geometry::Planar::GPC::fopen", _wrap_fopen}, {"Math::Geometry::Planar::GPC::fclose", _wrap_fclose}, {"Math::Geometry::Planar::GPC::int_array", _wrap_int_array}, {"Math::Geometry::Planar::GPC::int_destroy", _wrap_int_destroy}, {"Math::Geometry::Planar::GPC::int_set", _wrap_int_set}, {"Math::Geometry::Planar::GPC::int_get", _wrap_int_get}, {"Math::Geometry::Planar::GPC::gpc_vertex_array", _wrap_gpc_vertex_array}, {"Math::Geometry::Planar::GPC::gpc_vertex_destroy", _wrap_gpc_vertex_destroy}, {"Math::Geometry::Planar::GPC::gpc_vertex_set", _wrap_gpc_vertex_set}, {"Math::Geometry::Planar::GPC::gpc_vertex_get", _wrap_gpc_vertex_get}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_array", _wrap_gpc_vertex_list_array}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_destroy", _wrap_gpc_vertex_list_destroy}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_set", _wrap_gpc_vertex_list_set}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_get", _wrap_gpc_vertex_list_get}, {"Math::Geometry::Planar::GPC::gpc_vertex_x_set", _wrap_gpc_vertex_x_set}, {"Math::Geometry::Planar::GPC::gpc_vertex_x_get", _wrap_gpc_vertex_x_get}, {"Math::Geometry::Planar::GPC::gpc_vertex_y_set", _wrap_gpc_vertex_y_set}, {"Math::Geometry::Planar::GPC::gpc_vertex_y_get", _wrap_gpc_vertex_y_get}, {"Math::Geometry::Planar::GPC::new_gpc_vertex", _wrap_new_gpc_vertex}, {"Math::Geometry::Planar::GPC::delete_gpc_vertex", _wrap_delete_gpc_vertex}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_num_vertices_set", _wrap_gpc_vertex_list_num_vertices_set}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_num_vertices_get", _wrap_gpc_vertex_list_num_vertices_get}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_vertex_set", _wrap_gpc_vertex_list_vertex_set}, {"Math::Geometry::Planar::GPC::gpc_vertex_list_vertex_get", _wrap_gpc_vertex_list_vertex_get}, {"Math::Geometry::Planar::GPC::new_gpc_vertex_list", _wrap_new_gpc_vertex_list}, {"Math::Geometry::Planar::GPC::delete_gpc_vertex_list", _wrap_delete_gpc_vertex_list}, {"Math::Geometry::Planar::GPC::gpc_polygon_num_contours_set", _wrap_gpc_polygon_num_contours_set}, {"Math::Geometry::Planar::GPC::gpc_polygon_num_contours_get", _wrap_gpc_polygon_num_contours_get}, {"Math::Geometry::Planar::GPC::gpc_polygon_hole_set", _wrap_gpc_polygon_hole_set}, {"Math::Geometry::Planar::GPC::gpc_polygon_hole_get", _wrap_gpc_polygon_hole_get}, {"Math::Geometry::Planar::GPC::gpc_polygon_contour_set", _wrap_gpc_polygon_contour_set}, {"Math::Geometry::Planar::GPC::gpc_polygon_contour_get", _wrap_gpc_polygon_contour_get}, {"Math::Geometry::Planar::GPC::new_gpc_polygon", _wrap_new_gpc_polygon}, {"Math::Geometry::Planar::GPC::delete_gpc_polygon", _wrap_delete_gpc_polygon}, {"Math::Geometry::Planar::GPC::gpc_tristrip_num_strips_set", _wrap_gpc_tristrip_num_strips_set}, {"Math::Geometry::Planar::GPC::gpc_tristrip_num_strips_get", _wrap_gpc_tristrip_num_strips_get}, {"Math::Geometry::Planar::GPC::gpc_tristrip_strip_set", _wrap_gpc_tristrip_strip_set}, {"Math::Geometry::Planar::GPC::gpc_tristrip_strip_get", _wrap_gpc_tristrip_strip_get}, {"Math::Geometry::Planar::GPC::new_gpc_tristrip", _wrap_new_gpc_tristrip}, {"Math::Geometry::Planar::GPC::delete_gpc_tristrip", _wrap_delete_gpc_tristrip}, {"Math::Geometry::Planar::GPC::gpc_read_polygon", _wrap_gpc_read_polygon}, {"Math::Geometry::Planar::GPC::gpc_write_polygon", _wrap_gpc_write_polygon}, {"Math::Geometry::Planar::GPC::gpc_add_contour", _wrap_gpc_add_contour}, {"Math::Geometry::Planar::GPC::gpc_polygon_clip", _wrap_gpc_polygon_clip}, {"Math::Geometry::Planar::GPC::gpc_tristrip_clip", _wrap_gpc_tristrip_clip}, {"Math::Geometry::Planar::GPC::gpc_polygon_to_tristrip", _wrap_gpc_polygon_to_tristrip}, {"Math::Geometry::Planar::GPC::gpc_free_polygon", _wrap_gpc_free_polygon}, {"Math::Geometry::Planar::GPC::gpc_free_tristrip", _wrap_gpc_free_tristrip}, {0,0} }; #ifdef __cplusplus extern "C" #endif XS(SWIG_init) { dXSARGS; int i; static int _init = 0; if (!_init) { for (i = 0; swig_types_initial[i]; i++) { swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]); } _init = 1; } /* Install commands */ for (i = 0; swig_commands[i].name; i++) { newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__); } /* Install variables */ for (i = 0; swig_variables[i].name; i++) { SV *sv; sv = perl_get_sv((char*) swig_variables[i].name, TRUE | 0x2); if (swig_variables[i].type) { SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0); }else { sv_setiv(sv,(IV) 0); } swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); } /* Install constant */ for (i = 0; swig_constants[i].type; i++) { SV *sv; sv = perl_get_sv((char*)swig_constants[i].name, TRUE | 0x2); switch(swig_constants[i].type) { case SWIG_INT: sv_setiv(sv, (IV) swig_constants[i].lvalue); break; case SWIG_FLOAT: sv_setnv(sv, (double) swig_constants[i].dvalue); break; case SWIG_STRING: sv_setpv(sv, (char *) swig_constants[i].pvalue); break; case SWIG_POINTER: SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0); break; case SWIG_BINARY: /* obj = SWIG_NewPackedObj(swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype)); */ break; default: break; } SvREADONLY_on(sv); } ST(0) = &PL_sv_yes; XSRETURN(1); } /* Modified by Christopher Teh Boon Sung to remove compiler warnings. Modifications are denoted by comments starting with "CBSTEH". Updated: Mar. 2001 */ /* ########################################################################### Project: Generic Polygon Clipper A new algorithm for calculating the difference, intersection, exclusive-or or union of arbitrary polygon sets. File: GPC.c Author: Alan Murta (email: gpc@cs.man.ac.uk) Version: 2.31 Date: 4th June 1999 Copyright: (C) 1997-1999, Advanced Interfaces Group, University of Manchester. This software is free for non-commercial use. It may be copied, modified, and redistributed provided that this copyright notice is preserved on all copies. The intellectual property rights of the algorithms used reside with the University of Manchester Advanced Interfaces Group. You may not use this software, in whole or in part, in support of any commercial product without the express consent of the author. There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is". ########################################################################### */ /* ########################################################################### Includes ########################################################################### */ #include "GPC.h" #include #include #include /* ########################################################################### Constants ########################################################################### */ #ifndef TRUE #define FALSE 0 #define TRUE 1 #endif #define LEFT 0 #define RIGHT 1 #define ABOVE 0 #define BELOW 1 #define CLIP 0 #define SUBJ 1 #define INVERT_TRISTRIPS FALSE /* ########################################################################### Macros ########################################################################### */ #define EQ(a, b) (fabs((a) - (b)) <= GPC_EPSILON) #define PREV_INDEX(i, n) ((i - 1 + n) % n) #define NEXT_INDEX(i, n) ((i + 1 ) % n) #define OPTIMAL(v, i, n) ((v[PREV_INDEX(i, n)].y != v[i].y) || \ (v[NEXT_INDEX(i, n)].y != v[i].y)) #define FWD_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y >= v[i].vertex.y) \ && (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y)) #define NOT_FMAX(v, i, n) (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y) #define REV_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) \ && (v[NEXT_INDEX(i, n)].vertex.y >= v[i].vertex.y)) #define NOT_RMAX(v, i, n) (v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) #define VERTEX(e,p,s,x,y) {add_vertex(&((e)->outp[(p)]->v[(s)]), x, y); \ (e)->outp[(p)]->active++;} #define P_EDGE(d,e,p,i,j) {(d)= (e); \ do {(d)= (d)->prev;} while (!(d)->outp[(p)]); \ (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} #define N_EDGE(d,e,p,i,j) {(d)= (e); \ do {(d)= (d)->next;} while (!(d)->outp[(p)]); \ (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} #define MALLOC(p, b, s) {if ((b) > 0) { \ p= malloc(b); if (!(p)) { \ fprintf(stderr, "GPC malloc failure: %s\n", s); \ exit(0);}} else p= NULL;} #define FREE(p) {if (p) {free(p); (p)= NULL;}} /* CBSTEH: like MALLOC but this avoids compiler warnings */ #define CMALLOC(p, b, s) { \ p = malloc(b); \ if (!p) \ { \ fprintf(stderr, "GPC malloc failure: %s\n", s); \ exit(0); \ } \ } /* CBSTEH: like FREE but this avoids compiler warnings */ #define CFREE(p) free(p); /* ########################################################################### Private Data Types ########################################################################### */ typedef enum /* Edge intersection classes */ { NUL, /* Empty non-intersection */ EMX, /* External maximum */ ELI, /* External left intermediate */ TED, /* Top edge */ ERI, /* External right intermediate */ RED, /* Right edge */ IMM, /* Internal maximum and minimum */ IMN, /* Internal minimum */ EMN, /* External minimum */ EMM, /* External maximum and minimum */ LED, /* Left edge */ ILI, /* Internal left intermediate */ BED, /* Bottom edge */ IRI, /* Internal right intermediate */ IMX, /* Internal maximum */ FUL /* Full non-intersection */ } vertex_type; typedef enum /* Horizontal edge states */ { NH, /* No horizontal edge */ BH, /* Bottom horizontal edge */ TH /* Top horizontal edge */ } h_state; typedef enum /* Edge bundle state */ { UNBUNDLED, /* Isolated edge not within a bundle */ BUNDLE_HEAD, /* Bundle head node */ BUNDLE_TAIL /* Passive bundle tail node */ } bundle_state; typedef struct v_shape /* Internal vertex list datatype */ { double x; /* X coordinate component */ double y; /* Y coordinate component */ struct v_shape *next; /* Pointer to next vertex in list */ } vertex_node; typedef struct p_shape /* Internal contour / tristrip type */ { int active; /* Active flag / vertex count */ int hole; /* Hole / external contour flag */ vertex_node *v[2]; /* Left and right vertex list ptrs */ struct p_shape *next; /* Pointer to next polygon contour */ struct p_shape *proxy; /* Pointer to actual structure used */ } polygon_node; typedef struct edge_shape { gpc_vertex vertex; /* Piggy-backed contour vertex data */ gpc_vertex bot; /* Edge lower (x, y) coordinate */ gpc_vertex top; /* Edge upper (x, y) coordinate */ double xb; /* Scanbeam bottom x coordinate */ double xt; /* Scanbeam top x coordinate */ double dx; /* Change in x for a unit y increase */ int type; /* Clip / subject edge flag */ int bundle[2][2]; /* Bundle edge flags */ int bside[2]; /* Bundle left / right indicators */ bundle_state bstate[2]; /* Edge bundle state */ polygon_node *outp[2]; /* Output polygon / tristrip pointer */ struct edge_shape *prev; /* Previous edge in the AET */ struct edge_shape *next; /* Next edge in the AET */ struct edge_shape *pred; /* Edge connected at the lower end */ struct edge_shape *succ; /* Edge connected at the upper end */ struct edge_shape *next_bound; /* Pointer to next bound in LMT */ } edge_node; typedef struct lmt_shape /* Local minima table */ { double y; /* Y coordinate at local minimum */ edge_node *first_bound; /* Pointer to bound list */ struct lmt_shape *next; /* Pointer to next local minimum */ } lmt_node; typedef struct sbt_t_shape /* Scanbeam tree */ { double y; /* Scanbeam node y value */ struct sbt_t_shape *less; /* Pointer to nodes with lower y */ struct sbt_t_shape *more; /* Pointer to nodes with higher y */ } sb_tree; typedef struct it_shape /* Intersection table */ { edge_node *ie[2]; /* Intersecting edge (bundle) pair */ gpc_vertex point; /* Point of intersection */ struct it_shape *next; /* The next intersection table node */ } it_node; typedef struct st_shape /* Sorted edge table */ { edge_node *edge; /* Pointer to AET edge */ double xb; /* Scanbeam bottom x coordinate */ double xt; /* Scanbeam top x coordinate */ double dx; /* Change in x for a unit y increase */ struct st_shape *prev; /* Previous edge in sorted list */ } st_node; typedef struct bbox_shape /* Contour axis-aligned bounding box */ { double xmin; /* Minimum x coordinate */ double ymin; /* Minimum y coordinate */ double xmax; /* Maximum x coordinate */ double ymax; /* Maximum y coordinate */ } bbox; /* ########################################################################### Global Data ########################################################################### */ /* Horizontal edge state transitions within scanbeam boundary */ const h_state next_h_state[3][6]= { /* ABOVE BELOW CROSS */ /* L R L R L R */ /* NH */ {BH, TH, TH, BH, NH, NH}, /* BH */ {NH, NH, NH, NH, TH, TH}, /* TH */ {NH, NH, NH, NH, BH, BH} }; /* ########################################################################### Private Functions ########################################################################### */ static void reset_it(it_node **it) { it_node *itn; while (*it) { itn= (*it)->next; FREE(*it); *it= itn; } } static void reset_lmt(lmt_node **lmt) { lmt_node *lmtn; while (*lmt) { lmtn= (*lmt)->next; FREE(*lmt); *lmt= lmtn; } } static void insert_bound(edge_node **b, edge_node *e) { edge_node *existing_bound; if (!*b) { /* Link node e to the tail of the list */ *b= e; } else { /* Do primary sort on the x field */ if (e[0].bot.x < (*b)[0].bot.x) { /* Insert a new node mid-list */ existing_bound= *b; *b= e; (*b)->next_bound= existing_bound; } else { if (e[0].bot.x == (*b)[0].bot.x) { /* Do secondary sort on the dx field */ if (e[0].dx < (*b)[0].dx) { /* Insert a new node mid-list */ existing_bound= *b; *b= e; (*b)->next_bound= existing_bound; } else { /* Head further down the list */ insert_bound(&((*b)->next_bound), e); } } else { /* Head further down the list */ insert_bound(&((*b)->next_bound), e); } } } } static edge_node **bound_list(lmt_node **lmt, double y) { lmt_node *existing_node; if (!*lmt) { /* Add node onto the tail end of the LMT */ CMALLOC(*lmt, sizeof(lmt_node), "LMT insertion"); /* CBSTEH */ (*lmt)->y= y; (*lmt)->first_bound= NULL; (*lmt)->next= NULL; return &((*lmt)->first_bound); } else if (y < (*lmt)->y) { /* Insert a new LMT node before the current node */ existing_node= *lmt; CMALLOC(*lmt, sizeof(lmt_node), "LMT insertion"); /* CBSTEH */ (*lmt)->y= y; (*lmt)->first_bound= NULL; (*lmt)->next= existing_node; return &((*lmt)->first_bound); } else if (y > (*lmt)->y) /* Head further up the LMT */ return bound_list(&((*lmt)->next), y); else /* Use this existing LMT node */ return &((*lmt)->first_bound); } static void add_to_sbtree(int *entries, sb_tree **sbtree, double y) { if (!*sbtree) { /* Add a new tree node here */ CMALLOC(*sbtree, sizeof(sb_tree), "scanbeam tree insertion"); /* CBSTEH */ (*sbtree)->y= y; (*sbtree)->less= NULL; (*sbtree)->more= NULL; (*entries)++; } else { if ((*sbtree)->y > y) { /* Head into the 'less' sub-tree */ add_to_sbtree(entries, &((*sbtree)->less), y); } else { if ((*sbtree)->y < y) { /* Head into the 'more' sub-tree */ add_to_sbtree(entries, &((*sbtree)->more), y); } } } } static void build_sbt(int *entries, double *sbt, sb_tree *sbtree) { if (sbtree->less) build_sbt(entries, sbt, sbtree->less); sbt[*entries]= sbtree->y; (*entries)++; if (sbtree->more) build_sbt(entries, sbt, sbtree->more); } static void free_sbtree(sb_tree **sbtree) { if (*sbtree) { free_sbtree(&((*sbtree)->less)); free_sbtree(&((*sbtree)->more)); FREE(*sbtree); } } static int count_optimal_vertices(gpc_vertex_list c) { int result= 0, i; /* Ignore non-contributing contours */ if (c.num_vertices > 0) { for (i= 0; i < c.num_vertices; i++) /* Ignore superfluous vertices embedded in horizontal edges */ if (OPTIMAL(c.vertex, i, c.num_vertices)) result++; } return result; } static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree, int *sbt_entries, gpc_polygon *p, int type, gpc_op op) { int c, i, min, max, num_edges, v, num_vertices; int total_vertices= 0, e_index=0; edge_node *e, *edge_table; for (c= 0; c < p->num_contours; c++) total_vertices+= count_optimal_vertices(p->contour[c]); /* Create the entire input polygon edge table in one go */ MALLOC(edge_table, total_vertices * sizeof(edge_node), "edge table creation"); for (c= 0; c < p->num_contours; c++) { if (p->contour[c].num_vertices < 0) { /* Ignore the non-contributing contour and repair the vertex count */ p->contour[c].num_vertices= -p->contour[c].num_vertices; } else { /* Perform contour optimisation */ num_vertices= 0; for (i= 0; i < p->contour[c].num_vertices; i++) if (OPTIMAL(p->contour[c].vertex, i, p->contour[c].num_vertices)) { edge_table[num_vertices].vertex.x= p->contour[c].vertex[i].x; edge_table[num_vertices].vertex.y= p->contour[c].vertex[i].y; /* Record vertex in the scanbeam table */ add_to_sbtree(sbt_entries, sbtree, edge_table[num_vertices].vertex.y); num_vertices++; } /* Do the contour forward pass */ for (min= 0; min < num_vertices; min++) { /* If a forward local minimum... */ if (FWD_MIN(edge_table, min, num_vertices)) { /* Search for the next local maximum... */ num_edges= 1; max= NEXT_INDEX(min, num_vertices); while (NOT_FMAX(edge_table, max, num_vertices)) { num_edges++; max= NEXT_INDEX(max, num_vertices); } /* Build the next edge list */ e= &edge_table[e_index]; e_index+= num_edges; v= min; e[0].bstate[BELOW]= UNBUNDLED; e[0].bundle[BELOW][CLIP]= FALSE; e[0].bundle[BELOW][SUBJ]= FALSE; for (i= 0; i < num_edges; i++) { e[i].xb= edge_table[v].vertex.x; e[i].bot.x= edge_table[v].vertex.x; e[i].bot.y= edge_table[v].vertex.y; v= NEXT_INDEX(v, num_vertices); e[i].top.x= edge_table[v].vertex.x; e[i].top.y= edge_table[v].vertex.y; e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / (e[i].top.y - e[i].bot.y); e[i].type= type; e[i].outp[ABOVE]= NULL; e[i].outp[BELOW]= NULL; e[i].next= NULL; e[i].prev= NULL; e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? &(e[i + 1]) : NULL; e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; e[i].next_bound= NULL; e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; e[i].bside[SUBJ]= LEFT; } insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); } } /* Do the contour reverse pass */ for (min= 0; min < num_vertices; min++) { /* If a reverse local minimum... */ if (REV_MIN(edge_table, min, num_vertices)) { /* Search for the previous local maximum... */ num_edges= 1; max= PREV_INDEX(min, num_vertices); while (NOT_RMAX(edge_table, max, num_vertices)) { num_edges++; max= PREV_INDEX(max, num_vertices); } /* Build the previous edge list */ e= &edge_table[e_index]; e_index+= num_edges; v= min; e[0].bstate[BELOW]= UNBUNDLED; e[0].bundle[BELOW][CLIP]= FALSE; e[0].bundle[BELOW][SUBJ]= FALSE; for (i= 0; i < num_edges; i++) { e[i].xb= edge_table[v].vertex.x; e[i].bot.x= edge_table[v].vertex.x; e[i].bot.y= edge_table[v].vertex.y; v= PREV_INDEX(v, num_vertices); e[i].top.x= edge_table[v].vertex.x; e[i].top.y= edge_table[v].vertex.y; e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / (e[i].top.y - e[i].bot.y); e[i].type= type; e[i].outp[ABOVE]= NULL; e[i].outp[BELOW]= NULL; e[i].next= NULL; e[i].prev= NULL; e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? &(e[i + 1]) : NULL; e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; e[i].next_bound= NULL; e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; e[i].bside[SUBJ]= LEFT; } insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); } } } } return edge_table; } static void add_edge_to_aet(edge_node **aet, edge_node *edge, edge_node *prev) { if (!*aet) { /* Append edge onto the tail end of the AET */ *aet= edge; edge->prev= prev; edge->next= NULL; } else { /* Do primary sort on the xb field */ if (edge->xb < (*aet)->xb) { /* Insert edge here (before the AET edge) */ edge->prev= prev; edge->next= *aet; (*aet)->prev= edge; *aet= edge; } else { if (edge->xb == (*aet)->xb) { /* Do secondary sort on the dx field */ if (edge->dx < (*aet)->dx) { /* Insert edge here (before the AET edge) */ edge->prev= prev; edge->next= *aet; (*aet)->prev= edge; *aet= edge; } else { /* Head further into the AET */ add_edge_to_aet(&((*aet)->next), edge, *aet); } } else { /* Head further into the AET */ add_edge_to_aet(&((*aet)->next), edge, *aet); } } } } static void add_intersection(it_node **it, edge_node *edge0, edge_node *edge1, double x, double y) { it_node *existing_node; if (!*it) { /* Append a new node to the tail of the list */ CMALLOC(*it, sizeof(it_node), "IT insertion"); /* CBSTEH */ (*it)->ie[0]= edge0; (*it)->ie[1]= edge1; (*it)->point.x= x; (*it)->point.y= y; (*it)->next= NULL; } else { if ((*it)->point.y > y) { /* Insert a new node mid-list */ existing_node= *it; CMALLOC(*it, sizeof(it_node), "IT insertion"); /* CBSTEH */ (*it)->ie[0]= edge0; (*it)->ie[1]= edge1; (*it)->point.x= x; (*it)->point.y= y; (*it)->next= existing_node; } else /* Head further down the list */ add_intersection(&((*it)->next), edge0, edge1, x, y); } } static void add_st_edge(st_node **st, it_node **it, edge_node *edge, double dy) { st_node *existing_node; double den, r, x, y; if (!*st) { /* Append edge onto the tail end of the ST */ CMALLOC(*st, sizeof(st_node), "ST insertion"); /* CBSTEH */ (*st)->edge= edge; (*st)->xb= edge->xb; (*st)->xt= edge->xt; (*st)->dx= edge->dx; (*st)->prev= NULL; } else { den= ((*st)->xt - (*st)->xb) - (edge->xt - edge->xb); /* If new edge and ST edge don't cross */ if ((edge->xt >= (*st)->xt) || (edge->dx == (*st)->dx) || (fabs(den) <= DBL_EPSILON)) { /* No intersection - insert edge here (before the ST edge) */ existing_node= *st; CMALLOC(*st, sizeof(st_node), "ST insertion"); /* CBSTEH */ (*st)->edge= edge; (*st)->xb= edge->xb; (*st)->xt= edge->xt; (*st)->dx= edge->dx; (*st)->prev= existing_node; } else { /* Compute intersection between new edge and ST edge */ r= (edge->xb - (*st)->xb) / den; x= (*st)->xb + r * ((*st)->xt - (*st)->xb); y= r * dy; /* Insert the edge pointers and the intersection point in the IT */ add_intersection(it, (*st)->edge, edge, x, y); /* Head further into the ST */ add_st_edge(&((*st)->prev), it, edge, dy); } } } static void build_intersection_table(it_node **it, edge_node *aet, double dy) { st_node *st, *stp; edge_node *edge; /* Build intersection table for the current scanbeam */ reset_it(it); st= NULL; /* Process each AET edge */ for (edge= aet; edge; edge= edge->next) { if ((edge->bstate[ABOVE] == BUNDLE_HEAD) || edge->bundle[ABOVE][CLIP] || edge->bundle[ABOVE][SUBJ]) add_st_edge(&st, it, edge, dy); } /* Free the sorted edge table */ while (st) { stp= st->prev; FREE(st); st= stp; } } static int count_contours(polygon_node *polygon) { int nc, nv; vertex_node *v, *nextv; for (nc= 0; polygon; polygon= polygon->next) if (polygon->active) { /* Count the vertices in the current contour */ nv= 0; for (v= polygon->proxy->v[LEFT]; v; v= v->next) nv++; /* Record valid vertex counts in the active field */ if (nv > 2) { polygon->active= nv; nc++; } else { /* Invalid contour: just free the heap */ for (v= polygon->proxy->v[LEFT]; v; v= nextv) { nextv= v->next; CFREE(v); /* CBSTEH */ } polygon->active= 0; } } return nc; } static void add_left(polygon_node *p, double x, double y) { vertex_node *nv; /* Create a new vertex node and set its fields */ CMALLOC(nv, sizeof(vertex_node), "vertex node creation"); /* CBSTEH */ nv->x= x; nv->y= y; /* Add vertex nv to the left end of the polygon's vertex list */ nv->next= p->proxy->v[LEFT]; /* Update proxy->[LEFT] to point to nv */ p->proxy->v[LEFT]= nv; } static void merge_left(polygon_node *p, polygon_node *q, polygon_node *list) { polygon_node *target; /* Label contour as a hole */ q->proxy->hole= TRUE; if (p->proxy != q->proxy) { /* Assign p's vertex list to the left end of q's list */ p->proxy->v[RIGHT]->next= q->proxy->v[LEFT]; q->proxy->v[LEFT]= p->proxy->v[LEFT]; /* Redirect any p->proxy references to q->proxy */ for (target= p->proxy; list; list= list->next) { if (list->proxy == target) { list->active= FALSE; list->proxy= q->proxy; } } } } static void add_right(polygon_node *p, double x, double y) { vertex_node *nv; /* Create a new vertex node and set its fields */ CMALLOC(nv, sizeof(vertex_node), "vertex node creation"); /* CBSTEH */ nv->x= x; nv->y= y; nv->next= NULL; /* Add vertex nv to the right end of the polygon's vertex list */ p->proxy->v[RIGHT]->next= nv; /* Update proxy->v[RIGHT] to point to nv */ p->proxy->v[RIGHT]= nv; } static void merge_right(polygon_node *p, polygon_node *q, polygon_node *list) { polygon_node *target; /* Label contour as external */ q->proxy->hole= FALSE; if (p->proxy != q->proxy) { /* Assign p's vertex list to the right end of q's list */ q->proxy->v[RIGHT]->next= p->proxy->v[LEFT]; q->proxy->v[RIGHT]= p->proxy->v[RIGHT]; /* Redirect any p->proxy references to q->proxy */ for (target= p->proxy; list; list= list->next) { if (list->proxy == target) { list->active= FALSE; list->proxy= q->proxy; } } } } static void add_local_min(polygon_node **p, edge_node *edge, double x, double y) { polygon_node *existing_min; vertex_node *nv; existing_min= *p; CMALLOC(*p, sizeof(polygon_node), "polygon node creation"); /* CBSTEH */ /* Create a new vertex node and set its fields */ CMALLOC(nv, sizeof(vertex_node), "vertex node creation"); /* CBSTEH */ nv->x= x; nv->y= y; nv->next= NULL; /* Initialise proxy to point to p itself */ (*p)->proxy= (*p); (*p)->active= TRUE; (*p)->next= existing_min; /* Make v[LEFT] and v[RIGHT] point to new vertex nv */ (*p)->v[LEFT]= nv; (*p)->v[RIGHT]= nv; /* Assign polygon p to the edge */ edge->outp[ABOVE]= *p; } static int count_tristrips(polygon_node *tn) { int total; for (total= 0; tn; tn= tn->next) if (tn->active > 2) total++; return total; } static void add_vertex(vertex_node **t, double x, double y) { if (!(*t)) { CMALLOC(*t, sizeof(vertex_node), "tristrip vertex creation"); /* CBSTEH */ (*t)->x= x; (*t)->y= y; (*t)->next= NULL; } else /* Head further down the list */ add_vertex(&((*t)->next), x, y); } static void new_tristrip(polygon_node **tn, edge_node *edge, double x, double y) { if (!(*tn)) { CMALLOC(*tn, sizeof(polygon_node), "tristrip node creation"); /* CBSTEH */ (*tn)->next= NULL; (*tn)->v[LEFT]= NULL; (*tn)->v[RIGHT]= NULL; (*tn)->active= 1; add_vertex(&((*tn)->v[LEFT]), x, y); edge->outp[ABOVE]= *tn; } else /* Head further down the list */ new_tristrip(&((*tn)->next), edge, x, y); } static bbox *create_contour_bboxes(gpc_polygon *p) { bbox *box; int c, v; MALLOC(box, p->num_contours * sizeof(bbox), "Bounding box creation"); /* Construct contour bounding boxes */ for (c= 0; c < p->num_contours; c++) { /* Initialise bounding box extent */ box[c].xmin= DBL_MAX; box[c].ymin= DBL_MAX; box[c].xmax= -DBL_MAX; box[c].ymax= -DBL_MAX; for (v= 0; v < p->contour[c].num_vertices; v++) { /* Adjust bounding box */ if (p->contour[c].vertex[v].x < box[c].xmin) box[c].xmin= p->contour[c].vertex[v].x; if (p->contour[c].vertex[v].y < box[c].ymin) box[c].ymin= p->contour[c].vertex[v].y; if (p->contour[c].vertex[v].x > box[c].xmax) box[c].xmax= p->contour[c].vertex[v].x; if (p->contour[c].vertex[v].y > box[c].ymax) box[c].ymax= p->contour[c].vertex[v].y; } } return box; } static void minimax_test(gpc_polygon *subj, gpc_polygon *clip, gpc_op op) { bbox *s_bbox, *c_bbox; int s, c, *o_table, overlap; s_bbox= create_contour_bboxes(subj); c_bbox= create_contour_bboxes(clip); MALLOC(o_table, subj->num_contours * clip->num_contours * sizeof(int), "overlap table creation"); /* Check all subject contour bounding boxes against clip boxes */ for (s= 0; s < subj->num_contours; s++) for (c= 0; c < clip->num_contours; c++) o_table[c * subj->num_contours + s]= (!((s_bbox[s].xmax < c_bbox[c].xmin) || (s_bbox[s].xmin > c_bbox[c].xmax))) && (!((s_bbox[s].ymax < c_bbox[c].ymin) || (s_bbox[s].ymin > c_bbox[c].ymax))); /* For each clip contour, search for any subject contour overlaps */ for (c= 0; c < clip->num_contours; c++) { overlap= 0; for (s= 0; (!overlap) && (s < subj->num_contours); s++) overlap= o_table[c * subj->num_contours + s]; if (!overlap) /* Flag non contributing status by negating vertex count */ clip->contour[c].num_vertices = -clip->contour[c].num_vertices; } if (op == GPC_INT) { /* For each subject contour, search for any clip contour overlaps */ for (s= 0; s < subj->num_contours; s++) { overlap= 0; for (c= 0; (!overlap) && (c < clip->num_contours); c++) overlap= o_table[c * subj->num_contours + s]; if (!overlap) /* Flag non contributing status by negating vertex count */ subj->contour[s].num_vertices = -subj->contour[s].num_vertices; } } CFREE(s_bbox); /* CBSTEH */ CFREE(c_bbox); /* CBSTEH */ CFREE(o_table); /* CBSTEH */ } /* ########################################################################### Public Functions ########################################################################### */ void gpc_free_polygon(gpc_polygon *p) { int c; for (c= 0; c < p->num_contours; c++) FREE(p->contour[c].vertex); FREE(p->hole); FREE(p->contour); p->num_contours= 0; } void gpc_read_polygon(FILE *fp, int read_hole_flags, gpc_polygon *p) { int c, v; fscanf(fp, "%d", &(p->num_contours)); MALLOC(p->hole, p->num_contours * sizeof(int), "hole flag array creation"); MALLOC(p->contour, p->num_contours * sizeof(gpc_vertex_list), "contour creation"); for (c= 0; c < p->num_contours; c++) { fscanf(fp, "%d", &(p->contour[c].num_vertices)); if (read_hole_flags) fscanf(fp, "%d", &(p->hole[c])); else p->hole[c]= FALSE; /* Assume all contours to be external */ MALLOC(p->contour[c].vertex, p->contour[c].num_vertices * sizeof(gpc_vertex), "vertex creation"); for (v= 0; v < p->contour[c].num_vertices; v++) fscanf(fp, "%lf %lf", &(p->contour[c].vertex[v].x), &(p->contour[c].vertex[v].y)); } } void gpc_write_polygon(FILE *fp, int write_hole_flags, gpc_polygon *p) { int c, v; fprintf(fp, "%d\n", p->num_contours); for (c= 0; c < p->num_contours; c++) { fprintf(fp, "%d\n", p->contour[c].num_vertices); if (write_hole_flags) fprintf(fp, "%d\n", p->hole[c]); for (v= 0; v < p->contour[c].num_vertices; v++) fprintf(fp, "% .*lf % .*lf\n", DBL_DIG, p->contour[c].vertex[v].x, DBL_DIG, p->contour[c].vertex[v].y); } } void gpc_add_contour(gpc_polygon *p, gpc_vertex_list *new_contour, int hole) { int *extended_hole, c, v; gpc_vertex_list *extended_contour; /* Create an extended hole array */ MALLOC(extended_hole, (p->num_contours + 1) * sizeof(int), "contour hole addition"); /* Create an extended contour array */ MALLOC(extended_contour, (p->num_contours + 1) * sizeof(gpc_vertex_list), "contour addition"); /* Copy the old contour and hole data into the extended arrays */ for (c= 0; c < p->num_contours; c++) { extended_hole[c]= p->hole[c]; extended_contour[c]= p->contour[c]; } /* Copy the new contour and hole onto the end of the extended arrays */ c= p->num_contours; extended_hole[c]= hole; extended_contour[c].num_vertices= new_contour->num_vertices; MALLOC(extended_contour[c].vertex, new_contour->num_vertices * sizeof(gpc_vertex), "contour addition"); for (v= 0; v < new_contour->num_vertices; v++) extended_contour[c].vertex[v]= new_contour->vertex[v]; /* Dispose of the old contour */ FREE(p->contour); FREE(p->hole); /* Update the polygon information */ p->num_contours++; p->hole= extended_hole; p->contour= extended_contour; } void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, gpc_polygon *result) { sb_tree *sbtree= NULL; it_node *it= NULL, *intersect; edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL; lmt_node *lmt= NULL, *local_min; polygon_node *out_poly= NULL, *p, *q, *poly, *npoly, *cf= NULL; vertex_node *vtx, *nv; h_state horiz[2]; int in[2], exists[2], parity[2]= {LEFT, LEFT}; int c, v, contributing, search, scanbeam= 0, sbt_entries= 0; int vclass, bl, br, tl, tr; double *sbt= NULL, xb, px, yb, yt, dy, ix, iy; /* Test for trivial NULL result cases */ if (((subj->num_contours == 0) && (clip->num_contours == 0)) || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) || ((clip->num_contours == 0) && (op == GPC_INT))) { result->num_contours= 0; result->hole= NULL; result->contour= NULL; return; } /* Identify potentialy contributing contours */ if (((op == GPC_INT) || (op == GPC_DIFF)) && (subj->num_contours > 0) && (clip->num_contours > 0)) minimax_test(subj, clip, op); /* Build LMT */ if (subj->num_contours > 0) s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); if (clip->num_contours > 0) c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); /* Return a NULL result if no contours contribute */ if (lmt == NULL) { result->num_contours= 0; result->hole= NULL; result->contour= NULL; reset_lmt(&lmt); FREE(s_heap); FREE(c_heap); return; } /* Build scanbeam table from scanbeam tree */ MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation"); build_sbt(&scanbeam, sbt, sbtree); scanbeam= 0; free_sbtree(&sbtree); /* Allow pointer re-use without causing memory leak */ if (subj == result) gpc_free_polygon(subj); if (clip == result) gpc_free_polygon(clip); /* Invert clip polygon for difference operation */ if (op == GPC_DIFF) parity[CLIP]= RIGHT; local_min= lmt; /* Process each scanbeam */ while (scanbeam < sbt_entries) { /* Set yb and yt to the bottom and top of the scanbeam */ yb= sbt[scanbeam++]; if (scanbeam < sbt_entries) { yt= sbt[scanbeam]; dy= yt - yb; } /* ### SCANBEAM BOUNDARY PROCESSING ################################ */ /* If LMT node corresponding to yb exists */ if (local_min) { if (local_min->y == yb) { /* Add edges starting at this local minimum to the AET */ for (edge= local_min->first_bound; edge; edge= edge->next_bound) add_edge_to_aet(&aet, edge, NULL); local_min= local_min->next; } } /* Set dummy previous x value */ px= -DBL_MAX; /* Create bundles within AET */ e0= aet; /* e1= aet; */ /* CBSTEH */ /* Set up bundle fields of first edge */ aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); aet->bundle[ABOVE][!aet->type]= FALSE; aet->bstate[ABOVE]= UNBUNDLED; for (next_edge= aet->next; next_edge; next_edge= next_edge->next) { /* Set up bundle fields of next edge */ next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); next_edge->bundle[ABOVE][!next_edge->type]= FALSE; next_edge->bstate[ABOVE]= UNBUNDLED; /* Bundle edges above the scanbeam boundary if they coincide */ if (next_edge->bundle[ABOVE][next_edge->type]) { if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) && (e0->top.y != yb)) { next_edge->bundle[ABOVE][ next_edge->type]^= e0->bundle[ABOVE][ next_edge->type]; next_edge->bundle[ABOVE][!next_edge->type]= e0->bundle[ABOVE][!next_edge->type]; next_edge->bstate[ABOVE]= BUNDLE_HEAD; e0->bundle[ABOVE][CLIP]= FALSE; e0->bundle[ABOVE][SUBJ]= FALSE; e0->bstate[ABOVE]= BUNDLE_TAIL; } e0= next_edge; } } horiz[CLIP]= NH; horiz[SUBJ]= NH; /* Process each edge at this scanbeam boundary */ for (edge= aet; edge; edge= edge->next) { exists[CLIP]= edge->bundle[ABOVE][CLIP] + (edge->bundle[BELOW][CLIP] << 1); exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + (edge->bundle[BELOW][SUBJ] << 1); if (exists[CLIP] || exists[SUBJ]) { /* Set bundle side */ edge->bside[CLIP]= parity[CLIP]; edge->bside[SUBJ]= parity[SUBJ]; /* Determine contributing status and quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) && (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_XOR: contributing= exists[CLIP] || exists[SUBJ]; br= (parity[CLIP]) ^ (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_UNION: contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) || (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; } /* Update parity */ parity[CLIP]^= edge->bundle[ABOVE][CLIP]; parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; /* Update horizontal state */ if (exists[CLIP]) horiz[CLIP]= next_h_state[horiz[CLIP]] [((exists[CLIP] - 1) << 1) + parity[CLIP]]; if (exists[SUBJ]) horiz[SUBJ]= next_h_state[horiz[SUBJ]] [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; vclass= tr + (tl << 1) + (br << 2) + (bl << 3); if (contributing) { xb= edge->xb; switch (vclass) { case EMN: case IMN: add_local_min(&out_poly, edge, xb, yb); px= xb; cf= edge->outp[ABOVE]; break; case ERI: if (xb != px) { add_right(cf, xb, yb); px= xb; } edge->outp[ABOVE]= cf; cf= NULL; break; case ELI: add_left(edge->outp[BELOW], xb, yb); px= xb; cf= edge->outp[BELOW]; break; case EMX: if (xb != px) { add_left(cf, xb, yb); px= xb; } merge_right(cf, edge->outp[BELOW], out_poly); cf= NULL; break; case ILI: if (xb != px) { add_left(cf, xb, yb); px= xb; } edge->outp[ABOVE]= cf; cf= NULL; break; case IRI: add_right(edge->outp[BELOW], xb, yb); px= xb; cf= edge->outp[BELOW]; edge->outp[BELOW]= NULL; break; case IMX: if (xb != px) { add_right(cf, xb, yb); px= xb; } merge_left(cf, edge->outp[BELOW], out_poly); cf= NULL; edge->outp[BELOW]= NULL; break; case IMM: if (xb != px) { add_right(cf, xb, yb); px= xb; } merge_left(cf, edge->outp[BELOW], out_poly); edge->outp[BELOW]= NULL; add_local_min(&out_poly, edge, xb, yb); cf= edge->outp[ABOVE]; break; case EMM: if (xb != px) { add_left(cf, xb, yb); px= xb; } merge_right(cf, edge->outp[BELOW], out_poly); edge->outp[BELOW]= NULL; add_local_min(&out_poly, edge, xb, yb); cf= edge->outp[ABOVE]; break; case LED: if (edge->bot.y == yb) add_left(edge->outp[BELOW], xb, yb); edge->outp[ABOVE]= edge->outp[BELOW]; px= xb; break; case RED: if (edge->bot.y == yb) add_right(edge->outp[BELOW], xb, yb); edge->outp[ABOVE]= edge->outp[BELOW]; px= xb; break; default: break; } /* End of switch */ } /* End of contributing conditional */ } /* End of edge exists conditional */ } /* End of AET loop */ /* Delete terminating edges from the AET, otherwise compute xt */ for (edge= aet; edge; edge= edge->next) { if (edge->top.y == yb) { prev_edge= edge->prev; next_edge= edge->next; if (prev_edge) prev_edge->next= next_edge; else aet= next_edge; if (next_edge) next_edge->prev= prev_edge; /* Copy bundle head state to the adjacent tail edge if required */ if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) { if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) { prev_edge->outp[BELOW]= edge->outp[BELOW]; prev_edge->bstate[BELOW]= UNBUNDLED; if (prev_edge->prev) if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) prev_edge->bstate[BELOW]= BUNDLE_HEAD; } } } else { if (edge->top.y == yt) edge->xt= edge->top.x; else edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); } } if (scanbeam < sbt_entries) { /* ### SCANBEAM INTERIOR PROCESSING ############################## */ build_intersection_table(&it, aet, dy); /* Process each node in the intersection table */ for (intersect= it; intersect; intersect= intersect->next) { e0= intersect->ie[0]; e1= intersect->ie[1]; /* Only generate output for contributing intersections */ if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) { p= e0->outp[ABOVE]; q= e1->outp[ABOVE]; ix= intersect->point.x; iy= intersect->point.y + yb; in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] && e0->bside[CLIP] && e1->bside[CLIP]); in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] && e0->bside[SUBJ] && e1->bside[SUBJ]); /* Determine quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: tr= (in[CLIP]) && (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_XOR: tr= (in[CLIP]) ^ (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_UNION: tr= (in[CLIP]) || (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; } vclass= tr + (tl << 1) + (br << 2) + (bl << 3); switch (vclass) { case EMN: add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; break; case ERI: if (p) { add_right(p, ix, iy); e1->outp[ABOVE]= p; e0->outp[ABOVE]= NULL; } break; case ELI: if (q) { add_left(q, ix, iy); e0->outp[ABOVE]= q; e1->outp[ABOVE]= NULL; } break; case EMX: if (p && q) { add_left(p, ix, iy); merge_right(p, q, out_poly); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; } break; case IMN: add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; break; case ILI: if (p) { add_left(p, ix, iy); e1->outp[ABOVE]= p; e0->outp[ABOVE]= NULL; } break; case IRI: if (q) { add_right(q, ix, iy); e0->outp[ABOVE]= q; e1->outp[ABOVE]= NULL; } break; case IMX: if (p && q) { add_right(p, ix, iy); merge_left(p, q, out_poly); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; } break; case IMM: if (p && q) { add_right(p, ix, iy); merge_left(p, q, out_poly); add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; } break; case EMM: if (p && q) { add_left(p, ix, iy); merge_right(p, q, out_poly); add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; } break; default: break; } /* End of switch */ } /* End of contributing intersection conditional */ /* Swap bundle sides in response to edge crossing */ if (e0->bundle[ABOVE][CLIP]) e1->bside[CLIP]= !e1->bside[CLIP]; if (e1->bundle[ABOVE][CLIP]) e0->bside[CLIP]= !e0->bside[CLIP]; if (e0->bundle[ABOVE][SUBJ]) e1->bside[SUBJ]= !e1->bside[SUBJ]; if (e1->bundle[ABOVE][SUBJ]) e0->bside[SUBJ]= !e0->bside[SUBJ]; /* Swap e0 and e1 bundles in the AET */ prev_edge= e0->prev; next_edge= e1->next; if (next_edge) next_edge->prev= e0; if (e0->bstate[ABOVE] == BUNDLE_HEAD) { search= TRUE; while (search) { prev_edge= prev_edge->prev; if (prev_edge) { if (prev_edge->bstate[ABOVE] != BUNDLE_TAIL) search= FALSE; } else search= FALSE; } } if (!prev_edge) { aet->prev= e1; e1->next= aet; aet= e0->next; } else { prev_edge->next->prev= e1; e1->next= prev_edge->next; prev_edge->next= e0->next; } e0->next->prev= prev_edge; e1->next->prev= e1; e0->next= next_edge; } /* End of IT loop*/ /* Prepare for next scanbeam */ for (edge= aet; edge; edge= next_edge) { next_edge= edge->next; succ_edge= edge->succ; if ((edge->top.y == yt) && succ_edge) { /* Replace AET edge by its successor */ succ_edge->outp[BELOW]= edge->outp[ABOVE]; succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; prev_edge= edge->prev; if (prev_edge) prev_edge->next= succ_edge; else aet= succ_edge; if (next_edge) next_edge->prev= succ_edge; succ_edge->prev= prev_edge; succ_edge->next= next_edge; } else { /* Update this edge */ edge->outp[BELOW]= edge->outp[ABOVE]; edge->bstate[BELOW]= edge->bstate[ABOVE]; edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; edge->xb= edge->xt; } edge->outp[ABOVE]= NULL; } } } /* ### END OF SCANBEAM PROCESSING ################################## */ /* Generate result polygon from out_poly */ result->contour= NULL; result->hole= NULL; result->num_contours= count_contours(out_poly); if (result->num_contours > 0) { MALLOC(result->hole, result->num_contours * sizeof(int), "hole flag table creation"); MALLOC(result->contour, result->num_contours * sizeof(gpc_vertex_list), "contour creation"); c= 0; for (poly= out_poly; poly; poly= npoly) { npoly= poly->next; if (poly->active) { result->hole[c]= poly->proxy->hole; result->contour[c].num_vertices= poly->active; MALLOC(result->contour[c].vertex, result->contour[c].num_vertices * sizeof(gpc_vertex), "vertex creation"); v= result->contour[c].num_vertices - 1; for (vtx= poly->proxy->v[LEFT]; vtx; vtx= nv) { nv= vtx->next; result->contour[c].vertex[v].x= vtx->x; result->contour[c].vertex[v].y= vtx->y; CFREE(vtx); /* CBSTEH */ v--; } c++; } CFREE(poly); /* CBSTEH */ } } /* Tidy up */ reset_it(&it); reset_lmt(&lmt); FREE(c_heap); FREE(s_heap); FREE(sbt); } void gpc_free_tristrip(gpc_tristrip *t) { int s; for (s= 0; s < t->num_strips; s++) FREE(t->strip[s].vertex); FREE(t->strip); t->num_strips= 0; } void gpc_polygon_to_tristrip(gpc_polygon *s, gpc_tristrip *t) { gpc_polygon c; c.num_contours= 0; c.hole= NULL; c.contour= NULL; gpc_tristrip_clip(GPC_DIFF, s, &c, t); } void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, gpc_tristrip *result) { sb_tree *sbtree= NULL; it_node *it= NULL, *intersect; edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL, *cf; lmt_node *lmt= NULL, *local_min; polygon_node *tlist= NULL, *tn, *tnn, *p, *q; vertex_node *lt, *ltn, *rt, *rtn; h_state horiz[2]; vertex_type cft = NUL; /* CBSTEH: initialise! */ int in[2], exists[2], parity[2]= {LEFT, LEFT}; int s, v, contributing, search, scanbeam= 0, sbt_entries= 0; int vclass, bl, br, tl, tr; double *sbt= NULL, xb, px, nx, yb, yt, dy, ix, iy; int bInvert_TriStrips = INVERT_TRISTRIPS; /* CBSTEH: added to avoid compiler warnings */ /* Test for trivial NULL result cases */ if (((subj->num_contours == 0) && (clip->num_contours == 0)) || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) || ((clip->num_contours == 0) && (op == GPC_INT))) { result->num_strips= 0; result->strip= NULL; return; } /* Identify potentialy contributing contours */ if (((op == GPC_INT) || (op == GPC_DIFF)) && (subj->num_contours > 0) && (clip->num_contours > 0)) minimax_test(subj, clip, op); /* Build LMT */ if (subj->num_contours > 0) s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); if (clip->num_contours > 0) c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); /* Return a NULL result if no contours contribute */ if (lmt == NULL) { result->num_strips= 0; result->strip= NULL; reset_lmt(&lmt); FREE(s_heap); FREE(c_heap); return; } /* Build scanbeam table from scanbeam tree */ MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation"); build_sbt(&scanbeam, sbt, sbtree); scanbeam= 0; free_sbtree(&sbtree); /* Invert clip polygon for difference operation */ if (op == GPC_DIFF) parity[CLIP]= RIGHT; local_min= lmt; /* Process each scanbeam */ while (scanbeam < sbt_entries) { /* Set yb and yt to the bottom and top of the scanbeam */ yb= sbt[scanbeam++]; if (scanbeam < sbt_entries) { yt= sbt[scanbeam]; dy= yt - yb; } /* ### SCANBEAM BOUNDARY PROCESSING ################################ */ /* If LMT node corresponding to yb exists */ if (local_min) { if (local_min->y == yb) { /* Add edges starting at this local minimum to the AET */ for (edge= local_min->first_bound; edge; edge= edge->next_bound) add_edge_to_aet(&aet, edge, NULL); local_min= local_min->next; } } /* Set dummy previous x value */ px= -DBL_MAX; /* Create bundles within AET */ e0= aet; /* e1= aet; */ /* CBSTEH */ /* Set up bundle fields of first edge */ aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); aet->bundle[ABOVE][!aet->type]= FALSE; aet->bstate[ABOVE]= UNBUNDLED; for (next_edge= aet->next; next_edge; next_edge= next_edge->next) { /* Set up bundle fields of next edge */ next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); next_edge->bundle[ABOVE][!next_edge->type]= FALSE; next_edge->bstate[ABOVE]= UNBUNDLED; /* Bundle edges above the scanbeam boundary if they coincide */ if (next_edge->bundle[ABOVE][next_edge->type]) { if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) && (e0->top.y != yb)) { next_edge->bundle[ABOVE][ next_edge->type]^= e0->bundle[ABOVE][ next_edge->type]; next_edge->bundle[ABOVE][!next_edge->type]= e0->bundle[ABOVE][!next_edge->type]; next_edge->bstate[ABOVE]= BUNDLE_HEAD; e0->bundle[ABOVE][CLIP]= FALSE; e0->bundle[ABOVE][SUBJ]= FALSE; e0->bstate[ABOVE]= BUNDLE_TAIL; } e0= next_edge; } } horiz[CLIP]= NH; horiz[SUBJ]= NH; /* Process each edge at this scanbeam boundary */ for (edge= aet; edge; edge= edge->next) { exists[CLIP]= edge->bundle[ABOVE][CLIP] + (edge->bundle[BELOW][CLIP] << 1); exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + (edge->bundle[BELOW][SUBJ] << 1); if (exists[CLIP] || exists[SUBJ]) { /* Set bundle side */ edge->bside[CLIP]= parity[CLIP]; edge->bside[SUBJ]= parity[SUBJ]; /* Determine contributing status and quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) && (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_XOR: contributing= exists[CLIP] || exists[SUBJ]; br= (parity[CLIP]) ^ (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_UNION: contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) || (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; } /* Update parity */ parity[CLIP]^= edge->bundle[ABOVE][CLIP]; parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; /* Update horizontal state */ if (exists[CLIP]) horiz[CLIP]= next_h_state[horiz[CLIP]] [((exists[CLIP] - 1) << 1) + parity[CLIP]]; if (exists[SUBJ]) horiz[SUBJ]= next_h_state[horiz[SUBJ]] [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; vclass= tr + (tl << 1) + (br << 2) + (bl << 3); if (contributing) { xb= edge->xb; switch (vclass) { case EMN: new_tristrip(&tlist, edge, xb, yb); cf= edge; break; case ERI: edge->outp[ABOVE]= cf->outp[ABOVE]; if (xb != cf->xb) VERTEX(edge, ABOVE, RIGHT, xb, yb); cf= NULL; break; case ELI: VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= NULL; cf= edge; break; case EMX: if (xb != cf->xb) VERTEX(edge, BELOW, RIGHT, xb, yb); edge->outp[ABOVE]= NULL; cf= NULL; break; case IMN: if (cft == LED) { if (cf->bot.y != yb) VERTEX(cf, BELOW, LEFT, cf->xb, yb); new_tristrip(&tlist, cf, cf->xb, yb); } edge->outp[ABOVE]= cf->outp[ABOVE]; VERTEX(edge, ABOVE, RIGHT, xb, yb); break; case ILI: new_tristrip(&tlist, edge, xb, yb); cf= edge; cft= ILI; break; case IRI: if (cft == LED) { if (cf->bot.y != yb) VERTEX(cf, BELOW, LEFT, cf->xb, yb); new_tristrip(&tlist, cf, cf->xb, yb); } VERTEX(edge, BELOW, RIGHT, xb, yb); edge->outp[ABOVE]= NULL; break; case IMX: VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= NULL; cft= IMX; break; case IMM: VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= cf->outp[ABOVE]; if (xb != cf->xb) VERTEX(cf, ABOVE, RIGHT, xb, yb); cf= edge; break; case EMM: VERTEX(edge, BELOW, RIGHT, xb, yb); edge->outp[ABOVE]= NULL; new_tristrip(&tlist, edge, xb, yb); cf= edge; break; case LED: if (edge->bot.y == yb) VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= edge->outp[BELOW]; cf= edge; cft= LED; break; case RED: edge->outp[ABOVE]= cf->outp[ABOVE]; if (cft == LED) { if (cf->bot.y == yb) { VERTEX(edge, BELOW, RIGHT, xb, yb); } else { if (edge->bot.y == yb) { VERTEX(cf, BELOW, LEFT, cf->xb, yb); VERTEX(edge, BELOW, RIGHT, xb, yb); } } } else { VERTEX(edge, BELOW, RIGHT, xb, yb); VERTEX(edge, ABOVE, RIGHT, xb, yb); } cf= NULL; break; default: break; } /* End of switch */ } /* End of contributing conditional */ } /* End of edge exists conditional */ } /* End of AET loop */ /* Delete terminating edges from the AET, otherwise compute xt */ for (edge= aet; edge; edge= edge->next) { if (edge->top.y == yb) { prev_edge= edge->prev; next_edge= edge->next; if (prev_edge) prev_edge->next= next_edge; else aet= next_edge; if (next_edge) next_edge->prev= prev_edge; /* Copy bundle head state to the adjacent tail edge if required */ if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) { if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) { prev_edge->outp[BELOW]= edge->outp[BELOW]; prev_edge->bstate[BELOW]= UNBUNDLED; if (prev_edge->prev) if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) prev_edge->bstate[BELOW]= BUNDLE_HEAD; } } } else { if (edge->top.y == yt) edge->xt= edge->top.x; else edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); } } if (scanbeam < sbt_entries) { /* ### SCANBEAM INTERIOR PROCESSING ############################## */ build_intersection_table(&it, aet, dy); /* Process each node in the intersection table */ for (intersect= it; intersect; intersect= intersect->next) { e0= intersect->ie[0]; e1= intersect->ie[1]; /* Only generate output for contributing intersections */ if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) { p= e0->outp[ABOVE]; q= e1->outp[ABOVE]; ix= intersect->point.x; iy= intersect->point.y + yb; in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] && e0->bside[CLIP] && e1->bside[CLIP]); in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] && e0->bside[SUBJ] && e1->bside[SUBJ]); /* Determine quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: tr= (in[CLIP]) && (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_XOR: tr= (in[CLIP]) ^ (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_UNION: tr= (in[CLIP]) || (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; } vclass= tr + (tl << 1) + (br << 2) + (bl << 3); switch (vclass) { case EMN: new_tristrip(&tlist, e1, ix, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; break; case ERI: if (p) { P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); VERTEX(e0, ABOVE, RIGHT, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; e0->outp[ABOVE]= NULL; } break; case ELI: if (q) { N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; e1->outp[ABOVE]= NULL; } break; case EMX: if (p && q) { VERTEX(e0, ABOVE, LEFT, ix, iy); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; } break; case IMN: P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); new_tristrip(&tlist, prev_edge, px, iy); e1->outp[ABOVE]= prev_edge->outp[ABOVE]; VERTEX(e1, ABOVE, RIGHT, ix, iy); new_tristrip(&tlist, e0, ix, iy); next_edge->outp[ABOVE]= e0->outp[ABOVE]; VERTEX(next_edge, ABOVE, RIGHT, nx, iy); break; case ILI: if (p) { VERTEX(e0, ABOVE, LEFT, ix, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; e0->outp[ABOVE]= NULL; } break; case IRI: if (q) { VERTEX(e1, ABOVE, RIGHT, ix, iy); P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; e1->outp[ABOVE]= NULL; } break; case IMX: if (p && q) { VERTEX(e0, ABOVE, RIGHT, ix, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); new_tristrip(&tlist, prev_edge, px, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); next_edge->outp[ABOVE]= prev_edge->outp[ABOVE]; VERTEX(next_edge, ABOVE, RIGHT, nx, iy); } break; case IMM: if (p && q) { VERTEX(e0, ABOVE, RIGHT, ix, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); new_tristrip(&tlist, prev_edge, px, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e1->outp[ABOVE]= prev_edge->outp[ABOVE]; VERTEX(e1, ABOVE, RIGHT, ix, iy); new_tristrip(&tlist, e0, ix, iy); next_edge->outp[ABOVE]= e0->outp[ABOVE]; VERTEX(next_edge, ABOVE, RIGHT, nx, iy); } break; case EMM: if (p && q) { VERTEX(e0, ABOVE, LEFT, ix, iy); new_tristrip(&tlist, e1, ix, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; } break; default: break; } /* End of switch */ } /* End of contributing intersection conditional */ /* Swap bundle sides in response to edge crossing */ if (e0->bundle[ABOVE][CLIP]) e1->bside[CLIP]= !e1->bside[CLIP]; if (e1->bundle[ABOVE][CLIP]) e0->bside[CLIP]= !e0->bside[CLIP]; if (e0->bundle[ABOVE][SUBJ]) e1->bside[SUBJ]= !e1->bside[SUBJ]; if (e1->bundle[ABOVE][SUBJ]) e0->bside[SUBJ]= !e0->bside[SUBJ]; /* Swap e0 and e1 bundles in the AET */ prev_edge= e0->prev; next_edge= e1->next; if (e1->next) e1->next->prev= e0; if (e0->bstate[ABOVE] == BUNDLE_HEAD) { search= TRUE; while (search) { prev_edge= prev_edge->prev; if (prev_edge) { if (prev_edge->bundle[ABOVE][CLIP] || prev_edge->bundle[ABOVE][SUBJ] || (prev_edge->bstate[ABOVE] == BUNDLE_HEAD)) search= FALSE; } else search= FALSE; } } if (!prev_edge) { e1->next= aet; aet= e0->next; } else { e1->next= prev_edge->next; prev_edge->next= e0->next; } e0->next->prev= prev_edge; e1->next->prev= e1; e0->next= next_edge; } /* End of IT loop*/ /* Prepare for next scanbeam */ for (edge= aet; edge; edge= next_edge) { next_edge= edge->next; succ_edge= edge->succ; if ((edge->top.y == yt) && succ_edge) { /* Replace AET edge by its successor */ succ_edge->outp[BELOW]= edge->outp[ABOVE]; succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; prev_edge= edge->prev; if (prev_edge) prev_edge->next= succ_edge; else aet= succ_edge; if (next_edge) next_edge->prev= succ_edge; succ_edge->prev= prev_edge; succ_edge->next= next_edge; } else { /* Update this edge */ edge->outp[BELOW]= edge->outp[ABOVE]; edge->bstate[BELOW]= edge->bstate[ABOVE]; edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; edge->xb= edge->xt; } edge->outp[ABOVE]= NULL; } } } /* ### END OF SCANBEAM PROCESSING ################################## */ /* Generate result tristrip from tlist */ result->strip= NULL; result->num_strips= count_tristrips(tlist); if (result->num_strips > 0) { MALLOC(result->strip, result->num_strips * sizeof(gpc_vertex_list), "tristrip list creation"); s= 0; for (tn= tlist; tn; tn= tnn) { tnn= tn->next; if (tn->active > 2) { /* Valid tristrip: copy the vertices and free the heap */ result->strip[s].num_vertices= tn->active; MALLOC(result->strip[s].vertex, tn->active * sizeof(gpc_vertex), "tristrip creation"); v= 0; if (bInvert_TriStrips /* INVERT_TRISTRIPS */) /* CBSTEH */ { lt= tn->v[RIGHT]; rt= tn->v[LEFT]; } else { lt= tn->v[LEFT]; rt= tn->v[RIGHT]; } while (lt || rt) { if (lt) { ltn= lt->next; result->strip[s].vertex[v].x= lt->x; result->strip[s].vertex[v].y= lt->y; v++; CFREE(lt); /* CBSTEH */ lt= ltn; } if (rt) { rtn= rt->next; result->strip[s].vertex[v].x= rt->x; result->strip[s].vertex[v].y= rt->y; v++; CFREE(rt); /* CBSTEH */ rt= rtn; } } s++; } else { /* Invalid tristrip: just free the heap */ for (lt= tn->v[LEFT]; lt; lt= ltn) { ltn= lt->next; CFREE(lt); /* CBSTEH */ } for (rt= tn->v[RIGHT]; rt; rt=rtn) { rtn= rt->next; CFREE(rt); /* CBSTEH */ } } CFREE(tn); /* CBSTEH */ } } /* Tidy up */ reset_it(&it); reset_lmt(&lmt); FREE(c_heap); FREE(s_heap); FREE(sbt); } /* ########################################################################### End of file: gpc.c ########################################################################### */