# HG changeset patch # User Merten Sach # Date 1316693785 -7200 # Node ID 11a4bcadac2a38bd5e9981510248412d7467042d Initial SSR version diff -r 000000000000 -r 11a4bcadac2a .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Thu Sep 22 14:16:25 2011 +0200 @@ -0,0 +1,7 @@ +syntax: glob + +histograms +nbproject +c-ray-mt +*.ppm +*.o diff -r 000000000000 -r 11a4bcadac2a Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Thu Sep 22 14:16:25 2011 +0200 @@ -0,0 +1,48 @@ +obj = \ + SSR_lib/VMS/Histogram/Histogram.o \ + SSR_lib/VMS/Histogram/FloatHist.o \ + SSR_lib/VMS/CoreLoop.o \ + SSR_lib/VMS/VMS.o \ + SSR_lib/VMS/MasterLoop.o \ + SSR_lib/VMS/Queue_impl/PrivateQueue.o \ + SSR_lib/VMS/Hash_impl/PrivateHash.o \ + SSR_lib/VMS/DynArray/DynArray.o \ + SSR_lib/SSR_PluginFns.o \ + SSR_lib/SSR_lib.o \ + SSR_lib/VMS/Histogram/DblHist.o \ + SSR_lib/SSR.o \ + SSR_lib/VMS/probes.o \ + SSR_lib/VMS/ProcrContext.o \ + SSR_lib/SSR_Request_Handlers.o \ + SSR_lib/VMS/Hash_impl/MurmurHash2.o \ + SSR_lib/VMS/vmalloc.o \ + SSR_lib/VMS/contextSwitch.o \ + SSR_lib/VMS/Queue_impl/BlockingQueue.o \ + SSR_lib/VMS/vutilities.o \ + c-ray-mt.o + +bin = c-ray-mt + +CC = gcc +CFLAGS = -m64 -ffast-math -fwrapv -fno-omit-frame-pointer -O3 -D SSR -D APPLICATION=C-RAY -g -Wall + +$(bin): $(obj) + $(CC) -o $@ $(obj) -lm -lpthread + +%.o : %.c + $(CC) -c $(CFLAGS) -o $@ $< + +.PHONY: clean +clean: + rm -f $(obj) $(bin) + +.PHONY: install +install: + cp $(bin) /usr/local/bin/$(bin) + +.PHONY: uninstall +uninstall: + rm -f /usr/local/bin/$(bin) + + +# $@ Name des Targets diff -r 000000000000 -r 11a4bcadac2a README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Thu Sep 22 14:16:25 2011 +0200 @@ -0,0 +1,27 @@ +Kernel: Ray Tracing + +This is a kernel-type benchmark of a very simple and brute-force ray tracer. + +Installation: + +To install the kernel benchmark, navigate to the directory this file is located in, open up a terminal and simply type 'make'. For certain architectures +or special compilation options, you might need to change compilation parameters in the makefile. + +Usage: + +You may execute the benchmark by navigating to this directory after compilation and typing + +./c-ray-mt -i FILENAME -s RESOLUTION -o OUTPUT.ppm + +'FILENAME' has to be either "scene" or "sphfract" or another predefined scene description file if there is one. +'RESOLUTION' specifies the resolution of the produced image and has to be given in the form 1920x1200, for example. +'OUTPUT' is the name of the file the rendered image will be contained in after the benchmark ran. + +The specification of how many threads are used to perform the rendering depends on the parallel programming model. + +Benchmark Versions: + +Serial +POSIX Threads +OpenMP SuperScalar + diff -r 000000000000 -r 11a4bcadac2a c-ray-mt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c-ray-mt.c Thu Sep 22 14:16:25 2011 +0200 @@ -0,0 +1,704 @@ +/* c-ray-mt - a simple multithreaded raytracing filter. + * Copyright (C) 2006 John Tsiombikas + * + * You are free to use, modify and redistribute this program under the + * terms of the GNU General Public License v2 or (at your option) later. + * see "http://www.gnu.org/licenses/gpl.txt" for details. + * --------------------------------------------------------------------- + * Usage: + * compile: just type make + * (add any arch-specific optimizations for your compiler in CFLAGS first) + * run: cat scene | ./c-ray-mt [-t num-threads] >foo.ppm + * (on broken systems such as windows try: c-ray-mt -i scene -o foo.ppm) + * enjoy: display foo.ppm + * (with imagemagick, or use your favorite image viewer) + * --------------------------------------------------------------------- + * Scene file format: + * # sphere (many) + * s x y z rad r g b shininess reflectivity + * # light (many) + * l x y z + * # camera (one) + * c x y z fov tx ty tz + * --------------------------------------------------------------------- + */ +#include +#include +#include +#include +#include +#include +#include +#include "SSR_lib/SSR.h" + +#define VER_MAJOR 1 +#define VER_MINOR 1 +#define VER_STR "c-ray-mt v%d.%d\n" + +#if !defined(unix) && !defined(__unix__) +#ifdef __MACH__ +#define unix 1 +#define __unix__ 1 +#endif /* __MACH__ */ +#endif /* unix */ + +/* find the appropriate way to define explicitly sized types */ +/* for C99 or GNU libc (also mach's libc) we can use stdint.h */ +#if (__STDC_VERSION__ >= 199900) || defined(__GLIBC__) || defined(__MACH__) +#include +#elif defined(unix) || defined(__unix__) /* some UNIX systems have them in sys/types.h */ +#include +#elif defined(__WIN32__) || defined(WIN32) /* the nameless one */ +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +#endif /* sized type detection */ + +struct vec3 { + double x, y, z; +}; + +struct ray { + struct vec3 orig, dir; +}; + +struct material { + struct vec3 col; /* color */ + double spow; /* specular power */ + double refl; /* reflection intensity */ +}; + +struct sphere { + struct vec3 pos; + double rad; + struct material mat; + struct sphere *next; +}; + +struct spoint { + struct vec3 pos, normal, vref; /* position, normal and view reflection */ + double dist; /* parametric distance of intersection along the ray */ +}; + +struct camera { + struct vec3 pos, targ; + double fov; +}; + +struct procr_data { + VirtProcr *VP; + VirtProcr *parentVP; + int sl_start, sl_count; + uint32_t *pixels; +}; +typedef struct procr_data procr_data; + +void render_scanline(int xsz, int ysz, int sl, uint32_t *fb, int samples); +struct vec3 trace(struct ray ray, int depth); +struct vec3 shade(struct sphere *obj, struct spoint *sp, int depth); +struct vec3 reflect(struct vec3 v, struct vec3 n); +struct vec3 cross_product(struct vec3 v1, struct vec3 v2); +struct ray get_primary_ray(int x, int y, int sample); +struct vec3 get_sample_pos(int x, int y, int sample); +struct vec3 jitter(int x, int y, int s); +int ray_sphere(const struct sphere *sph, struct ray ray, struct spoint *sp); +void load_scene(FILE *fp); +unsigned long get_msec(void); + +void thread_func(void *tdata, VirtProcr *VProc); + +#define MAX_LIGHTS 16 /* maximum number of lights */ +#define RAY_MAG 1000.0 /* trace rays of this magnitude */ +#define MAX_RAY_DEPTH 5 /* raytrace recursion limit */ +#define FOV 0.78539816 /* field of view in rads (pi/4) */ +#define HALF_FOV (FOV * 0.5) +#define ERR_MARGIN 1e-6 /* an arbitrary error margin to avoid surface acne */ + +/* bit-shift ammount for packing each color into a 32bit uint */ +#ifdef LITTLE_ENDIAN +#define RSHIFT 16 +#define BSHIFT 0 +#else /* big endian */ +#define RSHIFT 0 +#define BSHIFT 16 +#endif /* endianess */ +#define GSHIFT 8 /* this is the same in both byte orders */ + +/* some helpful macros... */ +#define SQ(x) ((x) * (x)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define DOT(a, b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z) +#define NORMALIZE(a) do {\ + double len = sqrt(DOT(a, a));\ + (a).x /= len; (a).y /= len; (a).z /= len;\ +} while(0); + +//SSR Message Types +#define WORK_START 1 +#define WORK_END 2 + +/* global state */ +int xres = 800; +int yres = 600; +int rays_per_pixel = 1; +double aspect = 1.333333; +struct sphere *obj_list; +struct vec3 lights[MAX_LIGHTS]; +int lnum = 0; +struct camera cam; + +int thread_num = 1; +struct procr_data *procrs; + +volatile int end = 0; +volatile int start = 0; +int32 end_mutex, end_cond; +int32 start_cond, start_mutex; + +#define NRAN 1024 +#define MASK (NRAN - 1) +struct vec3 urand[NRAN]; +int irand[NRAN]; + +unsigned long rend_time, start_time; + +const char *usage = { + "Usage: c-ray-mt [options]\n" + " Reads a scene file from stdin, writes the image to stdout, and stats to stderr.\n\n" + "Options:\n" + " -t how many threads to use (default: 1)\n" + " -s WxH where W is the width and H the height of the image\n" + " -r shoot rays per pixel (antialiasing)\n" + " -i read from instead of stdin\n" + " -o write to instead of stdout\n" + " -h this help screen\n\n" +}; + +char __ProgrammName[] = "c-ray"; +char __DataSet[255]; + + +void raytrace(void *pixels, VirtProcr *Vprocr); + +int main(int argc, char **argv) { + int i; + uint32_t *pixels; + FILE *infile = stdin, *outfile = stdout; + + for(i=1; i> RSHIFT) & 0xff, outfile); + fputc((pixels[i] >> GSHIFT) & 0xff, outfile); + fputc((pixels[i] >> BSHIFT) & 0xff, outfile); + } + fflush(outfile); + + if(infile != stdin) fclose(infile); + if(outfile != stdout) fclose(outfile); + + struct sphere *walker = obj_list; + while(walker) { + struct sphere *tmp = walker; + walker = walker->next; + free(tmp); + } + free(pixels); + return 0; +} + +/* this is run after the VMS is set up*/ +void raytrace(void *pixels, VirtProcr *VProc) +{ + int i; + double sl, sl_per_procr; + + /* initialize the random number tables for the jitter */ + for(i=0; i yres) { + fprintf(stderr, "more threads than scanlines specified, reducing number of threads to %d\n", yres); + thread_num = yres; + } + + + if(!(procrs = SSR__malloc_to(thread_num * sizeof(procr_data), VProc))) { + perror("failed to allocate thread table"); + exit(EXIT_FAILURE); + } + + sl = 0.0; + sl_per_procr = (double)yres / (double)thread_num; + for(i=0; iprocrID); + start_time = get_msec(); + for(i=0; iprocrID); + for(i=0; inext; + + /* if we reached the recursion limit, bail out */ + if(depth >= MAX_RAY_DEPTH) { + col.x = col.y = col.z = 0.0; + return col; + } + + /* find the nearest intersection ... */ + while(iter) { + if(ray_sphere(iter, ray, &sp)) { + if(!nearest_obj || sp.dist < nearest_sp.dist) { + nearest_obj = iter; + nearest_sp = sp; + } + } + iter = iter->next; + } + + /* and perform shading calculations as needed by calling shade() */ + if(nearest_obj) { + col = shade(nearest_obj, &nearest_sp, depth); + } else { + col.x = col.y = col.z = 0.0; + } + + return col; +} + +/* Calculates direct illumination with the phong reflectance model. + * Also handles reflections by calling trace again, if necessary. + */ +struct vec3 shade(struct sphere *obj, struct spoint *sp, int depth) { + int i; + struct vec3 col = {0, 0, 0}; + + /* for all lights ... */ + for(i=0; inext; + int in_shadow = 0; + + ldir.x = lights[i].x - sp->pos.x; + ldir.y = lights[i].y - sp->pos.y; + ldir.z = lights[i].z - sp->pos.z; + + shadow_ray.orig = sp->pos; + shadow_ray.dir = ldir; + + /* shoot shadow rays to determine if we have a line of sight with the light */ + while(iter) { + if(ray_sphere(iter, shadow_ray, 0)) { + in_shadow = 1; + break; + } + iter = iter->next; + } + + /* and if we're not in shadow, calculate direct illumination with the phong model. */ + if(!in_shadow) { + NORMALIZE(ldir); + + idiff = MAX(DOT(sp->normal, ldir), 0.0); + ispec = obj->mat.spow > 0.0 ? pow(MAX(DOT(sp->vref, ldir), 0.0), obj->mat.spow) : 0.0; + + col.x += idiff * obj->mat.col.x + ispec; + col.y += idiff * obj->mat.col.y + ispec; + col.z += idiff * obj->mat.col.z + ispec; + } + } + + /* Also, if the object is reflective, spawn a reflection ray, and call trace() + * to calculate the light arriving from the mirror direction. + */ + if(obj->mat.refl > 0.0) { + struct ray ray; + struct vec3 rcol; + + ray.orig = sp->pos; + ray.dir = sp->vref; + ray.dir.x *= RAY_MAG; + ray.dir.y *= RAY_MAG; + ray.dir.z *= RAY_MAG; + + rcol = trace(ray, depth + 1); + col.x += rcol.x * obj->mat.refl; + col.y += rcol.y * obj->mat.refl; + col.z += rcol.z * obj->mat.refl; + } + + return col; +} + +/* calculate reflection vector */ +struct vec3 reflect(struct vec3 v, struct vec3 n) { + struct vec3 res; + double dot = v.x * n.x + v.y * n.y + v.z * n.z; + res.x = -(2.0 * dot * n.x - v.x); + res.y = -(2.0 * dot * n.y - v.y); + res.z = -(2.0 * dot * n.z - v.z); + return res; +} + +struct vec3 cross_product(struct vec3 v1, struct vec3 v2) { + struct vec3 res; + res.x = v1.y * v2.z - v1.z * v2.y; + res.y = v1.z * v2.x - v1.x * v2.z; + res.z = v1.x * v2.y - v1.y * v2.x; + return res; +} + +/* determine the primary ray corresponding to the specified pixel (x, y) */ +struct ray get_primary_ray(int x, int y, int sample) { + struct ray ray; + float m[3][3]; + struct vec3 i, j = {0, 1, 0}, k, dir, orig, foo; + + k.x = cam.targ.x - cam.pos.x; + k.y = cam.targ.y - cam.pos.y; + k.z = cam.targ.z - cam.pos.z; + NORMALIZE(k); + + i = cross_product(j, k); + j = cross_product(k, i); + m[0][0] = i.x; m[0][1] = j.x; m[0][2] = k.x; + m[1][0] = i.y; m[1][1] = j.y; m[1][2] = k.y; + m[2][0] = i.z; m[2][1] = j.z; m[2][2] = k.z; + + ray.orig.x = ray.orig.y = ray.orig.z = 0.0; + ray.dir = get_sample_pos(x, y, sample); + ray.dir.z = 1.0 / HALF_FOV; + ray.dir.x *= RAY_MAG; + ray.dir.y *= RAY_MAG; + ray.dir.z *= RAY_MAG; + + dir.x = ray.dir.x + ray.orig.x; + dir.y = ray.dir.y + ray.orig.y; + dir.z = ray.dir.z + ray.orig.z; + foo.x = dir.x * m[0][0] + dir.y * m[0][1] + dir.z * m[0][2]; + foo.y = dir.x * m[1][0] + dir.y * m[1][1] + dir.z * m[1][2]; + foo.z = dir.x * m[2][0] + dir.y * m[2][1] + dir.z * m[2][2]; + + orig.x = ray.orig.x * m[0][0] + ray.orig.y * m[0][1] + ray.orig.z * m[0][2] + cam.pos.x; + orig.y = ray.orig.x * m[1][0] + ray.orig.y * m[1][1] + ray.orig.z * m[1][2] + cam.pos.y; + orig.z = ray.orig.x * m[2][0] + ray.orig.y * m[2][1] + ray.orig.z * m[2][2] + cam.pos.z; + + ray.orig = orig; + ray.dir.x = foo.x + orig.x; + ray.dir.y = foo.y + orig.y; + ray.dir.z = foo.z + orig.z; + + return ray; +} + + +struct vec3 get_sample_pos(int x, int y, int sample) { + struct vec3 pt; + static double sf = 0.0; + + if(sf == 0.0) { + sf = 1.5 / (double)xres; + } + + pt.x = ((double)x / (double)xres) - 0.5; + pt.y = -(((double)y / (double)yres) - 0.65) / aspect; + + if(sample) { + struct vec3 jt = jitter(x, y, sample); + pt.x += jt.x * sf; + pt.y += jt.y * sf / aspect; + } + return pt; +} + +/* jitter function taken from Graphics Gems I. */ +struct vec3 jitter(int x, int y, int s) { + struct vec3 pt; + pt.x = urand[(x + (y << 2) + irand[(x + s) & MASK]) & MASK].x; + pt.y = urand[(y + (x << 2) + irand[(y + s) & MASK]) & MASK].y; + return pt; +} + +/* Calculate ray-sphere intersection, and return {1, 0} to signify hit or no hit. + * Also the surface point parameters like position, normal, etc are returned through + * the sp pointer if it is not NULL. + */ +int ray_sphere(const struct sphere *sph, struct ray ray, struct spoint *sp) { + double a, b, c, d, sqrt_d, t1, t2; + + a = SQ(ray.dir.x) + SQ(ray.dir.y) + SQ(ray.dir.z); + b = 2.0 * ray.dir.x * (ray.orig.x - sph->pos.x) + + 2.0 * ray.dir.y * (ray.orig.y - sph->pos.y) + + 2.0 * ray.dir.z * (ray.orig.z - sph->pos.z); + c = SQ(sph->pos.x) + SQ(sph->pos.y) + SQ(sph->pos.z) + + SQ(ray.orig.x) + SQ(ray.orig.y) + SQ(ray.orig.z) + + 2.0 * (-sph->pos.x * ray.orig.x - sph->pos.y * ray.orig.y - sph->pos.z * ray.orig.z) - SQ(sph->rad); + + if((d = SQ(b) - 4.0 * a * c) < 0.0) return 0; + + sqrt_d = sqrt(d); + t1 = (-b + sqrt_d) / (2.0 * a); + t2 = (-b - sqrt_d) / (2.0 * a); + + if((t1 < ERR_MARGIN && t2 < ERR_MARGIN) || (t1 > 1.0 && t2 > 1.0)) return 0; + + if(sp) { + if(t1 < ERR_MARGIN) t1 = t2; + if(t2 < ERR_MARGIN) t2 = t1; + sp->dist = t1 < t2 ? t1 : t2; + + sp->pos.x = ray.orig.x + ray.dir.x * sp->dist; + sp->pos.y = ray.orig.y + ray.dir.y * sp->dist; + sp->pos.z = ray.orig.z + ray.dir.z * sp->dist; + + sp->normal.x = (sp->pos.x - sph->pos.x) / sph->rad; + sp->normal.y = (sp->pos.y - sph->pos.y) / sph->rad; + sp->normal.z = (sp->pos.z - sph->pos.z) / sph->rad; + + sp->vref = reflect(ray.dir, sp->normal); + NORMALIZE(sp->vref); + } + return 1; +} + +/* Load the scene from an extremely simple scene description file */ +#define DELIM " \t\n" +void load_scene(FILE *fp) { + char line[256], *ptr, type; + + obj_list = malloc(sizeof(struct sphere)); + obj_list->next = 0; + + while((ptr = fgets(line, 256, fp))) { + int i; + struct vec3 pos, col; + double rad, spow, refl; + + while(*ptr == ' ' || *ptr == '\t') ptr++; + if(*ptr == '#' || *ptr == '\n') continue; + + if(!(ptr = strtok(line, DELIM))) continue; + type = *ptr; + + for(i=0; i<3; i++) { + if(!(ptr = strtok(0, DELIM))) break; + *((double*)&pos.x + i) = atof(ptr); + } + + if(type == 'l') { + lights[lnum++] = pos; + continue; + } + + if(!(ptr = strtok(0, DELIM))) continue; + rad = atof(ptr); + + for(i=0; i<3; i++) { + if(!(ptr = strtok(0, DELIM))) break; + *((double*)&col.x + i) = atof(ptr); + } + + if(type == 'c') { + cam.pos = pos; + cam.targ = col; + cam.fov = rad; + continue; + } + + if(!(ptr = strtok(0, DELIM))) continue; + spow = atof(ptr); + + if(!(ptr = strtok(0, DELIM))) continue; + refl = atof(ptr); + + if(type == 's') { + struct sphere *sph = malloc(sizeof *sph); + sph->next = obj_list->next; + obj_list->next = sph; + + sph->pos = pos; + sph->rad = rad; + sph->mat.col = col; + sph->mat.spow = spow; + sph->mat.refl = refl; + } else { + fprintf(stderr, "unknown type: %c\n", type); + } + } +} + + +/* provide a millisecond-resolution timer for each system */ +#if defined(unix) || defined(__unix__) +#include +#include +unsigned long get_msec(void) { + static struct timeval timeval, first_timeval; + + gettimeofday(&timeval, 0); + if(first_timeval.tv_sec == 0) { + first_timeval = timeval; + return 0; + } + return (timeval.tv_sec - first_timeval.tv_sec) * 1000 + (timeval.tv_usec - first_timeval.tv_usec) / 1000; +} +#elif defined(__WIN32__) || defined(WIN32) +#include +unsigned long get_msec(void) { + return GetTickCount(); +} +#else +#error "I don't know how to measure time on your platform" +#endif + +void thread_func(void *tdata, VirtProcr *VProc) { + int i; + procr_data *td = (procr_data*)tdata; + + SSR__receive_type_to(WORK_START, VProc); + + for(i=0; isl_count; i++) { + render_scanline(xres, yres, i + td->sl_start, td->pixels, rays_per_pixel); + } + + SSR__send_of_type_to(VProc, NULL, WORK_END, td->parentVP); + + SSR__dissipate_procr(VProc); +} diff -r 000000000000 -r 11a4bcadac2a scene --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scene Thu Sep 22 14:16:25 2011 +0200 @@ -0,0 +1,18 @@ +# spheres +# position radius color shininess reflectivity +s -1.5 -0.3 -1 0.7 1.0 0.2 0.05 50.0 0.3 +s 1.5 -0.4 0 0.6 0.1 0.85 1.0 50.0 0.4 + +# walls +s 0 -1000 2 999 0.1 0.2 0.6 80.0 0.5 + +# bouncing ball +s 0 0 2 1 0.0 0.0 0.0 60.0 0.7 + +# lights... +l -50 100 -50 +l 40 40 150 + +# camera (there can be only one!) +# position FOV target +c 0 6 -17 45 0 -1 0 diff -r 000000000000 -r 11a4bcadac2a sphfract --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sphfract Thu Sep 22 14:16:25 2011 +0200 @@ -0,0 +1,192 @@ +s 0 0 0 1.0 0.25 0.25 0.25 50.0 0.65 +s 1.4 0 0 0.4 0.25 0.25 0.25 50.0 0.65 +s 1.96 0 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 2.184 0 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.96 0.224 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.96 -0.224 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.96 0 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.96 0 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0.56 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 1.624 0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.176 0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0.784 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0.56 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0.56 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 -0.56 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 1.624 -0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.176 -0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 -0.784 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 -0.56 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 -0.56 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0 0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s 1.624 0 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.176 0 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0.224 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 -0.224 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0 0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0 -0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s 1.624 0 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.176 0 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0.224 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 -0.224 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 1.4 0 -0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0 0 0.4 0.25 0.25 0.25 50.0 0.65 +s -1.96 0 0 0.16 0.25 0.25 0.25 50.0 0.65 +s -2.184 0 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.96 0.224 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.96 -0.224 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.96 0 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.96 0 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0.56 0 0.16 0.25 0.25 0.25 50.0 0.65 +s -1.176 0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.624 0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0.784 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0.56 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0.56 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 -0.56 0 0.16 0.25 0.25 0.25 50.0 0.65 +s -1.176 -0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.624 -0.56 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 -0.784 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 -0.56 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 -0.56 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0 0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s -1.176 0 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.624 0 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0.224 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 -0.224 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0 0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0 -0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s -1.176 0 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.624 0 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0.224 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 -0.224 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -1.4 0 -0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.4 0 0.4 0.25 0.25 0.25 50.0 0.65 +s 0.56 1.4 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.784 1.4 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 1.624 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 1.176 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 1.4 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 1.4 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 1.4 0 0.16 0.25 0.25 0.25 50.0 0.65 +s -0.784 1.4 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 1.624 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 1.176 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 1.4 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 1.4 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.96 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 1.96 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 1.96 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 2.184 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.96 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.96 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.4 0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 1.4 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 1.4 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.624 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.176 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.4 0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.4 -0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 1.4 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 1.4 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.624 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.176 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 1.4 -0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.4 0 0.4 0.25 0.25 0.25 50.0 0.65 +s 0.56 -1.4 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.784 -1.4 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 -1.176 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 -1.624 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 -1.4 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 -1.4 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -1.4 0 0.16 0.25 0.25 0.25 50.0 0.65 +s -0.784 -1.4 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -1.176 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -1.624 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -1.4 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -1.4 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.96 0 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 -1.96 0 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 -1.96 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -2.184 0 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.96 0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.96 -0.224 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.4 0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 -1.4 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 -1.4 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.176 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.624 0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.4 0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.4 -0.56 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 -1.4 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 -1.4 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.176 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.624 -0.56 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -1.4 -0.784 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0 1.4 0.4 0.25 0.25 0.25 50.0 0.65 +s 0.56 0 1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.784 0 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 0.224 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 -0.224 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 0 1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 0 1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0 1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s -0.784 0 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0.224 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -0.224 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0 1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0 1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.56 1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 0.56 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 0.56 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.784 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.56 1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.56 1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.56 1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 -0.56 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 -0.56 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.784 1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.56 1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.56 1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0 1.96 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 0 1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 0 1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.224 1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.224 1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0 2.184 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0 -1.4 0.4 0.25 0.25 0.25 50.0 0.65 +s 0.56 0 -1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.784 0 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 0.224 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 -0.224 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 0 -1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s 0.56 0 -1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0 -1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s -0.784 0 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0.224 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 -0.224 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0 -1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.56 0 -1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.56 -1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 0.56 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 0.56 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.784 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.56 -1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.56 -1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.56 -1.4 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 -0.56 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 -0.56 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.784 -1.4 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.56 -1.176 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.56 -1.624 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0 -1.96 0.16 0.25 0.25 0.25 50.0 0.65 +s 0.224 0 -1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s -0.224 0 -1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0.224 -1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -0.224 -1.96 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 0 -2.184 0.064 0.25 0.25 0.25 50.0 0.65 +s 0 -10002.25 0 10000 0.2 0.35 0.5 80.0 0.4 +s 0 10100.00 0 10000 0.5 0.2 0.1 40.0 0.0 +l -50 68 -50 +l 40 40 150 +c -7 6 -12 45 0 -0.65 0