#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "INLINE.h" //file: Polygon/functions.c /* Copyright 2004 Eric L. Wilhelm GPL / Artistic License See Polygon.pm for details Version 0.04 */ #include "gpc.h" #include "gpc.c" /*#define DEBUG_PRINT*/ #ifdef DEBUG_PRINT #define dbg_p(x) printf x #else #define dbg_p(x) #endif SV* new (char* class); void remove_add_polygon(SV* obj, SV* pg, int hole); void DESTROY(SV* obj); int from_file(SV* obj, char* filename, int want_hole); void to_file(SV* obj, char* filename, int want_hole); SV* clip_to(SV* obj, SV* clp, char* action); void remove_add_polygon(SV* obj, SV* pg, int hole); void get_polygons(SV* obj); void pts_to_vertex_list(SV* pg, gpc_vertex_list* vl); AV* vertex_list_to_pts(gpc_vertex_list* vl); void gpc_free_polygon2(gpc_polygon *p); SV* new (char* class) { gpc_polygon* p = malloc(sizeof(gpc_polygon)); SV* obj_ref = newSViv(0); SV* obj = newSVrv(obj_ref, class); // bless it p->num_contours = 0; sv_setiv(obj, (IV)p); SvREADONLY_on(obj); return(obj_ref); } void DESTROY(SV* obj) { gpc_polygon* p = (gpc_polygon*) SvIV(SvRV(obj)); dbg_p(("running destroy for %d contours\n", p->num_contours)); if(p->num_contours > 0) { dbg_p(("free contents now\n")); gpc_free_polygon2(p); } dbg_p(("that's done now\n")); free(p); dbg_p(("p free... DESTROY complete\n")); } int from_file(SV* obj, char* filename, int want_hole) { gpc_polygon* p = (gpc_polygon*) SvIV(SvRV(obj)); FILE* sfp; dbg_p(("from %s file\n", filename)); sfp = fopen(filename, "r"); if(! sfp) { dbg_p(("file open failed\n")); return(0); } gpc_read_polygon(sfp, want_hole, p); dbg_p(("read %d contours\n", p->num_contours)); return(p->num_contours); } void to_file(SV* obj, char* filename, int want_hole) { gpc_polygon* p = (gpc_polygon*) SvIV(SvRV(obj)); FILE* ofp; ofp = fopen(filename, "w"); gpc_write_polygon(ofp, want_hole, p); } SV* clip_to(SV* obj, SV* clp, char* action) { gpc_polygon* p = (gpc_polygon*) SvIV(SvRV(obj)); HV* stash = SvSTASH(SvRV(obj)); // we need the classname to make a new object and to check on clp char * classname = HvNAME(stash); SV* result = new(classname); gpc_polygon* r = (gpc_polygon*) SvIV(SvRV(result)); gpc_op op; gpc_polygon* c; if(! sv_isobject(clp)) { croak("not an object"); } if(! sv_isa(clp, classname)) { croak("not a member of %s", classname); } c = (gpc_polygon*) SvIV(SvRV(clp)); if(! strcmp(action, "INTERSECT")) { dbg_p(("performing INTERSECT\n")); op = GPC_INT; } if(! strcmp(action, "DIFFERENCE")) { dbg_p(("performing DIFFERENCE\n")); op = GPC_DIFF; } if(! strcmp(action, "UNION")) { dbg_p(("performing UNION\n")); op = GPC_UNION; } /* FIXME: need some way to integrate this: printf("%s is not an operation". " (INTERSECT|DIFFERENCE|UNION)\n", action ); */ gpc_polygon_clip(op, p, c, r); return(result); } void remove_add_polygon(SV* obj, SV* pg, int hole) { gpc_polygon* p = (gpc_polygon*) SvIV(SvRV(obj)); dbg_p(("got my vl\n")); if(p->num_contours > 0) { gpc_vertex_list* c; MALLOC(c, sizeof(gpc_vertex_list), "addable contour creation\n"); pts_to_vertex_list(pg, c); dbg_p(("adding to existing\n")); gpc_add_contour(p, c, hole); } else { dbg_p(("adding as new\n")); MALLOC(p->hole, sizeof(int), "hole flag array\n"); dbg_p(("setting hole\n")); p->hole[0] = hole; dbg_p(("making contour\n")); MALLOC(p->contour, sizeof(gpc_vertex_list), "contour creation\n"); pts_to_vertex_list(pg, &(p->contour[0]) ); dbg_p(("got %d vertices\n", p->contour[0].num_vertices)); p->num_contours = 1; } dbg_p(("added\n")); } void get_polygons(SV* obj) { Inline_Stack_Vars; int c; gpc_polygon* p = (gpc_polygon*) SvIV(SvRV(obj)); Inline_Stack_Reset; if(p->num_contours < 1) { dbg_p(("no contours\n")); Inline_Stack_Done; return; } for(c = 0; c < p->num_contours; c++) { Inline_Stack_Push(newRV_noinc((SV*) vertex_list_to_pts(&(p->contour[c])))); } Inline_Stack_Done; } void pts_to_vertex_list(SV* pg, gpc_vertex_list* vl) { SV** psv; SV* val; AV* pt; AV* pts; I32 p; I32 num; if(!SvROK(pg)) croak("polygon must be reference\n"); pts = (AV*)SvRV(pg); num = av_len(pts) + 1; dbg_p(("going to allocate for %d pts\n", num)); MALLOC(vl->vertex, num * sizeof(gpc_vertex), "vertex creation"); vl->num_vertices = num; dbg_p(("MALLOC okay (%d vertices)\n", vl->num_vertices)); for(p = 0; p < num; p++) { psv = av_fetch(pts, p, 0); val = *psv; if(! SvROK(val)) croak("point %d not a ref", p); pt = (AV*)SvRV(val); psv = av_fetch(pt, 0, 0); val = *psv; vl->vertex[p].x = SvNV(val); psv = av_fetch(pt, 1, 0); val = *psv; vl->vertex[p].y = SvNV(val); dbg_p(("added %0.2f, %0.2f\n", vl->vertex[p].x, vl->vertex[p].y )); } dbg_p(("returning\n")); } AV* vertex_list_to_pts(gpc_vertex_list* vl) { AV* pts; AV* pt; int p; dbg_p(("%d vertices\n", vl->num_vertices)); pts = newAV(); for(p = 0; p < vl->num_vertices; p++) { pt = newAV(); av_push(pts, newRV_noinc((SV*) pt)); av_push(pt, newSVnv(vl->vertex[p].x)); av_push(pt, newSVnv(vl->vertex[p].y)); dbg_p(("point %d: %0.2f, %0.2f\n", p, vl->vertex[p].x, vl->vertex[p].y )); } return(pts); } void gpc_free_polygon2(gpc_polygon *p) { int c; for (c= 0; c < p->num_contours; c++) { dbg_p(("free contour %d\n", c)); FREE(p->contour[c].vertex); } dbg_p(("free hole\n")); FREE(p->hole); dbg_p(("free contour\n")); FREE(p->contour); p->num_contours= 0; } MODULE = Math::Geometry::Planar::GPC::Polygon PACKAGE = Math::Geometry::Planar::GPC::Polygon PREFIX = remove_ PROTOTYPES: DISABLE SV * new (class) char * class void DESTROY (obj) SV * obj PREINIT: I32* temp; PPCODE: temp = PL_markstack_ptr++; DESTROY(obj); if (PL_markstack_ptr != temp) { /* truly void, because dXSARGS not invoked */ PL_markstack_ptr = temp; XSRETURN_EMPTY; /* return empty stack */ } /* must have used dXSARGS; list context implied */ return; /* assume stack size is correct */ int from_file (obj, filename, want_hole) SV * obj char * filename int want_hole void to_file (obj, filename, want_hole) SV * obj char * filename int want_hole PREINIT: I32* temp; PPCODE: temp = PL_markstack_ptr++; to_file(obj, filename, want_hole); if (PL_markstack_ptr != temp) { /* truly void, because dXSARGS not invoked */ PL_markstack_ptr = temp; XSRETURN_EMPTY; /* return empty stack */ } /* must have used dXSARGS; list context implied */ return; /* assume stack size is correct */ SV * clip_to (obj, clp, action) SV * obj SV * clp char * action void remove_add_polygon (obj, pg, hole) SV * obj SV * pg int hole PREINIT: I32* temp; PPCODE: temp = PL_markstack_ptr++; remove_add_polygon(obj, pg, hole); if (PL_markstack_ptr != temp) { /* truly void, because dXSARGS not invoked */ PL_markstack_ptr = temp; XSRETURN_EMPTY; /* return empty stack */ } /* must have used dXSARGS; list context implied */ return; /* assume stack size is correct */ void get_polygons (obj) SV * obj PREINIT: I32* temp; PPCODE: temp = PL_markstack_ptr++; get_polygons(obj); if (PL_markstack_ptr != temp) { /* truly void, because dXSARGS not invoked */ PL_markstack_ptr = temp; XSRETURN_EMPTY; /* return empty stack */ } /* must have used dXSARGS; list context implied */ return; /* assume stack size is correct */ BOOT: printf("Hi from bootstrap\n");