diff options
author | mwturvey <michael.w.turvey@intel.com> | 2017-03-16 10:52:13 -0700 |
---|---|---|
committer | mwturvey <michael.w.turvey@intel.com> | 2017-03-16 10:52:13 -0700 |
commit | ccaa625c6161e14f5c2281cc43134d1928094620 (patch) | |
tree | c339acbb982d1f2d67977be98a4ae7cac85f8057 | |
parent | d9c9ebe6de1e6f255d645dd6e641f2c288238bc2 (diff) | |
parent | 6daf2506fcfbfcd26d63a8bddba319d67ecc33e5 (diff) | |
download | libsurvive-ccaa625c6161e14f5c2281cc43134d1928094620.tar.gz libsurvive-ccaa625c6161e14f5c2281cc43134d1928094620.tar.bz2 |
Merge branch 'master' into WinSupport2
# Conflicts:
# src/survive_vive.c
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | include/libsurvive/survive.h | 5 | ||||
-rwxr-xr-x | src/survive.c | 8 | ||||
-rwxr-xr-x | src/survive_cal.c | 2 | ||||
-rw-r--r-- | src/survive_data.c | 47 | ||||
-rwxr-xr-x | src/survive_vive.c | 62 | ||||
-rw-r--r-- | useful_files/lib_survive_logo3.svg | 236 |
8 files changed, 310 insertions, 73 deletions
@@ -5,3 +5,14 @@ windows/calibrate.exe windows/calinfo/1.json.gz windows/calibrate.def windows/calinfo/3.json.gz +windows/calinfo/WM1_points.csv +windows/calinfo/HMD_normals.csv +windows/calinfo/WM0_points.csv +windows/calinfo/WM1_normals.csv +windows/calinfo/HMD_points.csv +windows/calinfo/WM0_normals.csv +windows/calinfo/2.json.gz +windows/calinfo - Copy/WM1_points.csv +windows/udev[USB_DEV_LIGHTHOUSE] +windows/udev[USB_DEV_LIGHTHOUSE] +windows/config.json @@ -2,15 +2,25 @@ all : lib data_recorder test calibrate calibrate_client CC:=gcc -CFLAGS:=-Iinclude/libsurvive -I. -fPIC -g -O0 -Iredist -flto -DUSE_DOUBLE -std=gnu99 -rdynamic +CFLAGS:=-Iinclude/libsurvive -I. -fPIC -g -O3 -Iredist -flto -DUSE_DOUBLE -std=gnu99 -rdynamic LDFLAGS:=-lpthread -lusb-1.0 -lz -lX11 -lm -flto -g POSERS:=src/poser_dummy.o src/poser_daveortho.o src/poser_charlesslow.o REDISTS:=redist/json_helpers.o redist/linmath.o redist/jsmn.o LIBSURVIVE_CORE:=src/survive.o src/survive_usb.o src/survive_data.o src/survive_process.o src/ootx_decoder.o src/survive_driverman.o src/survive_vive.o src/survive_config.o src/survive_cal.o +LIBSURVIVE_CORE:=$(LIBSURVIVE_CORE) LIBSURVIVE_O:=$(POSERS) $(REDISTS) $(LIBSURVIVE_CORE) LIBSURVIVE_C:=$(LIBSURVIVE_O:.o=.c) +#Useful Preprocessor Directives: +# -DUSE_DOUBLE = use double instead of float for most operations. +# -DNOZLIB = use puff.c +# -DTCC = various things needed for TCC. +# -DWINDOWS -DWIN32 = Building for Windows +# -DHIDAPI = Build vive driver to use USBHID instead of interrupt/control messages. +# -DRUNTIME_SYMNUM = Don't assume __attribute__((constructor)) works. Instead comb for anything starting with REGISTER. + + GRAPHICS_LOFI:=redist/DrawFunctions.o redist/XDriver.o # unused: redist/crc32.c diff --git a/include/libsurvive/survive.h b/include/libsurvive/survive.h index eb30252..e3e167a 100644 --- a/include/libsurvive/survive.h +++ b/include/libsurvive/survive.h @@ -50,8 +50,8 @@ struct SurviveObject int8_t oldcode; int8_t sync_set_number; //0 = master, 1 = slave, -1 = fault. int8_t did_handle_ootx; //If unset, will send lightcap data for sync pulses next time a sensor is hit. - uint32_t last_time[NUM_LIGHTHOUSES]; - uint32_t last_length[NUM_LIGHTHOUSES]; + uint32_t last_sync_time[NUM_LIGHTHOUSES]; + uint32_t last_sync_length[NUM_LIGHTHOUSES]; uint32_t recent_sync_time; uint32_t last_lighttime; //May be a 24- or 32- bit number depending on what device. @@ -161,7 +161,6 @@ void survive_add_driver( SurviveContext * ctx, void * payload, DeviceDriverCb po typedef struct { uint8_t sensor_id; - uint8_t type; //Mostly unused. Set to 255 to ignore it. uint16_t length; uint32_t timestamp; } diff --git a/src/survive.c b/src/survive.c index 9d0ef01..81c45c3 100755 --- a/src/survive.c +++ b/src/survive.c @@ -66,7 +66,8 @@ SurviveContext * survive_init( int headless ) ctx->lh_config = malloc( sizeof(config_group) * NUM_LIGHTHOUSES); init_config_group(ctx->global_config_values,10); - init_config_group(ctx->lh_config,10); + init_config_group(&ctx->lh_config[0],10); + init_config_group(&ctx->lh_config[1],10); config_read(ctx, "config.json"); @@ -263,9 +264,10 @@ struct SurviveObject * survive_get_so_by_name( struct SurviveContext * ctx, cons int survive_simple_inflate( struct SurviveContext * ctx, const char * input, int inlen, char * output, int outlen ) { + //Tricky: we actually get 2 bytes of data on the front. I don't know what it's for. 0x78 0x9c - puff doesn't deal with it well. unsigned long ol = outlen; - unsigned long il = inlen; - int ret = puff( output, &ol, input, &il ); + unsigned long il = inlen-2; + int ret = puff( output, &ol, input+2, &il ); if( ret == 0 ) return ol; else diff --git a/src/survive_cal.c b/src/survive_cal.c index 0ea9337..985ab24 100755 --- a/src/survive_cal.c +++ b/src/survive_cal.c @@ -267,7 +267,7 @@ void survive_cal_angle( struct SurviveObject * so, int sensor_id, int acode, uin } if( sensors_visible < MIN_SENSORS_VISIBLE_PER_LH_FOR_CAL ) { - printf( "Dev %d, LH %d not enough visible points found.\n", i, j ); + //printf( "Dev %d, LH %d not enough visible points found.\n", i, j ); cd->found_common = 0; return; } diff --git a/src/survive_data.c b/src/survive_data.c index f87c69d..60849e2 100644 --- a/src/survive_data.c +++ b/src/survive_data.c @@ -25,10 +25,10 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) //The sync pulse finder is taking Charles's old disambiguator code and mixing it with a more linear //version of Julian Picht's disambiguator, available in 488c5e9. Removed afterwards into this //unified driver. - int ssn = so->sync_set_number; + int ssn = so->sync_set_number; //lighthouse number if( ssn < 0 ) ssn = 0; - int last_sync_time = so->last_time [ssn]; - int last_sync_length = so->last_length[ssn]; + int last_sync_time = so->last_sync_time [ssn]; + int last_sync_length = so->last_sync_length[ssn]; int32_t delta = le->timestamp - last_sync_time; //Handle time wrapping (be sure to be int32) if( delta < -so->pulsedist_max_ticks || delta > so->pulsedist_max_ticks ) @@ -36,6 +36,7 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) //Reset pulse, etc. so->sync_set_number = -1; delta = so->pulsedist_max_ticks; +// return; //if we don't know what lighthouse this is we don't care to do much else } @@ -43,6 +44,8 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) { int is_new_pulse = delta > so->pulselength_min_sync /*1500*/ + last_sync_length; + printf("m sync %d %d %d %d\n", le->sensor_id, so->last_sync_time[ssn], le->timestamp, delta); + so->did_handle_ootx = 0; if( is_new_pulse ) @@ -52,8 +55,8 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) if( is_master_sync_pulse ) { ssn = so->sync_set_number = 0; - so->last_time[ssn] = le->timestamp; - so->last_length[ssn] = le->length; + so->last_sync_time[ssn] = le->timestamp; + so->last_sync_length[ssn] = le->length; } else if( so->sync_set_number == -1 ) { @@ -69,8 +72,8 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) } else { - so->last_time[ssn] = le->timestamp; - so->last_length[ssn] = le->length; + so->last_sync_time[ssn] = le->timestamp; + so->last_sync_length[ssn] = le->length; } } } @@ -79,10 +82,10 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) //Find the longest pulse. if( le->length > last_sync_length ) { - if( so->last_time[ssn] > le->timestamp ) + if( so->last_sync_time[ssn] > le->timestamp ) { - so->last_time[ssn] = le->timestamp; - so->last_length[ssn] = le->length; + so->last_sync_time[ssn] = le->timestamp; + so->last_sync_length[ssn] = le->length; } } } @@ -93,8 +96,8 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) //See if this is a valid actual pulse. else if( le->length < so->pulse_max_for_sweep && delta > so->pulse_in_clear_time && ssn >= 0 ) { - int32_t dl = so->last_time[0]; - int32_t tpco = so->last_length[0]; + int32_t dl = so->last_sync_time[0]; + int32_t tpco = so->last_sync_length[0]; #if NUM_LIGHTHOUSES != 2 @@ -109,8 +112,8 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) int32_t acode_array[2] = { - (so->last_length[0]+main_divisor+50)/(main_divisor*2), //+50 adds a small offset and seems to help always get it right. - (so->last_length[1]+main_divisor+50)/(main_divisor*2), //Check the +50 in the future to see how well this works on a variety of hardware. + (so->last_sync_length[0]+main_divisor+50)/(main_divisor*2), //+50 adds a small offset and seems to help always get it right. + (so->last_sync_length[1]+main_divisor+50)/(main_divisor*2), //Check the +50 in the future to see how well this works on a variety of hardware. }; //XXX: TODO: Capture error count here. @@ -125,11 +128,13 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) if( !so->did_handle_ootx ) { - int32_t delta1 = so->last_time[0] - so->recent_sync_time; - int32_t delta2 = so->last_time[1] - so->last_time[0]; - ctx->lightproc( so, -1, acode_array[0], delta1, so->last_time[0], so->last_length[0] ); - ctx->lightproc( so, -2, acode_array[1], delta2, so->last_time[1], so->last_length[1] ); - so->recent_sync_time = so->last_time[1]; + int32_t delta1 = so->last_sync_time[0] - so->recent_sync_time; + int32_t delta2 = so->last_sync_time[1] - so->last_sync_time[0]; + + ctx->lightproc( so, -1, acode_array[0], delta1, so->last_sync_time[0], so->last_sync_length[0] ); + ctx->lightproc( so, -2, acode_array[1], delta2, so->last_sync_time[1], so->last_sync_length[1] ); + + so->recent_sync_time = so->last_sync_time[1]; //Throw out everything if our sync pulses look like they're bad. @@ -161,8 +166,8 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le ) //SV_INFO( "Warning: got a slave marker but only got a master sync." ); //This happens too frequently. Consider further examination. } - dl = so->last_time[1]; - tpco = so->last_length[1]; + dl = so->last_sync_time[1]; + tpco = so->last_sync_length[1]; } int32_t offset_from = le->timestamp - dl + le->length/2; diff --git a/src/survive_vive.c b/src/survive_vive.c index 116d18b..728c3c9 100755 --- a/src/survive_vive.c +++ b/src/survive_vive.c @@ -17,10 +17,10 @@ #include <errno.h> #include <string.h> #include <sys/stat.h> +#include <os_generic.h> #include <malloc.h> // for alloca #ifdef HIDAPI -#include <os_generic.h> #if defined(WINDOWS) || defined(WIN32) || defined (_WIN32) #include <windows.h> #undef WCHAR_MAX @@ -60,9 +60,13 @@ const char * devnames[] = { #define USB_DEV_WATCHMAN1 2 #define USB_DEV_WATCHMAN2 3 #define USB_DEV_TRACKER0 4 + +#ifdef HIDAPI #define USB_DEV_LIGHTHOUSEB 5 #define MAX_USB_DEVS 6 - +#else +#define MAX_USB_DEVS 5 +#endif #define USB_IF_HMD 0 #define USB_IF_LIGHTHOUSE 1 @@ -401,6 +405,7 @@ int survive_usb_init( struct SurviveViveData * sv, struct SurviveObject * hmd, s if( d == 0 ) { + printf( "!!%p %d %04x %04x %d\n", devnames[i], i, vid, pid, which ); SV_INFO( "Did not find device %s (%04x:%04x.%d)", devnames[i], vid, pid, which ); sv->udev[i] = 0; continue; @@ -478,36 +483,23 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c if( turnon ) { - //Magic from vl_magic.h, originally copywritten under LGPL. - // * Copyright (C) 2013 Fredrik Hultin - // * Copyright (C) 2013 Jakob Bornecrantz -#if 0 - static uint8_t vive_magic_power_on[] = { - 0x04, 0x78, 0x29, 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, - 0xa8, 0x0d, 0x76, 0x00, 0x40, 0xfc, 0x01, 0x05, 0xfa, 0xec, 0xd1, 0x6d, 0x00, - 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0d, 0x76, 0x00, 0x68, 0xfc, - 0x01, 0x05, 0x2c, 0xb0, 0x2e, 0x65, 0x7a, 0x0d, 0x76, 0x00, 0x68, 0x54, 0x72, - 0x00, 0x18, 0x54, 0x72, 0x00, 0x00, 0x6a, 0x72, 0x00, 0x00, 0x00, 0x00, - }; -#else //From actual steam. - static uint8_t vive_magic_power_on[64] = { 0x04, 0x78, 0x29, 0x38, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -#endif if (sv->udev[USB_DEV_HMD]) { + static uint8_t vive_magic_power_on[64] = { 0x04, 0x78, 0x29, 0x38 }; r = update_feature_report( sv->udev[USB_DEV_HMD], 0, vive_magic_power_on, sizeof( vive_magic_power_on ) ); if( r != sizeof( vive_magic_power_on ) ) return 5; } if (sv->udev[USB_DEV_LIGHTHOUSE]) { - static uint8_t vive_magic_enable_lighthouse[64] = { 0x04 }; //[64] wat? Why did that fix it? - r = update_feature_report( sv->udev[USB_DEV_LIGHTHOUSE], 0, vive_magic_enable_lighthouse, sizeof( vive_magic_enable_lighthouse ) ); ///XXX TODO: Shouldn't this be LIGHTHOUSEB for hidapi? + static uint8_t vive_magic_enable_lighthouse[5] = { 0x04 }; + r = update_feature_report( sv->udev[USB_DEV_LIGHTHOUSE], 0, vive_magic_enable_lighthouse, sizeof( vive_magic_enable_lighthouse ) ); if( r != sizeof( vive_magic_enable_lighthouse ) ) return 5; + + static uint8_t vive_magic_enable_lighthouse2[5] = { 0x07, 0x02 }; //Switch to 0x25 mode (able to get more light updates) + r = update_feature_report( sv->udev[USB_DEV_LIGHTHOUSE], 0, vive_magic_enable_lighthouse2, sizeof( vive_magic_enable_lighthouse2 ) ); + if( r != sizeof( vive_magic_enable_lighthouse2 ) ) return 5; } #if 0 @@ -619,16 +611,7 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno, int k; - uint8_t cfgbuff_send[64] = { - 0xff, 0x83, 0x00, 0xb6, 0x5b, 0xb0, 0x78, 0x69, - 0x0f, 0xf8, 0x78, 0x69, 0x0f, 0xa0, 0xf3, 0x18, - 0x00, 0xe8, 0xf2, 0x18, 0x00, 0x27, 0x44, 0x5a, - 0x0f, 0xf8, 0x78, 0x69, 0x0f, 0xf0, 0x77, 0x69, - 0x0f, 0xf0, 0x77, 0x69, 0x0f, 0x50, 0xca, 0x45, - 0x77, 0xa0, 0xf3, 0x18, 0x00, 0xf8, 0x78, 0x69, - 0x0f, 0x00, 0x00, 0xa0, 0x0f, 0xa0, 0x9b, 0x0a, - 0x01, 0x00, 0x00, 0x35, 0x00, 0x34, 0x02, 0x00 - }; + uint8_t cfgbuff_send[64] = { 0xff, 0x83 }; #ifdef HIDAPI //XXX TODO WRITEME @@ -709,7 +692,7 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno, int len = survive_simple_inflate( ctx, compressed_data, count, uncompressed_data, sizeof(uncompressed_data)-1 ); if( len <= 0 ) { - SV_INFO( "Error: data for config descriptor %d:%d is bad.", devno, iface ); + SV_INFO( "Error: data for config descriptor %d:%d is bad. (%d)", devno, iface, len ); return -5; } @@ -924,7 +907,6 @@ static void handle_watchman( struct SurviveObject * w, uint8_t * readdata ) //Use insertion sort, since we should most of the time, be in order. LightcapElement * le = &les[lese++]; le->sensor_id = led; - le->type = 0xfe; if( (uint32_t)(endtime - starttime) > 65535 ) { fault = 6; goto end; } //Length of pulse dumb. le->length = endtime - starttime; @@ -1078,24 +1060,16 @@ void survive_data_cb( SurviveUSBInterface * si ) case USB_IF_LIGHTCAP: { int i; - #ifdef HIDAPI - for( i = 0; i < 7; i++ ) + for( i = 0; i < 9; i++ ) { LightcapElement le; le.sensor_id = POP1; - le.type = 0xfe; le.length = POP2; le.timestamp = POP4; if( le.sensor_id == 0xff ) break; handle_lightcap( obj, &le ); } - #else - for( i = 0; i < 7; i++ ) - { - handle_lightcap( obj, (LightcapElement*)&readdata[i*8] ); - } break; - #endif } } } @@ -1226,7 +1200,7 @@ printf( "Loading config: %d\n", len ); return 1; } - char fname[20]; + char fname[64]; sprintf( fname, "calinfo/%s_points.csv", so->codename ); FILE * f = fopen( fname, "w" ); diff --git a/useful_files/lib_survive_logo3.svg b/useful_files/lib_survive_logo3.svg new file mode 100644 index 0000000..a6d003e --- /dev/null +++ b/useful_files/lib_survive_logo3.svg @@ -0,0 +1,236 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="238.93333" + height="238.93333" + viewBox="0 0 210 210" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="lib_survive_logo2(1).svg" + inkscape:export-filename="lib_survive_logo_sm.png" + inkscape:export-xdpi="13.499999" + inkscape:export-ydpi="13.499999"> + <defs + id="defs4"> + <linearGradient + inkscape:collect="always" + id="linearGradient4339"> + <stop + style="stop-color:#ff0000;stop-opacity:1;" + offset="0" + id="stop4341" /> + <stop + style="stop-color:#ff0000;stop-opacity:0;" + offset="1" + id="stop4343" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="304.07246 : 374.52182 : 1" + inkscape:vp_y="0 : 999.99998 : 0" + inkscape:vp_z="97.924826 : 490.48422 : 1" + inkscape:persp3d-origin="282.04724 : 396.50169 : 1" + id="perspective4191" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4339" + id="linearGradient4345" + x1="205.13866" + y1="791.02484" + x2="130.30968" + y2="856.89771" + gradientUnits="userSpaceOnUse" /> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath3493"> + <rect + style="fill:#666666;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3495" + width="146.20735" + height="147.45538" + x="115.33373" + y="738.79926" + ry="6.3883986" /> + </clipPath> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="133.52724" + inkscape:cy="93.936777" + inkscape:document-units="px" + inkscape:current-layer="g4414" + showgrid="false" + fit-margin-left="5" + fit-margin-top="5" + fit-margin-right="5" + fit-margin-bottom="5" + units="px" + inkscape:window-width="1920" + inkscape:window-height="905" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:snap-global="false" + showguides="false" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(5.0000003,-847.36221)"> + <g + id="g4433" + transform="translate(-60.902386,119.96554)"> + <rect + ry="8.6648569" + y="732.39667" + x="60.902386" + height="200" + width="200" + id="rect4412" + style="fill:#666666;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <g + id="g4414" + transform="matrix(1.3679202,0,0,1.3563425,-96.864952,-269.66815)" + clip-path="url(#clipPath3493)"> + <g + id="g4364" + transform="matrix(1.2848586,0,0,1.2848586,-47.09026,-225.40973)"> + <g + transform="matrix(0.70521296,0.07124105,0,0.70521296,22.935416,485.79994)" + id="g4326"> + <rect + style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35" + id="rect4277" + width="48.565189" + height="50.670372" + x="242.52609" + y="315.56894" + ry="12.130823" + transform="matrix(0.97464031,0.22377727,0,1,0,0)" /> + <rect + style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35" + id="rect4277-7" + width="48.565189" + height="50.670372" + x="262.80905" + y="292.12814" + ry="12.130823" + transform="matrix(0.97464031,0.22377727,0,1,0,0)" /> + <rect + style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35" + id="rect4294" + width="29.069714" + height="15.917919" + x="-73.198318" + y="437.03619" + ry="0" + transform="matrix(0.7329244,-0.68031009,0.66822927,0.7439554,0,0)" /> + <rect + style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35" + id="rect4294-3" + width="27.907652" + height="15.532421" + x="-54.329411" + y="487.7229" + ry="0" + transform="matrix(0.70821685,-0.70599496,0.63527567,0.77228545,0,0)" /> + <rect + style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.37930703;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4277-78" + width="47.474747" + height="49.333805" + x="243.31599" + y="316.28986" + ry="11.810841" + transform="matrix(0.97494341,0.22245301,0,1,0,0)" /> + </g> + <path + sodipodi:nodetypes="czcc" + inkscape:connector-curvature="0" + id="path4337" + d="m 84.852815,819.52204 c 0,0 111.599975,-40.64046 121.766705,-32.01632 10.16673,8.62414 -17.97354,123.43513 -17.97354,123.43513 z" + style="fill:url(#linearGradient4345);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> + </g> + <g + id="g4377-2" + style="fill:none;stroke:#00ff00;stroke-width:2.54694843;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + transform="matrix(1.6856173,0,0,1.6856173,-39.282189,-597.66653)"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4347-3" + d="m 106.31855,858.4553 15,0" + style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4347-5-21" + d="m 113.81855,850.73652 0,15" + style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4377-2-3" + style="fill:none;stroke:#00ff00;stroke-width:2.54694843;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + transform="matrix(1.6856173,0,0,1.6856173,-15.550497,-631.83198)"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4347-3-6" + d="m 106.31855,858.4553 15,0" + style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4347-5-21-7" + d="m 113.81855,850.73652 0,15" + style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + id="g4377-2-5" + style="fill:none;stroke:#00ff00;stroke-width:2.54694843;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + transform="matrix(1.6856173,0,0,1.6856173,8.7357605,-597.93633)"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4347-3-3" + d="m 106.31855,858.4553 15,0" + style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4347-5-21-5" + d="m 113.81855,850.73652 0,15" + style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + </g> + </g> + </g> +</svg> |