├── .gitignore ├── COPYING ├── Makefile.in ├── README ├── bundle ├── configure ├── configure.ac ├── examples ├── logo.c ├── triangles.c ├── ttf.c └── ttf.h ├── gfxpoly.h ├── html ├── background.png ├── index.html ├── logo.png ├── snapround.png ├── snapround.svg ├── stroketypes.png ├── stroketypes.svg ├── tutorial.html ├── windrule.png ├── windrule.svg ├── windstate.png └── windstate.svg ├── install-sh ├── src ├── active.c ├── active.h ├── convert.c ├── convert.h ├── dict.c ├── dict.h ├── gfxline.c ├── gfxline.h ├── heap.h ├── moments.c ├── moments.h ├── poly.c ├── poly.h ├── render.c ├── render.h ├── stroke.c ├── stroke.h ├── wind.c ├── wind.h ├── xrow.c └── xrow.h └── tests ├── polygons ├── t001.ps ├── t002.ps ├── t003.ps ├── t004.ps ├── t005.ps ├── t006.ps ├── t007.ps ├── t008.ps ├── t009.ps ├── t010.ps ├── t011.ps ├── t012.ps ├── t013.ps ├── t014.ps ├── t015.ps ├── t016.ps ├── t017.ps ├── t018.ps ├── t019.ps ├── t020.ps ├── t021.ps ├── t022.ps ├── t023.ps ├── t024.ps ├── t025.ps ├── t026.ps ├── t027.ps └── t028.ps └── run_ps.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | Makefile 3 | autom4te.cache 4 | m 5 | c 6 | r 7 | config.log 8 | config.status 9 | gfxpoly.a 10 | tags 11 | examples/logo 12 | examples/triangles 13 | tests/run_ps 14 | libgfxpoly.so 15 | libgfxpoly.a 16 | gfxpoly-*.*.*/ 17 | gfxpoly-*.*.*.tar.gz 18 | .session.vim 19 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Matthias Kramm 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | top_builddir=. 2 | 3 | CC=@CC@ @CPPFLAGS@ @CFLAGS@ @DEFS@ -fPIC -I. -Isrc -DCHECKS -Wno-unused-function 4 | L=@CC@ @CFLAGS@ -fPIC 5 | A=a 6 | SO=so 7 | AR=ar 8 | RANLIB=@RANLIB@ 9 | EXE=@EXEEXT@ 10 | LIBS=-lm 11 | O=@OBJEXT@ 12 | INSTALL=@INSTALL@ 13 | PACKAGE_NAME=@PACKAGE_NAME@ 14 | PACKAGE_VERSION=@PACKAGE_VERSION@ 15 | prefix=@prefix@ 16 | exec_prefix=@exec_prefix@ 17 | includedir=@includedir@ 18 | libdir=@libdir@ 19 | 20 | SRC_FILES = active.c convert.c poly.c wind.c render.c xrow.c stroke.c moments.c dict.c gfxline.c 21 | SRC_HEADERS = active.h convert.h poly.h wind.h render.h xrow.h stroke.h moments.h dict.h gfxline.h heap.h 22 | SRC_OBJECTS = $(addsuffix .o,$(basename $(SRC_FILES))) 23 | OBJECTS=$(addprefix src/, $(SRC_OBJECTS)) 24 | 25 | SOURCES = gfxpoly.h $(addprefix src/, $(SRC_FILES)) $(addprefix src/, $(SRC_HEADERS)) 26 | 27 | EXAMPLES=examples/logo$(EXE) examples/triangles$(EXE) 28 | TESTS=tests/run_ps$(EXE) 29 | 30 | all: libgfxpoly.$(A) libgfxpoly.$(SO) 31 | 32 | examples: $(EXAMPLES) 33 | 34 | tests: $(TESTS) 35 | tests/run_ps tests/polygons 36 | 37 | %.o: %.c 38 | $(CC) -c $< -o $@ 39 | 40 | src/active.o: src/active.c src/active.h src/poly.h 41 | src/convert.o: src/convert.c src/convert.h src/poly.h 42 | src/poly.o: src/poly.c src/poly.h src/active.h src/heap.h 43 | src/wind.o: src/wind.c src/wind.h src/poly.h 44 | src/dict.o: src/dict.c src/dict.h 45 | src/render.o: src/render.c src/wind.h src/poly.h src/render.h 46 | src/xrow.o: src/xrow.c src/xrow.h 47 | src/stroke.o: src/stroke.c src/poly.h src/convert.h src/wind.h 48 | src/moments.o: src/moments.c src/moments.h 49 | src/gfxline.o: src/gfxline.c src/gfxline.h 50 | 51 | examples/logo.o: examples/logo.c src/*.h examples/ttf.h 52 | examples/triangles.o: examples/triangles.c src/*.h examples/ttf.h 53 | examples/ttf.o: examples/ttf.c examples/ttf.h 54 | 55 | tests/run_ps.o: tests/run_ps.c gfxpoly.h 56 | 57 | libgfxpoly.$(A): $(OBJECTS) 58 | $(AR) cru $@ $(OBJECTS) 59 | $(RANLIB) $@ 60 | 61 | libgfxpoly.$(SO): $(OBJECTS) 62 | $(L) -shared $(OBJECTS) -o $@ 63 | 64 | examples/logo$(EXE): examples/logo.o examples/ttf.o libgfxpoly.$(A) 65 | $(L) examples/logo.o examples/ttf.o libgfxpoly.$(A) -o $@ $(LIBS) -lpdf 66 | 67 | examples/triangles$(EXE): examples/triangles.o examples/ttf.o libgfxpoly.$(A) 68 | $(L) examples/triangles.o examples/ttf.o libgfxpoly.$(A) -o $@ $(LIBS) -lpdf 69 | 70 | tests/run_ps$(EXE): tests/run_ps.o libgfxpoly.$(A) 71 | $(L) tests/run_ps.o libgfxpoly.$(A) -o $@ $(LIBS) 72 | 73 | install: 74 | cp gfxpoly.h $(includedir) 75 | cp libgfxpoly.$(A) $(libdir) 76 | cp libgfxpoly.$(SO) $(libdir)/libgfxpoly.$(SO).$(PACKAGE_VERSION) 77 | 78 | clean: 79 | rm -f src/*.o examples/*.o libgfxpoly.$(A) libgfxpoly.$(SO) 80 | 81 | .PHONY: tests examples 82 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | gfxpoly is a library for doing geometric polygon operations. 2 | (like polygon intersection, union, hidden surface removal, stroke to 3 | outline conversion, wind rule conversion etc.) 4 | It aims to be more easily embeddable than e.g. GX, livarot or CGAL, faster 5 | and more stable than libart, and is distributed under a non-commercial 6 | license (BSD-2). 7 | 8 | It's using the algorithm from Hobby [1] with a few additional ideas 9 | from Hershberger [2] and Bhattacharya et al [3] (in order to produce 10 | a grid-rounded glyph polygon intersection in a single scanline pass) 11 | 12 | It's very stable- at www.scribd.com, it's used to process (intersect) 13 | over 150,000,000 polygons (stemming from figures and illustrations 14 | in documents) every single day. 15 | 16 | 17 | [1] http://ect.bell-labs.com/who/hobby/93_2-27.pdf), 18 | [2] http://www.springerlink.com/content/p46t8502v6q6g687/ 19 | [3] http://cccg.ca/proceedings/2007/07a1full.pdf 20 | -------------------------------------------------------------------------------- /bundle: -------------------------------------------------------------------------------- 1 | include Makefile 2 | 3 | NAME=$(PACKAGE_NAME)-$(PACKAGE_VERSION) 4 | 5 | SOURCE_FILES=$(SOURCES) Makefile.in configure configure.ac install-sh COPYING README 6 | FILES=$(addprefix $(NAME)/, $(SOURCE_FILES)) 7 | 8 | all: 9 | echo creating $(NAME).tar.gz 10 | rm -f $(NAME) 11 | rm -f $(NAME).tar 12 | rm -f $(NAME).tar.gz 13 | ln -s ./ $(NAME) 14 | tar -chf $(NAME).tar $(FILES) 15 | gzip -9 $(NAME).tar 16 | rm -f $(NAME) 17 | cp $(NAME).tar.gz html/ 18 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(gfxpoly, 0.1.0) 2 | AC_PROG_CC 3 | AC_PROG_RANLIB 4 | AC_PROG_INSTALL 5 | AC_CONFIG_FILES([Makefile]) 6 | AC_OUTPUT 7 | -------------------------------------------------------------------------------- /examples/logo.c: -------------------------------------------------------------------------------- 1 | /* logo.c 2 | 3 | logo 4 | 5 | Copyright (c) 2012 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "gfxpoly.h" 33 | #include "ttf.h" 34 | 35 | //#define FONT "/usr/lib/win32/fonts/georgia.ttf" 36 | #define FONT "/usr/lib/win32/fonts/ariblk.ttf" 37 | 38 | static void save(gfxpoly_t*poly, double z, const char*filename) 39 | { 40 | FILE*fi = fopen(filename, "wb"); 41 | fprintf(fi, "%% begin\n"); 42 | int s,t; 43 | gfxsegmentlist_t*stroke = poly->strokes; 44 | for(;stroke;stroke=stroke->next) { 45 | fprintf(fi, "%g setgray\n", stroke->dir==DIR_UP ? 0.7 : 0); 46 | gridpoint_t p = stroke->points[0]; 47 | fprintf(fi, "%f %f moveto\n", p.x * z, p.y * z); 48 | for(s=1;snum_points;s++) { 49 | p = stroke->points[s]; 50 | fprintf(fi, "%f %f lineto\n", p.x * z, p.y * z); 51 | } 52 | fprintf(fi, "stroke\n"); 53 | } 54 | fprintf(fi, "showpage\n"); 55 | fclose(fi); 56 | } 57 | 58 | #include 59 | static void draw_on_pdf(gfxpoly_t*raw, const char*filename, double scale) 60 | { 61 | gfxbbox_t bbox = gfxpoly_calculate_bbox(raw); 62 | bbox.x1 *= scale; 63 | bbox.y1 *= scale; 64 | bbox.x2 *= scale; 65 | bbox.y2 *= scale; 66 | double tx = -bbox.x1 + 5; 67 | double ty = -bbox.y1 + 5; 68 | int width = bbox.x2 - bbox.x1 + 10; 69 | int height = bbox.y2 - bbox.y1 + 10; 70 | 71 | gfxpoly_t*evenodd = gfxpoly_process(raw, NULL, &windrule_evenodd, &onepolygon, NULL); 72 | gfxpoly_t*circular = gfxpoly_process(raw, NULL, &windrule_circular, &onepolygon, NULL); 73 | 74 | PDF*pdf = PDF_new(); 75 | PDF_open_file(pdf, filename); 76 | PDF_set_parameter(pdf, "usercoordinates", "true"); 77 | PDF_set_parameter(pdf, "topdown", "false"); 78 | 79 | double z = raw->gridsize * scale; 80 | 81 | PDF_begin_page(pdf, width, height); 82 | 83 | double fx,fy; 84 | PDF_setlinecap(pdf, /*round*/1); 85 | PDF_setlinejoin(pdf, /*round*/1); 86 | PDF_setrgbcolor_stroke(pdf, 0.7,0.7,0.7); 87 | PDF_setlinewidth(pdf, 2.0); 88 | for(fy=0;fy<=height;fy+=z) { 89 | for(fx=0;fx<=width;fx+=z) { 90 | PDF_moveto(pdf, fx, fy); 91 | PDF_lineto(pdf, fx, fy); 92 | PDF_stroke(pdf); 93 | } 94 | } 95 | 96 | gfxline_t* filled1 = gfxline_from_gfxpoly_with_direction(circular); 97 | gfxline_t* filled2 = gfxline_from_gfxpoly_with_direction(evenodd); 98 | 99 | gfxline_t*l; 100 | 101 | PDF_setrgbcolor_fill(pdf, 0xe8/255.0,0xec/255.0,0xff/255.0); 102 | for(l=filled1;l;l=l->next) { 103 | if(l->type == gfx_moveTo) { 104 | PDF_moveto(pdf, tx+l->x*scale, ty+l->y*scale); 105 | } else if(l->type == gfx_lineTo) { 106 | PDF_lineto(pdf, tx+l->x*scale, ty+l->y*scale); 107 | } 108 | } 109 | PDF_fill(pdf); 110 | 111 | PDF_setrgbcolor_fill(pdf, 0xd0/255.0,0xd8/255.0,0xff/255.0); 112 | for(l=filled2;l;l=l->next) { 113 | if(l->type == gfx_moveTo) { 114 | PDF_moveto(pdf, tx+l->x*scale, ty+l->y*scale); 115 | } else if(l->type == gfx_lineTo) { 116 | PDF_lineto(pdf, tx+l->x*scale, ty+l->y*scale); 117 | } 118 | } 119 | PDF_fill(pdf); 120 | 121 | gfxsegmentlist_t*stroke; 122 | PDF_setrgbcolor_stroke(pdf, 0.5,0.5,0.5); 123 | PDF_setlinewidth(pdf, 1.0); 124 | for(stroke=evenodd->strokes;stroke;stroke=stroke->next) { 125 | gridpoint_t p = stroke->points[0]; 126 | PDF_moveto(pdf, tx+p.x*z, ty+p.y*z); 127 | int s; 128 | for(s=1;snum_points;s++) { 129 | p = stroke->points[s]; 130 | PDF_lineto(pdf, tx+p.x*z, ty+p.y*z); 131 | } 132 | PDF_stroke(pdf); 133 | } 134 | 135 | PDF_setlinecap(pdf, /*round*/1); 136 | PDF_setrgbcolor_stroke(pdf, 0.0,0.0,0.0); 137 | PDF_setlinewidth(pdf, 3.0); 138 | for(stroke=evenodd->strokes;stroke;stroke=stroke->next) { 139 | gridpoint_t p = stroke->points[0]; 140 | int s; 141 | for(s=0;snum_points;s++) { 142 | p = stroke->points[s]; 143 | PDF_moveto(pdf, tx+p.x*z, ty+p.y*z); 144 | PDF_lineto(pdf, tx+p.x*z, ty+p.y*z); 145 | PDF_stroke(pdf); 146 | } 147 | } 148 | 149 | PDF_end_page(pdf); 150 | PDF_close(pdf); 151 | PDF_delete(pdf); 152 | } 153 | 154 | int main(int argn, char*argv[]) 155 | { 156 | double grid = 2; 157 | 158 | gfxcanvas_t*canvas = gfxcanvas_new(grid); 159 | 160 | char*str = "gfxpoly"; 161 | int length = strlen(str); 162 | ttf_t*ttf = ttf_open(FONT); 163 | int i; 164 | double s = 20; 165 | double scale_x = 0.003 * s; 166 | double scale_y = 0.001 * s; 167 | 168 | float x_pos[] = {0,0.2,0,0,0,0,0}; 169 | float y_pos[] = {10,10.7,9.3,10.3,9.4,10.3,10.5}; 170 | 171 | float pos_x = 0; 172 | for(i=0;inum_points;j++) { 180 | ttfpoint_t*p = &glyph->points[j]; 181 | ttfpoint_t*next = j < glyph->num_points-1 ? &glyph->points[j+1] : NULL; 182 | if(p->flags&GLYPH_CONTOUR_START) { 183 | canvas->moveTo(canvas, offset_x + p->x * scale_x, offset_y + p->y * scale_y); 184 | } /*else if(!(p->flags&GLYPH_ON_CURVE) && next && 185 | (next->flags&GLYPH_ON_CURVE)) { 186 | canvas->splineTo(canvas, offset_x + p->x * scale_x, 187 | offset_y + p->y * scale_y, 188 | offset_x + next->x * scale_x, 189 | offset_y + next->y * scale_y); 190 | j++; 191 | p = next; 192 | }*/ else { 193 | canvas->lineTo(canvas, offset_x + p->x * scale_x, offset_y + p->y * scale_y); 194 | } 195 | if(p->flags&GLYPH_CONTOUR_END) { 196 | canvas->close(canvas); 197 | } 198 | } 199 | pos_x += glyph->advance * 3 / 5 * scale_x; 200 | } 201 | 202 | gfxpoly_t*poly = (gfxpoly_t*)canvas->result(canvas); 203 | 204 | draw_on_pdf(poly, "logo.pdf", 50.0/s); 205 | 206 | system("pdftoppm -r 72 logo.pdf logo"); 207 | system("convert logo-000001.ppm html/logo.png"); 208 | system("rm -f logo.pdf logo-000001.ppm"); 209 | system("convert html/logo.png -crop 5x5+10+10 html/background.png"); 210 | 211 | gfxpoly_destroy(poly); 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /examples/triangles.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "gfxpoly.h" 5 | 6 | char colors[]={ 7 | 0,0,0, 255,255,255, 255,0,0, 0,255,255, 255,0,255, 0,255,255, 8 | 0,0,255, 255,255,0, 128,128,0, 64,64,0, 255,128,128, 64,64,64, 9 | 96, 96, 96, 128,255,128, 128,128,255, 128,128,128, 10 | 32,0,0,32,0,0 11 | }; 12 | 13 | typedef struct _xy 14 | { 15 | double x,y; 16 | } xy_t; 17 | 18 | typedef struct _triangle 19 | { 20 | xy_t p1,p2,p3; 21 | } triangle_t; 22 | 23 | static triangle_t triangle_turn(triangle_t orig, int x, int y, double ua, double z) 24 | { 25 | triangle_t tri; 26 | tri.p1.x = (orig.p1.x*cos(ua)-orig.p1.y*sin(ua))*z+x; 27 | tri.p1.y = (orig.p1.x*sin(ua)+orig.p1.y*cos(ua))*z+y; 28 | tri.p2.x = (orig.p2.x*cos(ua)-orig.p2.y*sin(ua))*z+x; 29 | tri.p2.y = (orig.p2.x*sin(ua)+orig.p2.y*cos(ua))*z+y; 30 | tri.p3.x = (orig.p3.x*cos(ua)-orig.p3.y*sin(ua))*z+x; 31 | tri.p3.y = (orig.p3.x*sin(ua)+orig.p3.y*cos(ua))*z+y; 32 | return tri; 33 | } 34 | 35 | static triangle_t t1 = {{0,-100},{-100,100},{10,100}}; 36 | static triangle_t t2 = {{-100,-100},{-100,100},{100,100}}; 37 | static triangle_t t3 = {{100,-100},{-100,-100},{100,100}}; 38 | 39 | static void add(gfxcanvas_t*canvas, triangle_t*t) 40 | { 41 | canvas->setUserData(canvas, t); 42 | canvas->moveTo(canvas, t->p1.x, t->p1.y); 43 | canvas->lineTo(canvas, t->p2.x, t->p2.y); 44 | canvas->lineTo(canvas, t->p3.x, t->p3.y); 45 | canvas->close(canvas); 46 | } 47 | 48 | int main(int argn, char*argv[]) 49 | { 50 | xy_t rpix[16384]; 51 | int i; 52 | for(i=0;i<16384;i++) { 53 | rpix[i].x=lrand48()%640-320, 54 | rpix[i].y=lrand48()%480-240; 55 | } 56 | 57 | double ua=0,ub=0,uc=0; 58 | 59 | 60 | while(1) { 61 | gfxcanvas_t*canvas = gfxcanvas_new(0.05); 62 | 63 | triangle_t b1 = triangle_turn(t2, -32, -24, ua, 1); 64 | add(canvas, &b1); 65 | triangle_t b2 = triangle_turn(t3, -32, -24, ua, 1); 66 | add(canvas, &b2); 67 | 68 | triangle_t turned[16384]; 69 | for(i=0;i<128;i++) { 70 | turned[i] = triangle_turn(t1, rpix[i].x, rpix[i].y, ua+0.8*i, (60-i)/32.0); 71 | add(canvas, &turned[i]); 72 | } 73 | gfxpoly_t* poly = (gfxpoly_t*)canvas->result(canvas); 74 | 75 | gfxpoly_t*p2 = gfxpoly_selfintersect_evenodd(poly); 76 | 77 | ua+=0.03; 78 | ub+=0.04568; 79 | uc+=0.05693; 80 | } 81 | 82 | return 0; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /examples/ttf.h: -------------------------------------------------------------------------------- 1 | /* ttf.h 2 | 3 | Parser and writer for truetype font files. 4 | 5 | Copyright (c) 2010,2011,2012 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __ttf_h__ 30 | #define __ttf_h__ 31 | 32 | #include 33 | 34 | typedef struct _ttf_table { 35 | uint32_t id; 36 | struct _ttf_table*prev; 37 | struct _ttf_table*next; 38 | 39 | uint8_t*data; 40 | int len; 41 | int memsize; 42 | } ttf_table_t; 43 | 44 | typedef struct _table_maxp { 45 | uint16_t maxPoints; 46 | uint16_t maxContours; 47 | uint16_t maxComponentPoints; 48 | uint16_t maxComponentContours; 49 | uint16_t maxZones; 50 | uint16_t maxTwilightPoints; 51 | uint16_t maxStorage; 52 | uint16_t maxFunctionDefs; 53 | uint16_t maxInstructionDefs; 54 | uint16_t maxStackElements; 55 | uint16_t maxSizeOfInstructions; 56 | uint16_t maxComponentElements; 57 | uint16_t maxComponentDepth; 58 | } table_maxp_t; 59 | 60 | typedef struct _table_os2 { 61 | int16_t xAvgCharWidth; 62 | uint16_t usWeightClass; 63 | uint16_t usWidthClass; 64 | uint16_t ySubscriptXSize; 65 | uint16_t ySubscriptYSize; 66 | uint16_t ySubscriptXOffset; 67 | uint16_t ySubscriptYOffset; 68 | uint16_t ySuperscriptXSize; 69 | uint16_t ySuperscriptYSize; 70 | uint16_t ySuperscriptXOffset; 71 | uint16_t ySuperscriptYOffset; 72 | uint16_t yStrikeoutSize; 73 | uint16_t yStrikeoutPosition; 74 | uint16_t sFamilyClass; 75 | uint8_t panose_FamilyType; 76 | uint8_t panose_SerifStyle; 77 | uint8_t panose_Weight; 78 | uint8_t panose_Proportion; 79 | uint8_t panose_Contrast; 80 | uint8_t panose_StrokeVariation; 81 | uint8_t panose_ArmStyle; 82 | uint8_t panose_Letterform; 83 | uint8_t panose_Midline; 84 | uint8_t panose_XHeight; 85 | uint32_t ulCharRange[4]; 86 | 87 | uint16_t fsSelection; 88 | uint16_t fsFirstCharIndex; 89 | uint16_t fsLastCharIndex; 90 | 91 | int16_t sTypoAscender; 92 | int16_t sTypoDescender; 93 | int16_t sTypoLineGap; 94 | uint16_t usWinAscent; 95 | uint16_t usWinDescent; 96 | 97 | /* for version >= 0x0001 */ 98 | uint32_t ulCodePageRange1; 99 | uint32_t ulCodePageRange2; 100 | 101 | /* for version >= 0x0002 */ 102 | int16_t sxHeight; 103 | int16_t sCapHeight; 104 | uint16_t usDefaultChar; 105 | uint16_t usBreakChar; 106 | uint16_t usMaxContext; 107 | } table_os2_t; 108 | 109 | typedef struct _table_hea 110 | { 111 | uint16_t advanceWidthMax; 112 | int16_t minLeftSideBearing; 113 | int16_t minRightSideBearing; 114 | int16_t xMaxExtent; 115 | int16_t caretSlopeRise; 116 | int16_t caretSlopeRun; 117 | int16_t caretOffset; 118 | } table_hea_t; 119 | 120 | #define GLYPH_ON_CURVE 0x01 121 | #define GLYPH_CONTOUR_START 0x40 122 | #define GLYPH_CONTOUR_END 0x80 123 | 124 | typedef uint32_t unicode_t; 125 | 126 | typedef struct _ttfpoint { 127 | int x,y; 128 | uint8_t flags; 129 | } ttfpoint_t; 130 | 131 | typedef struct _ttfglyph { 132 | uint16_t advance; 133 | int16_t bearing; 134 | int16_t xmin,ymin,xmax,ymax; 135 | int code_size; 136 | uint8_t*code; 137 | int num_points; 138 | ttfpoint_t*points; 139 | } ttfglyph_t; 140 | 141 | typedef struct _table_head { 142 | uint16_t flags; 143 | uint16_t units_per_em; 144 | int16_t xmin,ymin,xmax,ymax; 145 | uint16_t macStyle; 146 | uint16_t lowest_readable_size; 147 | int16_t dir_hint; 148 | } table_head_t; 149 | 150 | typedef struct _table_post { 151 | uint32_t italic_angle; 152 | uint16_t underline_position; 153 | uint16_t underline_thickness; 154 | } table_post_t; 155 | 156 | typedef struct _table_cvt { 157 | int16_t*values; 158 | int num; 159 | } table_cvt_t; 160 | 161 | typedef struct _table_gasp { 162 | int num; 163 | struct { 164 | uint16_t size; 165 | uint16_t behaviour; 166 | } *records; 167 | } table_gasp_t; 168 | 169 | typedef struct _table_code { 170 | uint8_t*code; 171 | int size; 172 | } table_code_t; 173 | 174 | typedef struct _ttf { 175 | char*family_name; /* nameId 1 */ 176 | char*subfamily_name; /* nameId 2 */ 177 | char*font_uid; /* nameId 3 */ 178 | char*full_name; /* nameId 4 */ 179 | char*version_string; /* nameId 5 */ 180 | char*postscript_name; /* nameId 6 */ 181 | 182 | ttf_table_t*tables; 183 | 184 | table_head_t*head; 185 | table_maxp_t*maxp; 186 | table_os2_t*os2; 187 | table_hea_t*hea; 188 | table_post_t*post; 189 | table_cvt_t*cvt; 190 | table_gasp_t*gasp; 191 | table_code_t*prep; 192 | table_code_t*fpgm; 193 | 194 | char is_vertical; 195 | 196 | int16_t ascent; 197 | int16_t descent; // ymin, *not* negative ymin 198 | int16_t lineGap; 199 | 200 | int num_glyphs; 201 | ttfglyph_t*glyphs; 202 | 203 | int unicode_size; 204 | unicode_t*unicode; 205 | 206 | uint32_t version; 207 | } ttf_t; 208 | 209 | 210 | ttf_t*ttf_new(); 211 | ttf_t* ttf_open(const char*filename); 212 | void ttf_reduce(ttf_t*ttf); 213 | ttf_t*ttf_load(void*data, int length); 214 | ttf_table_t*ttf_addtable(ttf_t*ttf, uint32_t tag); 215 | void ttf_create_truetype_tables(ttf_t*ttf); 216 | void ttf_dump(ttf_t*ttf); 217 | void ttf_destroy(ttf_t*ttf); 218 | void ttf_save(ttf_t*ttf, const char*filename); 219 | void ttf_save_eot(ttf_t*ttf, const char*filename); 220 | ttfglyph_t* ttf_find_unicode(ttf_t*ttf, uint32_t unicode); 221 | 222 | #endif 223 | -------------------------------------------------------------------------------- /gfxpoly.h: -------------------------------------------------------------------------------- 1 | /* gfxpoly.h 2 | 3 | Boolean polygon operations library 4 | 5 | Copyright (c) 2009-2012 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __gfxpoly_h__ 30 | #define __gfxpoly_h__ 31 | 32 | #include 33 | 34 | /* +----------------------------------------------------------------+ */ 35 | /* | Definitions | */ 36 | /* +----------------------------------------------------------------+ */ 37 | 38 | /* A "grid" value is the granularity at which polygon intersection operates. 39 | It usually makes sense to set this to the smallest value that can actually be represented 40 | in the output device (e.g. 0.05 for Flash animations). */ 41 | #define DEFAULT_GRID (0.05) 42 | 43 | /* A coordinate on the grid. This is represented as integers, and the real coordinate 44 | can be derived by multiplying each component with the grid size */ 45 | typedef struct _gridpoint { 46 | int32_t x; 47 | int32_t y; 48 | } gridpoint_t; 49 | 50 | /* A coordinate in the original space (i.e., not on the grid, and hence represented 51 | as floating point number */ 52 | typedef double gfxcoord_t; 53 | 54 | /* a bounding box (in real coordinate space) */ 55 | typedef struct _gfxbbox { 56 | gfxcoord_t x1,y1,x2,y2; 57 | } gfxbbox_t; 58 | 59 | /* Every segment has an original direction, which is the direction 60 | the segment had in the input data. 61 | as our scanline moves from minimum y to maximum y, "DOWN" means 62 | the the (original) segment's y2 is larger than its y1 */ 63 | typedef enum {DIR_UP, DIR_DOWN, DIR_UNKNOWN} segment_dir_t; 64 | 65 | typedef struct _edgestyle { 66 | void*internal; 67 | } edgestyle_t; 68 | 69 | /* +----------------------------------------------------------------+ */ 70 | /* | version | */ 71 | /* +----------------------------------------------------------------+ */ 72 | const char* gfxpoly_version(); 73 | 74 | /* +----------------------------------------------------------------+ */ 75 | /* | gfxpoly_t objects | */ 76 | /* +----------------------------------------------------------------+ */ 77 | 78 | typedef struct _gfxsegmentlist { 79 | segment_dir_t dir; 80 | edgestyle_t*fs; 81 | int points_size; 82 | int num_points; 83 | gridpoint_t*points; 84 | struct _gfxsegmentlist*next; 85 | } gfxsegmentlist_t; 86 | 87 | typedef struct _gfxpoly { 88 | double gridsize; 89 | gfxsegmentlist_t*strokes; 90 | } gfxpoly_t; 91 | 92 | gfxbbox_t gfxpoly_calculate_bbox(gfxpoly_t*poly); 93 | void gfxpoly_destroy(gfxpoly_t*poly); 94 | 95 | /* +----------------------------------------------------------------+ */ 96 | /* | Operators | */ 97 | /* +----------------------------------------------------------------+ */ 98 | 99 | gfxpoly_t* gfxpoly_intersect(gfxpoly_t*p1, gfxpoly_t*p2); 100 | gfxpoly_t* gfxpoly_union(gfxpoly_t*p1, gfxpoly_t*p2); 101 | 102 | gfxpoly_t* gfxpoly_selfintersect_evenodd(gfxpoly_t*p); 103 | gfxpoly_t* gfxpoly_selfintersect_circular(gfxpoly_t*p); 104 | 105 | /* +----------------------------------------------------------------+ */ 106 | /* | Area and Moments | */ 107 | /* +----------------------------------------------------------------+ */ 108 | 109 | typedef struct _moments { 110 | double area; 111 | double m[3][3]; 112 | } moments_t; 113 | 114 | double gfxpoly_area(gfxpoly_t*p); 115 | double gfxpoly_intersection_area(gfxpoly_t*p1, gfxpoly_t*p2); 116 | moments_t gfxpoly_moments(gfxpoly_t*p); 117 | 118 | /* +----------------------------------------------------------------+ */ 119 | /* | Conversion from curves and floating point coordinates | */ 120 | /* +----------------------------------------------------------------+ */ 121 | 122 | typedef enum {gfx_moveTo, gfx_lineTo, gfx_splineTo} gfx_linetype; 123 | typedef enum {gfx_joinMiter, gfx_joinRound, gfx_joinBevel} gfx_joinType; 124 | typedef enum {gfx_capButt, gfx_capRound, gfx_capSquare} gfx_capType; 125 | 126 | typedef struct _gfxline { 127 | gfx_linetype type; 128 | gfxcoord_t x,y; 129 | gfxcoord_t sx,sy; 130 | struct _gfxline*prev; 131 | struct _gfxline*next; 132 | } gfxline_t; 133 | 134 | gfxline_t* gfxline_new(); 135 | gfxline_t* gfxline_moveTo(gfxline_t*line, gfxcoord_t x, gfxcoord_t y); 136 | gfxline_t* gfxline_lineTo(gfxline_t*line, gfxcoord_t x, gfxcoord_t y); 137 | gfxline_t* gfxline_splineTo(gfxline_t*line, gfxcoord_t sx, gfxcoord_t sy, gfxcoord_t x, gfxcoord_t y); 138 | 139 | gfxpoly_t* gfxpoly_from_fill(gfxline_t*line, double gridsize); 140 | gfxpoly_t* gfxpoly_from_stroke(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit, double gridsize); 141 | void gfxline_destroy(gfxline_t*l); 142 | 143 | /* +----------------------------------------------------------------+ */ 144 | /* | creation of gfxpoly objects by drawing on a "gfxcanvas" | */ 145 | /* +----------------------------------------------------------------+ */ 146 | 147 | typedef struct _gfxcanvas 148 | { 149 | void*internal; 150 | gfxcoord_t x,y; 151 | 152 | void (*setUserData)(struct _gfxcanvas*d, void*user); 153 | 154 | void (*moveTo)(struct _gfxcanvas*d, gfxcoord_t x, gfxcoord_t y); 155 | void (*lineTo)(struct _gfxcanvas*d, gfxcoord_t x, gfxcoord_t y); 156 | void (*splineTo)(struct _gfxcanvas*d, gfxcoord_t sx, gfxcoord_t sy, gfxcoord_t x, gfxcoord_t y); 157 | void (*close)(struct _gfxcanvas*d); 158 | 159 | void* (*result)(struct _gfxcanvas*d); 160 | } gfxcanvas_t; 161 | 162 | gfxcanvas_t* gfxcanvas_new(double gridsize); 163 | 164 | /* +----------------------------------------------------------------+ */ 165 | /* | conversion from gfxpoly to gfxline lists | */ 166 | /* +----------------------------------------------------------------+ */ 167 | 168 | gfxline_t* gfxline_from_gfxpoly(gfxpoly_t*poly); 169 | gfxline_t* gfxline_from_gfxpoly_with_direction(gfxpoly_t*poly); 170 | 171 | /* +----------------------------------------------------------------+ */ 172 | /* | convenience functions | */ 173 | /* +----------------------------------------------------------------+ */ 174 | 175 | gfxline_t* gfxpoly_circular_to_evenodd(gfxline_t*line, double gridsize); 176 | gfxpoly_t* gfxpoly_createbox(double x1, double y1,double x2, double y2, double gridsize); 177 | 178 | /* +----------------------------------------------------------------+ */ 179 | /* | load /save | */ 180 | /* +----------------------------------------------------------------+ */ 181 | 182 | gfxpoly_t* gfxpoly_from_file(const char*filename); 183 | void gfxpoly_save(gfxpoly_t*poly, const char*filename); 184 | 185 | /* +----------------------------------------------------------------+ */ 186 | /* | Low level scanline processing interface | */ 187 | /* +----------------------------------------------------------------+ */ 188 | 189 | typedef struct _windstate { 190 | void*user; 191 | char is_filled; 192 | int wind_nr; 193 | } windstate_t; 194 | 195 | typedef struct _windcontext { 196 | void*user; 197 | int num_polygons; 198 | } windcontext_t; 199 | 200 | extern windcontext_t onepolygon; 201 | extern windcontext_t twopolygons; 202 | 203 | typedef struct _windrule 204 | { 205 | windstate_t (*start)(windcontext_t* context); 206 | windstate_t (*add)(windcontext_t*context, windstate_t left, edgestyle_t*edge, segment_dir_t dir, int polygon_nr); 207 | edgestyle_t* (*diff)(windcontext_t*context, windstate_t*left, windstate_t*right); 208 | } windrule_t; 209 | 210 | extern windrule_t windrule_evenodd; 211 | extern windrule_t windrule_circular; 212 | extern windrule_t windrule_intersect; 213 | extern windrule_t windrule_union; 214 | 215 | gfxpoly_t* gfxpoly_process(gfxpoly_t*poly1, gfxpoly_t*poly2, windrule_t*windrule, windcontext_t*context, moments_t*moments); 216 | 217 | #endif 218 | -------------------------------------------------------------------------------- /html/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/html/background.png -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 94 | 95 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 112 |

gfxpoly

113 | 114 |
115 | 116 | 122 | 123 |

About

124 |

125 | gfxpoly is a library for doing geometric polygon operations. 126 | (like polygon intersection, union, hidden surface removal, stroke to 127 | outline conversion, wind rule conversion etc.)
128 | It's distributed under a non-commercial license (BSD-2). 129 |

130 | 131 |

132 | It's very stable- e.g. at www.scribd.com, it's used to process (intersect) 133 | over 150,000,000 polygons (stemming from figures and illustrations 134 | in document uploads) every single day. 135 |

136 | 137 |

Documentation

138 | 139 |

140 | gfxpoly tutorial 141 |

142 | 143 |

Download

144 | 145 |

The current version is 0.1.0. 146 |

147 | 148 | 149 |
Jun 2, 2012gfxpoly-0.1.0.tar.gz(74941 bytes)
150 | 151 |

git

152 | 153 |
git clone git@github.com:matthiaskramm/gfxpoly.git
154 | 155 |
156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /html/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/html/logo.png -------------------------------------------------------------------------------- /html/snapround.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/html/snapround.png -------------------------------------------------------------------------------- /html/stroketypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/html/stroketypes.png -------------------------------------------------------------------------------- /html/tutorial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | gfxpoly tutorial 8 | 9 | 10 |
11 |

gfxpoly tutorial

12 |
13 | 14 |
15 | 16 |

Polygon representation

17 | 18 |

19 | Polygons in gfxpoly are represented as a set of line segments. 20 | The internal representation doesn't have a way to represent curves (splines), 21 | however it's possible to convert splines to a gfxpoly structure 22 | by approximating them with lines (See creating polygons.) 23 |

24 | 25 |

26 | Polygon endpoints, furthermore, are rounded to a grid (i.e., represented as integer coordinates.)
27 | During polygon intersection, the resulting polygons are again rounded- also, new intersection 28 | points will cause adjacent lines (i.e. lines passing through that grid point) 29 | to be "routed" through the intersection point, a concept known as "snap rounding to hot pixels":
30 | 31 |

32 | 33 |

34 | 35 | This approach ensures robustness of intersection, since there's always a unique representation of 36 | the output polygon (as opposed to doing polygon intersection on floating point numbers where 37 | due to numerical precision, intersection points might now have an actual representation as floating 38 | point number, leading to errors when they are "rounded" to a float.) 39 |

40 | 41 |

42 | There are a lot of academic papers about why snap rounding is preferrable to numeric approaches. 43 | gfxpoly uses the algorithm from Hobby 44 | with a few additional ideas 45 | from Hershberger and 46 | Bhattacharya et al. 47 |

48 | 49 |

(In the above figure, you might have noticed that gfxpoly snaps to the lower right corner 50 | of grid points, instead of the center- this is an optimization that makes snapping faster) 51 |

52 | 53 |

Creating polygons

54 | 55 |

56 | The easiest way to create a gfxpoly polygon is to first represent 57 | the shape you want to process as an outline of lines and splines: 58 |

59 | 60 |
 61 | double gridsize = 0.01;
 62 | 
 63 | gfxline_t*outline = NULL;
 64 | outline = gfx_moveTo(outline, 0,0);
 65 | outline = gfx_lineTo(outline, 100,0);
 66 | outline = gfx_lineTo(outline, 100,100);
 67 | outline = gfx_splineTo(outline, 50,50, 0,100);
 68 | outline = gfx_lineTo(outline, 0,0);
 69 | 
 70 | gfxpoly_t*poly = gfxpoly_from_fill(outline, gridsize);
 71 | 
72 | 73 |

74 | Here, gridsize is the spacing of grid points- i.e., the numerical 75 | precision of your coordinate system. So a coordinate like 7.392 will 76 | be truncated to 7.39 during conversion to gfxpoly_t (and since gfxpoly_t 77 | represents coordinates as integers, be internally stored as 739.) 78 |

79 | 80 |

81 | You can also create polygons from a stroke: 82 |

83 | 84 |
 85 | gfxpoly_t*poly = gfxpoly_from_stroke(outline, /*line width*/10.0, gfx_capRound, gfx_joinRound, 0.0, gridsize);
 86 | 
87 | 88 |

89 | The parameters are defined as following: 90 |

91 | 92 | 93 | 94 |

Boolean operations between polygons

95 | 96 |

Once you have a representation of your polygon as gfxpoly you 97 | can intersect polygons:

98 | 99 |
100 | gfxpoly_t*poly12 = gfxpoly_intersect(poly1, poly2);
101 | 
102 | 103 |

You can also build the union of two polygons:

104 | 105 |
106 | gfxpoly_t*poly12 = gfxpoly_union(poly1, poly2);
107 | 
108 | 109 |

It also sometimes makes sense to intersect a polygon with itself (for example, 110 | to determine which parts of it are filled.)
111 | There are two convenience functions that apply the corresponding fillstyle 112 | and generate a self-intersected polygon: 113 |

114 | 115 |
116 | gfxpoly_t* new_polygon = gfxpoly_selfintersect_evenodd(poly);
117 | 
118 | 119 |
120 | gfxpoly_t* new_polygon = gfxpoly_selfintersect_circular(poly);
121 | 
122 | 123 | 124 |

125 | Notice: gfxpoly_intersect, gfxpoly_union and gfxpoly_selfintersect_* are really just convenience 126 | wrappers for gfxpoly_process. See gfxpoly_process.
127 | By using gfxpoly_process directly, you can implement other polygon operations, like symmetric 128 | difference, overlay, transparency etc. 129 |

130 | 131 |

Polygon area and moments

132 | 133 |

134 | You can also compute the area of a polygon: 135 |

136 | 137 |
138 | double area = gfxpoly_area(poly);
139 | 
140 | 141 |

142 | If you're interested in the degree of overlap between two polygons, there's 143 | a shortcut that does gfxpoly_intersect and gfxpoly_area in 144 | a single step: 145 |

146 | 147 |
148 | double area = gfxpoly_intersection_area(poly1, poly2);
149 | 
150 | 151 |

Advanced

152 |

Creating gfxpoly through gfxcanvas

153 |

154 | Representing polygons as a gfxline_t list first has the disadvantage 155 | of having to allocate that structure first. A faster way is to use the 156 | gfxcanvas_t abstraction to convert a shape to a gfxpoly on the fly: 157 |

158 | 159 |
160 | gfxcanvas_t*canvas = gfxcanvas_new(gridsize);
161 | canvas->moveTo(canvas, 0,0);
162 | canvas->lineTo(canvas, 100,0);
163 | canvas->lineTo(canvas, 100,100);
164 | canvas->splineTo(canvas, 50,50, 0,100);
165 | canvas->lineTo(canvas, 0,0);
166 | canvas->close(canvas);
167 | gfxpoly_t* poly = (gfxpoly_t*)canvas->result(canvas);
168 | 
169 | 170 |

171 | This also has the advantage that you can overlay multiple input polygons using 172 | the same gfxcanvas object, and then later process them in one go. 173 | Use canvas->setUserData(canvas, data) to store polygon-specific data. This 174 | data will later be passed back to you by windrule.add(). 175 |

176 | 177 |

gfxpoly_process

178 | 179 |

180 | Internally, for every polygon operation, a scanline pass is run over all 181 | the line segments using gfxpoly_process. It has the following prototype: 182 |

183 | 184 |
185 | gfxpoly_t* gfxpoly_process(gfxpoly_t*poly1, gfxpoly_t*poly2, 
186 |                            windrule_t*windrule, windcontext_t*context, 
187 | 			   moments_t*moments);
188 | 
189 | 190 |

To implement custom polygon operations, you would create your own windcontext. 191 | To understand how this works, we need to talk about scanline algorithms first.
192 | A scanline algorithm processes a set of line segments from top to bottom (or left to right, 193 | depending on the implementation), and during every scanline, shoots an imaginary ray from negative 194 | infinity to positive infinity, looking at which polygon segments it hits, and in which order: 195 |

196 | 197 |

198 | 199 |

200 | 201 |

The state of the ray is represented as a windstate_t structure- it e.g. stores 202 | whether the current polygon area we're in is filled or not, or how many polygons are currently 203 | on top of each other. 204 |

205 | 206 |

A windrule_t structure specifies what should happen to the windstate_t every 207 | time we pass through an edge, it's initial value (at negative infinity) and also, when generating 208 | the output polygon, what kind of edge to place between two different windstate_t areas. 209 |

210 | 211 |

An edgestyle_t structure is attached to every edge, and can store user data that applies 212 | to that edge (e.g. for polygon overlays, the color of the polygon belonging to that edge.) 213 |

214 | 215 |

Hence, for creating your own windrule, you have to implement the following functions: 216 |

217 | 218 |
219 | windstate_t start(windcontext_t*context);
220 | windstate_t add(windcontext_t*context, windstate_t left, edgestyle_t*edge, segment_dir_t dir, int polygon_nr);
221 | edgestyle_t* diff(windstate_t*left, windstate_t*right);
222 | 
223 | 224 |

225 | 226 |

227 | 228 |

winrules / fillstyles

229 |

230 | gfxpoly already contains windrule (a.k.a. fillstyle) implementations for: 231 |

    232 |
  • Even/Odd self-intersection (windrule_evenodd)
  • 233 |
  • Circular self-intersection (windrule_circular)
  • 234 |
  • Two polygon intersection (windrule_intersect)
  • 235 |
  • Two polygon union (windrule_union)
  • 236 |
237 |

238 | 239 |
240 | 241 | 246 | 247 | 248 | -------------------------------------------------------------------------------- /html/windrule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/html/windrule.png -------------------------------------------------------------------------------- /html/windstate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/html/windstate.png -------------------------------------------------------------------------------- /html/windstate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 27 | 32 | 33 | 34 | 52 | 59 | 60 | 62 | 63 | 65 | image/svg+xml 66 | 68 | 69 | 70 | 71 | 72 | 76 | 82 | 87 | 93 | scanline 104 | 110 | windstate 121 | 127 | edgestyle 138 | 143 | 148 | 153 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2010-02-06.18; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | shift;; 160 | 161 | -T) no_target_directory=true;; 162 | 163 | --version) echo "$0 $scriptversion"; exit $?;; 164 | 165 | --) shift 166 | break;; 167 | 168 | -*) echo "$0: invalid option: $1" >&2 169 | exit 1;; 170 | 171 | *) break;; 172 | esac 173 | shift 174 | done 175 | 176 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 177 | # When -d is used, all remaining arguments are directories to create. 178 | # When -t is used, the destination is already specified. 179 | # Otherwise, the last argument is the destination. Remove it from $@. 180 | for arg 181 | do 182 | if test -n "$dst_arg"; then 183 | # $@ is not empty: it contains at least $arg. 184 | set fnord "$@" "$dst_arg" 185 | shift # fnord 186 | fi 187 | shift # arg 188 | dst_arg=$arg 189 | done 190 | fi 191 | 192 | if test $# -eq 0; then 193 | if test -z "$dir_arg"; then 194 | echo "$0: no input file specified." >&2 195 | exit 1 196 | fi 197 | # It's OK to call `install-sh -d' without argument. 198 | # This can happen when creating conditional directories. 199 | exit 0 200 | fi 201 | 202 | if test -z "$dir_arg"; then 203 | do_exit='(exit $ret); exit $ret' 204 | trap "ret=129; $do_exit" 1 205 | trap "ret=130; $do_exit" 2 206 | trap "ret=141; $do_exit" 13 207 | trap "ret=143; $do_exit" 15 208 | 209 | # Set umask so as not to create temps with too-generous modes. 210 | # However, 'strip' requires both read and write access to temps. 211 | case $mode in 212 | # Optimize common cases. 213 | *644) cp_umask=133;; 214 | *755) cp_umask=22;; 215 | 216 | *[0-7]) 217 | if test -z "$stripcmd"; then 218 | u_plus_rw= 219 | else 220 | u_plus_rw='% 200' 221 | fi 222 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 223 | *) 224 | if test -z "$stripcmd"; then 225 | u_plus_rw= 226 | else 227 | u_plus_rw=,u+rw 228 | fi 229 | cp_umask=$mode$u_plus_rw;; 230 | esac 231 | fi 232 | 233 | for src 234 | do 235 | # Protect names starting with `-'. 236 | case $src in 237 | -*) src=./$src;; 238 | esac 239 | 240 | if test -n "$dir_arg"; then 241 | dst=$src 242 | dstdir=$dst 243 | test -d "$dstdir" 244 | dstdir_status=$? 245 | else 246 | 247 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 248 | # might cause directories to be created, which would be especially bad 249 | # if $src (and thus $dsttmp) contains '*'. 250 | if test ! -f "$src" && test ! -d "$src"; then 251 | echo "$0: $src does not exist." >&2 252 | exit 1 253 | fi 254 | 255 | if test -z "$dst_arg"; then 256 | echo "$0: no destination specified." >&2 257 | exit 1 258 | fi 259 | 260 | dst=$dst_arg 261 | # Protect names starting with `-'. 262 | case $dst in 263 | -*) dst=./$dst;; 264 | esac 265 | 266 | # If destination is a directory, append the input filename; won't work 267 | # if double slashes aren't ignored. 268 | if test -d "$dst"; then 269 | if test -n "$no_target_directory"; then 270 | echo "$0: $dst_arg: Is a directory" >&2 271 | exit 1 272 | fi 273 | dstdir=$dst 274 | dst=$dstdir/`basename "$src"` 275 | dstdir_status=0 276 | else 277 | # Prefer dirname, but fall back on a substitute if dirname fails. 278 | dstdir=` 279 | (dirname "$dst") 2>/dev/null || 280 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 281 | X"$dst" : 'X\(//\)[^/]' \| \ 282 | X"$dst" : 'X\(//\)$' \| \ 283 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 284 | echo X"$dst" | 285 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 286 | s//\1/ 287 | q 288 | } 289 | /^X\(\/\/\)[^/].*/{ 290 | s//\1/ 291 | q 292 | } 293 | /^X\(\/\/\)$/{ 294 | s//\1/ 295 | q 296 | } 297 | /^X\(\/\).*/{ 298 | s//\1/ 299 | q 300 | } 301 | s/.*/./; q' 302 | ` 303 | 304 | test -d "$dstdir" 305 | dstdir_status=$? 306 | fi 307 | fi 308 | 309 | obsolete_mkdir_used=false 310 | 311 | if test $dstdir_status != 0; then 312 | case $posix_mkdir in 313 | '') 314 | # Create intermediate dirs using mode 755 as modified by the umask. 315 | # This is like FreeBSD 'install' as of 1997-10-28. 316 | umask=`umask` 317 | case $stripcmd.$umask in 318 | # Optimize common cases. 319 | *[2367][2367]) mkdir_umask=$umask;; 320 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 321 | 322 | *[0-7]) 323 | mkdir_umask=`expr $umask + 22 \ 324 | - $umask % 100 % 40 + $umask % 20 \ 325 | - $umask % 10 % 4 + $umask % 2 326 | `;; 327 | *) mkdir_umask=$umask,go-w;; 328 | esac 329 | 330 | # With -d, create the new directory with the user-specified mode. 331 | # Otherwise, rely on $mkdir_umask. 332 | if test -n "$dir_arg"; then 333 | mkdir_mode=-m$mode 334 | else 335 | mkdir_mode= 336 | fi 337 | 338 | posix_mkdir=false 339 | case $umask in 340 | *[123567][0-7][0-7]) 341 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 342 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 343 | ;; 344 | *) 345 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 346 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 347 | 348 | if (umask $mkdir_umask && 349 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 350 | then 351 | if test -z "$dir_arg" || { 352 | # Check for POSIX incompatibilities with -m. 353 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 354 | # other-writeable bit of parent directory when it shouldn't. 355 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 356 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 357 | case $ls_ld_tmpdir in 358 | d????-?r-*) different_mode=700;; 359 | d????-?--*) different_mode=755;; 360 | *) false;; 361 | esac && 362 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 363 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 364 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 365 | } 366 | } 367 | then posix_mkdir=: 368 | fi 369 | rmdir "$tmpdir/d" "$tmpdir" 370 | else 371 | # Remove any dirs left behind by ancient mkdir implementations. 372 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 373 | fi 374 | trap '' 0;; 375 | esac;; 376 | esac 377 | 378 | if 379 | $posix_mkdir && ( 380 | umask $mkdir_umask && 381 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 382 | ) 383 | then : 384 | else 385 | 386 | # The umask is ridiculous, or mkdir does not conform to POSIX, 387 | # or it failed possibly due to a race condition. Create the 388 | # directory the slow way, step by step, checking for races as we go. 389 | 390 | case $dstdir in 391 | /*) prefix='/';; 392 | -*) prefix='./';; 393 | *) prefix='';; 394 | esac 395 | 396 | eval "$initialize_posix_glob" 397 | 398 | oIFS=$IFS 399 | IFS=/ 400 | $posix_glob set -f 401 | set fnord $dstdir 402 | shift 403 | $posix_glob set +f 404 | IFS=$oIFS 405 | 406 | prefixes= 407 | 408 | for d 409 | do 410 | test -z "$d" && continue 411 | 412 | prefix=$prefix$d 413 | if test -d "$prefix"; then 414 | prefixes= 415 | else 416 | if $posix_mkdir; then 417 | (umask=$mkdir_umask && 418 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 419 | # Don't fail if two instances are running concurrently. 420 | test -d "$prefix" || exit 1 421 | else 422 | case $prefix in 423 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 424 | *) qprefix=$prefix;; 425 | esac 426 | prefixes="$prefixes '$qprefix'" 427 | fi 428 | fi 429 | prefix=$prefix/ 430 | done 431 | 432 | if test -n "$prefixes"; then 433 | # Don't fail if two instances are running concurrently. 434 | (umask $mkdir_umask && 435 | eval "\$doit_exec \$mkdirprog $prefixes") || 436 | test -d "$dstdir" || exit 1 437 | obsolete_mkdir_used=true 438 | fi 439 | fi 440 | fi 441 | 442 | if test -n "$dir_arg"; then 443 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 444 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 445 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 446 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 447 | else 448 | 449 | # Make a couple of temp file names in the proper directory. 450 | dsttmp=$dstdir/_inst.$$_ 451 | rmtmp=$dstdir/_rm.$$_ 452 | 453 | # Trap to clean up those temp files at exit. 454 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 455 | 456 | # Copy the file name to the temp name. 457 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 458 | 459 | # and set any options; do chmod last to preserve setuid bits. 460 | # 461 | # If any of these fail, we abort the whole thing. If we want to 462 | # ignore errors from any of these, just make sure not to ignore 463 | # errors from the above "$doit $cpprog $src $dsttmp" command. 464 | # 465 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 466 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 467 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 468 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 469 | 470 | # If -C, don't bother to copy if it wouldn't change the file. 471 | if $copy_on_change && 472 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 473 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 474 | 475 | eval "$initialize_posix_glob" && 476 | $posix_glob set -f && 477 | set X $old && old=:$2:$4:$5:$6 && 478 | set X $new && new=:$2:$4:$5:$6 && 479 | $posix_glob set +f && 480 | 481 | test "$old" = "$new" && 482 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 483 | then 484 | rm -f "$dsttmp" 485 | else 486 | # Rename the file to the real destination. 487 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 488 | 489 | # The rename failed, perhaps because mv can't rename something else 490 | # to itself, or perhaps because mv is so ancient that it does not 491 | # support -f. 492 | { 493 | # Now remove or move aside any old file at destination location. 494 | # We try this two ways since rm can't unlink itself on some 495 | # systems and the destination file might be busy for other 496 | # reasons. In this case, the final cleanup might fail but the new 497 | # file should still install successfully. 498 | { 499 | test ! -f "$dst" || 500 | $doit $rmcmd -f "$dst" 2>/dev/null || 501 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 502 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 503 | } || 504 | { echo "$0: cannot unlink or rename $dst" >&2 505 | (exit 1); exit 1 506 | } 507 | } && 508 | 509 | # Now rename the file to the real destination. 510 | $doit $mvcmd "$dsttmp" "$dst" 511 | } 512 | fi || exit 1 513 | 514 | trap '' 0 515 | fi 516 | done 517 | 518 | # Local variables: 519 | # eval: (add-hook 'write-file-hooks 'time-stamp) 520 | # time-stamp-start: "scriptversion=" 521 | # time-stamp-format: "%:y-%02m-%02d.%02H" 522 | # time-stamp-time-zone: "UTC" 523 | # time-stamp-end: "; # UTC" 524 | # End: 525 | -------------------------------------------------------------------------------- /src/active.h: -------------------------------------------------------------------------------- 1 | /* active.h 2 | 3 | Active list 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __active_h__ 30 | #define __active_h__ 31 | 32 | #include "poly.h" 33 | 34 | typedef struct _actlist 35 | { 36 | segment_t*list; 37 | int size; 38 | #ifdef SPLAY 39 | segment_t*root; 40 | #endif 41 | } actlist_t; 42 | 43 | #define actlist_left(a,s) ((s)->left) 44 | #define actlist_right(a,s) ((s)?(s)->right:(a)->list) 45 | 46 | actlist_t* actlist_new(); 47 | void actlist_destroy(actlist_t*a); 48 | int actlist_size(actlist_t*a); 49 | void actlist_verify(actlist_t*a, int32_t y); 50 | void actlist_dump(actlist_t*a, int32_t y, double gridsize); 51 | segment_t* actlist_find(actlist_t*a, point_t p1, point_t p2); // finds segment immediately to the left of p1 (breaking ties w/ p2) 52 | void actlist_insert(actlist_t*a, point_t p1, point_t p2, segment_t*s); 53 | void actlist_delete(actlist_t*a, segment_t*s); 54 | void actlist_swap(actlist_t*a, segment_t*s1, segment_t*s2); 55 | segment_t* actlist_leftmost(actlist_t*a); 56 | segment_t* actlist_rightmost(actlist_t*a); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/convert.c: -------------------------------------------------------------------------------- 1 | /* convert.c 2 | 3 | Polygon conversion functions 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "poly.h" 33 | #include "convert.h" 34 | #include "wind.h" 35 | #include "dict.h" 36 | #include "gfxline.h" 37 | 38 | /* factor that determines into how many line fragments a spline is converted */ 39 | #define SUBFRACTION (2.4) 40 | 41 | static inline int32_t convert_coord(double x, double z) 42 | { 43 | /* we clamp to 26 bit because: 44 | a) we use a (x1-x2) shortcut when comparing coordinates 45 | b) we need to be able to multiply two coordinates and store them in a double w/o loss of precision 46 | */ 47 | x *= z; 48 | if(x < -0x2000000) x = -0x2000000; 49 | if(x > 0x1ffffff) x = 0x1ffffff; 50 | return ceil(x); 51 | } 52 | 53 | static void convert_gfxline(gfxline_t*_line, polywriter_t*w, double gridsize) 54 | { 55 | gfxline_t*line = gfxline_rewind(_line); 56 | assert(!line || line[0].type == gfx_moveTo); 57 | double lastx=0,lasty=0; 58 | double z = 1.0 / gridsize; 59 | while(line) { 60 | if(line->type == gfx_moveTo) { 61 | if(line->next && line->next->type != gfx_moveTo && (line->x!=lastx || line->y!=lasty)) { 62 | w->moveto(w, convert_coord(line->x,z), convert_coord(line->y,z)); 63 | } 64 | } else if(line->type == gfx_lineTo) { 65 | w->lineto(w, convert_coord(line->x,z), convert_coord(line->y,z)); 66 | } else if(line->type == gfx_splineTo) { 67 | int parts = (int)(sqrt(fabs(line->x-2*line->sx+lastx) + 68 | fabs(line->y-2*line->sy+lasty))*SUBFRACTION); 69 | if(!parts) parts = 1; 70 | double stepsize = 1.0/parts; 71 | int i; 72 | for(i=0;ix*t*t + 2*line->sx*t*(1-t) + lastx*(1-t)*(1-t)); 75 | double sy = (line->y*t*t + 2*line->sy*t*(1-t) + lasty*(1-t)*(1-t)); 76 | w->lineto(w, convert_coord(sx,z), convert_coord(sy,z)); 77 | } 78 | w->lineto(w, convert_coord(line->x,z), convert_coord(line->y,z)); 79 | } 80 | lastx = line->x; 81 | lasty = line->y; 82 | line = line->next; 83 | } 84 | } 85 | 86 | static char* readline(FILE*fi) 87 | { 88 | /* FIXME: Rather than reading the file byte by byte, we should really use 89 | buffers or mmap */ 90 | char c; 91 | while(1) { 92 | int l = fread(&c, 1, 1, fi); 93 | if(!l) 94 | return 0; 95 | if(c!=10 || c!=13) 96 | break; 97 | } 98 | char line[256]; 99 | int pos = 0; 100 | while(1) { 101 | if(posmoveto(w, convert_coord(x,z), convert_coord(y,z)); 131 | count++; 132 | } else if(!strcmp(s,"lineto")) { 133 | w->lineto(w, convert_coord(x,z), convert_coord(y,z)); 134 | count++; 135 | } else { 136 | fprintf(stderr, "invalid command: %s\n", s); 137 | } 138 | } else if(sscanf(line, "%% gridsize %lf", &g) == 1) { 139 | gridsize = g; 140 | z = 1.0 / gridsize; 141 | w->setgridsize(w, g); 142 | } 143 | free(line); 144 | } 145 | fclose(fi); 146 | if(g) { 147 | fprintf(stderr, "loaded %d points from %s (gridsize %f)\n", count, filename, g); 148 | } else { 149 | fprintf(stderr, "loaded %d points from %s\n", count, filename); 150 | } 151 | } 152 | 153 | typedef struct _compactpoly { 154 | void*fs; 155 | gfxpoly_t*poly; 156 | point_t last; 157 | point_t*points; 158 | int num_points; 159 | int points_size; 160 | segment_dir_t dir; 161 | char new; 162 | } compactpoly_t; 163 | 164 | void finish_segment(compactpoly_t*data, void*fs) 165 | { 166 | /* FIXME: we should just skip segments if they have a NULL edge style, 167 | instead of requiring this to be non-NULL */ 168 | assert(fs); 169 | 170 | if(data->num_points <= 1) 171 | return; 172 | point_t*p = malloc(sizeof(point_t)*data->num_points); 173 | gfxsegmentlist_t*s = calloc(1,sizeof(gfxsegmentlist_t)); 174 | s->fs = fs; 175 | s->next = data->poly->strokes; 176 | data->poly->strokes = s; 177 | s->num_points = s->points_size = data->num_points; 178 | s->dir = data->dir; 179 | s->points = p; 180 | assert(data->dir != DIR_UNKNOWN); 181 | if(data->dir == DIR_UP) { 182 | int t; 183 | int s = data->num_points; 184 | for(t=0;tnum_points;t++) { 185 | p[--s] = data->points[t]; 186 | } 187 | } else { 188 | memcpy(p, data->points, sizeof(point_t)*data->num_points); 189 | } 190 | #ifdef CHECKS 191 | int t; 192 | for(t=0;tnum_points-1;t++) { 193 | assert(p[t].y<=p[t+1].y); 194 | } 195 | #endif 196 | } 197 | 198 | static void compactsetedgestyle(polywriter_t*w, void*fs) 199 | { 200 | compactpoly_t*data = (compactpoly_t*)w->internal; 201 | data->fs = fs; 202 | } 203 | 204 | static void compactmoveto(polywriter_t*w, int32_t x, int32_t y) 205 | { 206 | compactpoly_t*data = (compactpoly_t*)w->internal; 207 | point_t p; 208 | p.x = x; 209 | p.y = y; 210 | if(p.x != data->last.x || p.y != data->last.y) { 211 | data->new = 1; 212 | } 213 | data->last = p; 214 | } 215 | 216 | static inline int direction(point_t p1, point_t p2) 217 | { 218 | int diff = p1.y - p2.y; 219 | if(diff) return diff; 220 | return p1.x - p2.x; 221 | } 222 | 223 | static void compactlineto(polywriter_t*w, int32_t x, int32_t y) 224 | { 225 | compactpoly_t*data = (compactpoly_t*)w->internal; 226 | point_t p; 227 | p.x = x; 228 | p.y = y; 229 | 230 | int diff = direction(p, data->last); 231 | if(!diff) 232 | return; 233 | segment_dir_t dir = diff<0?DIR_UP:DIR_DOWN; 234 | 235 | if(dir!=data->dir || data->new) { 236 | finish_segment(data, data->fs); 237 | data->dir = dir; 238 | data->points[0] = data->last; 239 | data->num_points = 1; 240 | } 241 | data->new = 0; 242 | 243 | if(data->points_size == data->num_points) { 244 | data->points_size <<= 1; 245 | assert(data->points_size > data->num_points); 246 | data->points = realloc(data->points, sizeof(point_t)*data->points_size); 247 | } 248 | data->points[data->num_points++] = p; 249 | data->last = p; 250 | } 251 | static void compactsetgridsize(polywriter_t*w, double gridsize) 252 | { 253 | compactpoly_t*d = (compactpoly_t*)w->internal; 254 | d->poly->gridsize = gridsize; 255 | } 256 | /*static int compare_stroke(const void*_s1, const void*_s2) 257 | { 258 | gfxsegmentlist_t*s1 = (gfxsegmentlist_t*)_s1; 259 | gfxsegmentlist_t*s2 = (gfxsegmentlist_t*)_s2; 260 | return s1->points[0].y - s2->points[0].y; 261 | }*/ 262 | static void*compactfinish(polywriter_t*w) 263 | { 264 | compactpoly_t*data = (compactpoly_t*)w->internal; 265 | finish_segment(data, data->fs); 266 | //qsort(data->poly->strokes, data->poly->num_strokes, sizeof(gfxsegmentlist_t), compare_stroke); 267 | free(data->points); 268 | gfxpoly_t*poly = data->poly; 269 | free(w->internal);w->internal = 0; 270 | return (void*)poly; 271 | } 272 | void gfxpolywriter_init(polywriter_t*w) 273 | { 274 | w->setedgestyle = compactsetedgestyle; 275 | w->moveto = compactmoveto; 276 | w->lineto = compactlineto; 277 | w->setgridsize = compactsetgridsize; 278 | w->finish = compactfinish; 279 | compactpoly_t*data = w->internal = calloc(1,sizeof(compactpoly_t)); 280 | data->poly = calloc(1,sizeof(gfxpoly_t)); 281 | data->poly->gridsize = 1.0; 282 | data->last.x = data->last.y = 0; 283 | data->num_points = 0; 284 | data->points_size = 16; 285 | data->new = 1; 286 | data->dir = DIR_UNKNOWN; 287 | data->points = (point_t*)malloc(sizeof(point_t)*data->points_size); 288 | data->poly->strokes = 0; 289 | data->fs = &edgestyle_default; 290 | } 291 | 292 | gfxpoly_t* gfxpoly_from_fill(gfxline_t*line, double gridsize) 293 | { 294 | polywriter_t writer; 295 | gfxpolywriter_init(&writer); 296 | writer.setgridsize(&writer, gridsize); 297 | convert_gfxline(line, &writer, gridsize); 298 | return (gfxpoly_t*)writer.finish(&writer); 299 | } 300 | gfxpoly_t* gfxpoly_from_file(const char*filename) 301 | { 302 | polywriter_t writer; 303 | gfxpolywriter_init(&writer); 304 | double default_gridsize = 1.0; 305 | writer.setgridsize(&writer, default_gridsize); 306 | convert_file(filename, &writer, default_gridsize); 307 | return (gfxpoly_t*)writer.finish(&writer); 308 | } 309 | void gfxpoly_destroy(gfxpoly_t*poly) 310 | { 311 | gfxsegmentlist_t*stroke = poly->strokes; 312 | while(stroke) { 313 | gfxsegmentlist_t*next = stroke->next; 314 | free(stroke->points); 315 | free(stroke); 316 | stroke = next; 317 | } 318 | free(poly); 319 | } 320 | 321 | typedef struct _polydraw_internal 322 | { 323 | double lx, ly; 324 | int32_t lastx, lasty; 325 | int32_t x0, y0; 326 | double z; 327 | char last; 328 | polywriter_t writer; 329 | } polydraw_internal_t; 330 | 331 | static void polydraw_setUserData(gfxcanvas_t*d, void*fs) 332 | { 333 | polydraw_internal_t*i = (polydraw_internal_t*)d->internal; 334 | i->writer.setedgestyle(&i->writer, fs); 335 | } 336 | static void polydraw_moveTo(gfxcanvas_t*d, gfxcoord_t _x, gfxcoord_t _y) 337 | { 338 | polydraw_internal_t*i = (polydraw_internal_t*)d->internal; 339 | int32_t x = convert_coord(_x, i->z); 340 | int32_t y = convert_coord(_y, i->z); 341 | if(i->lastx != x || i->lasty != y) { 342 | i->writer.moveto(&i->writer, x, y); 343 | } 344 | i->lx = _x; 345 | i->ly = _y; 346 | i->x0 = x; 347 | i->y0 = y; 348 | i->lastx = x; 349 | i->lasty = y; 350 | i->last = 1; 351 | } 352 | static void polydraw_lineTo(gfxcanvas_t*d, gfxcoord_t _x, gfxcoord_t _y) 353 | { 354 | polydraw_internal_t*i = (polydraw_internal_t*)d->internal; 355 | if(!i->last) { 356 | polydraw_moveTo(d, _x, _y); 357 | return; 358 | } 359 | int32_t x = convert_coord(_x, i->z); 360 | int32_t y = convert_coord(_y, i->z); 361 | if(i->lastx != x || i->lasty != y) { 362 | i->writer.lineto(&i->writer, x, y); 363 | } 364 | i->lx = _x; 365 | i->ly = _y; 366 | i->lastx = x; 367 | i->lasty = y; 368 | i->last = 1; 369 | } 370 | static void polydraw_splineTo(gfxcanvas_t*d, gfxcoord_t sx, gfxcoord_t sy, gfxcoord_t x, gfxcoord_t y) 371 | { 372 | polydraw_internal_t*i = (polydraw_internal_t*)d->internal; 373 | if(!i->last) { 374 | polydraw_moveTo(d, x, y); 375 | return; 376 | } 377 | double c = fabs(x-2*sx+i->lx) + fabs(y-2*sy+i->ly); 378 | int parts = (int)(sqrt(c)*SUBFRACTION); 379 | if(!parts) parts = 1; 380 | int t; 381 | int32_t nx,ny; 382 | for(t=0;tlx)/(double)(parts*parts), i->z); 384 | ny = convert_coord((double)(t*t*y + 2*t*(parts-t)*sy + (parts-t)*(parts-t)*i->ly)/(double)(parts*parts), i->z); 385 | if(nx != i->lastx || ny != i->lasty) { 386 | i->writer.lineto(&i->writer, nx, ny); 387 | i->lastx = nx; i->lasty = ny; 388 | } 389 | } 390 | nx = convert_coord(x,i->z); 391 | ny = convert_coord(y,i->z); 392 | if(nx != i->lastx || ny != i->lasty) { 393 | i->writer.lineto(&i->writer, nx, ny); 394 | } 395 | i->lx = x; 396 | i->ly = y; 397 | i->lastx = nx; 398 | i->lasty = ny; 399 | i->last = 1; 400 | } 401 | static void polydraw_close(gfxcanvas_t*d) 402 | { 403 | polydraw_internal_t*i = (polydraw_internal_t*)d->internal; 404 | assert(!(i->last && (i->x0 == INVALID_COORD || i->y0 == INVALID_COORD))); 405 | if(!i->last) 406 | return; 407 | if(i->lastx != i->x0 || i->lasty != i->y0) { 408 | i->writer.lineto(&i->writer, i->x0, i->y0); 409 | i->lastx = i->x0; 410 | i->lasty = i->y0; 411 | } 412 | i->last = 0; 413 | i->x0 = INVALID_COORD; 414 | i->y0 = INVALID_COORD; 415 | } 416 | static void* polydraw_result(gfxcanvas_t*d) 417 | { 418 | polydraw_internal_t*i = (polydraw_internal_t*)d->internal; 419 | assert(!i->last); 420 | void*result = i->writer.finish(&i->writer); 421 | free(i); 422 | free(d); 423 | return result; 424 | } 425 | 426 | gfxcanvas_t* gfxcanvas_new(double gridsize) 427 | { 428 | gfxcanvas_t*d = calloc(1, sizeof(gfxcanvas_t)); 429 | polydraw_internal_t*i = (polydraw_internal_t*)calloc(1, sizeof(polydraw_internal_t)); 430 | d->internal = i; 431 | i->lastx = INVALID_COORD; // convert_coord can never return this value 432 | i->lasty = INVALID_COORD; 433 | i->x0 = INVALID_COORD; 434 | i->y0 = INVALID_COORD; 435 | d->setUserData = polydraw_setUserData; 436 | d->moveTo = polydraw_moveTo; 437 | d->lineTo = polydraw_lineTo; 438 | d->splineTo = polydraw_splineTo; 439 | d->close = polydraw_close; 440 | d->result = polydraw_result; 441 | gfxpolywriter_init(&i->writer); 442 | i->writer.setgridsize(&i->writer, gridsize); 443 | i->z = 1.0 / gridsize; 444 | return d; 445 | } 446 | 447 | static gfxline_t*mkgfxline(gfxpoly_t*poly, char preserve_direction) 448 | { 449 | gfxsegmentlist_t*stroke; 450 | int count = 0; 451 | if(!poly->strokes) 452 | return 0; 453 | dict_t*d = dict_new(&point_type); 454 | dict_t*todo = dict_new(&ptr_type); 455 | gfxsegmentlist_t*stroke_min= poly->strokes; 456 | int32_t x_min=stroke_min->points[0].x; 457 | int32_t y_min=stroke_min->points[0].y; 458 | for(stroke=poly->strokes;stroke;stroke=stroke->next) { 459 | dict_put(todo, stroke, stroke); 460 | assert(stroke->num_points>1); 461 | count += stroke->num_points; 462 | if(stroke->dir == DIR_UP) { 463 | dict_put(d, &stroke->points[stroke->num_points-1], stroke); 464 | if(!preserve_direction) 465 | dict_put(d, &stroke->points[0], stroke); 466 | } else { 467 | dict_put(d, &stroke->points[0], stroke); 468 | if(!preserve_direction) 469 | dict_put(d, &stroke->points[stroke->num_points-1], stroke); 470 | } 471 | if(stroke->points[0].y < y_min || 472 | (stroke->points[0].y == y_min && stroke->points[0].x < x_min)) { 473 | y_min = stroke->points[0].y; 474 | stroke_min = stroke; 475 | } 476 | } 477 | gfxsegmentlist_t*next_todo = poly->strokes; 478 | stroke = stroke_min; 479 | 480 | point_t last = {INVALID_COORD, INVALID_COORD}; 481 | char should_connect = 0; 482 | 483 | gfxline_t*l = gfxline_new(); 484 | while(stroke) { 485 | if(stroke && !preserve_direction) { 486 | char del1 = dict_del2(d, &stroke->points[0], stroke); 487 | char del2 = dict_del2(d, &stroke->points[stroke->num_points-1], stroke); 488 | assert(del1 && del2); 489 | } 490 | assert(dict_contains(todo, stroke)); 491 | int t; 492 | int pos = 0; 493 | int incr = 1; 494 | if(preserve_direction) { 495 | if(stroke->dir == DIR_UP) { 496 | pos = stroke->num_points-1; 497 | incr = -1; 498 | } 499 | } else { 500 | // try to find matching point on either end. 501 | // Prefer downward. 502 | if(last.x == stroke->points[stroke->num_points-1].x && 503 | last.y == stroke->points[stroke->num_points-1].y) { 504 | pos = stroke->num_points-1; 505 | incr = -1; 506 | } 507 | } 508 | if(last.x != stroke->points[pos].x || last.y != stroke->points[pos].y) { 509 | l = gfxline_moveTo(l, stroke->points[pos].x * poly->gridsize, 510 | stroke->points[pos].y * poly->gridsize); 511 | assert(!should_connect); 512 | } 513 | pos += incr; 514 | for(t=1;tnum_points;t++) { 515 | l = gfxline_lineTo(l, stroke->points[pos].x * poly->gridsize, 516 | stroke->points[pos].y * poly->gridsize); 517 | pos += incr; 518 | } 519 | last = stroke->points[pos-incr]; 520 | char del = dict_del(todo, stroke); 521 | assert(del); 522 | assert(!dict_contains(todo, stroke)); 523 | 524 | /* try to find a poly which starts at the point we have drawn last */ 525 | stroke = dict_lookup(d, &last); 526 | should_connect = 1; 527 | while(!dict_contains(todo, stroke)) { 528 | should_connect = 0; 529 | stroke = next_todo; 530 | if(!next_todo) { 531 | stroke = 0; 532 | break; 533 | } 534 | next_todo = next_todo->next; 535 | } 536 | } 537 | dict_destroy(todo); 538 | dict_destroy(d); 539 | return l; 540 | } 541 | 542 | gfxline_t*gfxline_from_gfxpoly(gfxpoly_t*poly) 543 | { 544 | return gfxline_rewind(mkgfxline(poly, 0)); 545 | } 546 | 547 | gfxline_t*gfxline_from_gfxpoly_with_direction(gfxpoly_t*poly) 548 | { 549 | return gfxline_rewind(mkgfxline(poly, 1)); 550 | } 551 | 552 | gfxline_t* gfxpoly_circular_to_evenodd(gfxline_t*line, double gridsize) 553 | { 554 | gfxpoly_t*poly = gfxpoly_from_fill(line, gridsize); 555 | gfxpoly_t*poly2 = gfxpoly_process(poly, 0, &windrule_circular, &onepolygon, 0); 556 | gfxline_t*line2 = gfxline_from_gfxpoly(poly2); 557 | gfxpoly_destroy(poly); 558 | gfxpoly_destroy(poly2); 559 | return line2; 560 | } 561 | 562 | gfxline_t*gfxline_makerectangle(double x1,double y1,double x2, double y2) 563 | { 564 | gfxline_t* line = gfxline_new(); 565 | line = gfxline_moveTo(line, x1, y1); 566 | line = gfxline_lineTo(line, x2, y1); 567 | line = gfxline_lineTo(line, x2, y2); 568 | line = gfxline_lineTo(line, x1, y2); 569 | line = gfxline_lineTo(line, x1, y1); 570 | return line; 571 | } 572 | 573 | gfxpoly_t* gfxpoly_createbox(double x1, double y1,double x2, double y2, double gridsize) 574 | { 575 | gfxline_t* line = gfxline_makerectangle(x1, y1, x2, y2); 576 | gfxpoly_t* poly = gfxpoly_from_fill(line, gridsize); 577 | gfxline_destroy(line); 578 | return poly; 579 | } 580 | 581 | void gfxline_print(gfxline_t*_l) 582 | { 583 | gfxline_t*l = gfxline_rewind(_l); 584 | while(l) { 585 | if(l->type == gfx_moveTo) { 586 | printf("moveTo %.2f,%.2f\n", l->x, l->y); 587 | } 588 | if(l->type == gfx_lineTo) { 589 | printf("lineTo %.2f,%.2f\n", l->x, l->y); 590 | } 591 | if(l->type == gfx_splineTo) { 592 | printf("splineTo %.2f,%.2f %.2f,%.2f\n", l->sx, l->sy, l->x, l->y); 593 | } 594 | l = l->next; 595 | } 596 | } 597 | 598 | void gfxline_destroy(gfxline_t*_l) 599 | { 600 | gfxline_t* l = gfxline_rewind(_l); 601 | if(l && (l+1) == l->next) { 602 | /* flattened */ 603 | free(l); 604 | } else { 605 | gfxline_t*next; 606 | while(l) { 607 | next = l->next; 608 | l->next = 0; 609 | free(l); 610 | l = next; 611 | } 612 | } 613 | } 614 | 615 | -------------------------------------------------------------------------------- /src/convert.h: -------------------------------------------------------------------------------- 1 | /* convert.h 2 | 3 | Polygon conversion functions 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __poly_convert_h__ 30 | #define __poly_convert_h__ 31 | 32 | #include "poly.h" 33 | 34 | typedef struct _polywriter 35 | { 36 | void(*setedgestyle)(struct _polywriter*, void*style); 37 | void(*moveto)(struct _polywriter*, int32_t x, int32_t y); 38 | void(*lineto)(struct _polywriter*, int32_t x, int32_t y); 39 | void(*setgridsize)(struct _polywriter*, double g); 40 | void*(*finish)(struct _polywriter*); 41 | void*internal; 42 | } polywriter_t; 43 | 44 | void gfxcanvas_target_poly(gfxcanvas_t*d, double gridsize); 45 | 46 | void gfxpolywriter_init(polywriter_t*w); 47 | gfxpoly_t* gfxpoly_from_fill(gfxline_t*line, double gridsize); 48 | gfxpoly_t* gfxpoly_from_file(const char*filename); 49 | 50 | #endif //__poly_convert_h__ 51 | -------------------------------------------------------------------------------- /src/dict.c: -------------------------------------------------------------------------------- 1 | /* dict.c 2 | 3 | Hashtable implementation 4 | 5 | Copyright (c) 2010-2011 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "dict.h" 33 | 34 | // ------------------------------- crc32 ------------------------------- 35 | static unsigned int crc32[256]; 36 | static char crc32_initialized=0; 37 | static void crc32_init(void) 38 | { 39 | int t; 40 | if(crc32_initialized) 41 | return; 42 | crc32_initialized = 1; 43 | for(t=0; t<256; t++) { 44 | unsigned int c = t; 45 | int s; 46 | for (s = 0; s < 8; s++) { 47 | c = (0xedb88320L*(c&1)) ^ (c >> 1); 48 | } 49 | crc32[t] = c; 50 | } 51 | } 52 | // ------------------------------- hash function ----------------------- 53 | unsigned int crc32_add_byte(unsigned int checksum, unsigned char b) 54 | { 55 | crc32_init(); 56 | return checksum>>8 ^ crc32[(b^checksum)&0xff]; 57 | } 58 | unsigned int crc32_add_string(unsigned int checksum, const char*s) 59 | { 60 | crc32_init(); 61 | if(!s) 62 | return checksum; 63 | while(*s) { 64 | checksum = checksum>>8 ^ crc32[(*s^checksum)&0xff]; 65 | s++; 66 | } 67 | return checksum; 68 | } 69 | unsigned int crc32_add_bytes(unsigned int checksum, const void*_s, int len) 70 | { 71 | unsigned char*s = (unsigned char*)_s; 72 | crc32_init(); 73 | if(!s || !len) 74 | return checksum; 75 | do { 76 | checksum = checksum>>8 ^ crc32[(*s^checksum)&0xff]; 77 | s++; 78 | } while(--len); 79 | return checksum; 80 | } 81 | unsigned int hash_block(const unsigned char*data, int len) 82 | { 83 | int t; 84 | unsigned int checksum = 0; 85 | crc32_init(); 86 | for(t=0;t>8 ^ crc32[(data[t]^checksum)&0xff]; 88 | } 89 | return checksum; 90 | } 91 | 92 | // ------------------------------- type_t ------------------------------- 93 | 94 | bool ptr_equals(const void*o1, const void*o2) 95 | { 96 | return o1==o2; 97 | } 98 | unsigned int ptr_hash(const void*o) 99 | { 100 | return hash_block((unsigned char*)&o, sizeof(o)); 101 | } 102 | void* ptr_dup(const void*o) 103 | { 104 | return (void*)o; 105 | } 106 | void ptr_free(void*o) 107 | { 108 | return; 109 | } 110 | 111 | bool int_equals(const void*o1, const void*o2) 112 | { 113 | return o1==o2; 114 | } 115 | unsigned int int_hash(const void*o) 116 | { 117 | return hash_block((const unsigned char*)&o, sizeof(o)); 118 | } 119 | void* int_dup(const void*o) 120 | { 121 | return (void*)o; 122 | } 123 | void int_free(void*o) 124 | { 125 | return; 126 | } 127 | 128 | bool charptr_equals(const void*o1, const void*o2) 129 | { 130 | if(!o1 || !o2) 131 | return o1==o2; 132 | return !strcmp(o1,o2); 133 | } 134 | unsigned int charptr_hash(const void*o) 135 | { 136 | if(!o) 137 | return 0; 138 | int l = strlen(o); 139 | return hash_block((unsigned char*)o, l); 140 | } 141 | void* charptr_dup(const void*o) 142 | { 143 | if(!o) 144 | return 0; 145 | return strdup(o); 146 | } 147 | void charptr_free(void*o) 148 | { 149 | if(o) { 150 | free(o); 151 | } 152 | } 153 | 154 | type_t int_type = { 155 | equals: int_equals, 156 | hash: int_hash, 157 | dup: int_dup, 158 | free: int_free, 159 | }; 160 | 161 | type_t ptr_type = { 162 | equals: ptr_equals, 163 | hash: ptr_hash, 164 | dup: ptr_dup, 165 | free: ptr_free, 166 | }; 167 | 168 | type_t charptr_type = { 169 | equals: charptr_equals, 170 | hash: charptr_hash, 171 | dup: charptr_dup, 172 | free: charptr_free, 173 | }; 174 | 175 | // ------------------------------- dictionary_t ------------------------------- 176 | 177 | #define INITIAL_SIZE 1 178 | 179 | dict_t*dict_new(type_t*t) 180 | { 181 | dict_t*d = malloc(sizeof(dict_t)); 182 | dict_init(d, INITIAL_SIZE); 183 | d->key_type = t; 184 | return d; 185 | } 186 | void dict_init(dict_t*h, int size) 187 | { 188 | memset(h, 0, sizeof(dict_t)); 189 | h->hashsize = size; 190 | h->slots = h->hashsize?(dictentry_t**)calloc(1,sizeof(dictentry_t*)*h->hashsize):0; 191 | h->num = 0; 192 | h->key_type = &charptr_type; 193 | } 194 | void dict_init2(dict_t*h, type_t*t, int size) 195 | { 196 | memset(h, 0, sizeof(dict_t)); 197 | h->hashsize = size; 198 | h->slots = h->hashsize?(dictentry_t**)calloc(1,sizeof(dictentry_t*)*h->hashsize):0; 199 | h->num = 0; 200 | h->key_type = t; 201 | } 202 | 203 | dict_t*dict_clone(dict_t*o) 204 | { 205 | dict_t*h = malloc(sizeof(dict_t)); 206 | memcpy(h, o, sizeof(dict_t)); 207 | h->slots = h->hashsize?(dictentry_t**)calloc(1,sizeof(dictentry_t*)*h->hashsize):0; 208 | int t; 209 | for(t=0;thashsize;t++) { 210 | dictentry_t*e = o->slots[t]; 211 | while(e) { 212 | dictentry_t*n = (dictentry_t*)malloc(sizeof(dictentry_t)); 213 | memcpy(n, e, sizeof(dictentry_t)); 214 | n->key = h->key_type->dup(e->key); 215 | n->data = e->data; 216 | n->next = h->slots[t]; 217 | h->slots[t] = n; 218 | e = e->next; 219 | } 220 | } 221 | return h; 222 | } 223 | 224 | static void dict_expand(dict_t*h, int newlen) 225 | { 226 | assert(h->hashsize < newlen); 227 | dictentry_t**newslots = (dictentry_t**)calloc(1,sizeof(dictentry_t*)*newlen); 228 | int t; 229 | for(t=0;thashsize;t++) { 230 | dictentry_t*e = h->slots[t]; 231 | while(e) { 232 | dictentry_t*next = e->next; 233 | unsigned int newhash = e->hash%newlen; 234 | e->next = newslots[newhash]; 235 | newslots[newhash] = e; 236 | e = next; 237 | } 238 | } 239 | if(h->slots) 240 | free(h->slots); 241 | h->slots = newslots; 242 | h->hashsize = newlen; 243 | } 244 | 245 | dictentry_t* dict_put(dict_t*h, const void*key, void* data) 246 | { 247 | unsigned int hash = h->key_type->hash(key); 248 | dictentry_t*e = (dictentry_t*)malloc(sizeof(dictentry_t)); 249 | 250 | if(!h->hashsize) 251 | dict_expand(h, 1); 252 | 253 | unsigned int hash2 = hash % h->hashsize; 254 | 255 | e->key = h->key_type->dup(key); 256 | e->hash = hash; //for resizing 257 | e->next = h->slots[hash2]; 258 | e->data = data; 259 | h->slots[hash2] = e; 260 | h->num++; 261 | return e; 262 | } 263 | void dict_put2(dict_t*h, const char*s, void*data) 264 | { 265 | assert(h->key_type == &charptr_type); 266 | dict_put(h, s, data); 267 | } 268 | void dict_dump(dict_t*h, FILE*fi, const char*prefix) 269 | { 270 | int t; 271 | for(t=0;thashsize;t++) { 272 | dictentry_t*e = h->slots[t]; 273 | while(e) { 274 | if(h->key_type!=&charptr_type) { 275 | fprintf(fi, "%s%p=%p\n", prefix, e->key, e->data); 276 | } else { 277 | fprintf(fi, "%s%s=%p\n", prefix, (char*)e->key, e->data); 278 | } 279 | e = e->next; 280 | } 281 | } 282 | } 283 | 284 | int dict_count(dict_t*h) 285 | { 286 | return h->num; 287 | } 288 | 289 | static inline dictentry_t* dict_do_lookup(dict_t*h, const void*key) 290 | { 291 | if(!h->num) { 292 | return 0; 293 | } 294 | 295 | unsigned int ohash = h->key_type->hash(key); 296 | unsigned int hash = ohash % h->hashsize; 297 | 298 | /* check first entry for match */ 299 | dictentry_t*e = h->slots[hash]; 300 | if(e && h->key_type->equals(e->key, key)) { 301 | return e; 302 | } else if(e) { 303 | e = e->next; 304 | } 305 | 306 | /* if dict is 2/3 filled, double the size. Do 307 | this the first time we have to actually iterate 308 | through a slot to find our data */ 309 | if(e && h->num*3 >= h->hashsize*2) { 310 | int newsize = h->hashsize; 311 | while(h->num*3 >= newsize*2) { 312 | newsize = newsize<15?15:(newsize+1)*2-1; 313 | } 314 | dict_expand(h, newsize); 315 | hash = ohash % h->hashsize; 316 | e = h->slots[hash]; 317 | if(e && h->key_type->equals(e->key, key)) { 318 | // omit move to front 319 | return e; 320 | } else if(e) { 321 | e = e->next; 322 | } 323 | } 324 | 325 | /* check subsequent entries for a match */ 326 | dictentry_t*last = h->slots[hash]; 327 | while(e) { 328 | if(h->key_type->equals(e->key, key)) { 329 | /* move to front- makes a difference of about 10% in most applications */ 330 | last->next = e->next; 331 | e->next = h->slots[hash]; 332 | h->slots[hash] = e; 333 | return e; 334 | } 335 | last=e; 336 | e = e->next; 337 | } 338 | return 0; 339 | } 340 | void* dict_lookup(dict_t*h, const void*key) 341 | { 342 | dictentry_t*e = dict_do_lookup(h, key); 343 | if(e) 344 | return e->data; 345 | return 0; 346 | } 347 | char dict_contains(dict_t*h, const void*key) 348 | { 349 | dictentry_t*e = dict_do_lookup(h, key); 350 | return !!e; 351 | } 352 | 353 | char dict_del(dict_t*h, const void*key) 354 | { 355 | if(!h->num) 356 | return 0; 357 | unsigned int hash = h->key_type->hash(key) % h->hashsize; 358 | dictentry_t*head = h->slots[hash]; 359 | dictentry_t*e = head, *prev=0; 360 | while(e) { 361 | if(h->key_type->equals(e->key, key)) { 362 | dictentry_t*next = e->next; 363 | h->key_type->free(e->key); 364 | memset(e, 0, sizeof(dictentry_t)); 365 | free(e); 366 | if(e == head) { 367 | h->slots[hash] = next; 368 | } else { 369 | assert(prev); 370 | prev->next = next; 371 | } 372 | h->num--; 373 | return 1; 374 | } 375 | prev = e; 376 | e = e->next; 377 | } 378 | return 0; 379 | } 380 | 381 | char dict_del2(dict_t*h, const void*key, void*data) 382 | { 383 | if(!h->num) 384 | return 0; 385 | unsigned int hash = h->key_type->hash(key) % h->hashsize; 386 | dictentry_t*head = h->slots[hash]; 387 | dictentry_t*e = head, *prev=0; 388 | while(e) { 389 | if(h->key_type->equals(e->key, key) && e->data == data) { 390 | dictentry_t*next = e->next; 391 | h->key_type->free(e->key); 392 | memset(e, 0, sizeof(dictentry_t)); 393 | free(e); 394 | if(e == head) { 395 | h->slots[hash] = next; 396 | } else { 397 | assert(prev); 398 | prev->next = next; 399 | } 400 | h->num--; 401 | return 1; 402 | } 403 | prev = e; 404 | e = e->next; 405 | } 406 | return 0; 407 | } 408 | 409 | dictentry_t* dict_get_slot(dict_t*h, const void*key) 410 | { 411 | if(!h->num) 412 | return 0; 413 | unsigned int ohash = h->key_type->hash(key); 414 | unsigned int hash = ohash % h->hashsize; 415 | return h->slots[hash]; 416 | } 417 | 418 | void dict_foreach_keyvalue(dict_t*h, void (*runFunction)(void*data, const void*key, void*val), void*data) 419 | { 420 | int t; 421 | for(t=0;thashsize;t++) { 422 | dictentry_t*e = h->slots[t]; 423 | while(e) { 424 | dictentry_t*next = e->next; 425 | if(runFunction) { 426 | runFunction(data, e->key, e->data); 427 | } 428 | e = next; 429 | } 430 | } 431 | } 432 | void dict_foreach_value(dict_t*h, void (*runFunction)(void*)) 433 | { 434 | int t; 435 | for(t=0;thashsize;t++) { 436 | dictentry_t*e = h->slots[t]; 437 | while(e) { 438 | dictentry_t*next = e->next; 439 | if(runFunction) { 440 | runFunction(e->data); 441 | } 442 | e = next; 443 | } 444 | } 445 | } 446 | 447 | void dict_free_all(dict_t*h, char free_keys, void (*free_data_function)(void*)) 448 | { 449 | int t; 450 | for(t=0;thashsize;t++) { 451 | dictentry_t*e = h->slots[t]; 452 | while(e) { 453 | dictentry_t*next = e->next; 454 | if(free_keys) { 455 | h->key_type->free(e->key); 456 | } 457 | if(free_data_function) { 458 | free_data_function(e->data); 459 | } 460 | memset(e, 0, sizeof(dictentry_t)); 461 | free(e); 462 | e = next; 463 | } 464 | h->slots[t]=0; 465 | } 466 | free(h->slots); 467 | memset(h, 0, sizeof(dict_t)); 468 | } 469 | 470 | void dict_clear_shallow(dict_t*h) 471 | { 472 | dict_free_all(h, 0, 0); 473 | } 474 | 475 | void dict_clear(dict_t*h) 476 | { 477 | dict_free_all(h, 1, 0); 478 | } 479 | 480 | void dict_destroy_shallow(dict_t*dict) 481 | { 482 | dict_clear_shallow(dict); 483 | free(dict); 484 | } 485 | 486 | void dict_destroy(dict_t*dict) 487 | { 488 | if(!dict) 489 | return; 490 | dict_clear(dict); 491 | free(dict); 492 | } 493 | 494 | void dict_destroy_with_data(dict_t*dict) 495 | { 496 | if(!dict) 497 | return; 498 | dict_free_all(dict, 1, free); 499 | free(dict); 500 | } 501 | 502 | -------------------------------------------------------------------------------- /src/dict.h: -------------------------------------------------------------------------------- 1 | /* dict.h 2 | 3 | Hash tables 4 | 5 | Copyright (c) 2010-2011 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __dict_h__ 30 | #define __dict_h__ 31 | 32 | #include 33 | #include 34 | 35 | typedef bool (*equals_func)(const void*o1, const void*o2); 36 | typedef unsigned int (*hash_func)(const void*o); 37 | typedef void* (*dup_func)(const void*o); 38 | typedef void (*free_func)(void*o); 39 | 40 | typedef struct _type_t { 41 | equals_func equals; 42 | hash_func hash; 43 | dup_func dup; 44 | free_func free; 45 | } type_t; 46 | 47 | extern type_t charptr_type; 48 | extern type_t stringstruct_type; 49 | extern type_t ptr_type; 50 | extern type_t int_type; 51 | 52 | #define PTR_TO_INT(p) (((char*)(p))-((char*)NULL)) 53 | #define INT_TO_PTR(i) (((char*)NULL)+(int)(i)) 54 | 55 | typedef struct _dictentry { 56 | void*key; 57 | unsigned int hash; 58 | void*data; 59 | struct _dictentry*next; 60 | } dictentry_t; 61 | 62 | typedef struct _dict { 63 | dictentry_t**slots; 64 | type_t*key_type; 65 | int hashsize; 66 | int num; 67 | } dict_t; 68 | 69 | dict_t*dict_new(type_t*type); 70 | void dict_init(dict_t*dict, int size); 71 | void dict_init2(dict_t*dict, type_t*type, int size); 72 | dictentry_t*dict_put(dict_t*h, const void*key, void* data); 73 | void dict_put2(dict_t*h, const char*s, void*data); 74 | int dict_count(dict_t*h); 75 | void dict_dump(dict_t*h, FILE*fi, const char*prefix); 76 | dictentry_t* dict_get_slot(dict_t*h, const void*key); 77 | char dict_contains(dict_t*h, const void*s); 78 | void* dict_lookup(dict_t*h, const void*s); 79 | char dict_del(dict_t*h, const void*s); 80 | char dict_del2(dict_t*h, const void*key, void*data); 81 | dict_t*dict_clone(dict_t*); 82 | 83 | void dict_foreach_keyvalue(dict_t*h, void (*runFunction)(void*data, const void*key, void*val), void*data); 84 | void dict_foreach_value(dict_t*h, void (*runFunction)(void*)); 85 | void dict_free_all(dict_t*h, char free_keys, void (*free_data_function)(void*)); 86 | void dict_clear(dict_t*h); 87 | void dict_destroy_shallow(dict_t*dict); 88 | void dict_destroy(dict_t*dict); 89 | #define DICT_ITERATE_DATA(d,t,v) \ 90 | int v##_i;dictentry_t*v##_e;t v;\ 91 | for(v##_i=0;v##_i<(d)->hashsize;v##_i++) \ 92 | for(v##_e=(d)->slots[v##_i]; v##_e && ((v=(t)v##_e->data)||1); v##_e=v##_e->next) 93 | #define DICT_ITERATE_KEY(d,t,v) \ 94 | int v##_i;dictentry_t*v##_e;t v;\ 95 | for(v##_i=0;v##_i<(d)->hashsize;v##_i++) \ 96 | for(v##_e=(d)->slots[v##_i];v##_e && ((v=(t)v##_e->key)||1);v##_e=v##_e->next) 97 | #define DICT_ITERATE_ITEMS(d,t1,v1,t2,v2) \ 98 | int v1##_i;dictentry_t*v1##_e;t1 v1;t2 v2; \ 99 | for(v1##_i=0;v1##_i<(d)->hashsize;v1##_i++) \ 100 | for(v1##_e=(d)->slots[v1##_i]; v1##_e && (((v1=(t1)v1##_e->key)||1)&&((v2=(t2)v1##_e->data)||1)); v1##_e=v1##_e->next) 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /src/gfxline.c: -------------------------------------------------------------------------------- 1 | /* gfxline.c 2 | 3 | Utility functions for linked lists of lines and splines (gfxline_t struct). 4 | 5 | Copyright (c) 2012 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include "gfxpoly.h" 31 | #include "gfxline.h" 32 | 33 | gfxline_t* gfxline_new() 34 | { 35 | return NULL; // list is initially empty 36 | } 37 | 38 | gfxline_t* gfxline_moveTo(gfxline_t*prev, gfxcoord_t x, gfxcoord_t y) 39 | { 40 | gfxline_t*line = malloc(sizeof(gfxline_t)); 41 | line->type = gfx_moveTo; 42 | line->x = x; 43 | line->y = y; 44 | line->prev = prev; 45 | line->next = NULL; 46 | if(prev) { 47 | prev->next = line; 48 | } 49 | return line; 50 | } 51 | 52 | gfxline_t* gfxline_lineTo(gfxline_t*prev, gfxcoord_t x, gfxcoord_t y) 53 | { 54 | gfxline_t*line = malloc(sizeof(gfxline_t)); 55 | line->type = gfx_lineTo; 56 | line->x = x; 57 | line->y = y; 58 | line->prev = prev; 59 | line->next = NULL; 60 | if(prev) { 61 | prev->next = line; 62 | } 63 | return line; 64 | } 65 | 66 | gfxline_t* gfxline_splineTo(gfxline_t*prev, gfxcoord_t sx, gfxcoord_t sy, gfxcoord_t x, gfxcoord_t y) 67 | { 68 | gfxline_t*line = malloc(sizeof(gfxline_t)); 69 | line->type = gfx_splineTo; 70 | line->x = x; 71 | line->y = y; 72 | line->sx = sx; 73 | line->sy = sy; 74 | line->prev = prev; 75 | line->next = NULL; 76 | if(prev) { 77 | prev->next = line; 78 | } 79 | return line; 80 | } 81 | 82 | gfxline_t* gfxline_rewind(gfxline_t*line) 83 | { 84 | while(line && line->prev) 85 | line = line->prev; 86 | return line; 87 | } 88 | -------------------------------------------------------------------------------- /src/gfxline.h: -------------------------------------------------------------------------------- 1 | /* gfxline.h 2 | 3 | Utility functions for linked lists of lines and splines (gfxline_t struct). 4 | 5 | Copyright (c) 2012 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __gfxline_h__ 30 | #define __gfxline_h__ 31 | 32 | gfxline_t* gfxline_rewind(gfxline_t*line); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/heap.h: -------------------------------------------------------------------------------- 1 | /* heap.h 2 | 3 | An inline heap implementation 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #define HEAP_DEFINE(name,t,lt) \ 30 | typedef struct { \ 31 | t**elements; \ 32 | int size; \ 33 | int max_size; \ 34 | } name##_t; \ 35 | static void name##_put(name##_t*h, t*e) \ 36 | { \ 37 | int parent = h->size++; \ 38 | if(h->size>=h->max_size) { \ 39 | h->max_size = h->max_size<15?15:(h->max_size+1)*2-1; \ 40 | h->elements = (t**)realloc(h->elements, \ 41 | h->max_size*sizeof(t*)); \ 42 | } \ 43 | int node; \ 44 | do { \ 45 | node = parent; \ 46 | if(!node) break; \ 47 | parent = (node-1)/2; \ 48 | h->elements[node] = h->elements[parent]; \ 49 | } while(lt(e, h->elements[parent])); \ 50 | h->elements[node] = e; \ 51 | } \ 52 | static t* name##_get(name##_t*h) \ 53 | { \ 54 | if(!h->size) return 0; \ 55 | t*r = h->elements[0]; \ 56 | int node,child = 0; \ 57 | t*node_p = h->elements[--h->size]; \ 58 | h->elements[0] = node_p; /* for the size==1 case */ \ 59 | do { \ 60 | node = child; \ 61 | child = node<<1|1; \ 62 | if(child >= h->size) { \ 63 | break; \ 64 | } \ 65 | if(child+1 < h->size && lt(h->elements[child+1], \ 66 | h->elements[child])) \ 67 | child++; \ 68 | h->elements[node] = h->elements[child]; \ 69 | } while(lt(h->elements[child],node_p)); \ 70 | h->elements[node] = node_p; \ 71 | return r; \ 72 | } \ 73 | static void name##_init(name##_t*h) \ 74 | { \ 75 | memset(h, 0, sizeof(*h)); \ 76 | h->max_size = 15; \ 77 | h->elements = malloc(h->max_size*sizeof(t*)); \ 78 | } \ 79 | static void name##_destroy(name##_t*h) \ 80 | { \ 81 | free((h)->elements); \ 82 | } 83 | -------------------------------------------------------------------------------- /src/moments.c: -------------------------------------------------------------------------------- 1 | /* moments.c 2 | 3 | nth order moments of polygons 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include "gfxpoly.h" 30 | #include "poly.h" 31 | #include "wind.h" 32 | #include "moments.h" 33 | 34 | #define MOMENTS 35 | 36 | void moments_update(moments_t*moments, actlist_t*actlist, int32_t y1, int32_t y2) 37 | { 38 | segment_t* s = actlist_leftmost(actlist); 39 | segment_t* l = 0; 40 | 41 | /* the actual coordinate of grid points is at the bottom right, hence 42 | we have to add 1.0 to both coordinates (or just 1.0 to the sum) */ 43 | double mid = (y1+y2)/2.0 + 1.0; 44 | 45 | double area = 0.0; 46 | 47 | while(s) { 48 | if(l && l->wind.is_filled) { 49 | area += (XPOS(s,mid) - XPOS(l,mid)); 50 | 51 | #ifdef MOMENTS 52 | double dx1 = (l->b.x - l->a.x) / (double)(l->b.y - l->a.y); 53 | double o1 = l->a.x - l->a.y*dx1; 54 | 55 | double dx2 = (s->b.x - s->a.x) / (double)(s->b.y - s->a.y); 56 | double o2 = s->b.x - s->b.y*dx2; 57 | 58 | #ifdef DEBUG 59 | printf("y=%f-%f\n\tl1=([%f,%f,%f,%f] dx=%f o=%f)\n\tl2=([%f,%f,%f,%f] dx=%f o=%f)\n", 60 | y1*0.05, y2*0.05, 61 | l->a.x*0.05, l->a.y*0.05, l->b.x*0.05, l->b.y*0.05, dx1*0.05, o1*0.05, 62 | s->a.x*0.05, s->a.y*0.05, s->b.x*0.05, s->b.y*0.05, dx2*0.05, o2*0.05); 63 | #endif 64 | 65 | #define S1(y) 0.5*(1/3.0*(dx2*dx2-dx1*dx1)*(y)*(y)*(y)+1/2.0*(2*dx2*o2-2*dx1*o1)*(y)*(y)+(o2*o2-o1*o1)*(y)) 66 | double m1x = S1(y2)-S1(y1); 67 | #define S2(y) (1/3.0)*(1/4.0*(dx2*dx2*dx2-dx1*dx1*dx1)*(y)*(y)*(y)*(y)+1/3.0*(3*dx2*dx2*o2-3*dx1*dx1*o1)*(y)*(y)*(y)+1/2.0*(3*dx2*o2*o2-3*dx1*o1*o1)*(y)*(y)+(o2*o2*o2-o1*o1*o1)*(y)) 68 | double m2x = S2(y2)-S2(y1); 69 | moments->m[0][0] += (XPOS(s,mid) - XPOS(l,mid))*(y2-y1); 70 | moments->m[1][0] += m1x; 71 | moments->m[2][0] += m2x; 72 | #endif 73 | } 74 | l = s; 75 | s = s->right; 76 | } 77 | 78 | area *= (y2-y1); 79 | 80 | moments->area += area; 81 | } 82 | void moments_normalize(moments_t*moments, double gridsize) 83 | { 84 | moments->area *= gridsize*gridsize; 85 | moments->m[0][0] *= gridsize*gridsize; 86 | moments->m[1][0] *= gridsize*gridsize*gridsize*gridsize; 87 | moments->m[2][0] *= gridsize*gridsize*gridsize*gridsize*gridsize*gridsize; 88 | } 89 | 90 | double gfxpoly_area(gfxpoly_t*p) 91 | { 92 | moments_t moments; 93 | gfxpoly_t*p2 = gfxpoly_process(p, 0, &windrule_evenodd, &onepolygon, &moments); 94 | gfxpoly_destroy(p2); 95 | moments_normalize(&moments, p->gridsize); 96 | return moments.area; 97 | } 98 | double gfxpoly_intersection_area(gfxpoly_t*p1, gfxpoly_t*p2) 99 | { 100 | moments_t moments; 101 | gfxpoly_t*p3 = gfxpoly_process(p1, p2, &windrule_intersect, &twopolygons, &moments); 102 | gfxpoly_destroy(p3); 103 | 104 | moments_normalize(&moments, p1->gridsize); 105 | return moments.area; 106 | } 107 | moments_t gfxpoly_moments(gfxpoly_t*p) 108 | { 109 | moments_t moments; 110 | gfxpoly_t*p2 = gfxpoly_process(p, 0, &windrule_evenodd, &onepolygon, &moments); 111 | gfxpoly_destroy(p2); 112 | moments_normalize(&moments, p->gridsize); 113 | return moments; 114 | } 115 | -------------------------------------------------------------------------------- /src/moments.h: -------------------------------------------------------------------------------- 1 | /* moments.h 2 | 3 | nth order moments of polygons 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __moments_h__ 30 | #define __moments_h__ 31 | 32 | #include "poly.h" 33 | #include "active.h" 34 | 35 | void moments_update(moments_t*moments, actlist_t*actlist, int32_t y1, int32_t y2); 36 | void moments_normalize(moments_t*moments, double gridsize); 37 | #endif 38 | -------------------------------------------------------------------------------- /src/poly.h: -------------------------------------------------------------------------------- 1 | /* poly.h 2 | 3 | Polygon intersection 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __poly_h__ 30 | #define __poly_h__ 31 | 32 | #include 33 | #include "gfxpoly.h" 34 | #include "wind.h" 35 | #include "dict.h" 36 | 37 | /* features */ 38 | #define SPLAY 39 | #define DONT_REMEMBER_CROSSINGS 40 | 41 | typedef enum {EVENT_CROSS, EVENT_END, EVENT_START, EVENT_HORIZONTAL} eventtype_t; 42 | typedef enum {SLOPE_POSITIVE, SLOPE_NEGATIVE} slope_t; 43 | 44 | #define point_t gridpoint_t 45 | 46 | #define INVALID_COORD (0x7fffffff) 47 | #define SEGNR(s) ((int)((s)?(s)->nr:-1)) 48 | type_t point_type; 49 | 50 | typedef struct _segment { 51 | point_t a; 52 | point_t b; 53 | point_t delta; 54 | double k; //k = a.x*b.y-a.y*b.x = delta.y*a.x - delta.x*a.y (=0 for points on the segment) 55 | int32_t minx, maxx; 56 | 57 | segment_dir_t dir; 58 | edgestyle_t*fs; 59 | edgestyle_t*fs_out; 60 | #ifdef CHECKS 61 | char fs_out_ok; 62 | #endif 63 | 64 | int polygon_nr; 65 | windstate_t wind; 66 | uintptr_t nr; 67 | 68 | #ifdef SPLAY 69 | struct _segment*parent; 70 | struct _segment*leftchild; 71 | struct _segment*rightchild; 72 | #endif 73 | struct _segment*left; 74 | struct _segment*right; 75 | char changed; 76 | 77 | point_t pos; 78 | 79 | gfxsegmentlist_t*stroke; 80 | int stroke_pos; 81 | 82 | #ifndef DONT_REMEMBER_CROSSINGS 83 | dict_t scheduled_crossings; 84 | #endif 85 | } segment_t; 86 | 87 | #define LINE_EQ(p,s) ((double)(s)->delta.y*(p).x - (double)(s)->delta.x*(p).y - (s)->k) 88 | 89 | /* x1 + ((x2-x1)*(y-y1)) / dy = 90 | (x1*(y2-y1) + (x2-x1)*(y-y1)) / dy = 91 | (x1*(y2-y) + x2 *(y-y1)) / dy = 92 | (x1*y2 - x2*y1 + x2*y - y*x1) / dy = 93 | (k + x2*y - x1*y) / dy 94 | (k + dx*y) / dy 95 | */ 96 | //#define XPOS(s,ypos) ((s)->a.x + ((s)->delta.x * (double)((ypos) - (s)->a.y)) / (s)->delta.y) 97 | #define XPOS(s,ypos) (((s)->k + (double)(s)->delta.x*ypos) / (s)->delta.y) 98 | 99 | #define XPOS_INT(s,ypos) ((int)ceil(XPOS((s),ypos))) 100 | #define XDIFF(s1,s2,ypos) (((s1)->k + (double)(s1)->delta.x*ypos)*(s2)->delta.y - \ 101 | ((s2)->k + (double)(s2)->delta.x*ypos)*(s1)->delta.y) 102 | 103 | void gfxpoly_fail(char*expr, char*file, int line, const char*function); 104 | 105 | char gfxpoly_check(gfxpoly_t*poly, char updown); 106 | int gfxpoly_num_segments(gfxpoly_t*poly); 107 | int gfxpoly_size(gfxpoly_t*poly); 108 | void gfxpoly_dump(gfxpoly_t*poly); 109 | void gfxpoly_save(gfxpoly_t*poly, const char*filename); 110 | void gfxpoly_save_arrows(gfxpoly_t*poly, const char*filename); 111 | gfxpoly_t* gfxpoly_process(gfxpoly_t*poly1, gfxpoly_t*poly2, windrule_t*windrule, windcontext_t*context, moments_t*moments); 112 | 113 | gfxpoly_t* gfxpoly_intersect(gfxpoly_t*p1, gfxpoly_t*p2); 114 | gfxpoly_t* gfxpoly_union(gfxpoly_t*p1, gfxpoly_t*p2); 115 | double gfxpoly_area(gfxpoly_t*p); 116 | double gfxpoly_intersection_area(gfxpoly_t*p1, gfxpoly_t*p2); 117 | 118 | #ifndef CHECKS 119 | #ifdef assert 120 | #undef assert 121 | #endif 122 | #define assert(x) 123 | #else 124 | #define assert(x) ((x)?0:gfxpoly_fail(__STRING(x), __FILE__, __LINE__, __PRETTY_FUNCTION__)) 125 | #endif 126 | 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /src/render.c: -------------------------------------------------------------------------------- 1 | /* render.c 2 | 3 | Polygon rendering (for debugging) 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "render.h" 33 | 34 | typedef struct _renderpoint 35 | { 36 | double x; 37 | segment_dir_t dir; 38 | edgestyle_t*fs; 39 | int polygon_nr; 40 | } renderpoint_t; 41 | 42 | typedef struct _renderline 43 | { 44 | renderpoint_t*points; 45 | int size; 46 | int num; 47 | } renderline_t; 48 | 49 | typedef struct _renderbuf 50 | { 51 | intbbox_t bbox; 52 | int width; 53 | int height; 54 | double zoom; 55 | renderline_t*lines; 56 | } renderbuf_t; 57 | 58 | static inline void add_pixel(renderbuf_t*buf, double x, int y, segment_dir_t dir, edgestyle_t*fs, int polygon_nr) 59 | { 60 | renderpoint_t p; 61 | p.x = x; 62 | p.dir = dir; 63 | p.fs = fs; 64 | p.polygon_nr = polygon_nr; 65 | 66 | if(y >= buf->bbox.ymax || y < buf->bbox.ymin) 67 | return; 68 | 69 | renderline_t*l = &buf->lines[y-buf->bbox.ymin]; 70 | 71 | if(l->num == l->size) { 72 | l->size += 32; 73 | l->points = (renderpoint_t*)realloc(l->points, l->size * sizeof(renderpoint_t)); 74 | } 75 | l->points[l->num] = p; 76 | l->num++; 77 | } 78 | #define CUT 0.5 79 | static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, edgestyle_t*fs, segment_dir_t dir, int polygon_nr) 80 | { 81 | x1 *= buf->zoom; 82 | y1 *= buf->zoom; 83 | x2 *= buf->zoom; 84 | y2 *= buf->zoom; 85 | double diffx, diffy; 86 | double ny1, ny2, stepx; 87 | 88 | if(y2 < y1) { 89 | dir ^= DIR_UP^DIR_DOWN; 90 | double x,y; 91 | x = x1;x1 = x2;x2=x; 92 | y = y1;y1 = y2;y2=y; 93 | } 94 | 95 | diffx = x2 - x1; 96 | diffy = y2 - y1; 97 | ny1 = floor(y1)+CUT; 98 | ny2 = floor(y2)+CUT; 99 | 100 | if(ny1 < y1) { 101 | ny1 = floor(y1) + 1.0 + CUT; 102 | } 103 | if(ny2 >= y2) { 104 | ny2 = floor(y2) - 1.0 + CUT; 105 | } 106 | if(ny1 > ny2) 107 | return; 108 | 109 | stepx = diffx/diffy; 110 | x1 = x1 + (ny1-y1)*stepx; 111 | x2 = x2 + (ny2-y2)*stepx; 112 | 113 | int posy=floor(ny1); 114 | int endy=floor(ny2); 115 | double posx=0; 116 | double startx = x1; 117 | 118 | //printf("line %d from %f to %f dir=%s\n", polygon_nr, y1, y2, dir==DIR_UP?"up":"down"); 119 | 120 | while(posy<=endy) { 121 | double xx = startx + posx; 122 | add_pixel(buf, xx, posy, dir, fs, polygon_nr); 123 | posx+=stepx; 124 | posy++; 125 | } 126 | } 127 | 128 | static int compare_renderpoints(const void * _a, const void * _b) 129 | { 130 | renderpoint_t*a = (renderpoint_t*)_a; 131 | renderpoint_t*b = (renderpoint_t*)_b; 132 | if(a->x < b->x) return -1; 133 | if(a->x > b->x) return 1; 134 | return 0; 135 | } 136 | 137 | static void fill_bitwise(unsigned char*line, int x1, int x2) 138 | { 139 | int p1 = x1>>3; 140 | int p2 = x2>>3; 141 | int b1 = 0xff >> (x1&7); 142 | int b2 = 0xff << (1+7-(x2&7)); 143 | if(p1==p2) { 144 | line[p1] |= b1&b2; 145 | } else { 146 | line[p1] |= b1; 147 | memset(&line[p1+1], 255, p2-(p1+1)); 148 | line[p2] = b2; 149 | } 150 | } 151 | 152 | unsigned char* render_polygon(gfxpoly_t*polygon, intbbox_t*bbox, double zoom, windrule_t*rule, windcontext_t*context) 153 | { 154 | renderbuf_t _buf, *buf=&_buf; 155 | buf->width = (bbox->xmax - bbox->xmin); 156 | buf->height = (bbox->ymax - bbox->ymin); 157 | buf->bbox = *bbox; 158 | buf->zoom = zoom * polygon->gridsize; 159 | int width8 = (buf->width+7) >> 3; 160 | char bleeding = 0; 161 | unsigned char* image = (unsigned char*)malloc(width8*buf->height); 162 | memset(image, 0, width8*buf->height); 163 | 164 | buf->lines = (renderline_t*)malloc(buf->height*sizeof(renderline_t)); 165 | int y; 166 | for(y=0;yheight;y++) { 167 | memset(&buf->lines[y], 0, sizeof(renderline_t)); 168 | buf->lines[y].points = 0; 169 | buf->lines[y].num = 0; 170 | } 171 | 172 | int polygon_nr = 0; 173 | int t; 174 | gfxsegmentlist_t*stroke = polygon->strokes; 175 | for(;stroke;stroke=stroke->next) { 176 | for(t=0;tnum_points-1;t++) { 177 | point_t a = stroke->points[t]; 178 | point_t b = stroke->points[t+1]; 179 | add_line(buf, a.x, a.y, b.x, b.y, stroke->fs, stroke->dir, polygon_nr); 180 | } 181 | } 182 | 183 | for(y=0;yheight;y++) { 184 | renderpoint_t*points = buf->lines[y].points; 185 | unsigned char*line = &image[width8*y]; 186 | int n; 187 | int num = buf->lines[y].num; 188 | qsort(points, num, sizeof(renderpoint_t), compare_renderpoints); 189 | int lastx = 0; 190 | 191 | windstate_t fill = rule->start(context); 192 | for(n=0;nx - bbox->xmin); 195 | 196 | if(x < lastx) 197 | x = lastx; 198 | if(x > buf->width) 199 | x = buf->width; 200 | 201 | if(fill.is_filled && lastxadd(context, fill, p->fs, p->dir, p->polygon_nr); 205 | lastx = x; 206 | } 207 | if(fill.is_filled && lastx!=buf->width) { 208 | /* we're bleeding, fill over padding, too. */ 209 | fprintf(stderr, "Polygon %p is bleeding in line %d\n", polygon, y); 210 | fill_bitwise(line, lastx, width8*8); 211 | assert(line[width8-1]&0x01); 212 | bleeding = 1; 213 | exit(1); 214 | 215 | } 216 | } 217 | 218 | for(y=0;yheight;y++) { 219 | if(buf->lines[y].points) { 220 | free(buf->lines[y].points); 221 | } 222 | memset(&buf->lines[y], 0, sizeof(renderline_t)); 223 | } 224 | if(bleeding) { 225 | assert(!bitmap_ok(bbox, image)); 226 | } 227 | free(buf->lines);buf->lines=0; 228 | return image; 229 | } 230 | 231 | #define MAX_WIDTH 8192 232 | #define MAX_HEIGHT 4096 233 | 234 | static inline double max(double a, double b) {return a>b?a:b;} 235 | static inline double min(double a, double b) {return agridsize; 263 | 264 | if(polygon->strokes && polygon->strokes->num_points) { 265 | b.xmin = polygon->strokes->points[0].x*g; 266 | b.ymin = polygon->strokes->points[0].y*g; 267 | b.xmax = polygon->strokes->points[0].x*g; 268 | b.ymax = polygon->strokes->points[0].y*g; 269 | } 270 | int t; 271 | gfxsegmentlist_t*stroke = polygon->strokes; 272 | for(;stroke;stroke=stroke->next) { 273 | for(t=0;tnum_points;t++) { 274 | point_t p = stroke->points[t]; 275 | int x1 = floor(p.x); 276 | int y1 = floor(p.y); 277 | int x2 = ceil(p.x); 278 | int y2 = ceil(p.y); 279 | if(x1 < b.xmin) b.xmin = x1; 280 | if(y1 < b.ymin) b.ymin = y1; 281 | if(x2 > b.xmax) b.xmax = x2; 282 | if(y2 > b.ymax) b.ymax = y2; 283 | } 284 | } 285 | 286 | if(b.xmax > (int)(MAX_WIDTH*zoom)) 287 | b.xmax = (int)(MAX_WIDTH*zoom); 288 | if(b.ymax > (int)(MAX_HEIGHT*zoom)) 289 | b.ymax = (int)(MAX_HEIGHT*zoom); 290 | if(b.xmin < -(int)(MAX_WIDTH*zoom)) 291 | b.xmin = -(int)(MAX_WIDTH*zoom); 292 | if(b.ymin < -(int)(MAX_HEIGHT*zoom)) 293 | b.ymin = -(int)(MAX_HEIGHT*zoom); 294 | 295 | if(b.xmin > b.xmax) 296 | b.xmin = b.xmax; 297 | if(b.ymin > b.ymax) 298 | b.ymin = b.ymax; 299 | 300 | b.xmax = adjust_x(b.xmin, b.xmax); 301 | 302 | b.width = b.xmax - b.xmin; 303 | b.height = b.ymax - b.ymin; 304 | return b; 305 | } 306 | 307 | #define B11111000 0xf8 308 | #define B01111100 0x7c 309 | #define B00111110 0x3e 310 | #define B00011111 0x1f 311 | #define B11100000 0xe0 312 | #define B01110000 0x70 313 | #define B00111000 0x38 314 | #define B00011100 0x1c 315 | #define B00001110 0x0e 316 | #define B00000111 0x07 317 | #define B10000000 0x80 318 | #define B01000000 0x40 319 | #define B00100000 0x20 320 | #define B00010000 0x10 321 | #define B00001000 0x08 322 | #define B00000100 0x04 323 | #define B00000010 0x02 324 | #define B00000001 0x01 325 | 326 | int bitmap_ok(intbbox_t*bbox, unsigned char*data) 327 | { 328 | int y; 329 | int width8 = (bbox->width+7) >> 3; 330 | for(y=0;yheight;y++) { 331 | if(data[width8-1]&0x01) 332 | return 0; //bleeding 333 | data += width8; 334 | } 335 | return 1; 336 | } 337 | 338 | int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2) 339 | { 340 | if(!data1 || !data2) 341 | return 0; 342 | int x,y; 343 | int height = bbox->height; 344 | int width = bbox->width; 345 | int width8 = (width+7) >> 3; 346 | unsigned char*l1 = &data1[width8*2]; 347 | unsigned char*l2 = &data2[width8*2]; 348 | for(y=2;ywidth+7) >> 3; 381 | unsigned char*data = malloc(b->width*b->height*4*4); 382 | unsigned char*p = data; 383 | int x,y; 384 | unsigned char*b1 = data1; 385 | unsigned char*b2 = data2; 386 | compare_bitmaps(b, data1, data2); 387 | //# define MARK ((abs(x-badx)<3 && abs(y-bady)<3)*255) 388 | #define MARK 0 389 | for(y=0;yheight;y++) { 390 | for(x=0;xwidth;x++) { 391 | unsigned char c1 = (b1[x>>3]&(0x80>>(x&7)))?255:0; 392 | unsigned char c2 = (b2[x>>3]&(0x80>>(x&7)))?255:0; 393 | *p++ = 255; 394 | *p++ = c1^c2; 395 | *p++ = c1^c2; 396 | *p++ = MARK; 397 | } 398 | for(x=0;xwidth;x++) { 399 | unsigned char c = (b2[x>>3]&(0x80>>(x&7)))?255:0; 400 | *p++ = 255; 401 | *p++ = c; 402 | *p++ = c; 403 | *p++ = MARK; 404 | } 405 | b1 += width8; 406 | b2 += width8; 407 | } 408 | b1 = data1; 409 | for(y=0;yheight;y++) { 410 | for(x=0;xwidth;x++) { 411 | unsigned char c = (b1[x>>3]&(0x80>>(x&7)))?255:0; 412 | *p++ = 255; 413 | *p++ = c; 414 | *p++ = c; 415 | *p++ = MARK; 416 | } 417 | for(x=0;xwidth;x++) { 418 | *p++ = 255; 419 | *p++ = 0; 420 | *p++ = 0; 421 | *p++ = 0; 422 | } 423 | b1 += width8; 424 | } 425 | //png_write(filename, data, b->width*2, b->height*2); 426 | free(data); 427 | } 428 | -------------------------------------------------------------------------------- /src/render.h: -------------------------------------------------------------------------------- 1 | /* render.h 2 | 3 | Polygon rendering (for debugging) 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __render_h__ 30 | #define __render_h__ 31 | 32 | #include "poly.h" 33 | #include "wind.h" 34 | 35 | typedef struct { 36 | int xmin; 37 | int ymin; 38 | int xmax; 39 | int ymax; 40 | int width; 41 | int height; 42 | } intbbox_t; 43 | 44 | unsigned char* render_polygon(gfxpoly_t*polygon, intbbox_t*bbox, double zoom, windrule_t*rule, windcontext_t*context); 45 | 46 | intbbox_t intbbox_new(int x1, int y1, int x2, int y2); 47 | intbbox_t intbbox_from_polygon(gfxpoly_t*polygon, double zoom); 48 | 49 | int bitmap_ok(intbbox_t*bbox, unsigned char*data); 50 | int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/stroke.c: -------------------------------------------------------------------------------- 1 | /* stroke.c 2 | 3 | Stroke to polygon conversion 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "poly.h" 33 | #include "wind.h" 34 | #include "convert.h" 35 | #include "gfxline.h" 36 | 37 | /* notice: left/right for a coordinate system where y goes up, not down */ 38 | typedef enum {LEFT=0, RIGHT=1} leftright_t; 39 | 40 | /* factor that determines into how many line fragments a spline is converted */ 41 | #define SUBFRACTION (2.4) 42 | 43 | // spline equation: 44 | // s(t) = t*t*x2 + 2*t*(1-t)*cx + (1-t)*(1-t)*x1 45 | // 46 | // s(0.5) = 0.25*x2 + 0.5*cx + 0.25*x1 47 | // ds(t)/dt = 2*t*x2 + (2-2t)*cx + (2t-2)*x1 48 | // ds(0) = 2*(cx-x1) 49 | 50 | static void draw_arc(gfxcanvas_t*draw, double x, double y, double a1, double a2, double r) 51 | { 52 | if(a2lineTo(draw, x+cos(a1)*r,y+sin(a1)*r); 66 | for(t=1;t<=steps;t++) { 67 | double a = a1 + t*step; 68 | double c = cos(a)*r; 69 | double s = sin(a)*r; 70 | double xx = c + x; 71 | double yy = s + y; 72 | double dx = x + cos(a-step/2)*r2; 73 | double dy = y + sin(a-step/2)*r2; 74 | draw->splineTo(draw, dx, dy, xx, yy); 75 | } 76 | } 77 | 78 | typedef struct _gfxpoint 79 | { 80 | gfxcoord_t x,y; 81 | } gfxpoint_t; 82 | 83 | static void draw_single_stroke(gfxpoint_t*p, int num, gfxcanvas_t*draw, double width, gfx_capType cap, gfx_joinType join, double limit) 84 | { 85 | width/=2; 86 | if(width<=0) 87 | width = 0.05; 88 | 89 | /* remove duplicate points */ 90 | int s=1,t; 91 | gfxpoint_t last = p[0]; 92 | for(t=1;t2 && p[0].x == p[num-1].x && p[0].y == p[num-1].y); 100 | 101 | int start = 0; 102 | int end = num-1; 103 | int incr = 1; 104 | 105 | double lastw=0; 106 | /* iterate through the points two times: first forward, then backward, 107 | adding a stroke outline to the right side and line caps after each 108 | pass */ 109 | int pass; 110 | for(pass=0;pass<2;pass++) { 111 | if(closed) { 112 | double dx = p[end].x - p[end-incr].x; 113 | double dy = p[end].y - p[end-incr].y; 114 | lastw = atan2(dy,dx); 115 | if(lastw<0) lastw+=M_PI*2; 116 | } 117 | 118 | int pos; 119 | for(pos=start;pos!=end;pos+=incr) { 120 | //printf("%d) %.2f %.2f\n", pos, p[pos].x, p[pos].y); 121 | double dx = p[pos+incr].x - p[pos].x; 122 | double dy = p[pos+incr].y - p[pos].y; 123 | double w = atan2(dy,dx); 124 | if(w<0) w+=M_PI*2; 125 | 126 | if(closed || pos!=start) { 127 | double d = w-lastw; 128 | leftright_t turn; 129 | if(d>=0 && d-M_PI) turn=RIGHT; 131 | else if(d>=M_PI) {turn=RIGHT;} 132 | else if(d<=-M_PI) {turn=LEFT;d+=M_PI*2;} 133 | else {assert(0);} 134 | if(turn!=LEFT || join==gfx_joinBevel) { 135 | // nothing to do. bevel joins are easy 136 | } else if(join==gfx_joinRound) { 137 | draw_arc(draw, p[pos].x, p[pos].y, lastw-M_PI/2, w-M_PI/2, width); 138 | } else if(join==gfx_joinMiter) { 139 | double xw = M_PI/2 - d/2; 140 | if(xw>0) { 141 | double r2 = 1.0 / sin(M_PI/2-d/2); 142 | if(r2 < limit) { 143 | r2 *= width; 144 | double addx = cos(lastw-M_PI/2+d/2)*r2; 145 | double addy = sin(lastw-M_PI/2+d/2)*r2; 146 | draw->lineTo(draw, p[pos].x+addx, p[pos].y+addy); 147 | } 148 | } 149 | } 150 | } 151 | 152 | double addx = cos(w-M_PI/2)*width; 153 | double addy = sin(w-M_PI/2)*width; 154 | draw->lineTo(draw, p[pos].x+addx, p[pos].y+addy); 155 | draw->lineTo(draw, p[pos+incr].x+addx, p[pos+incr].y+addy); 156 | lastw = w; 157 | } 158 | 159 | if(closed) { 160 | draw->close(draw); 161 | } else { 162 | /* draw stroke ends. We draw duplicates of some points here. The drawer 163 | implementation should be smart enough to remove them. */ 164 | double c = cos(lastw-M_PI/2)*width; 165 | double s = sin(lastw-M_PI/2)*width; 166 | if(cap == gfx_capButt) { 167 | draw->lineTo(draw, p[pos].x+c, p[pos].y+s); 168 | draw->lineTo(draw, p[pos].x-c, p[pos].y-s); 169 | } else if(cap == gfx_capRound) { 170 | draw_arc(draw, p[pos].x, p[pos].y, lastw-M_PI/2, lastw+M_PI/2, width); 171 | } else if(cap == gfx_capSquare) { 172 | double c = cos(lastw-M_PI/2)*width; 173 | double s = sin(lastw-M_PI/2)*width; 174 | draw->lineTo(draw, p[pos].x+c, p[pos].y+s); 175 | draw->lineTo(draw, p[pos].x+c-s, p[pos].y+s+c); 176 | draw->lineTo(draw, p[pos].x-c-s, p[pos].y-s+c); 177 | draw->lineTo(draw, p[pos].x-c, p[pos].y-s); 178 | } 179 | lastw += M_PI; // for dots 180 | } 181 | start=num-1; 182 | end=0; 183 | incr=-1; 184 | } 185 | if(!closed) 186 | draw->close(draw); 187 | } 188 | 189 | void draw_stroke(gfxline_t*_start, gfxcanvas_t*draw, double width, gfx_capType cap, gfx_joinType join, double miterLimit) 190 | { 191 | gfxline_t*start = gfxline_rewind(_start); 192 | if(!start) 193 | return; 194 | assert(start->type == gfx_moveTo); 195 | gfxline_t*line = start; 196 | // measure array size 197 | int size = 0; 198 | int pos = 0; 199 | double lastx,lasty; 200 | while(line) { 201 | if(line->type == gfx_moveTo) { 202 | if(pos>size) size = pos; 203 | pos++; 204 | } else if(line->type == gfx_lineTo) { 205 | pos++; 206 | } else if(line->type == gfx_splineTo) { 207 | int parts = (int)(sqrt(fabs(line->x-2*line->sx+lastx) + fabs(line->y-2*line->sy+lasty))*SUBFRACTION); 208 | if(!parts) parts = 1; 209 | pos+=parts+1; 210 | } 211 | lastx = line->x; 212 | lasty = line->y; 213 | line = line->next; 214 | } 215 | if(pos>size) size = pos; 216 | if(!size) return; 217 | 218 | gfxpoint_t* points = malloc(sizeof(gfxpoint_t)*size); 219 | line = start; 220 | pos = 0; 221 | while(line) { 222 | if(line->type == gfx_moveTo) { 223 | if(pos) 224 | draw_single_stroke(points, pos, draw, width, cap, join, miterLimit); 225 | pos = 0; 226 | } else if(line->type == gfx_splineTo) { 227 | int parts = (int)(sqrt(fabs(line->x-2*line->sx+lastx) + fabs(line->y-2*line->sy+lasty))*SUBFRACTION); 228 | if(!parts) parts = 1; 229 | double stepsize = 1.0/parts; 230 | int i; 231 | for(i=0;ix*t*t + 2*line->sx*t*(1-t) + lastx*(1-t)*(1-t)); 234 | points[pos].y = (line->y*t*t + 2*line->sy*t*(1-t) + lasty*(1-t)*(1-t)); 235 | pos++; 236 | } 237 | } 238 | lastx = points[pos].x = line->x; 239 | lasty = points[pos].y = line->y; 240 | pos++; 241 | line = line->next; 242 | } 243 | if(pos) draw_single_stroke(points, pos, draw, width, cap, join, miterLimit); 244 | free(points); 245 | } 246 | 247 | gfxpoly_t* gfxpoly_from_stroke(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit, double gridsize) 248 | { 249 | gfxcanvas_t*d = gfxcanvas_new(gridsize); 250 | draw_stroke(line, d, width, cap_style, joint_style, miterLimit); 251 | gfxpoly_t*poly = (gfxpoly_t*)d->result(d); 252 | assert(gfxpoly_check(poly, 1)); 253 | gfxpoly_t*poly2 = gfxpoly_process(poly, 0, &windrule_circular, &onepolygon, 0); 254 | gfxpoly_destroy(poly); 255 | return poly2; 256 | } 257 | 258 | -------------------------------------------------------------------------------- /src/stroke.h: -------------------------------------------------------------------------------- 1 | /* stroke.h 2 | 3 | Stroke to polygon conversion 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __stroke_h__ 30 | #define __stroke_h__ 31 | #include "poly.h" 32 | gfxpoly_t* gfxpoly_from_stroke(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit, double gridsize); 33 | #endif 34 | -------------------------------------------------------------------------------- /src/wind.c: -------------------------------------------------------------------------------- 1 | /* wind.c 2 | 3 | Fillstyle tyles (wind rules) 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include "poly.h" 30 | 31 | edgestyle_t edgestyle_default; 32 | 33 | windstate_t windstate_nonfilled = { 34 | is_filled: 0, 35 | wind_nr: 0, 36 | }; 37 | 38 | windcontext_t onepolygon = {NULL,1}; 39 | windcontext_t twopolygons = {NULL,2}; 40 | 41 | // -------------------- even/odd ---------------------- 42 | 43 | windstate_t evenodd_start(windcontext_t*context) 44 | { 45 | return windstate_nonfilled; 46 | } 47 | windstate_t evenodd_add(windcontext_t*context, windstate_t left, edgestyle_t*edge, segment_dir_t dir, int master) 48 | { 49 | assert(edge); 50 | left.is_filled ^= 1; 51 | return left; 52 | } 53 | edgestyle_t* evenodd_diff(windcontext_t*context, windstate_t*left, windstate_t*right) 54 | { 55 | if(left->is_filled==right->is_filled) 56 | return 0; 57 | else 58 | return &edgestyle_default; 59 | } 60 | 61 | windrule_t windrule_evenodd = { 62 | start: evenodd_start, 63 | add: evenodd_add, 64 | diff: evenodd_diff, 65 | }; 66 | 67 | // -------------------- circular ---------------------- 68 | 69 | windstate_t circular_start(windcontext_t*context) 70 | { 71 | return windstate_nonfilled; 72 | } 73 | 74 | windstate_t circular_add(windcontext_t*context, windstate_t left, edgestyle_t*edge, segment_dir_t dir, int master) 75 | { 76 | assert(edge); 77 | /* which one is + and which one - doesn't actually make any difference */ 78 | if(dir == DIR_DOWN) 79 | left.wind_nr++; 80 | else 81 | left.wind_nr--; 82 | 83 | left.is_filled = left.wind_nr != 0; 84 | return left; 85 | } 86 | 87 | edgestyle_t* circular_diff(windcontext_t*context, windstate_t*left, windstate_t*right) 88 | { 89 | if(left->is_filled==right->is_filled) 90 | return 0; 91 | else 92 | return &edgestyle_default; 93 | } 94 | 95 | windrule_t windrule_circular = { 96 | start: circular_start, 97 | add: circular_add, 98 | diff: circular_diff, 99 | }; 100 | 101 | // -------------------- intersect ---------------------- 102 | 103 | windstate_t intersect_start(windcontext_t*context) 104 | { 105 | return windstate_nonfilled; 106 | } 107 | 108 | windstate_t intersect_add(windcontext_t*context, windstate_t left, edgestyle_t*edge, segment_dir_t dir, int master) 109 | { 110 | assert(master < context->num_polygons); 111 | 112 | left.wind_nr ^= 1<num_polygons)-1); 114 | return left; 115 | } 116 | 117 | edgestyle_t* intersect_diff(windcontext_t*context, windstate_t*left, windstate_t*right) 118 | { 119 | if(left->is_filled==right->is_filled) 120 | return 0; 121 | else 122 | return &edgestyle_default; 123 | } 124 | 125 | windrule_t windrule_intersect = { 126 | start: intersect_start, 127 | add: intersect_add, 128 | diff: intersect_diff, 129 | }; 130 | 131 | // -------------------- union ---------------------- 132 | 133 | windstate_t union_start(windcontext_t*context) 134 | { 135 | return windstate_nonfilled; 136 | } 137 | 138 | windstate_t union_add(windcontext_t*context, windstate_t left, edgestyle_t*edge, segment_dir_t dir, int master) 139 | { 140 | assert(masteris_filled==right->is_filled) 149 | return 0; 150 | else 151 | return &edgestyle_default; 152 | } 153 | 154 | windrule_t windrule_union = { 155 | start: union_start, 156 | add: union_add, 157 | diff: union_diff, 158 | }; 159 | 160 | 161 | /* 162 | } else if (rule == WIND_NONZERO) { 163 | fill = wind!=0; 164 | } else if (rule == WIND_ODDEVEN) { 165 | fill = wind&1; 166 | } else { // rule == WIND_POSITIVE 167 | fill = wind>=1; 168 | } 169 | */ 170 | -------------------------------------------------------------------------------- /src/wind.h: -------------------------------------------------------------------------------- 1 | /* wind.h 2 | 3 | Fillstyle tyles (wind rules) 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __wind_h__ 30 | #define __wind_h__ 31 | 32 | #include "gfxpoly.h" 33 | 34 | #define DIR_INVERT(d) ((d)^(DIR_UP^DIR_DOWN)) 35 | 36 | extern edgestyle_t edgestyle_default; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/xrow.c: -------------------------------------------------------------------------------- 1 | /* xrow.c 2 | 3 | Representation of point positions in scanlines 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include "xrow.h" 33 | #include "poly.h" 34 | 35 | xrow_t* xrow_new() 36 | { 37 | xrow_t*r = calloc(1,sizeof(xrow_t)); 38 | r->size = 16; 39 | r->x = malloc(sizeof(r->x[0])*r->size); 40 | return r; 41 | } 42 | 43 | void xrow_add(xrow_t*r, int32_t x) 44 | { 45 | if(r->num && r->lastx==x) 46 | return; 47 | r->lastx = x; 48 | if(r->num >= r->size) { 49 | r->size *= 2; 50 | r->x = realloc(r->x, sizeof(r->x[0])*r->size); 51 | } 52 | r->x[r->num++]=x; 53 | } 54 | 55 | int compare_int32(const void*_i1,const void*_i2) 56 | { 57 | int32_t*i1 = (int32_t*)_i1; 58 | int32_t*i2 = (int32_t*)_i2; 59 | return *i1-*i2; 60 | } 61 | 62 | void xrow_sort(xrow_t*r) 63 | { 64 | if(!r->num) 65 | return; 66 | qsort(r->x, r->num, sizeof(r->x[0]), compare_int32); 67 | int t; 68 | int pos = 1; 69 | int32_t lastx=r->x[0]; 70 | for(t=1;tnum;t++) { 71 | if(r->x[t]!=lastx) { 72 | r->x[pos++] = lastx = r->x[t]; 73 | } 74 | } 75 | r->num = pos; 76 | } 77 | 78 | int xrow_find(xrow_t*r, int32_t x) 79 | { 80 | int min, max, i, l; 81 | 82 | for(min=0, max=r->num, i=r->num/2, l=r->num; i != l; l=i, i=(min+max)/2) { 83 | if(x < r->x[i]) max=i; 84 | else min=i; 85 | } 86 | 87 | #ifdef CHECKS 88 | int t; 89 | for(t=0;tnum;t++) { 90 | if(x < r->x[t]) 91 | break; 92 | } 93 | assert(max == t); 94 | #endif 95 | 96 | return max; 97 | } 98 | 99 | char xrow_contains(xrow_t*r, int32_t x) 100 | { 101 | int pos = xrow_find(r,x) - 1; 102 | return (pos>=0 && r->x[pos]==x); 103 | } 104 | 105 | void xrow_reset(xrow_t*r) 106 | { 107 | r->num = 0; 108 | } 109 | 110 | void xrow_dump(xrow_t*xrow, double gridsize) 111 | { 112 | fprintf(stderr, "x: "); 113 | int t; 114 | for(t=0;tnum;t++) { 115 | if(t) 116 | fprintf(stderr, ", "); 117 | fprintf(stderr, "%.2f", xrow->x[t] * gridsize); 118 | } 119 | fprintf(stderr, "\n"); 120 | } 121 | 122 | void xrow_destroy(xrow_t*r) 123 | { 124 | if(r->x) { 125 | free(r->x);r->x = 0; 126 | } 127 | free(r); 128 | } 129 | -------------------------------------------------------------------------------- /src/xrow.h: -------------------------------------------------------------------------------- 1 | /* xrow.h 2 | 3 | Representation of point positions in scanlines 4 | 5 | Copyright (c) 2009 Matthias Kramm 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. */ 28 | 29 | #ifndef __xrow_h__ 30 | #define __xrow_h__ 31 | 32 | #include 33 | 34 | #include "poly.h" 35 | 36 | typedef struct _xrow { 37 | int32_t*x; 38 | int num; 39 | int size; 40 | int32_t lastx; 41 | } xrow_t; 42 | 43 | xrow_t* xrow_new(); 44 | 45 | void xrow_add(xrow_t*xrow, int32_t x); 46 | void xrow_sort(xrow_t*xrow); 47 | int xrow_find(xrow_t*r, int32_t x); 48 | char xrow_contains(xrow_t*xrow, int32_t x); 49 | void xrow_dump(xrow_t*xrow, double gridsize); 50 | void xrow_reset(xrow_t*xrow); 51 | void xrow_destroy(xrow_t*xrow); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /tests/polygons/t001.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | -12.94300000000001205080479849129915 -17.52800000000010527401173021644354 moveto 4 | -12.94300000000001205080479849129915 21.67199999999988335730449762195349 lineto 5 | stroke 6 | 0 setgray 7 | -12.94300000000001205080479849129915 -17.52800000000010527401173021644354 moveto 8 | 72.45699999999999363353708758950233 -17.52800000000010527401173021644354 lineto 9 | stroke 10 | 0 setgray 11 | 72.45699999999999363353708758950233 -17.52800000000010527401173021644354 moveto 12 | 78.35702170138888789097109111025929 -15.93089713541677276964492193656042 lineto 13 | 83.98208680555555361024744343012571 -14.20208854166677170383081829641014 lineto 14 | 89.33219531250000500222085975110531 -12.34157421875010562928309809649363 lineto 15 | 96.85377734375001068656274583190680 -9.40383007812510562928309809649363 lineto 16 | 103.77106249999999931787897367030382 -6.28971875000010616219014991656877 lineto 17 | 110.09601367187499931787897367030382 -3.09921582031260633982583385659382 lineto 18 | 115.83102343750000784439180279150605 0.14768359374989292742696989080287 lineto 19 | 120.98805468750001068656274583190680 3.35100390624989241672437856323086 lineto 20 | 125.56949999999999079136614454910159 6.49074999999989188381732674315572 lineto 21 | 129.58492968749999363353708758950233 9.48694140624989046273185522295535 lineto 22 | 133.04391406249999363353708758950233 12.25959765624988939691775158280507 lineto 23 | 135.04076736111110790261591318994761 13.98384895833322261182729562278837 lineto 24 | 136.79669184027778783274698071181774 15.55543098958322190128455986268818 lineto 25 | 138.31168750000000500222085975110531 16.97434374999988904164638370275497 lineto 26 | 139.58575434027775941103755030781031 18.24058723958322403291276714298874 lineto 27 | 140.62527256944443365682673174887896 19.30084114583322474345550290308893 lineto 28 | 141.43024218749997089616954326629639 20.15510546874989117327459098305553 lineto 29 | 142.45699999999999363353708758950233 21.32199999999988904164638370275497 lineto 30 | stroke 31 | 0.7 setgray 32 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 33 | 0.00000000000000000000000000000000 213.07899999999995088728610426187515 lineto 34 | stroke 35 | 0 setgray 36 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 37 | 195.97899999999998499333742074668407 0.00000000000000000000000000000000 lineto 38 | stroke 39 | 0 setgray 40 | 195.97899999999998499333742074668407 0.00000000000000000000000000000000 moveto 41 | 195.97899999999998499333742074668407 213.07899999999995088728610426187515 lineto 42 | stroke 43 | 0 setgray 44 | 142.45699999999999363353708758950233 21.32199999999988904164638370275497 moveto 45 | -12.94300000000001205080479849129915 21.67199999999988335730449762195349 lineto 46 | stroke 47 | 0.7 setgray 48 | 0.00000000000000000000000000000000 213.07899999999995088728610426187515 moveto 49 | 195.97899999999998499333742074668407 213.07899999999995088728610426187515 lineto 50 | stroke 51 | showpage 52 | -------------------------------------------------------------------------------- /tests/polygons/t008.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 4 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 5 | stroke 6 | 0 setgray 7 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 8 | 800.00000000000000000000000000000000 0.00000000000000000000000000000000 lineto 9 | stroke 10 | 0 setgray 11 | 800.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 12 | 800.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 13 | stroke 14 | 0.7 setgray 15 | 100.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 16 | 100.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 17 | stroke 18 | 0 setgray 19 | 100.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 20 | 190.00000000000000000000000000000000 410.00000000000000000000000000000000 lineto 21 | stroke 22 | 0 setgray 23 | 190.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 24 | 190.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 25 | stroke 26 | 0.7 setgray 27 | 100.00000000000000000000000000000000 500.00000000000000000000000000000000 moveto 28 | 190.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 29 | stroke 30 | 0.7 setgray 31 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 moveto 32 | 800.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 33 | stroke 34 | showpage 35 | -------------------------------------------------------------------------------- /tests/polygons/t009.ps: -------------------------------------------------------------------------------- 1 | % begin0.7 setgray 2 | 100.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 3 | 100.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 4 | stroke 5 | 0.7 setgray 6 | 100.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 7 | 190.00000000000000000000000000000000 410.00000000000000000000000000000000 lineto 8 | 190.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 9 | stroke 10 | 0.7 setgray 11 | 100.00000000000000000000000000000000 500.00000000000000000000000000000000 moveto 12 | 190.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 13 | stroke 14 | showpage 15 | -------------------------------------------------------------------------------- /tests/polygons/t010.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 4 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 5 | stroke 6 | 0 setgray 7 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 8 | 800.00000000000000000000000000000000 0.00000000000000000000000000000000 lineto 9 | stroke 10 | 0 setgray 11 | 800.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 12 | 800.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 13 | stroke 14 | 0.7 setgray 15 | 100.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 16 | 100.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 17 | stroke 18 | 0 setgray 19 | 100.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 20 | 190.00000000000000000000000000000000 410.00000000000000000000000000000000 lineto 21 | stroke 22 | 0 setgray 23 | 190.00000000000000000000000000000000 410.00000000000000000000000000000000 moveto 24 | 190.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 25 | stroke 26 | 0.7 setgray 27 | 100.00000000000000000000000000000000 500.00000000000000000000000000000000 moveto 28 | 190.00000000000000000000000000000000 500.00000000000000000000000000000000 lineto 29 | stroke 30 | 0.7 setgray 31 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 moveto 32 | 800.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 33 | stroke 34 | showpage 35 | -------------------------------------------------------------------------------- /tests/polygons/t013.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 200.00002586478879607057024259120226 380.00067822446936816049856133759022 moveto 4 | 80.00027510453540458001953084021807 500.00004857438011640624608844518661 lineto 5 | 99.99998716597397674377134535461664 520.00094555004773155815200880169868 lineto 6 | stroke 7 | 0 setgray 8 | 200.00002586478879607057024259120226 380.00067822446936816049856133759022 moveto 9 | 220.00022527966518737230217084288597 399.99959206323541138772270642220974 lineto 10 | 99.99958503356882033585861790925264 520.00054271539556793868541717529297 lineto 11 | stroke 12 | 0.7 setgray 13 | 99.99903260114325576068949885666370 409.99948577354126655336585827171803 moveto 14 | 99.99925958089356470281927613541484 499.99921761760407434849184937775135 lineto 15 | stroke 16 | 0 setgray 17 | 99.99903260114325576068949885666370 409.99948577354126655336585827171803 moveto 18 | 189.99927446315356860395695548504591 410.00060835350842580737662501633167 lineto 19 | 190.00099784903599697827303316444159 499.99943651381062181826564483344555 lineto 20 | 99.99931335817851163483283016830683 499.99980188878851095068966969847679 lineto 21 | stroke 22 | showpage 23 | -------------------------------------------------------------------------------- /tests/polygons/t014.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 200.00002586478879607057024259120226 380.00067822446936816049856133759022 moveto 4 | 80.00027510453540458001953084021807 500.00004857438011640624608844518661 lineto 5 | 99.99998716597397674377134535461664 520.00094555004773155815200880169868 lineto 6 | stroke 7 | 0 setgray 8 | 200.00002586478879607057024259120226 380.00067822446936816049856133759022 moveto 9 | 220.00022527966518737230217084288597 399.99959206323541138772270642220974 lineto 10 | 99.99958503356882033585861790925264 520.00054271539556793868541717529297 lineto 11 | stroke 12 | 0.7 setgray 13 | 99.99903260114325576068949885666370 409.99948577354126655336585827171803 moveto 14 | 99.99925958089356470281927613541484 499.99921761760407434849184937775135 lineto 15 | stroke 16 | 0 setgray 17 | 99.99903260114325576068949885666370 409.99948577354126655336585827171803 moveto 18 | 189.99927446315356860395695548504591 410.00060835350842580737662501633167 lineto 19 | 190.00099784903599697827303316444159 499.99943651381062181826564483344555 lineto 20 | stroke 21 | 0.7 setgray 22 | 190.00099784903599697827303316444159 499.99943651381062181826564483344555 moveto 23 | 99.99931335817851163483283016830683 499.99980188878851095068966969847679 lineto 24 | stroke 25 | showpage 26 | -------------------------------------------------------------------------------- /tests/polygons/t015.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 99.99903260114325576068949885666370 409.99948577354126655336585827171803 moveto 4 | 99.99925958089356470281927613541484 499.99921761760407434849184937775135 lineto 5 | stroke 6 | 0.7 setgray 7 | 99.99903260114325576068949885666370 409.99948577354126655336585827171803 moveto 8 | 189.99927446315356860395695548504591 410.00060835350842580737662501633167 lineto 9 | 190.00099784903599697827303316444159 499.99943651381062181826564483344555 lineto 10 | 99.99931335817851163483283016830683 499.99980188878851095068966969847679 lineto 11 | stroke 12 | showpage 13 | -------------------------------------------------------------------------------- /tests/polygons/t019.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 437.39636906962766715878387913107872 54.46113824562361571679502958431840 moveto 4 | 435.48466028835622410042560659348965 54.62859729776629080788552528247237 lineto 5 | 433.65885563975029981520492583513260 55.13751250416656546349258860573173 lineto 6 | 432.00166960071049970792955718934536 55.94623413927948263335565570741892 lineto 7 | 430.52662621164438405685359612107277 57.04478337783486807666122331283987 lineto 8 | 429.29618432756626589252846315503120 58.40548950788812021528428886085749 lineto 9 | 428.37346869508525060155079700052738 59.99229323807465164009045111015439 lineto 10 | 427.77110532411217036496964283287525 61.80121968793382336571085033938289 lineto 11 | 427.56939073701124698345665819942951 63.78767183637557991460198536515236 lineto 12 | 427.76208006273128603424993343651295 65.82956436876247607870027422904968 lineto 13 | 428.34378139643837357652955688536167 67.55807891192407055314106401056051 lineto 14 | 429.24246273518895122833782806992531 68.99353523780294494827103335410357 lineto 15 | 430.43968223033186859538545832037926 70.13594229869838159174832981079817 lineto 16 | 431.87682224716496648397878743708134 71.00381755564843899719562614336610 lineto 17 | 433.49529411994990368839353322982788 71.61068550992035852686967700719833 lineto 18 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 19 | stroke 20 | 0 setgray 21 | 437.39636906962766715878387913107872 54.46113824562361571679502958431840 moveto 22 | 441.06159718172870043417788110673428 54.90554652808121716134337475523353 lineto 23 | 442.69034708423805568600073456764221 55.49540059796912316869565984234214 lineto 24 | 444.14146650291604601079598069190979 56.34678332062953387548986938782036 lineto 25 | stroke 26 | 0.7 setgray 27 | 437.39684754768609309394378215074539 54.46287863018449826313371886499226 moveto 28 | 435.48312719129512515792157500982285 54.62989589306683768654693267308176 lineto 29 | 433.66037114602971769272699020802975 55.13731997323084499385004164651036 lineto 30 | 432.00251428428163080752710811793804 55.94564617976055131975954282097518 lineto 31 | 430.52700790463524072038126178085804 57.04432971181260825233039213344455 lineto 32 | 429.29654556489032302124542184174061 58.40437721985028218796287546865642 lineto 33 | 428.37300074926253046214696951210499 59.99326056823937136641688994131982 lineto 34 | 427.77165438854189005724037997424603 61.80129466187470654858771013095975 lineto 35 | 427.57038539166438795291469432413578 63.78824328141998023511405335739255 lineto 36 | 427.76246623202166574628790840506554 65.82973940287206460197921842336655 lineto 37 | 428.34465103096090388135053217411041 67.55920258127603972297947620972991 lineto 38 | 429.24094767504846004158025607466698 68.99251619671964874669356504455209 lineto 39 | 430.43801708298747143999207764863968 70.13619869024053343764535384252667 lineto 40 | 431.87745190918542448343941941857338 71.00526333447723459357803221791983 lineto 41 | 433.49615859772910653191502206027508 71.61100800519476194949675118550658 lineto 42 | 437.15859837203174720343668013811111 72.07034675289243352835910627618432 lineto 43 | stroke 44 | 0 setgray 45 | 437.39684754768609309394378215074539 54.46287863018449826313371886499226 moveto 46 | 441.06233008082114110948168672621250 54.90550091996581016928757890127599 lineto 47 | 442.68903248839654906987561844289303 55.49713795183964748503058217465878 lineto 48 | 444.13954560093952750321477651596069 56.34577499016190671454751281999052 lineto 49 | stroke 50 | 0 setgray 51 | 437.39605626535228566353907808661461 55.80478328252011976928770309314132 moveto 52 | 435.73256720118234852634486742317677 55.94977945461907609114859951660037 lineto 53 | 434.15384868383125649415887892246246 56.38747175201253014620306203141809 lineto 54 | 432.72125069630970983780571259558201 57.08117134711252305123707628808916 lineto 55 | 431.44896075009864944149740040302277 58.02595870742542416564901941455901 lineto 56 | 430.39227298418995815154630690813065 59.19131550700200250503257848322392 lineto 57 | 429.59761750433887073086225427687168 60.54820131025946494673917186446488 lineto 58 | 429.08361898169061987573513761162758 62.09206854317712753754676668904722 lineto 59 | 428.91157531251133150362875312566757 63.78897114176302807209140155464411 lineto 60 | 429.07345469993299502675654366612434 65.49229855808067668476724065840244 lineto 61 | 429.55789282356710145904798991978168 66.93705042568160479277139529585838 lineto 62 | 430.31109880564974901062669232487679 68.13712096580007937518530525267124 lineto 63 | 431.32116487359280654345639050006866 69.09425494171290438316646032035351 lineto 64 | 432.54743875993784740785486064851284 69.82038649365684079839411424472928 lineto 65 | 433.94289458149296478950418531894684 70.33101005432008889783901395276189 lineto 66 | 437.15781542851630092627601698040962 70.72701130576892580847925273701549 lineto 67 | stroke 68 | 0.7 setgray 69 | 437.39605626535228566353907808661461 55.80478328252011976928770309314132 moveto 70 | 440.62288806099780913427821360528469 56.18640287324254245504562277346849 lineto 71 | 442.02825586145331726584117859601974 56.68507170012929918812005780637264 lineto 72 | 443.26402825806940199981909245252609 57.39733211991500638760044239461422 lineto 73 | 444.28706857382150019475375302135944 58.34053301841883865108684403821826 lineto 74 | 445.05099414830709747548098675906658 59.53080289347069253835798008367419 lineto 75 | 445.54238255042133687311434186995029 60.97064884406226781266013858839869 lineto 76 | 445.70767124868729069930850528180599 62.67867827174946171453484566882253 lineto 77 | 445.53245198884445699150091968476772 64.36990560508284886509500211104751 lineto 78 | 445.01125859633356185440788976848125 65.91981975532875992485060123726726 lineto 79 | 444.20763253085465294134337455034256 67.28664220254815120370039949193597 lineto 80 | 443.13636615017901476676343008875847 68.46546536683703720882476773113012 lineto 81 | 441.85466572813959373888792470097542 69.42426362360505720516812289133668 lineto 82 | 440.41235745821973068814259022474289 70.13106142862088177025725599378347 lineto 83 | 438.82361314991527478923671878874302 70.57897767538628386319032870233059 lineto 84 | 437.15781542851630092627601698040962 70.72701130576892580847925273701549 lineto 85 | stroke 86 | 0 setgray 87 | 437.39612080778653080415097065269947 55.80498916722551427938014967367053 moveto 88 | 435.73244062779571095234132371842861 55.94967632752970132514747092500329 lineto 89 | 434.15281117723083070814027450978756 56.38857466210048841048774193041027 lineto 90 | 432.72080650696960901768761686980724 57.08147060198829336741255247034132 lineto 91 | 431.44931656212497728120069950819016 58.02555186198600978286776808090508 lineto 92 | 430.39164791835725054625072516500950 59.19119549330579843626765068620443 lineto 93 | 429.59804462784654788265470415353775 60.54956158719851089244912145659328 lineto 94 | 429.08297231979128127932199276983738 62.09313778575656073144273250363767 lineto 95 | 428.91228526188120895312749780714512 63.78833229913625757490081014111638 lineto 96 | 429.07390473165611410877318121492863 65.49309807225830581955960951745510 lineto 97 | 429.55769856733490996703039854764938 66.93783276567677376078790985047817 lineto 98 | 430.31190016235780149145284667611122 68.13572687717724818412534659728408 lineto 99 | 431.32112848213614597625564783811569 69.09277534719937818863400025293231 lineto 100 | 432.54745006153638087198487482964993 69.82125212682363724070455646142364 lineto 101 | 433.94118088070314342985511757433414 70.33135470214500628571840934455395 lineto 102 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 lineto 103 | stroke 104 | 0.7 setgray 105 | 437.39612080778653080415097065269947 55.80498916722551427938014967367053 moveto 106 | 440.62178039211318036905140615999699 56.18661237146090314809043775312603 lineto 107 | 442.02781228010576342057902365922928 56.68422037677484581763565074652433 lineto 108 | 443.26443312574292576755397021770477 57.39742831650038823454451630823314 lineto 109 | 444.28769636813689203336252830922604 58.34015593135271160463162232190371 lineto 110 | 445.05015339152902242858544923365116 59.53133314406775156157891615293920 lineto 111 | 445.54275115782803595720906741917133 60.97085350551643045946548227220774 lineto 112 | 445.70604994076774119093897752463818 62.67958742051095555325446184724569 lineto 113 | 445.53347369836160396516788750886917 64.36924334876812281436286866664886 lineto 114 | 445.00993809681312995962798595428467 65.91859282926034779848123434931040 lineto 115 | 444.20814025409691794266109354794025 67.28769011437144342835381394252181 lineto 116 | 443.13801669380802650266559794545174 68.46464541562555439213610952720046 lineto 117 | 441.85311332417757057555718347430229 69.42493718151828829832084011286497 lineto 118 | 440.41248723596703484872705303132534 70.13152276194156797828327398747206 lineto 119 | 438.82310524404255147601361386477947 70.57930010154443323244777275249362 lineto 120 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 lineto 121 | stroke 122 | 0 setgray 123 | 444.13954560093952750321477651596069 56.34577499016190671454751281999052 moveto 124 | 445.35164010988029303916846401989460 57.47504768075557279871645732782781 lineto 125 | 446.26173580414968000695807859301567 58.90067961578692745661101071164012 lineto 126 | 446.85399937898193911678390577435493 60.62646779277940822794334962964058 lineto 127 | 447.04935317153967844205908477306366 62.67969950675679768892223364673555 lineto 128 | 446.84492994143187161171226762235165 64.66133739748578079797880491241813 lineto 129 | 446.23538604634177318075671792030334 66.47238434559523057032492943108082 lineto 130 | 445.30165432785940993198892101645470 68.06891870075192230160610051825643 lineto 131 | 444.06022608347592495192657224833965 69.44316459198405766528594540432096 lineto 132 | 442.57190125806920377726783044636250 70.55850719033473694707936374470592 lineto 133 | 440.90597951204495075216982513666153 71.38027029954390911825612420216203 lineto 134 | 439.07288735909389743028441444039345 71.90027084165903659140894887968898 lineto 135 | 437.15859837203174720343668013811111 72.07034675289243352835910627618432 lineto 136 | stroke 137 | 0 setgray 138 | 444.14146650291604601079598069190979 56.34678332062953387548986938782036 moveto 139 | 445.35170016738067033656989224255085 57.47497407037059247159049846231937 lineto 140 | 446.26155124801925921929068863391876 58.89963297430347211047774180769920 lineto 141 | 446.85324154703556587264756672084332 60.62681581826264931578407413326204 lineto 142 | 447.05072166899486774127581156790257 62.67848306651072221029608044773340 lineto 143 | 446.84591401173895519605139270424843 64.65999786967795159853267250582576 lineto 144 | 446.23574126283017449168255552649498 66.47353179189845207019970985129476 lineto 145 | 445.30290690113690743601182475686073 68.06950000180152926532173296436667 lineto 146 | 444.06010764633566623160731978714466 69.44463389753914839275239501148462 lineto 147 | 442.57241794045864935469580814242363 70.55914870603332644805050222203135 lineto 148 | 440.90485566006248063786188140511513 71.38089321080093441196368075907230 lineto 149 | 439.07411618172903899903758428990841 71.89905690750794065024820156395435 lineto 150 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 151 | stroke 152 | 0 setgray 153 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 moveto 154 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 155 | stroke 156 | 0.7 setgray 157 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 moveto 158 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 159 | stroke 160 | showpage 161 | -------------------------------------------------------------------------------- /tests/polygons/t020.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 0.0 0.0 moveto 4 | 0.0 400.0 lineto 5 | stroke 6 | 0.0 setgray 7 | 400.0 0.0 moveto 8 | 400.0 400.0 lineto 9 | stroke 10 | 0.7 setgray 11 | 0.0 0.0 moveto 12 | 400.0 0.0 lineto 13 | stroke 14 | 0.0 setgray 15 | 0.0 400.0 moveto 16 | 400.0 400.0 lineto 17 | stroke 18 | showpage 19 | -------------------------------------------------------------------------------- /tests/polygons/t025.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 437.39636906962766715878387913107872 54.46113824562361571679502958431840 moveto 4 | 435.48466028835622410042560659348965 54.62859729776629080788552528247237 lineto 5 | 433.65885563975029981520492583513260 55.13751250416656546349258860573173 lineto 6 | 432.00166960071049970792955718934536 55.94623413927948263335565570741892 lineto 7 | 430.52662621164438405685359612107277 57.04478337783486807666122331283987 lineto 8 | 429.29618432756626589252846315503120 58.40548950788812021528428886085749 lineto 9 | 428.37346869508525060155079700052738 59.99229323807465164009045111015439 lineto 10 | 427.77110532411217036496964283287525 61.80121968793382336571085033938289 lineto 11 | 427.56939073701124698345665819942951 63.78767183637557991460198536515236 lineto 12 | 427.76208006273128603424993343651295 65.82956436876247607870027422904968 lineto 13 | 428.34378139643837357652955688536167 67.55807891192407055314106401056051 lineto 14 | 429.24246273518895122833782806992531 68.99353523780294494827103335410357 lineto 15 | 430.43968223033186859538545832037926 70.13594229869838159174832981079817 lineto 16 | 431.87682224716496648397878743708134 71.00381755564843899719562614336610 lineto 17 | 433.49529411994990368839353322982788 71.61068550992035852686967700719833 lineto 18 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 19 | stroke 20 | 0 setgray 21 | 437.39636906962766715878387913107872 54.46113824562361571679502958431840 moveto 22 | 441.06159718172870043417788110673428 54.90554652808121716134337475523353 lineto 23 | 442.69034708423805568600073456764221 55.49540059796912316869565984234214 lineto 24 | 444.14146650291604601079598069190979 56.34678332062953387548986938782036 lineto 25 | stroke 26 | 0.7 setgray 27 | 437.39684754768609309394378215074539 54.46287863018449826313371886499226 moveto 28 | 435.48312719129512515792157500982285 54.62989589306683768654693267308176 lineto 29 | 433.66037114602971769272699020802975 55.13731997323084499385004164651036 lineto 30 | 432.00251428428163080752710811793804 55.94564617976055131975954282097518 lineto 31 | 430.52700790463524072038126178085804 57.04432971181260825233039213344455 lineto 32 | 429.29654556489032302124542184174061 58.40437721985028218796287546865642 lineto 33 | 428.37300074926253046214696951210499 59.99326056823937136641688994131982 lineto 34 | 427.77165438854189005724037997424603 61.80129466187470654858771013095975 lineto 35 | 427.57038539166438795291469432413578 63.78824328141998023511405335739255 lineto 36 | 427.76246623202166574628790840506554 65.82973940287206460197921842336655 lineto 37 | 428.34465103096090388135053217411041 67.55920258127603972297947620972991 lineto 38 | 429.24094767504846004158025607466698 68.99251619671964874669356504455209 lineto 39 | 430.43801708298747143999207764863968 70.13619869024053343764535384252667 lineto 40 | 431.87745190918542448343941941857338 71.00526333447723459357803221791983 lineto 41 | 433.49615859772910653191502206027508 71.61100800519476194949675118550658 lineto 42 | 437.15859837203174720343668013811111 72.07034675289243352835910627618432 lineto 43 | stroke 44 | 0 setgray 45 | 437.39684754768609309394378215074539 54.46287863018449826313371886499226 moveto 46 | 441.06233008082114110948168672621250 54.90550091996581016928757890127599 lineto 47 | 442.68903248839654906987561844289303 55.49713795183964748503058217465878 lineto 48 | 444.13954560093952750321477651596069 56.34577499016190671454751281999052 lineto 49 | stroke 50 | 0 setgray 51 | 437.39605626535228566353907808661461 55.80478328252011976928770309314132 moveto 52 | 435.73256720118234852634486742317677 55.94977945461907609114859951660037 lineto 53 | 434.15384868383125649415887892246246 56.38747175201253014620306203141809 lineto 54 | 432.72125069630970983780571259558201 57.08117134711252305123707628808916 lineto 55 | 431.44896075009864944149740040302277 58.02595870742542416564901941455901 lineto 56 | 430.39227298418995815154630690813065 59.19131550700200250503257848322392 lineto 57 | 429.59761750433887073086225427687168 60.54820131025946494673917186446488 lineto 58 | 429.08361898169061987573513761162758 62.09206854317712753754676668904722 lineto 59 | 428.91157531251133150362875312566757 63.78897114176302807209140155464411 lineto 60 | 429.07345469993299502675654366612434 65.49229855808067668476724065840244 lineto 61 | 429.55789282356710145904798991978168 66.93705042568160479277139529585838 lineto 62 | 430.31109880564974901062669232487679 68.13712096580007937518530525267124 lineto 63 | 431.32116487359280654345639050006866 69.09425494171290438316646032035351 lineto 64 | 432.54743875993784740785486064851284 69.82038649365684079839411424472928 lineto 65 | 433.94289458149296478950418531894684 70.33101005432008889783901395276189 lineto 66 | 437.15781542851630092627601698040962 70.72701130576892580847925273701549 lineto 67 | stroke 68 | 0.7 setgray 69 | 437.39605626535228566353907808661461 55.80478328252011976928770309314132 moveto 70 | 440.62288806099780913427821360528469 56.18640287324254245504562277346849 lineto 71 | 442.02825586145331726584117859601974 56.68507170012929918812005780637264 lineto 72 | 443.26402825806940199981909245252609 57.39733211991500638760044239461422 lineto 73 | 444.28706857382150019475375302135944 58.34053301841883865108684403821826 lineto 74 | 445.05099414830709747548098675906658 59.53080289347069253835798008367419 lineto 75 | 445.54238255042133687311434186995029 60.97064884406226781266013858839869 lineto 76 | 445.70767124868729069930850528180599 62.67867827174946171453484566882253 lineto 77 | 445.53245198884445699150091968476772 64.36990560508284886509500211104751 lineto 78 | 445.01125859633356185440788976848125 65.91981975532875992485060123726726 lineto 79 | 444.20763253085465294134337455034256 67.28664220254815120370039949193597 lineto 80 | 443.13636615017901476676343008875847 68.46546536683703720882476773113012 lineto 81 | 441.85466572813959373888792470097542 69.42426362360505720516812289133668 lineto 82 | 440.41235745821973068814259022474289 70.13106142862088177025725599378347 lineto 83 | 438.82361314991527478923671878874302 70.57897767538628386319032870233059 lineto 84 | 437.15781542851630092627601698040962 70.72701130576892580847925273701549 lineto 85 | stroke 86 | 0 setgray 87 | 437.39612080778653080415097065269947 55.80498916722551427938014967367053 moveto 88 | 435.73244062779571095234132371842861 55.94967632752970132514747092500329 lineto 89 | 434.15281117723083070814027450978756 56.38857466210048841048774193041027 lineto 90 | 432.72080650696960901768761686980724 57.08147060198829336741255247034132 lineto 91 | 431.44931656212497728120069950819016 58.02555186198600978286776808090508 lineto 92 | 430.39164791835725054625072516500950 59.19119549330579843626765068620443 lineto 93 | 429.59804462784654788265470415353775 60.54956158719851089244912145659328 lineto 94 | 429.08297231979128127932199276983738 62.09313778575656073144273250363767 lineto 95 | 428.91228526188120895312749780714512 63.78833229913625757490081014111638 lineto 96 | 429.07390473165611410877318121492863 65.49309807225830581955960951745510 lineto 97 | 429.55769856733490996703039854764938 66.93783276567677376078790985047817 lineto 98 | 430.31190016235780149145284667611122 68.13572687717724818412534659728408 lineto 99 | 431.32112848213614597625564783811569 69.09277534719937818863400025293231 lineto 100 | 432.54745006153638087198487482964993 69.82125212682363724070455646142364 lineto 101 | 433.94118088070314342985511757433414 70.33135470214500628571840934455395 lineto 102 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 lineto 103 | stroke 104 | 0.7 setgray 105 | 437.39612080778653080415097065269947 55.80498916722551427938014967367053 moveto 106 | 440.62178039211318036905140615999699 56.18661237146090314809043775312603 lineto 107 | 442.02781228010576342057902365922928 56.68422037677484581763565074652433 lineto 108 | 443.26443312574292576755397021770477 57.39742831650038823454451630823314 lineto 109 | 444.28769636813689203336252830922604 58.34015593135271160463162232190371 lineto 110 | 445.05015339152902242858544923365116 59.53133314406775156157891615293920 lineto 111 | 445.54275115782803595720906741917133 60.97085350551643045946548227220774 lineto 112 | 445.70604994076774119093897752463818 62.67958742051095555325446184724569 lineto 113 | 445.53347369836160396516788750886917 64.36924334876812281436286866664886 lineto 114 | 445.00993809681312995962798595428467 65.91859282926034779848123434931040 lineto 115 | 444.20814025409691794266109354794025 67.28769011437144342835381394252181 lineto 116 | 443.13801669380802650266559794545174 68.46464541562555439213610952720046 lineto 117 | 441.85311332417757057555718347430229 69.42493718151828829832084011286497 lineto 118 | 440.41248723596703484872705303132534 70.13152276194156797828327398747206 lineto 119 | 438.82310524404255147601361386477947 70.57930010154443323244777275249362 lineto 120 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 lineto 121 | stroke 122 | 0 setgray 123 | 444.13954560093952750321477651596069 56.34577499016190671454751281999052 moveto 124 | 445.35164010988029303916846401989460 57.47504768075557279871645732782781 lineto 125 | 446.26173580414968000695807859301567 58.90067961578692745661101071164012 lineto 126 | 446.85399937898193911678390577435493 60.62646779277940822794334962964058 lineto 127 | 447.04935317153967844205908477306366 62.67969950675679768892223364673555 lineto 128 | 446.84492994143187161171226762235165 64.66133739748578079797880491241813 lineto 129 | 446.23538604634177318075671792030334 66.47238434559523057032492943108082 lineto 130 | 445.30165432785940993198892101645470 68.06891870075192230160610051825643 lineto 131 | 444.06022608347592495192657224833965 69.44316459198405766528594540432096 lineto 132 | 442.57190125806920377726783044636250 70.55850719033473694707936374470592 lineto 133 | 440.90597951204495075216982513666153 71.38027029954390911825612420216203 lineto 134 | 439.07288735909389743028441444039345 71.90027084165903659140894887968898 lineto 135 | 437.15859837203174720343668013811111 72.07034675289243352835910627618432 lineto 136 | stroke 137 | 0 setgray 138 | 444.14146650291604601079598069190979 56.34678332062953387548986938782036 moveto 139 | 445.35170016738067033656989224255085 57.47497407037059247159049846231937 lineto 140 | 446.26155124801925921929068863391876 58.89963297430347211047774180769920 lineto 141 | 446.85324154703556587264756672084332 60.62681581826264931578407413326204 lineto 142 | 447.05072166899486774127581156790257 62.67848306651072221029608044773340 lineto 143 | 446.84591401173895519605139270424843 64.65999786967795159853267250582576 lineto 144 | 446.23574126283017449168255552649498 66.47353179189845207019970985129476 lineto 145 | 445.30290690113690743601182475686073 68.06950000180152926532173296436667 lineto 146 | 444.06010764633566623160731978714466 69.44463389753914839275239501148462 lineto 147 | 442.57241794045864935469580814242363 70.55914870603332644805050222203135 lineto 148 | 440.90485566006248063786188140511513 71.38089321080093441196368075907230 lineto 149 | 439.07411618172903899903758428990841 71.89905690750794065024820156395435 lineto 150 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 151 | stroke 152 | 0 setgray 153 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 moveto 154 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 155 | stroke 156 | 0.7 setgray 157 | 437.15723928421004984556930139660835 70.72701112313843907486443640664220 moveto 158 | 437.15745592554588938583037815988064 72.07109063566716145032842177897692 lineto 159 | stroke 160 | showpage 161 | -------------------------------------------------------------------------------- /tests/polygons/t027.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 4 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 5 | stroke 6 | 0.7 setgray 7 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 8 | 800.00000000000000000000000000000000 0.84644720000000006621121428906918 lineto 9 | 800.00000000000000000000000000000000 800.84644720000005690963007509708405 lineto 10 | stroke 11 | 0.7 setgray 12 | 100.00000000000000000000000000000000 410.10580590000000711370375938713551 moveto 13 | 100.00000000000000000000000000000000 500.10580590000000711370375938713551 lineto 14 | stroke 15 | 0.7 setgray 16 | 100.00000000000000000000000000000000 410.10580590000000711370375938713551 moveto 17 | 190.00000000000000000000000000000000 410.20103120999999646301148459315300 lineto 18 | 190.00000000000000000000000000000000 500.20103120999999646301148459315300 lineto 19 | stroke 20 | 0.7 setgray 21 | 100.00000000000000000000000000000000 500.10580590000000711370375938713551 moveto 22 | 190.00000000000000000000000000000000 500.20103120999999646301148459315300 lineto 23 | stroke 24 | 0.7 setgray 25 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 moveto 26 | 800.00000000000000000000000000000000 800.84644720000005690963007509708405 lineto 27 | stroke 28 | showpage 29 | -------------------------------------------------------------------------------- /tests/polygons/t028.ps: -------------------------------------------------------------------------------- 1 | % begin 2 | 0.7 setgray 3 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 4 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 lineto 5 | stroke 6 | 0.7 setgray 7 | 0.00000000000000000000000000000000 0.00000000000000000000000000000000 moveto 8 | 800.00000000000000000000000000000000 0.84644720000000006621121428906918 lineto 9 | 800.00000000000000000000000000000000 800.84644720000005690963007509708405 lineto 10 | stroke 11 | 0.7 setgray 12 | 100.00000000000000000000000000000000 410.10580590000000711370375938713551 moveto 13 | 100.00000000000000000000000000000000 500.10580590000000711370375938713551 lineto 14 | stroke 15 | 0.7 setgray 16 | 100.00000000000000000000000000000000 410.10580590000000711370375938713551 moveto 17 | 190.00000000000000000000000000000000 410.20103120999999646301148459315300 lineto 18 | 190.00000000000000000000000000000000 500.20103120999999646301148459315300 lineto 19 | stroke 20 | 0.7 setgray 21 | 100.00000000000000000000000000000000 500.10580590000000711370375938713551 moveto 22 | 190.00000000000000000000000000000000 500.20103120999999646301148459315300 lineto 23 | stroke 24 | 0.7 setgray 25 | 0.00000000000000000000000000000000 800.00000000000000000000000000000000 moveto 26 | 800.00000000000000000000000000000000 800.84644720000005690963007509708405 lineto 27 | stroke 28 | showpage 29 | -------------------------------------------------------------------------------- /tests/run_ps.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthiaskramm/gfxpoly/083e6a89cee62dfcb07f7a21b0bd83c762087741/tests/run_ps.c --------------------------------------------------------------------------------