diff --git a/AUTHORS b/AUTHORS.txt similarity index 69% rename from AUTHORS rename to AUTHORS.txt index 3b2f8d59..7ae1f770 100644 --- a/AUTHORS +++ b/AUTHORS.txt @@ -1,10 +1,8 @@ -Authors: - -Primary maintainer: -Jason Huggins - -Contributors: -Chris Williams <> +Appium +Chris G. Williams Erik Kastner Jason Fox -Chris G. Williams +Jason Huggins +Michal Laskowski <> +Orange +Tapster \ No newline at end of file diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt new file mode 100644 index 00000000..77745ad1 --- /dev/null +++ b/CONTRIBUTORS.txt @@ -0,0 +1,10 @@ +Chris Williams <> +Chris G. Williams +Dan Cuellar +Erik Kastner +Jason Fox +Jason Huggins +Jason Huggins +Michal Laskowski <> +Pierre-Yves Lapersonne +Pierre-Yves Lapersonne \ No newline at end of file diff --git a/LICENSE b/LICENSE index c5c83c05..53d46bec 100644 --- a/LICENSE +++ b/LICENSE @@ -1,24 +1,52 @@ -Copyright (c) 2011-2019, Tapster Committers -All rights reserved. +Copyright (c) 2018 Orange SA +This project is under dual license BSD-2-Clause OR MIT -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + + +The BSD 2-Cluse license + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; #OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is a 2-Clause BSD License. You can find it at https://opensource.org/licenses/BSD-2-Clause] + + + + +The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 00ec1add..a5a61f80 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,57 @@ -## Tapster - Mobile Automation Robot +# Important notice +This GitHub repository is a fork of the original [Jason Huggin's tapsterbot](https://github.com/hugs/tapsterbot) project. +It contains also improvements (direct or not) from [Dan Cuellar's fork](https://github.com/penguinho/tapsterbot). +Some parts of this project have been implemented or reviewed internaly at Orange in 2018 and were expected to be sumbmitted in open source. +This project has been finaly released so as to not prevent community to use it, and because forks on personal spaces was not appropriate. +**You should not considere this proejct as active nor maintained since 2018**. -![Tapsterbot](http://hugs.github.io/img/tapster-2-desk.jpg) +# Tapster - Mobile Automation Robot -## Dependencies -- Node.js -- One Tapster robot +## Why using such bot? +- Bring fun in your office +- Bring automation for your tests +- Extend your software-based instrumented tests (using UI Automator, Espresso, Kakao, Appium or whatever) with hardware-based tests +- Improve quality of your products +- Deal with secured elements on which no software can click +- Be as close as possible of the ideal use case (users use their fingers to click :3) +- Get a new tool for software development and mobile app tests: robots! -## Getting Started +## Projects files -1. Download and install the Arduino Client: [http://arduino.cc/en/Guide/HomePage](http://arduino.cc/en/Guide/HomePage) -2. Follow the setup procedure, and use the "blink" test script to verify your Arduino is working. -3. From the Arduino IDE upload the "Firmata" script: File -> Open -> Examples > Firmata > StandardFirmata -4. Install the dependencies: `cd software; npm install` -5. Start'er up: `node src/bot.js` -6. Start moving: `go(0,0,-140)` +### Clients +Contains Python and *Roboto Framwork* client to send request to *Taspter* bot + +### Calibration +Contains Android and iOS app to claibrate the robot + +### Hardware +This part contains all the assets to build the Tapster robots. As far as we remember, we did not change them. +The model we worked on where *Taspter 2*. + +### Licenses +Contains some license files for information. + +### Softwares +Contains source code to calibrate the bot, receive commands and process them. + +## How it works +1. Calibrate the robot: you will have to run a claibration app from *Appium*, run the *calibrate* script of the robot and wait for capabilities after the calibration ; +2. The calibration process is quite simple: the robot tap on the screen, the app displays coordinates and *Appium* get it and process ; +3. The robot then must be used with the capabilities ; +4. It exposes a REST HTTP server which receives requests you can send with *Python* code or *Robot Framework*. +5. The brian of the robot is an *Arduino* board you must flash *Firmata* on +6. The project is quite cool and only few iPhones models were manage with conversion tables between keypads and coordinates + +## Some references and things to see +- http://www.tapster.io (the creator of the Tapster bots) +- https://twitter.com/tapsterbot +- https://www.tindie.com/products/hugs/tapster/ +- https://github.com/hugs/tapsterbot +- https://github.com/tapsterbot/tapsterbot +- https://github.com/appium/appium +- https://github.com/appium/robots +- https://github.com/penguinho/tapsterbot +- https://github.com/jackskalitzky/tapsterbot +- https://github.com/pylapp/tapsterbot +- https://speakerdeck.com/pylapp/why-not-tapster \ No newline at end of file diff --git a/calibration/README.md b/calibration/README.md new file mode 100644 index 00000000..a62389a7 --- /dev/null +++ b/calibration/README.md @@ -0,0 +1,6 @@ +# calibration folder + +Here are binary files and sources for Android and iOS apps to use so as to calibrate the robot. +Desired capabilities to use for the calibration workflow are stored in a dedicated folder here. +The JavaScript Node.js scripts to use to trigger the calibration workflow are in the _software/src_ folder. +You can find more details about this workflow in the _doc/calibration-workflow.md_ file. diff --git a/calibration/android/.idea/android.iml b/calibration/android/.idea/android.iml new file mode 100644 index 00000000..d6ebd480 --- /dev/null +++ b/calibration/android/.idea/android.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/calibration/android/.idea/modules.xml b/calibration/android/.idea/modules.xml new file mode 100644 index 00000000..9dddca50 --- /dev/null +++ b/calibration/android/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/calibration/android/.idea/workspace.xml b/calibration/android/.idea/workspace.xml new file mode 100644 index 00000000..8cd17c5d --- /dev/null +++ b/calibration/android/.idea/workspace.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1540547598819 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/.gitignore b/calibration/android/calibration-android/.gitignore new file mode 100644 index 00000000..39fb081a --- /dev/null +++ b/calibration/android/calibration-android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/calibration/android/calibration-android/.idea/.gitignore b/calibration/android/calibration-android/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/calibration/android/calibration-android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/calibration/android/calibration-android/.idea/caches/build_file_checksums.ser b/calibration/android/calibration-android/.idea/caches/build_file_checksums.ser new file mode 100644 index 00000000..61d58eed Binary files /dev/null and b/calibration/android/calibration-android/.idea/caches/build_file_checksums.ser differ diff --git a/calibration/android/calibration-android/.idea/codeStyles/Project.xml b/calibration/android/calibration-android/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..30aa626c --- /dev/null +++ b/calibration/android/calibration-android/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/.idea/gradle.xml b/calibration/android/calibration-android/.idea/gradle.xml new file mode 100644 index 00000000..cb865f69 --- /dev/null +++ b/calibration/android/calibration-android/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/.idea/misc.xml b/calibration/android/calibration-android/.idea/misc.xml new file mode 100644 index 00000000..dd0bc613 --- /dev/null +++ b/calibration/android/calibration-android/.idea/misc.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/.idea/other.xml b/calibration/android/calibration-android/.idea/other.xml new file mode 100644 index 00000000..49481ad4 --- /dev/null +++ b/calibration/android/calibration-android/.idea/other.xml @@ -0,0 +1,329 @@ + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/.idea/vcs.xml b/calibration/android/calibration-android/.idea/vcs.xml new file mode 100644 index 00000000..c2365ab1 --- /dev/null +++ b/calibration/android/calibration-android/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/app/.gitignore b/calibration/android/calibration-android/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/calibration/android/calibration-android/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/calibration/android/calibration-android/app/build.gradle b/calibration/android/calibration-android/app/build.gradle new file mode 100644 index 00000000..11857215 --- /dev/null +++ b/calibration/android/calibration-android/app/build.gradle @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2018 Orange SA +// SPDX-License-Identifier: BSD-2-Clause OR MIT + +//noinspection GradleCompatible +apply plugin: 'com.android.application' + +android { + + compileSdkVersion 26 + buildToolsVersion "26.0.1" + + defaultConfig { + applicationId "orange.iva.toolfactory.tapster.calibration.android" + minSdkVersion 15 + targetSdkVersion 26 + versionCode 1 + versionName "1.0.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + + compile fileTree(include: ['*.jar'], dir: 'libs') + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + + compile 'com.android.support:appcompat-v7:26.0.0-alpha1' + compile 'com.android.support.constraint:constraint-layout:1.0.2' + +} diff --git a/calibration/android/calibration-android/app/proguard-rules.pro b/calibration/android/calibration-android/app/proguard-rules.pro new file mode 100644 index 00000000..bbf1c15c --- /dev/null +++ b/calibration/android/calibration-android/app/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/tapster/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/calibration/android/calibration-android/app/src/main/AndroidManifest.xml b/calibration/android/calibration-android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8b3ced4f --- /dev/null +++ b/calibration/android/calibration-android/app/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/app/src/main/java/orange/iva/toolfactory/tapster/calibration/android/MainActivity.java b/calibration/android/calibration-android/app/src/main/java/orange/iva/toolfactory/tapster/calibration/android/MainActivity.java new file mode 100644 index 00000000..ac223c16 --- /dev/null +++ b/calibration/android/calibration-android/app/src/main/java/orange/iva/toolfactory/tapster/calibration/android/MainActivity.java @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: 2018 Orange SA +// SPDX-License-Identifier: BSD-2-Clause OR MIT + +package orange.iva.toolfactory.tapster.calibration.android; + +import android.graphics.Point; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.view.Display; +import android.view.MotionEvent; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.FrameLayout.LayoutParams; + +/** + * The main screen of the app. + * Will display the 2D coordinates of each contact point in the layout. + * + * @version 1.0.0 + * @since 23/10/2017 + */ +public class MainActivity extends AppCompatActivity { + + + /** + * The width of the screen + */ + private int mScreenWidth; + + /** + * The heigfht of the screen + */ + private int mScreenHeight; + + + /** + * Triggered when the activity will be created + * @param savedInstanceState - Maye be null + */ + @Override + protected void onCreate( Bundle savedInstanceState ){ + + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + + // Get dimensions of screen + Display display = getWindowManager().getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + mScreenWidth = size.x; + mScreenHeight = size.y; + + // Define the layout wichi will coontain the labels + RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout); + LayoutParams params = new LayoutParams(mScreenWidth, mScreenHeight); + layout.setLayoutParams(params); + + // Without aciton bar, title is hidden, and the bot can click in a higher area + if( getSupportActionBar() != null ){ + ActionBar actionBar = getSupportActionBar(); + actionBar.hide(); + } + + } + + /** + * Method used when the user (or the bot) touches the screen. + * A label is displayed with the 2D coordinates of the contact point. + * + * @param event - The touch event, cannot be null + * @return boolean - Always true + */ + @Override + public boolean onTouchEvent( MotionEvent event ){ + + // The layout + RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout); + + // The number of contact points + int pointerCount = event.getPointerCount(); + + layout.removeAllViews(); + + // When the last finger is up: clean the layout + if ( event.getAction() == MotionEvent.ACTION_UP ){ + + layout.removeAllViews(); + + // Displays the contact coordinates + } else { + + for ( int i = 0; i < pointerCount; i++ ){ + + // FIXME Seems to be the (X,Y) coordinate adjusted to the parent view + TextView coordinates = new TextView(this); + int x = (int) event.getX(i); + int y = (int) event.getY(i); + coordinates.setText("("+x+", "+y+")"); + coordinates.setTextSize(30); + + final float THRESHOLD_BORDER = 0.25f; + final float DISPLAY_RATIO_X = 0.60f; + final float DISPLAY_RATIO_Y = 0.90f; + + // If the contact point is too close of borders, displays the label at the opposite to keep it fully visible + + // Case #1: Here point placed too close of right border + if ( x >= mScreenWidth - mScreenWidth * THRESHOLD_BORDER ){ + coordinates.setX(mScreenWidth * DISPLAY_RATIO_X); + coordinates.setY(y); + // Case #2: Here point placed too close of bottom border + } else if ( y >= mScreenHeight - mScreenHeight * THRESHOLD_BORDER ){ + coordinates.setX(x); + coordinates.setY(mScreenHeight * DISPLAY_RATIO_Y); + } else { + coordinates.setX(x); + coordinates.setY(y); + } + + layout.addView(coordinates); + + } + + } // End of else of if ( event.getAction() == MotionEvent.ACTION_UP ) + + return true; + + } + +} diff --git a/calibration/android/calibration-android/app/src/main/res/layout/activity_main.xml b/calibration/android/calibration-android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..ff7923fa --- /dev/null +++ b/calibration/android/calibration-android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/calibration/android/calibration-android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/calibration/android/calibration-android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..81e22499 Binary files /dev/null and b/calibration/android/calibration-android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/calibration/android/calibration-android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/calibration/android/calibration-android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..89287047 Binary files /dev/null and b/calibration/android/calibration-android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/calibration/android/calibration-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/calibration/android/calibration-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..2c20cd32 Binary files /dev/null and b/calibration/android/calibration-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/calibration/android/calibration-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/calibration/android/calibration-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..814ee624 Binary files /dev/null and b/calibration/android/calibration-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/calibration/android/calibration-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/calibration/android/calibration-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..22a60d1c Binary files /dev/null and b/calibration/android/calibration-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/calibration/android/calibration-android/app/src/main/res/values/colors.xml b/calibration/android/calibration-android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..07ca4a90 --- /dev/null +++ b/calibration/android/calibration-android/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #607D8B + #000000 + #03A9F4 + diff --git a/calibration/android/calibration-android/app/src/main/res/values/strings.xml b/calibration/android/calibration-android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..0fb30093 --- /dev/null +++ b/calibration/android/calibration-android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + RobotCalibration + diff --git a/calibration/android/calibration-android/app/src/main/res/values/styles.xml b/calibration/android/calibration-android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..266ed891 --- /dev/null +++ b/calibration/android/calibration-android/app/src/main/res/values/styles.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/calibration/android/calibration-android/build.gradle b/calibration/android/calibration-android/build.gradle new file mode 100644 index 00000000..d632b167 --- /dev/null +++ b/calibration/android/calibration-android/build.gradle @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2018 Orange SA +// SPDX-License-Identifier: BSD-2-Clause OR MIT + +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + google() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/calibration/android/calibration-android/gradle.properties b/calibration/android/calibration-android/gradle.properties new file mode 100644 index 00000000..aac7c9b4 --- /dev/null +++ b/calibration/android/calibration-android/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/calibration/android/calibration-android/gradle/wrapper/gradle-wrapper.jar b/calibration/android/calibration-android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..13372aef Binary files /dev/null and b/calibration/android/calibration-android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/calibration/android/calibration-android/gradle/wrapper/gradle-wrapper.properties b/calibration/android/calibration-android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..f5517c35 --- /dev/null +++ b/calibration/android/calibration-android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Oct 28 14:38:27 CET 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/calibration/android/calibration-android/gradlew b/calibration/android/calibration-android/gradlew new file mode 100755 index 00000000..9d82f789 --- /dev/null +++ b/calibration/android/calibration-android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/calibration/android/calibration-android/gradlew.bat b/calibration/android/calibration-android/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/calibration/android/calibration-android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/calibration/android/calibration-android/settings.gradle b/calibration/android/calibration-android/settings.gradle new file mode 100644 index 00000000..e7b4def4 --- /dev/null +++ b/calibration/android/calibration-android/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/calibration/capabilities/README.md b/calibration/capabilities/README.md new file mode 100644 index 00000000..6765f3c0 --- /dev/null +++ b/calibration/capabilities/README.md @@ -0,0 +1,6 @@ +# capabilities folder + +Here are stored the desired capabilities you may use with the calibration workflow. +They define the configuration of the device which will be used in the calibration process. +These files should remain in this folder. Indeed, you should keep the file tree of the project. +The files are used in the calibration script at _software/src/calibrate.js_: they are loaded in this script to as to read the desired capabilities. diff --git a/calibration/capabilities/android-desired-capabilities.json b/calibration/capabilities/android-desired-capabilities.json new file mode 100644 index 00000000..74b44b74 --- /dev/null +++ b/calibration/capabilities/android-desired-capabilities.json @@ -0,0 +1,8 @@ +{ + "app":"../android/calibration-android.apk", + "platformName":"Android", + "platformVersion":"", + "deviceName":"", + "appPackage":"orange.iva.toolfactory.tapster.calibration.android", + "appActivity":"orange.iva.toolfactory.tapster.calibration.android.MainActivity" +} diff --git a/calibration/capabilities/ios-desired-capabilities.json b/calibration/capabilities/ios-desired-capabilities.json new file mode 100644 index 00000000..7640b369 --- /dev/null +++ b/calibration/capabilities/ios-desired-capabilities.json @@ -0,0 +1,9 @@ +{ + "udid": "", + "app": "orange.iva.toolfactory.tapster.calibration.ios.RobotCalibration", + "platformName": "iOS", + "deviceName": "", + "platformVersion": "", + "xcodeSigningId": "iPhone Developer", + "xcodeOrgId": "" +} diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.pbxproj b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.pbxproj new file mode 100644 index 00000000..de768911 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.pbxproj @@ -0,0 +1,529 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 3E166C6B1683954A008893AA /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E166C6A1683954A008893AA /* UIKit.framework */; }; + 3E166C6D1683954A008893AA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E166C6C1683954A008893AA /* Foundation.framework */; }; + 3E166C6F1683954A008893AA /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E166C6E1683954A008893AA /* CoreGraphics.framework */; }; + 3E166C751683954A008893AA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3E166C731683954A008893AA /* InfoPlist.strings */; }; + 3E166C771683954A008893AA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E166C761683954A008893AA /* main.m */; }; + 3E166C7B1683954A008893AA /* RCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E166C7A1683954A008893AA /* RCAppDelegate.m */; }; + 3E166C841683954A008893AA /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3E166C821683954A008893AA /* MainStoryboard.storyboard */; }; + 3E166C8A1683954A008893AA /* RCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E166C891683954A008893AA /* RCViewController.m */; }; + 3E166C921683954A008893AA /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E166C911683954A008893AA /* SenTestingKit.framework */; }; + 3E166C931683954A008893AA /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E166C6A1683954A008893AA /* UIKit.framework */; }; + 3E166C941683954A008893AA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E166C6C1683954A008893AA /* Foundation.framework */; }; + 3E166C9C1683954A008893AA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3E166C9A1683954A008893AA /* InfoPlist.strings */; }; + 3E166C9F1683954A008893AA /* RobotCalibrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E166C9E1683954A008893AA /* RobotCalibrationTests.m */; }; + 6E6D168823B0CD0D00DDE8E9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6E6D168723B0CD0D00DDE8E9 /* Images.xcassets */; }; + 6E6D168C23B128B300DDE8E9 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6E6D168B23B128B300DDE8E9 /* Launch Screen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 3E166C951683954A008893AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3E166C5F1683954A008893AA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3E166C661683954A008893AA; + remoteInfo = RobotCalibration; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 3E166C671683954A008893AA /* RobotCalibration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RobotCalibration.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 3E166C6A1683954A008893AA /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 3E166C6C1683954A008893AA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 3E166C6E1683954A008893AA /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 3E166C721683954A008893AA /* RobotCalibration-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RobotCalibration-Info.plist"; sourceTree = ""; }; + 3E166C741683954A008893AA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 3E166C761683954A008893AA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 3E166C781683954A008893AA /* RobotCalibration-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RobotCalibration-Prefix.pch"; sourceTree = ""; }; + 3E166C791683954A008893AA /* RCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCAppDelegate.h; sourceTree = ""; }; + 3E166C7A1683954A008893AA /* RCAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCAppDelegate.m; sourceTree = ""; }; + 3E166C831683954A008893AA /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = ""; }; + 3E166C881683954A008893AA /* RCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCViewController.h; sourceTree = ""; }; + 3E166C891683954A008893AA /* RCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCViewController.m; sourceTree = ""; }; + 3E166C901683954A008893AA /* RobotCalibrationTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RobotCalibrationTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3E166C911683954A008893AA /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + 3E166C991683954A008893AA /* RobotCalibrationTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RobotCalibrationTests-Info.plist"; sourceTree = ""; }; + 3E166C9B1683954A008893AA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 3E166C9D1683954A008893AA /* RobotCalibrationTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RobotCalibrationTests.h; sourceTree = ""; }; + 3E166C9E1683954A008893AA /* RobotCalibrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RobotCalibrationTests.m; sourceTree = ""; }; + 6E6D168723B0CD0D00DDE8E9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 6E6D168B23B128B300DDE8E9 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3E166C641683954A008893AA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3E166C6B1683954A008893AA /* UIKit.framework in Frameworks */, + 3E166C6D1683954A008893AA /* Foundation.framework in Frameworks */, + 3E166C6F1683954A008893AA /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3E166C8C1683954A008893AA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3E166C921683954A008893AA /* SenTestingKit.framework in Frameworks */, + 3E166C931683954A008893AA /* UIKit.framework in Frameworks */, + 3E166C941683954A008893AA /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3E166C5E1683954A008893AA = { + isa = PBXGroup; + children = ( + 3E166C701683954A008893AA /* RobotCalibration */, + 3E166C971683954A008893AA /* RobotCalibrationTests */, + 3E166C691683954A008893AA /* Frameworks */, + 3E166C681683954A008893AA /* Products */, + ); + sourceTree = ""; + }; + 3E166C681683954A008893AA /* Products */ = { + isa = PBXGroup; + children = ( + 3E166C671683954A008893AA /* RobotCalibration.app */, + 3E166C901683954A008893AA /* RobotCalibrationTests.octest */, + ); + name = Products; + sourceTree = ""; + }; + 3E166C691683954A008893AA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3E166C6A1683954A008893AA /* UIKit.framework */, + 3E166C6C1683954A008893AA /* Foundation.framework */, + 3E166C6E1683954A008893AA /* CoreGraphics.framework */, + 3E166C911683954A008893AA /* SenTestingKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 3E166C701683954A008893AA /* RobotCalibration */ = { + isa = PBXGroup; + children = ( + 3E166C791683954A008893AA /* RCAppDelegate.h */, + 3E166C7A1683954A008893AA /* RCAppDelegate.m */, + 3E166C821683954A008893AA /* MainStoryboard.storyboard */, + 3E166C881683954A008893AA /* RCViewController.h */, + 3E166C891683954A008893AA /* RCViewController.m */, + 6E6D168723B0CD0D00DDE8E9 /* Images.xcassets */, + 3E166C711683954A008893AA /* Supporting Files */, + 6E6D168B23B128B300DDE8E9 /* Launch Screen.storyboard */, + ); + path = RobotCalibration; + sourceTree = ""; + }; + 3E166C711683954A008893AA /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 3E166C721683954A008893AA /* RobotCalibration-Info.plist */, + 3E166C731683954A008893AA /* InfoPlist.strings */, + 3E166C761683954A008893AA /* main.m */, + 3E166C781683954A008893AA /* RobotCalibration-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 3E166C971683954A008893AA /* RobotCalibrationTests */ = { + isa = PBXGroup; + children = ( + 3E166C9D1683954A008893AA /* RobotCalibrationTests.h */, + 3E166C9E1683954A008893AA /* RobotCalibrationTests.m */, + 3E166C981683954A008893AA /* Supporting Files */, + ); + path = RobotCalibrationTests; + sourceTree = ""; + }; + 3E166C981683954A008893AA /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 3E166C991683954A008893AA /* RobotCalibrationTests-Info.plist */, + 3E166C9A1683954A008893AA /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 3E166C661683954A008893AA /* RobotCalibration */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3E166CA21683954A008893AA /* Build configuration list for PBXNativeTarget "RobotCalibration" */; + buildPhases = ( + 3E166C631683954A008893AA /* Sources */, + 3E166C641683954A008893AA /* Frameworks */, + 3E166C651683954A008893AA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RobotCalibration; + productName = RobotCalibration; + productReference = 3E166C671683954A008893AA /* RobotCalibration.app */; + productType = "com.apple.product-type.application"; + }; + 3E166C8F1683954A008893AA /* RobotCalibrationTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3E166CA51683954A008893AA /* Build configuration list for PBXNativeTarget "RobotCalibrationTests" */; + buildPhases = ( + 3E166C8B1683954A008893AA /* Sources */, + 3E166C8C1683954A008893AA /* Frameworks */, + 3E166C8D1683954A008893AA /* Resources */, + 3E166C8E1683954A008893AA /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 3E166C961683954A008893AA /* PBXTargetDependency */, + ); + name = RobotCalibrationTests; + productName = RobotCalibrationTests; + productReference = 3E166C901683954A008893AA /* RobotCalibrationTests.octest */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3E166C5F1683954A008893AA /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = RC; + LastUpgradeCheck = 1110; + ORGANIZATIONNAME = "Appium Contributors"; + TargetAttributes = { + 3E166C661683954A008893AA = { + DevelopmentTeam = A3ZT87L5Y5; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 3E166C621683954A008893AA /* Build configuration list for PBXProject "RobotCalibration" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = 3E166C5E1683954A008893AA; + productRefGroup = 3E166C681683954A008893AA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3E166C661683954A008893AA /* RobotCalibration */, + 3E166C8F1683954A008893AA /* RobotCalibrationTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 3E166C651683954A008893AA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3E166C751683954A008893AA /* InfoPlist.strings in Resources */, + 6E6D168823B0CD0D00DDE8E9 /* Images.xcassets in Resources */, + 6E6D168C23B128B300DDE8E9 /* Launch Screen.storyboard in Resources */, + 3E166C841683954A008893AA /* MainStoryboard.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3E166C8D1683954A008893AA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3E166C9C1683954A008893AA /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3E166C8E1683954A008893AA /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 3E166C631683954A008893AA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3E166C771683954A008893AA /* main.m in Sources */, + 3E166C7B1683954A008893AA /* RCAppDelegate.m in Sources */, + 3E166C8A1683954A008893AA /* RCViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3E166C8B1683954A008893AA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3E166C9F1683954A008893AA /* RobotCalibrationTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 3E166C961683954A008893AA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3E166C661683954A008893AA /* RobotCalibration */; + targetProxy = 3E166C951683954A008893AA /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 3E166C731683954A008893AA /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 3E166C741683954A008893AA /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 3E166C821683954A008893AA /* MainStoryboard.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 3E166C831683954A008893AA /* en */, + ); + name = MainStoryboard.storyboard; + sourceTree = ""; + }; + 3E166C9A1683954A008893AA /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 3E166C9B1683954A008893AA /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 3E166CA01683954A008893AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 3E166CA11683954A008893AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3E166CA31683954A008893AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A3ZT87L5Y5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "RobotCalibration/RobotCalibration-Prefix.pch"; + INFOPLIST_FILE = "RobotCalibration/RobotCalibration-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + PRODUCT_BUNDLE_IDENTIFIER = orange.iva.toolfactory.tapster.calibration.ios; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 3E166CA41683954A008893AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = A3ZT87L5Y5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "RobotCalibration/RobotCalibration-Prefix.pch"; + INFOPLIST_FILE = "RobotCalibration/RobotCalibration-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + PRODUCT_BUNDLE_IDENTIFIER = orange.iva.toolfactory.tapster.calibration.ios; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 3E166CA61683954A008893AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/RobotCalibration.app/RobotCalibration"; + FRAMEWORK_SEARCH_PATHS = ( + "\"$(SDKROOT)/Developer/Library/Frameworks\"", + "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "RobotCalibration/RobotCalibration-Prefix.pch"; + INFOPLIST_FILE = "RobotCalibrationTests/RobotCalibrationTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "Appium.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = octest; + }; + name = Debug; + }; + 3E166CA71683954A008893AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/RobotCalibration.app/RobotCalibration"; + FRAMEWORK_SEARCH_PATHS = ( + "\"$(SDKROOT)/Developer/Library/Frameworks\"", + "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "RobotCalibration/RobotCalibration-Prefix.pch"; + INFOPLIST_FILE = "RobotCalibrationTests/RobotCalibrationTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "Appium.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = octest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3E166C621683954A008893AA /* Build configuration list for PBXProject "RobotCalibration" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3E166CA01683954A008893AA /* Debug */, + 3E166CA11683954A008893AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3E166CA21683954A008893AA /* Build configuration list for PBXNativeTarget "RobotCalibration" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3E166CA31683954A008893AA /* Debug */, + 3E166CA41683954A008893AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3E166CA51683954A008893AA /* Build configuration list for PBXNativeTarget "RobotCalibrationTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3E166CA61683954A008893AA /* Debug */, + 3E166CA71683954A008893AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3E166C5F1683954A008893AA /* Project object */; +} diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..f51919ac --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcuserdata/danc.xcuserdatad/UserInterfaceState.xcuserstate b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcuserdata/danc.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..7cad3dde Binary files /dev/null and b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcuserdata/danc.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcuserdata/tapster.xcuserdatad/UserInterfaceState.xcuserstate b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcuserdata/tapster.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..14ffad56 Binary files /dev/null and b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/project.xcworkspace/xcuserdata/tapster.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/danc.xcuserdatad/xcschemes/RobotCalibration.xcscheme b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/danc.xcuserdatad/xcschemes/RobotCalibration.xcscheme new file mode 100644 index 00000000..b054a906 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/danc.xcuserdatad/xcschemes/RobotCalibration.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/danc.xcuserdatad/xcschemes/xcschememanagement.plist b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/danc.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..db989a9b --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/danc.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + RobotCalibration.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 3E166C661683954A008893AA + + primary + + + 3E166C8F1683954A008893AA + + primary + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/RobotCalibration.xcscheme b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/RobotCalibration.xcscheme new file mode 100644 index 00000000..4f24aefd --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/RobotCalibration.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/RobotCalibrationTests.xcscheme b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/RobotCalibrationTests.xcscheme new file mode 100644 index 00000000..cfae6da3 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/RobotCalibrationTests.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/xcschememanagement.plist b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..2e7d85ad --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration.xcodeproj/xcuserdata/tapster.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + RobotCalibration.xcscheme + + orderHint + 0 + + RobotCalibrationTests.xcscheme + + orderHint + 1 + + + SuppressBuildableAutocreation + + 3E166C661683954A008893AA + + primary + + + 3E166C8F1683954A008893AA + + primary + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration/Images.xcassets/AppIcon.appiconset/Contents.json b/calibration/ios/RobotCalibration/RobotCalibration/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d8db8d65 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/calibration/ios/RobotCalibration/RobotCalibration/Images.xcassets/Contents.json b/calibration/ios/RobotCalibration/RobotCalibration/Images.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/calibration/ios/RobotCalibration/RobotCalibration/Launch Screen.storyboard b/calibration/ios/RobotCalibration/RobotCalibration/Launch Screen.storyboard new file mode 100644 index 00000000..87c06304 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/Launch Screen.storyboard @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration/RCAppDelegate.h b/calibration/ios/RobotCalibration/RobotCalibration/RCAppDelegate.h new file mode 100644 index 00000000..eef56611 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/RCAppDelegate.h @@ -0,0 +1,28 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import + +@interface RCAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/calibration/ios/RobotCalibration/RobotCalibration/RCAppDelegate.m b/calibration/ios/RobotCalibration/RobotCalibration/RCAppDelegate.m new file mode 100644 index 00000000..a29502d6 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/RCAppDelegate.m @@ -0,0 +1,59 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import "RCAppDelegate.h" + +@implementation RCAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/calibration/ios/RobotCalibration/RobotCalibration/RCViewController.h b/calibration/ios/RobotCalibration/RobotCalibration/RCViewController.h new file mode 100644 index 00000000..03d166d5 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/RCViewController.h @@ -0,0 +1,29 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import + +@interface RCViewController : UIViewController +@property (strong, nonatomic) IBOutlet UITapGestureRecognizer *tapRecognizer; +@property (strong, nonatomic) IBOutlet UILabel *coordinateLabel; +@property (strong, nonatomic) IBOutlet UISwipeGestureRecognizer *swipeRecognizer; + +@end diff --git a/calibration/ios/RobotCalibration/RobotCalibration/RCViewController.m b/calibration/ios/RobotCalibration/RobotCalibration/RCViewController.m new file mode 100644 index 00000000..e6cff7d6 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/RCViewController.m @@ -0,0 +1,117 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import "RCViewController.h" + +@interface RCViewController () + +@end + +@implementation RCViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + [self becomeFirstResponder]; + +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskAllButUpsideDown; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation +{ + if ((orientation == UIInterfaceOrientationPortrait) || + (orientation == UIInterfaceOrientationLandscapeLeft) || + (orientation == UIInterfaceOrientationLandscapeRight)) + return YES; + + return NO; +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + [self.view setNeedsLayout]; + [self.view setNeedsDisplay]; +} + + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + //UITouch *touch = [touches anyObject]; + for (UIView *view in self.view.subviews) { + [view removeFromSuperview]; + } + for (UITouch *touch in [[event allTouches] allObjects]) { + [self displayCoordinatesForTouch:touch]; + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + //UITouch *touch = [touches anyObject]; + for (UIView *view in self.view.subviews) { + [view removeFromSuperview]; + } + for (UITouch *touch in [[event allTouches] allObjects]) { + [self displayCoordinatesForTouch:touch]; + } + +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + for (UIView *view in self.view.subviews) { + [view removeFromSuperview]; + } +} + +- (void)displayCoordinatesForTouch:(UITouch *)touch { + CGPoint locationInView = [touch locationInView:self.view]; + int viewWidth = self.view.frame.size.width; + int viewHeight = self.view.frame.size.height; + + if (([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) || + ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)) { + viewWidth = self.view.frame.size.height; + viewHeight = self.view.frame.size.width; + } + // Calculate the Coordinate Label Frame + CGRect coordinateLabelFrame = CGRectMake(0, 0, 0, 0); + coordinateLabelFrame.size.height = 20; + coordinateLabelFrame.size.width = 100; + // We want the label to stay 40pts from the edges + coordinateLabelFrame.origin.x = MIN(MAX(locationInView.x - 40, 40), viewWidth - coordinateLabelFrame.size.width - 40); + coordinateLabelFrame.origin.y = MIN(MAX(locationInView.y - 30, 40), viewHeight - coordinateLabelFrame.size.height - 40); + + // Set the frame and test of the label + UILabel *coordinateLabel = [[UILabel alloc] initWithFrame:coordinateLabelFrame]; + coordinateLabel.text = [NSString stringWithFormat:@"(%d, %d)", (int)locationInView.x, (int)locationInView.y]; + coordinateLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:18.0f]; + [self.view addSubview:coordinateLabel]; +} + +@end diff --git a/calibration/ios/RobotCalibration/RobotCalibration/RobotCalibration-Info.plist b/calibration/ios/RobotCalibration/RobotCalibration/RobotCalibration-Info.plist new file mode 100644 index 00000000..19a0e60b --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/RobotCalibration-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + Launch Screen + UIMainStoryboardFile + MainStoryboard + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationPortrait + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration/RobotCalibration-Prefix.pch b/calibration/ios/RobotCalibration/RobotCalibration/RobotCalibration-Prefix.pch new file mode 100644 index 00000000..4f465794 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/RobotCalibration-Prefix.pch @@ -0,0 +1,31 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/calibration/ios/RobotCalibration/RobotCalibration/en.lproj/InfoPlist.strings b/calibration/ios/RobotCalibration/RobotCalibration/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/calibration/ios/RobotCalibration/RobotCalibration/en.lproj/MainStoryboard.storyboard b/calibration/ios/RobotCalibration/RobotCalibration/en.lproj/MainStoryboard.storyboard new file mode 100644 index 00000000..08aedc1d --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/en.lproj/MainStoryboard.storyboard @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/calibration/ios/RobotCalibration/RobotCalibration/main.m b/calibration/ios/RobotCalibration/RobotCalibration/main.m new file mode 100644 index 00000000..33de82e5 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibration/main.m @@ -0,0 +1,31 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import + +#import "RCAppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([RCAppDelegate class])); + } +} diff --git a/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests-Info.plist b/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests-Info.plist new file mode 100644 index 00000000..169b6f71 --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests.h b/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests.h new file mode 100644 index 00000000..4e12eccf --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests.h @@ -0,0 +1,26 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import + +@interface RobotCalibrationTests : SenTestCase + +@end diff --git a/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests.m b/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests.m new file mode 100644 index 00000000..5b04c65e --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibrationTests/RobotCalibrationTests.m @@ -0,0 +1,45 @@ +/** + * Copyright 2012 Appium Committers + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import "RobotCalibrationTests.h" + +@implementation RobotCalibrationTests + +- (void)setUp +{ + [super setUp]; + + // Set-up code here. +} + +- (void)tearDown +{ + // Tear-down code here. + + [super tearDown]; +} + +- (void)testExample +{ + STFail(@"Unit tests are not implemented yet in RobotCalibrationTests"); +} + +@end diff --git a/calibration/ios/RobotCalibration/RobotCalibrationTests/en.lproj/InfoPlist.strings b/calibration/ios/RobotCalibration/RobotCalibrationTests/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/calibration/ios/RobotCalibration/RobotCalibrationTests/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/clients/README.md b/clients/README.md new file mode 100644 index 00000000..14705145 --- /dev/null +++ b/clients/README.md @@ -0,0 +1,3 @@ +# clients folder + +Here are stored the clients and other programs to use in order to drive the robot and send to it requests. diff --git a/clients/python/README.md b/clients/python/README.md new file mode 100644 index 00000000..841f547e --- /dev/null +++ b/clients/python/README.md @@ -0,0 +1,65 @@ +# python folder + +Here are elements defining a client written in Python which can drive the bot (i.e. send to it requests) + +## List of files +- _client.py_ The Python-written client to use so as to drive the robot, i.e. the "main" program +- _config.py_ The file having the configuration to use with for examples regular expresions, API's URL, etc. +- _glue.py_ Some Python glue so as to give logic to client and make the link with the _robot_api.py_ file +- _robot_api.py_ The file which uses the HTTP API of the robot +- *commands_parser.py* The file providing methods to parse and check commands + +## Usage +```shell +python client.py [-h] [--url ROBORSERVERURL] [--light COMMAND] [--file COMMANDSFILE] [--version] +``` + +## Samples of commands to give +- tap 100 100 +- n-tap 42 100 100 +- stress-tap 666 100 100 +- reset +- swipe 300 300 100 100 +- n-swipe 5 300 300 100 100 +- stress-swipe 666 300 300 100 100 +- set-position 20 20 -155 + +## How to use the client +1. Define the configuration of your Tapster2 robot in _config.py_ if needed +2. Then... + +To run the Python client in interactive / verbose mode, use: +```shell + python client.py --url your-robot-url +``` +or using the config.py file +```shell + python client.py +``` + +To run the Python client in light mode using only a command, use: +```shell + python client.py --url your-robot-url --light the-command-to-process +``` + +To run the Python client with a file of commands to process, use: +```shell + python client.py --url your-robot-url --file path-to-the-command-file +``` + +If you want to get the version of the Python client, use: +```shell + python client.py --version +``` + +The URL you may use must match the pattern _protocol://ip:port_, e.g. _http://192.168.1.13:4242_ + +## Note +The default value for _--url_ parameter is a combination of variables defined in _config.py_ like **http://127.0.0.1:4242**. +If you want to use this client, you have to have ['requests'](docs.python-requests.org/en/latest/ "Requests module") module installed. +To do so, you can run the following command or read this [topic](https://stackoverflow.com/questions/17309288/importerror-no-module-named-requests "Stack Overflox post"): +The installed version of _requests_ for this project is **2.18.4** + +```shell + sudo pip install requests +``` diff --git a/clients/python/client.py b/clients/python/client.py new file mode 100644 index 00000000..ef10fab1 --- /dev/null +++ b/clients/python/client.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# -*- coding: utf_8 -*- +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +""" +File.......: client.py +Brief......: The Python client to use so as to drive the Tapster 2 bot +Version....: 2.0.1 +Since......: 10/01/2018 +""" + +import argparse +import sys + +import glue +from config import * +from commands_parser import * + +if __name__ == "__main__": + + # Check args if this execution is a "light" execution, i.e. without verbatims + parser = argparse.ArgumentParser(description='Python client for Tapster2 robot.') + parser.add_argument('--url', dest='robotserverurl', help="The URL of the robot's server", required=False) + parser.add_argument('--light', dest='command', help='Run in light mode, i.e. without verbatims nor prompts.', required=False) + parser.add_argument('--file', dest='commandsfile', help='Load a file at this path containing a list of commands to process seperated by a line break.', required=False) + parser.add_argument('--version', action='version', help='Displays the version of this program.', version='%(prog)s '+CLIENT_VERSION) + args = parser.parse_args() + + if args.robotserverurl: + config.ROBOT_URL = args.robotserverurl + else: + config.ROBOT_URL = DEFAULT_ROBOT_URL + +# In this case we are in light mode + + if args.command: + if not checkRobotConnection(): + sys.exit() + command = args.command + if isRobotCommand(command): + parseCommand(command) + elif glue.isHelpCommand(command): + glue.help() + elif glue.isConfigCommand(command): + glue.config() + else: + print "ERROR: Bad command: '" + command + "'" + sys.exit() + +# In this case we are in commands file mode + + if args.commandsfile: + if not checkRobotConnection(): + sys.exit() + pathOfFile = args.commandsfile + if glue.checkFile(pathOfFile): + print "Will process file: '" + pathOfFile + "'" + glue.processCommandsFile(pathOfFile) + else: + print "ERROR: File not found: '" + commandsFile + "'" + sys.exit() + +# In that case we are in verbose / interactive mode + + # Welcome guys! + print "Version " + CLIENT_VERSION + glue.welcome() + + checkRobotConnection() + + # Some help? + glue.help() + + # Deal with commands + stop = False + lastCommand = None + while not stop: + command = glue.askForCommand() + if glue.isRepeatCommand(command): + command = lastCommand + if isRobotCommand(command): + parseCommand( command ) + elif glue.isHelpCommand(command): + glue.help() + elif glue.isConfigCommand(command): + glue.config() + elif glue.isStopCommand(command): + stop = True + else: + print "Nope. Bad command: '" + command + "'" + lastCommand = command + # Bye! + print "Ok, bye!" diff --git a/clients/python/commands_parser.py b/clients/python/commands_parser.py new file mode 100644 index 00000000..6395d924 --- /dev/null +++ b/clients/python/commands_parser.py @@ -0,0 +1,476 @@ +# -*- coding: utf_8 -*- +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +""" +File.......: commands_parser.py +Brief......: File including features to use to as to parse commands +Version....: 1.3.0 +Since......: 11/01/2018 +""" + +# ******* +# IMPORTS +# ******* + +from glue import * +from config import * +from robot_api import * + + +# ********* +# FUNCTIONS +# ********* + +# Function: isRobotCommand( command ) +def isRobotCommand( command ): + """ + Checks if the command is suitable, i.e. if it matches one of the managed commands. + Returns a boolean value, true if the command is good, false otherwise. + """ + + # get-angles + result = bool(ROBOT_PATTERN_GET_ANGLES.match(command)) + if result: + return True + + # set-angles a b c + result = bool(ROBOT_PATTERN_SET_ANGLES.match(command)) + if result: + return True + + # get-position + result = bool(ROBOT_PATTERN_GET_POSITION.match(command)) + if result: + return True + + # set-position x y z + result = bool(ROBOT_PATTERN_SET_POSITION.match(command)) + if result: + return True + + # tap x y + result = bool(ROBOT_PATTERN_TAP.match(command)) + if result: + return True + + # long tap x y + result = bool(ROBOT_PATTERN_LONG_TAP.match(command)) + if result: + return True + + # Double tap x y + result = bool(ROBOT_PATTERN_DOUBLE_TAP.match(command)) + if result: + return True + + # Triple tap x y + result = bool(ROBOT_PATTERN_TRIPLE_TAP.match(command)) + if result: + return True + + # reset + result = bool(ROBOT_PATTERN_RESET.match(command)) + if result: + return True + + # get-calibration + result = bool(ROBOT_PATTERN_GET_CALIBRATION.match(command)) + if result: + return True + + # set-calibration JSON + result = bool(ROBOT_PATTERN_SET_CALIBRATION.match(command)) + if result: + return True + + # status + result = bool(ROBOT_PATTERN_STATUS.match(command)) + if result: + return True + + # dance + result = bool(ROBOT_PATTERN_DANCE.match(command)) + if result: + return True + + # stop dancing + result = bool(ROBOT_PATTERN_STOP_DANCE.match(command)) + if result: + return True + + # swipe + result = bool(ROBOT_PATTERN_SWIPE.match(command)) + if result: + return True + + # n-click + result = bool(ROBOT_PATTERN_N_TAP.match(command)) + if result: + return True + + # posForScreen + result = bool(ROBOT_PATTERN_POSITION_FOR_SCREEN_COORD.match(command)) + if result: + return True + + # angForPos + result = bool(ROBOT_PATTERN_ANGLES_FOR_POSITION.match(command)) + if result: + return True + + # robot's connection + result = bool(ROBOT_PATTERN_CHECK.match(command)) + if result: + return True + + # stress-swipe + result = bool(ROBOT_PATTERN_STRESS_SWIPE.match(command)) + if result: + return True + + # stress-tap + result = bool(ROBOT_PATTERN_STRESS_TAP.match(command)) + if result: + return True + + # contact-z + result = bool(ROBOT_PATTERN_CONTACT_Z.match(command)) + if result: + return True + + # n-swipe + result = bool(ROBOT_PATTERN_N_SWIPE.match(command)) + if result: + return True + + # draw square + result = bool(ROBOT_PATTERN_DRAW_SQUARE.match(command)) + if result: + return True + + # draw star + result = bool(ROBOT_PATTERN_DRAW_STAR.match(command)) + if result: + return True + + # draw triangle + result = bool(ROBOT_PATTERN_DRAW_TRIANGLE.match(command)) + if result: + return True + + # draw circle + result = bool(ROBOT_PATTERN_DRAW_CIRCLE.match(command)) + if result: + return True + + # draw cross + result = bool(ROBOT_PATTERN_DRAW_CROSS.match(command)) + if result: + return True + + # draw spiral + result = bool(ROBOT_PATTERN_DRAW_SPIRAL.match(command)) + if result: + return True + + # draw random + result = bool(ROBOT_PATTERN_DRAW_RANDOM.match(command)) + if result: + return True + + return False + +# End of Function: isRobotCommand( command ) + +# Function: parseCommand( command ) +def parseCommand( command ): + """ + Parses the command the user has written. + Parameter: the command to parse. + It will get the main keyword and then the arguments if needed. + Once the real command has been found, the dedicated feature in the API will be triggered + Returns: True if the command has been weel parsed, False if a problem occred + """ + + # get-angles + result = bool(ROBOT_PATTERN_GET_ANGLES.match(command)) + if result: + robot_getAngles() + return True + + # set-angles a b c + result = bool(ROBOT_PATTERN_SET_ANGLES.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_setAngles(theta1=splits[1], theta2=splits[2], theta3=splits[3]) + return True + else: + print "Bad parameters" + return False + + # get-position + result = bool(ROBOT_PATTERN_GET_POSITION.match(command)) + if result: + robot_getPosition() + return True + + # set-position x y z + result = bool(ROBOT_PATTERN_SET_POSITION.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_setPosition(x=splits[1], y=splits[2], z=splits[3]) + return True + else: + print "Bad parameters" + return False + + # tap x y + result = bool(ROBOT_PATTERN_TAP.match(command)) + if result: + splits = command.split( ) + if len(splits) == 3: + robot_tap(x=splits[1], y=splits[2]) + return True + else: + print "Bad parameters" + return False + + # long tap x y + result = bool(ROBOT_PATTERN_LONG_TAP.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_longTap(x=splits[1], y=splits[2], duration=splits[3]) + return True + else: + print "Bad parameters" + return False + + # double tap x y + result = bool(ROBOT_PATTERN_DOUBLE_TAP.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_doubleTap(x=splits[1], y=splits[2], duration=splits[3]) + return True + else: + print "Bad parameters" + return False + + # triple tap x y + result = bool(ROBOT_PATTERN_TRIPLE_TAP.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_tripleTap(x=splits[1], y=splits[2], duration=splits[3]) + return True + else: + print "Bad parameters" + return False + + # reset + result = bool(ROBOT_PATTERN_RESET.match(command)) + if result: + robot_reset() + return True + + # get-calibration + result = bool(ROBOT_PATTERN_GET_CALIBRATION.match(command)) + if result: + robot_getCalibration() + return True + + # set-calibration JSON + result = bool(ROBOT_PATTERN_SET_CALIBRATION.match(command)) + if result: + splits = command.split( ) + if len(splits) == 2: + robot_setCalibration(jsonData=splits[1]) + return True + else: + print "Bad parameters" + return False + + # status + result = bool(ROBOT_PATTERN_STATUS.match(command)) + if result: + robot_status() + return True + + # dance + result = bool(ROBOT_PATTERN_DANCE.match(command)) + if result: + robot_dance() + return True + + # stop dancing + result = bool(ROBOT_PATTERN_STOP_DANCE.match(command)) + if result: + robot_stopDance() + return True + + # swipe + result = bool(ROBOT_PATTERN_SWIPE.match(command)) + if result: + splits = command.split( ) + if len(splits) == 5: + robot_swipe(startX=splits[1], startY=splits[2], endX=splits[3], endY=splits[4]) + return True + else: + print "Bad parameters" + return False + + # n-tap + result = bool(ROBOT_PATTERN_N_TAP.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_ntap(n=splits[1], x=splits[2], y=splits[3]) + return True + else: + print "Bad parameters" + return False + + # posForScreen + result = bool(ROBOT_PATTERN_POSITION_FOR_SCREEN_COORD.match(command)) + if result: + splits = command.split( ) + if len(splits) == 3: + robot_posForScreen(x=splits[1], y=splits[2]) + return True + else: + print "Bad parameters" + return False + + # angForPos + result = bool(ROBOT_PATTERN_ANGLES_FOR_POSITION.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_angForPos(x=splits[1], y=splits[2], z=splits[3]) + return True + else: + print "Bad parameters" + return False + + # check robot's server connection + result = bool(ROBOT_PATTERN_CHECK.match(command)) + if result: + checkRobotConnection() + return True + + # stress swipe + result = bool(ROBOT_PATTERN_STRESS_SWIPE.match(command)) + if result: + splits = command.split( ) + if len(splits) == 6: + robot_stressSwipe(n=splits[1], startX=splits[2], startY=splits[3], endX=splits[4], endY=splits[5]) + return True + else: + print "Bad parameters" + return False + + # stress tap + result = bool(ROBOT_PATTERN_STRESS_TAP.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_stressTap(n=splits[1], x=splits[2], y=splits[3]) + return True + else: + print "Bad parameters" + return False + + # contact-z + result = bool(ROBOT_PATTERN_CONTACT_Z.match(command)) + if result: + robot_getContactZ() + return True + + # n-swipe + result = bool(ROBOT_PATTERN_N_SWIPE.match(command)) + if result: + splits = command.split( ) + if len(splits) == 6: + robot_nswipe(n=splits[1], startX=splits[2], startY=splits[3], endX=splits[4], endY=splits[5]) + return True + else: + print "Bad parameters" + return False + + # draw square + result = bool(ROBOT_PATTERN_DRAW_SQUARE.match(command)) + if result: + splits = command.split( ) + if len(splits) == 3: + robot_drawSquare(n=splits[1], length=splits[2]) + return True + else: + print "Bad parameters" + return False + + # draw star + result = bool(ROBOT_PATTERN_DRAW_STAR.match(command)) + if result: + robot_drawStar() + return True + + # draw triangle + result = bool(ROBOT_PATTERN_DRAW_TRIANGLE.match(command)) + if result: + splits = command.split( ) + if len(splits) == 7: + robot_drawTriangle(x1=splits[1], y1=splits[2], x2=splits[3], y2=splits[4], x3=splits[5], y3=splits[6]) + return True + else: + print "Bad parameters" + return False + + # draw circle + result = bool(ROBOT_PATTERN_DRAW_CIRCLE.match(command)) + if result: + splits = command.split( ) + if len(splits) == 4: + robot_drawCircle(x=splits[1], y=splits[2], r=splits[3]) + return True + else: + print "Bad parameters" + return False + + # draw cross + result = bool(ROBOT_PATTERN_DRAW_CROSS.match(command)) + if result: + splits = command.split( ) + if len(splits) == 9: + robot_drawCross(x1=splits[1], y1=splits[2], x2=splits[3], y2=splits[4], x3=splits[5], y3=splits[6], x4=splits[7], y4=splits[8]) + return True + else: + print "Bad parameters" + return False + + # draw circle + result = bool(ROBOT_PATTERN_DRAW_SPIRAL.match(command)) + if result: + splits = command.split( ) + if len(splits) == 5: + robot_drawSpiral(x=splits[1], y=splits[2], n=splits[3], r=splits[4]) + return True + else: + print "Bad parameters" + return False + + # draw random + result = bool(ROBOT_PATTERN_DRAW_RANDOM.match(command)) + if result: + splits = command.split( ) + if len(splits) == 6: + robot_drawRandom(n=splits[1], minWidth=splits[2], minHeight=splits[3], maxWidth=splits[4], maxHeight=splits[5]) + return True + else: + print "Bad parameters" + return False + +# End of Function: parseCommand( command ) diff --git a/clients/python/config.py b/clients/python/config.py new file mode 100644 index 00000000..ab21b89d --- /dev/null +++ b/clients/python/config.py @@ -0,0 +1,121 @@ +# -*- coding: utf_8 -*- +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +""" +File.......: config.py +Brief......: File including configuration to use and to apply on the client +Version....: 1.3.0 +Since......: 10/01/2018 +""" + +import re + +# Version of this Tapster2 Python client +CLIENT_VERSION = "v3.0.0" + +# ************ +# Robot things +# ************ + +# Default IP address where the Tapster2 bot is reachable +DEFAULT_ROBOT_IP_ADDRESS = "127.0.0.1" + +# Default port to use to as to reach the robot +DEFAULT_ROBOT_PORT = "4242" + +# Default protocol to use for the robot +DEFAULT_ROBOT_PROTOCOL = "http" + +# Default URL to use to as to reach the robot +DEFAULT_ROBOT_URL = DEFAULT_ROBOT_PROTOCOL + "://" + DEFAULT_ROBOT_IP_ADDRESS + ":" + DEFAULT_ROBOT_PORT + +# The URL of the robot's server which will be used / may be overriden by the user +ROBOT_URL = DEFAULT_ROBOT_URL + +# Delay in seconds between each tap +WAIT_TIME_BETWEEN_TAP = 0.5 + +# Delay in seconds between each swipe +WAIT_TIME_BETWEEN_SWIPE = 0.5 + +# Delay in seconds between each swipe during stress swipes process +WAIT_TIME_STRESS_SWIPE = 0.33 + +# Delay in seconds between each tap during stress taps process +WAIT_TIME_STRESS_TAP = 0.25 + +# Deal in seconds between each operation picked and triggered from a commands file +WAIT_BETWEEN_CASCADED_OPERATION = 2 + +# The escape symbol to commnt a command store din the commands files +ESCAPE_SYMBOL = "#" + +# **************** +# URL of Robot API +# **************** + +ROBOT_URL_GET_ANGLES = "/angles" +ROBOT_URL_SET_ANGLES = "/setAngles" +ROBOT_URL_GET_POSITION = "/position" +ROBOT_URL_SET_POSITION = "/setPosition" +ROBOT_URL_TAP = "/tap" +ROBOT_URL_LONG_TAP = "/longTap" +ROBOT_URL_DOUBLE_TAP = "/doubleTap" +ROBOT_URL_TRIPLE_TAP = "/tripleTap" +ROBOT_URL_RESET = "/reset" +ROBOT_URL_GET_CALIBRATION = "/calibrationData" +ROBOT_URL_SET_CALIBRATION = "/setCalibrationData" +ROBOT_URL_STATUS = "/status" +ROBOT_URL_DANCE = "/dance" +ROBOT_URL_STOP_DANCE = "/stopDancing" +ROBOT_URL_SWIPE = "/swipe" +ROBOT_URL_POSITION_FOR_SCREEN_COORD = "/positionForScreenCoordinates" +ROBOT_URL_ANGLES_FOR_POSITION = "/anglesForPosition" +ROBOT_URL_CONTACT_Z = "/contactZ" +ROBOT_URL_DRAW_SQUARE = "/drawSquare" +ROBOT_URL_DRAW_STAR = "/drawStar" +ROBOT_URL_DRAW_TRIANGLE = "/drawTriangle" +ROBOT_URL_DRAW_CIRCLE = "/drawCircle" +ROBOT_URL_DRAW_CROSS = "/drawCross" +ROBOT_URL_DRAW_SPIRAL = "/drawSpiral" +ROBOT_URL_DRAW_RANDOM = "/drawRandomPattern" + +# ******************************** +# Regular expressions for commands +# ******************************** + +ROBOT_PATTERN_GET_ANGLES = re.compile("^get-angles$") +ROBOT_PATTERN_SET_ANGLES = re.compile("^set-angles (-*\d+(\.\d+)?) (-*\d+(\.\d+)?) (-*\d+(\.\d+)?)$") +ROBOT_PATTERN_GET_POSITION = re.compile("^get-position$") +ROBOT_PATTERN_SET_POSITION = re.compile("^set-position (-*\d+(\.\d+)?) (-*\d+(\.\d+)?) (-*\d+(\.\d+)?)$") +ROBOT_PATTERN_TAP = re.compile("^tap (\d+) (\d+)$") +ROBOT_PATTERN_LONG_TAP = re.compile("^long-tap (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_DOUBLE_TAP = re.compile("^double-tap (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_TRIPLE_TAP = re.compile("^triple-tap (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_RESET = re.compile("^reset$") +ROBOT_PATTERN_GET_CALIBRATION = re.compile("^get-calibration$") +ROBOT_PATTERN_SET_CALIBRATION = re.compile("^set-calibration .+$") #FIXME Improve the regex to make it match to JSON calibration data string +ROBOT_PATTERN_CONFIG = re.compile("^config$") +ROBOT_PATTERN_HELP = re.compile("^help$") +ROBOT_PATTERN_BYE = re.compile("^bye$") +ROBOT_PATTERN_STATUS = re.compile("^status$") +ROBOT_PATTERN_DANCE = re.compile("^dance$") +ROBOT_PATTERN_STOP_DANCE = re.compile("^stop-dance$") +ROBOT_PATTERN_SWIPE = re.compile("^swipe (\d+) (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_N_TAP = re.compile("^n-tap (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_POSITION_FOR_SCREEN_COORD = re.compile("^posForScreen (\d+) (\d+)$") +ROBOT_PATTERN_ANGLES_FOR_POSITION = re.compile("^angForPos (-*\d+) (-*\d+) (-*\d+)$") +ROBOT_PATTERN_CHECK = re.compile("^check$") +ROBOT_PATTERN_STRESS_SWIPE = re.compile("^stress-swipe (\d+) (\d+) (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_STRESS_TAP = re.compile("^stress-tap (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_REPEAT = re.compile("^repeat$") +ROBOT_PATTERN_CONTACT_Z = re.compile("^contact-z$") +ROBOT_PATTERN_N_SWIPE = re.compile("^n-swipe (\d+) (\d+) (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_DRAW_SQUARE = re.compile("square (\d+) (\d+)$") +ROBOT_PATTERN_DRAW_STAR = re.compile("^star$") +ROBOT_PATTERN_DRAW_TRIANGLE = re.compile("^triangle (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_DRAW_CIRCLE = re.compile("^circle (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_DRAW_CROSS = re.compile("^cross (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_DRAW_SPIRAL = re.compile("^spiral (\d+) (\d+) (\d+) (\d+)$") +ROBOT_PATTERN_DRAW_RANDOM = re.compile("^random (\d+) (\d+) (\d+) (\d+) (\d+)$") diff --git a/clients/python/glue.py b/clients/python/glue.py new file mode 100644 index 00000000..7389b2ae --- /dev/null +++ b/clients/python/glue.py @@ -0,0 +1,213 @@ +# -*- coding: utf_8 -*- +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +""" +File.......: glue.py +Brief......: File including all the Python glue to use for the client, except the API of the bot +Version....: 2.3.0 +Since......: 10/01/2018 +""" + +# ******* +# IMPORTS +# ******* + +# For robot connection check process +import requests + +# To wait between each cascaded command +import time + +# For files +import os.path + +# For regular expressions and patterns +import config as clientConfig + +# Commands parsing +from commands_parser import * + + +# ********* +# FUNCTIONS +# ********* + +# Function: welcome() +def welcome(): + """ + Displays the welcome message. + """ + print "*************************************" + print "* Welcome to Tapster2 Python client *" + print "*************************************" + return +# End of Function: welcome() + +# Function: help() +def help(): + """ + Displays the help, i.e. the commands the client can deal with. + """ + print "" + print "Here are the commands you can use for the Tapster2 bot:" + print "\ttap x y.........................: Tap on (x,y) using the 2D landmark of the device" + print "\tlong-tap x y d..................: Make a long tap on (x,y) with a duration of d (in ms) using the 2D landmark of the device" + print "\tdouble-tap x y d................: Make a double tap on (x,y) with a duration of d (in ms) using the 2D landmark of the device" + print "\ttriple-tap x y d................: Make a triple tap on (x,y) with a duration of d (in ms) using the 2D landmark of the device" + print "\tn-tap n x y.....................: Tap n times on (x,y) using the 2D landmark of the device" + print "\tstress-tap n x y................: Make n taps on (x, y) with a dedicated duration between each swipe which can be short enough to stress the app" + print "\tswipe x1 y1 x2 y2...............: Swipe from (x1, y1) to (x2, y2) using the 2D landmark of the device" + print "\tn-swipe n x1 y1 x2 y2...........: Make n swipes from (x1, y1) to (x2, y2) using the 2D landmark of the device" + print "\tstress-swipe n x1 y1 x2 y2......: Make n swipe from (x1, y1) to (x2, y2) with a dedicated duration between each swipe which can be short enough to stress the app" + print "\treset...........................: Reset the position of the bot" + print "\tget-angles......................: Get the angles of the arms of the bot" + print "\tset-angles a b c................: Define the 3 angles (a = theta 1, b = theta 2, c = theta3) for the arms of the bot" + print "\tget-position....................: Get the posiition of the arms in its 3D landmark" + print "\tset-position x y z..............: Set the position of the bot in its 3D landmark at (x,y,z) coordinates" + print "\tconfig..........................: Display the global configuration in use" + print "\tstatus..........................: What is the status of the bot?" + print "\tcheck...........................: Check if the robot's server is up" + print "\trepeat..........................: Repeat the last executed command" + print "\tdance...........................: Let's dance!" + print "\tstop-dance......................: Stop dancing" + print "\tget-calibration.................: Get the calibration data in use for the bot" + print "\tset-calibration JSON............: Define the calibraiton data to use for the bot, defined in JSON format" + print "\tcontact-z.......................: Get the Z-axis value of the contact point, i.e. the point where the device's screen should be touched" + print "\tposForScreen x y................: Get the position of the bot for these (x,y) screen-based coordinates" + print "\tangForPos x y z.................: Get the angles of the arms for the (x,y,z) 3D coordinates" + print "\tsquare n length.................: Draw a square with a dedicated length, and draw each nth point" + print "\tstar............................: Draw a star" + print "\ttriangle x1 y1 x2 y2 x3 y3......: Draw a triangle using 3 points (x1, y1) (x2, y2) (x3, y3)" + print "\tcircle x y r....................: Draw a circle centered on point (x,y) with r radius" + print "\tcross x1, y1 x2 y2 x3 y3 x4 y4..: Draw a cross using 4 points, drawing two strokes, with strokes (x1, y1) -> (x4, y4) and (x2, y2) -> (x3, y3)" + print "\tspiral x y n r..................: Draw a spiral centered on (x,y) using n rings with an r radius" + print "\trandom n minW minH maxW mawH....: Draw a random pattern with (n-1) strokes in a defined area (points picked with [minW ; maxW] and [minH; maxH])" + print "\thelp............................: Display this help" + print "\tbye.............................: Good bye!" + print "" + return +# End of Function: welcome() + +# Function: config() +def config(): + """ + Displays the configuration in use. + """ + print "" + print "\tVersion of Python client...............: " + CLIENT_VERSION + print "\tRobot's server URL.....................: " + clientConfig.ROBOT_URL + print "\tWait between tap (s)...................: " + str(WAIT_TIME_BETWEEN_TAP) + print "\tWait between stress swipe (s)..........: " + str(WAIT_TIME_STRESS_SWIPE) + print "\tWait between cascaded ops (s)..........: " + str(WAIT_BETWEEN_CASCADED_OPERATION) + print "\tWait between stress tap (s)............: " + str(WAIT_TIME_STRESS_TAP) + print "\tEscape symbol..........................: '" + ESCAPE_SYMBOL + "'" + print "\tDefault IP address of the robot........: " + DEFAULT_ROBOT_IP_ADDRESS + print "\tDefault port fo the robot..............: " + DEFAULT_ROBOT_PORT + print "\tDefault protocol of the robot..........: " + DEFAULT_ROBOT_PROTOCOL + print "\tDefault URl of the robot...............: " + DEFAULT_ROBOT_URL + print "" +# End of Function: config() + +# Function: checkFile( path ) +def checkFile( path ): + """ + Checks if the target at the end of the path is a file. + Returns True if a file, False otherwise + """ + return os.path.isfile(path) + +# Ed of Function: checkFile( path ) + +# Function: processCommandsFile( path ) +def processCommandsFile( path ): + """ + Processes the file at this path, file containing commands separated by a line break. + WIll parse each line as a command, except if the line starts with a # + """ + + # Parse the file + with open(path) as file: + lines = [line.strip() for line in file] + + # Remove empty lines + lines = [line for line in lines if len(line) > 0] + + # Process each line + lastCommand = None + command = None + for line in lines: + + # Check if commented command + if line.startswith(ESCAPE_SYMBOL): + print "Escaped command." + continue + # Repeat command, but check previously if there was a previous command + if isRepeatCommand(line): + if lastCommand == None: + print "Nope. Did you want to repeat nothing?" + continue + command = lastCommand + else: + command = line + # Command for robot + if isRobotCommand(command): + parseCommand(command) + # Client-help command + elif isHelpCommand(command): + help() + # Client-config command + elif isConfigCommand(command): + config() + else: + print "Nope. Bad command: " + command + continue + lastCommand = command + time.sleep(WAIT_BETWEEN_CASCADED_OPERATION) + +# End of Function: processCommandsFile( path ) + +# Function: askForCommand() +def askForCommand(): + """ + Asks for a command to the user. + Returns the written command. + """ + return raw_input("> Enter a command: ") +# End of Function: askForCommand() + +# Function isStopCommand( command ) +def isStopCommand( command ): + """ + Checks if the command is a stop command. + Returns a boolean value, true if the command is good, false otherwise. + """ + return bool(ROBOT_PATTERN_BYE.match(command)) +# End of Function isStopCommand( command ) + +# Function isHelpCommand( command ) +def isHelpCommand( command ): + """ + Checks if the command is an help command. + Returns a boolean value, true if the command is good, false otherwise. + """ + return bool(ROBOT_PATTERN_HELP.match(command)) +# End of Function isHelpCommand( command ) + +# Function isConfigCommand( command ) +def isConfigCommand( command ): + """ + Checks if the command is a config command. + Returns a boolean value, true if the command is good, false otherwise. + """ + return bool(ROBOT_PATTERN_CONFIG.match(command)) +# End of Function isConfigCommand( command ) + +# Function isRepeatCommand( command ) +def isRepeatCommand( command ): + """ + Checks if the command is a repeat command. + Returns a boolean value, true if the command is good, false otherwise. + """ + return bool(ROBOT_PATTERN_REPEAT.match(command)) +# End of Function isRepeatCommand( command ) diff --git a/clients/python/robot_api.py b/clients/python/robot_api.py new file mode 100644 index 00000000..4cdac6d2 --- /dev/null +++ b/clients/python/robot_api.py @@ -0,0 +1,468 @@ +# -*- coding: utf_8 -*- +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +""" +File.......: robot-api.py +Brief......: File including the API of the robot, using HTTP requests +Version....: 1.4.0 +Since......: 10/01/2018 +""" + +# ******* +# IMPORTS +# ******* + +import requests # You must install previously this module +import json +import time +import config + +# ********* +# FUNCTIONS +# ********* + +# Function: checkRobotConnection() +def checkRobotConnection(): + """ + Checks the robot server's connection, i.e. if the server is running. + Returns the True if status code is 200, False otherwise + """ + # FIXME Make a better management + try: + r = requests.head(config.ROBOT_URL+"/status") + print "Connection made. Status code: " + str(r.status_code) + return r.status_code == 200 + except requests.exceptions.ConnectionError: + print "ERROR: Connection error" + return False +# End of Function: checkRobotConnection() + +# Function: robot_getAngles() +def robot_getAngles(): + """ + Sends to the robot's server an HTTP request so as to get the arms' angles values. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending get-angles request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_GET_ANGLES) + print request.text + return request.json() +# End of Function: robot_getAngles() + +# Function robot_setAngles( theta1, theta1, theta3 ) +def robot_setAngles( theta1, theta2, theta3 ): + """ + Sends to the robot's server an HTTP request so as to set the arms' angles values. + Parameters: theta1, theta2, theta3 as float numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending set-angles request..." + payload = {'theta1': theta1, 'theta2': theta2, 'theta3': theta3} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_SET_ANGLES, data=payload) + print request.text + return request.json() +# End of Function: robot_setAngles( theta1, theta1, theta3 ) + +# Function: robot_getPosition() +def robot_getPosition(): + """ + Sends to the robot's server an HTTP request so as to get its position in 3D landmark + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending get-position request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_GET_POSITION) + print request.text + return request.json() +# End of Function: robot_getPosition() + +# Function: robot_setPosition( x, y, z ) +def robot_setPosition( x, y, z ): + """ + Sends to the robot's server an HTTP request so as to set the position of its arms in 3D landmark. + Parameters: x, y, z as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending set-position request..." + payload = {'x': x, 'y': y, 'z': z} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_SET_POSITION, data=payload) + print request.text + return request.json() +# End of Function: robot_setPosition( x, y, z ) + +# Function: robot_tap( x, y ) +def robot_tap( x, y ): + """ + Sends to the robot's server an HTTP request so as to make it tp at (x, y) using the device's 2D landmark. + Parameters: x, y as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending tap request..." + payload = {'x': x, 'y': y} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_TAP, data=payload) + print request.text + return request.json() +# End of Function: robot_tap( x, y ) + +# Function: robot_longTap( x, y, duration ) +def robot_longTap( x, y, duration ): + """ + Sends to the robot's server an HTTP request so as to make a long tap at (x, y) using the device's 2D landmark. + Parameters: x, y, duration as integer numbers, (x,) in 2D device landmark + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending long tap request..." + payload = {'x': x, 'y': y, 'duration': duration} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_LONG_TAP, data=payload) + print request.text + return request.json() +# End of Function: robot_longTap( x, y, duration ) + +# Function: robot_doubleTap( x, y, duration ) +def robot_doubleTap( x, y, duration ): + """ + Sends to the robot's server an HTTP request so as to make a double tap at (x, y) using the device's 2D landmark. + Parameters: x, y, duration as integer numbers, (x,) in 2D device landmark + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending long tap request..." + payload = {'x': x, 'y': y, 'duration': duration} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DOUBLE_TAP, data=payload) + print request.text + return request.json() +# End of Function: robot_doubleTap( x, y, duration ) + +# Function: robot_tripleTap( x, y, duration ) +def robot_tripleTap( x, y, duration ): + """ + Sends to the robot's server an HTTP request so as to make a triple tap at (x, y) using the device's 2D landmark. + Parameters: x, y, duration as integer numbers, (x,) in 2D device landmark + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending long tap request..." + payload = {'x': x, 'y': y, 'duration': duration} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_TRIPLE_TAP, data=payload) + print request.text + return request.json() +# End of Function: robot_tripleTap( x, y, duration ) + +# Function: robot_reset() +def robot_reset(): + """ + Sends to the robot's server an HTTP request so as to reset it. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending reset request..." + payload = {} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_RESET, data=payload) + print request.text + return request.json() +# End of Function: robot_reset() + +# Function: robot_getCalibration() +def robot_getCalibration(): + """ + Sends to the robot's server an HTTP request so as to get its calibration data. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending get-calibration request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_GET_CALIBRATION) + print request.text + return request.json() +# End of Function: robot_getCalibration() + +# Function: robot_setCalibration( jsonData ) +def robot_setCalibration( jsonData ): + """ + Sends to the robot's server an HTTP request so as to define its calibration data to use. + Parameter: the calibration data in JSON format. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending set-calibration request..." + payload = json.loads(jsonData) + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_SET_CALIBRATION, data=payload) + print request.text + return request.json() +# End of Function: robot_setCalibration( jsonData ) + +# Function: robot_status() +def robot_status(): + """ + Sends to the robot's server an HTTP request so as to get its status. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending get-status request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_STATUS) + print request.text + return request.json() +# End of Function: robot_status() + +# Function: robot_dance() +def robot_dance(): + """ + Sends to the robot's server an HTTP request so as to make it dance. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending dance request..." + payload = {} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DANCE) + print request.text + return request.json() +# End of Function: robot_dance() + +# Function: robot_stopDance() +def robot_stopDance(): + """ + Sends to the robot's server an HTTP request so as to make it stop dancing. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending stop-dance request..." + payload = {} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_STOP_DANCE) + print request.text + return request.json() +# End of Function: robot_stopDance() + +# Function: robot_swipe( startX, startY, endX, endY ) +def robot_swipe( startX, startY, endX, endY ): + """ + Sends to the robot's server an HTTP request so as to swipe from (startX, startY) to (endX, endY). + Parameters: startX, startY, endX, endY as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending swipe request..." + payload = {'startX': startX, 'startY': startY, 'endX': endX, 'endY': endY} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_SWIPE, data=payload) + print request.text + return request.json() +# End of Function: robot_swipe( x, y, z ) + +# Function: robot_ntap( n, x, y ) +def robot_ntap( n, x, y ): + """ + Sends to the robot's server n HTTP requests so as to tap n times on (x,y). + Parameters: n, x, y as integer numbers. + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending "+ n + " tap requests..." + payload = {'x': x, 'y': y} + for i in range(0, int(n)): + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_TAP, data=payload) + print request.text + time.sleep(config.WAIT_TIME_BETWEEN_TAP) + return request.json() +# End of Function: robot_ntap( n, x, y ) + +# Function: robot_posForScreen( x, y ) +def robot_posForScreen( x, y ): + """ + Sends to the robot's server an HTTP request so as to get the 3D coordinates according to the (x,y) 2D coordinates. + Parameters: x, y as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending posForScreen request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_POSITION_FOR_SCREEN_COORD+"/x/"+x+"/y/"+y) + print request.text + return request.json() +# End of Function: robot_posForScreen( x, y ) + +# Function: robot_angForPos( x, y, z ) +def robot_angForPos( x, y, z ): + """ + Sends to the robot's server an HTTP request so as to get the angles of the arms for the (x,y,z) 3D coordinates + Parameters: x, y, z as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending angForPos request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_ANGLES_FOR_POSITION+"/x/"+x+"/y/"+y+"/z/"+z) + print request.text + return request.json() +# End of Function: robot_angForPos( x, y, z ) + +# Function: robot_stressSwipe( n, startX, startY, endX, endY ) +def robot_stressSwipe( n, startX, startY, endX, endY ): + """ + Sends to the robot's server n HTTP requests for swipes from (startX, startY) to (endX, endY) with WAIT_TIME_STRESS_SWIPE duration between each swipe to as to stress the app. + Parameters: n, startX, startY, endX, endY as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending "+ n + " stress swipe requests..." + payload = {'startX': startX, 'startY': startY, 'endX': endX, 'endY': endY} + for i in range(0, int(n)): + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_SWIPE, data=payload) + print request.text + time.sleep(config.WAIT_TIME_STRESS_SWIPE) + return request.json() +# End of Function: robot_stressSwipe( n, startX, startY, endX, endY ) + +# Function: robot_stressTap( n, x, y ) +def robot_stressTap( n, x, y ): + """ + Sends to the robot's server n HTTP requests for taps to (x, y) with WAIT_TIME_STRESS_TAP duration between each tap to as to stress the app. + Parameters: n, x, y as integer numbers. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending "+ n + " stress tap requests..." + payload = {'x': x, 'y': y} + for i in range(0, int(n)): + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_TAP, data=payload) + print request.text + time.sleep(config.WAIT_TIME_STRESS_TAP) + return request.json() +# End of Function: robot_stressTap( n, x, y ) + +# Function: robot_getContactZ() +def robot_getContactZ(): + """ + Sends to the robot's server an HTTP request so as to get its Z contact value. + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending contact-z request..." + request = requests.get(config.ROBOT_URL + config.ROBOT_URL_CONTACT_Z) + print request.text + return request.json() +# End of Function: robot_getContactZ() + +# Function: robot_nswipe( n, startX, startY, endX, endY ) +def robot_nswipe( n, startX, startY, endX, endY ): + """ + Sends to the robot's server n HTTP requests so as to make n swipes from (startX, startY) to (endX, endY). + Parameters: n, startX, startY, endX, endY as integer numbers. + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending "+ n + " swipe requests..." + payload = {'startX': startX, 'startY': startY, 'endX': endX, 'endY': endY} + for i in range(0, int(n)): + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_SWIPE, data=payload) + print request.text + time.sleep(config.WAIT_TIME_BETWEEN_SWIPE) + return request.json() +# End of Function: robot_nswipe( n, startX, startY, endX, endY ) + +# Function: robot_drawSquare( n, length ) +def robot_drawSquare( n, length ): + """ + Sends to the robot's serverHTTP requests so as to draw a square with a dedicated length, and draw each n points + Parameters: n, length integer numbers. + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending draw square request..." + payload = {'n': n, 'length': length} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_SQUARE, data=payload) + print request.text + return request.json() +# End of Function: robot_drawSquare( n, length ) + + +# Function: robot_drawStar() +def robot_drawStar(): + """ + Sends to the robot's server an HTTP request so as to draw a star + Displays a text and readable results of the command. + Returns the results of the command. + """ + print "Sending draw star request..." + payload = {} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_STAR, data=payload) + print request.text + return request.json() +# End of Function: robot_getContactZ() + +# Function: robot_drawTriangle(x1, y1, x2, y2, x3, y3) +def robot_drawTriangle(x1, y1, x2, y2, x3, y3): + """ + Sends to the robot's server HTTP requests so as to draw a triangle using poitns (x1,y1) (x2,y2) (x3,y3) + Parameters: x1, y1, x2, y2, x3, y3 as integer numbers, based on device 2D landmark + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending draw triangle request..." + payload = {'x1': x1, 'y1': y1, 'x2': x2,'y2': y2, 'x3': x3,'y3': y3} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_TRIANGLE, data=payload) + print request.text + return request.json() +# End of Function: robot_drawTriangle(x1, y1, x2, y2, x3, y3) + +# Function: robot_drawCircle(x, y, r) +def robot_drawCircle(x, y, r): + """ + Sends to the robot's server an HTTP requests so as to draw a circle centered on(x,y) with r radius + Parameters: x, y, r as integer numbers, based on device 2D landmark + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending draw circle request..." + payload = {'x': x, 'y': y, 'r': r} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_CIRCLE, data=payload) + print request.text + return request.json() +# End of Function: robot_drawCircle(x, y, r) + +# Function: robot_drawCross(x1, y1, x2, y2, x3, y3, x4, y4) +def robot_drawCross(x1, y1, x2, y2, x3, y3, x4, y4): + """ + Sends to the robot's server an HTTP requests so as to draw a cross using 4 points + Parameters: x1, y1, x2, y2, x3, y3, x4, y4 as integer numbers, based on device 2D landmark + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending draw cross request..." + payload = {'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2, 'x3': x3, 'y3': y3, 'x4': x4, 'y4': y4} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_CROSS, data=payload) + print request.text + return request.json() +# End of Function: robot_drawCross(x1, y1, x2, y2, x3, y3, x4, y4) + +# Function: robot_drawSpiral(x, y, n, r) +def robot_drawSpiral(x, y, n, r): + """ + Sends to the robot's server an HTTP requests so as to draw a spiral starting from a points, with n rings and a radius r + Parameters: x, y, n ,r as integer numbers, based on device 2D landmark + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending draw spiral request..." + payload = {'x': x, 'y': y, 'n': n, 'r': r} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_SPIRAL, data=payload) + print request.text + return request.json() +# End of Function: robot_drawSpiral(x, y, n, r) + +# Function: robot_drawRandom(n, minWidth, minHeight, maxWidth, maxHeight) +def robot_drawRandom(n, minWidth, minHeight, maxWidth, maxHeight): + """ + Sends to the robot's server an HTTP requests so as to draw a random pattern + with (n-1) strokes in a defined area (points picked with [minWidth ; minHeight] and [maxWidth; maxHeight]) + Parameters: n, minWidth, minHeight, maxWidth, maxHeight as integer numbers, based on device 2D landmark + Displays a text and readable results of the command. + Returns the results of the last executed command. + """ + print "Sending draw random request..." + payload = {'n': n, 'minWidth': minWidth, 'minHeight': minHeight, 'maxWidth': maxWidth, 'maxHeight': maxHeight} + request = requests.post(config.ROBOT_URL + config.ROBOT_URL_DRAW_RANDOM, data=payload) + print request.text + return request.json() +# End of Function: robot_drawRandom(n, minWidth, minHeight, maxWidth, maxHeight) diff --git a/clients/robotframework/README.md b/clients/robotframework/README.md new file mode 100644 index 00000000..5e0cf112 --- /dev/null +++ b/clients/robotframework/README.md @@ -0,0 +1,24 @@ +# robotframework folder + +Here are elements defining [Robot Framework](http://robotframework.org/ "Robot Framework homepage") keywords to integrate into test cases. + +## List of files + - _config.robot_ The configuration file used in the one containing keywords + - *tapster_keywords.robot* The file containing the keywords to integrate in your test cases, using the configuration file + - *tapster_wrapper.robot* The wrapper using Tapster and Appium keywords to bring more abstraction for tests + - *demo/tapster_demo.robot* Just a file with test cases using the keywords and the configuration defined in the other files. + +## How to use the client + 1. Thirst you need to install on your computer these libraries so send HTTP requests (for the keywords) and use Appium (for the wrapper) + ```shell + pip install -U requests + pip install -U robotframework-requests + pip install robotframework-appiumlibrary + ``` + +## Note + 1. Here a the Robot Framework [user guide](http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html "User guide") + 2. You may need to get the [robotframework-requests library](https://github.com/bulkan/robotframework-requests "GitHub of robotframework-requests") + 3. The installed version of _robotframework_requests_ library is **0.4.7** + 4. You will need also the [Appium library](https://github.com/serhatbolsu/robotframework-appiumlibrary "GitHub of AppiumLibrary for Robot Framework") + 5. The installed version of _Appium_ library for _Robot Framework_ is **1.4.3** diff --git a/clients/robotframework/config.robot b/clients/robotframework/config.robot new file mode 100644 index 00000000..0b274ced --- /dev/null +++ b/clients/robotframework/config.robot @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +# +# File.......: config.robot +# Brief......: File contaning configuration to apply to kewyrods +# Version....: 2.0.0 +# Since......: 17/01/2018 + +*** Settings *** + +Documentation +... Here are the variables which will be used by the keywords. +... You can define here the IP adress of the robot, the port in use or other things. + +*** Variables *** + +# Version of the Robot Framework "client" +${CLIENT_VERSION} v2.0.0 + +# ************ +# Robot things +# ************ + +# Default IP address where the Tapster2 bot is reachable +${DEFAULT_ROBOT_IP_ADDRESS} 127.0.0.1 + +# Default port to use to as to reach the robot +${DEFAULT_ROBOT_PORT} 4242 + +# Default protocol to use for the robot +${DEFAULT_ROBOT_PROTOCOL} http + +# Default URL to use to as to reach the robot +${DEFAULT_ROBOT_URL} ${DEFAULT_ROBOT_PROTOCOL}://${DEFAULT_ROBOT_IP_ADDRESS}:${DEFAULT_ROBOT_PORT} + +# Delay in seconds between each tap +${WAIT_TIME_BETWEEN_TAP} 0.5s + +# Delay in seconds between each swipe +${WAIT_TIME_BETWEEN_SWIPE} 0.5s + +# Delay in seconds between each swipe during stress swipes process +${WAIT_TIME_STRESS_SWIPE} 0.33s + +# Delay in seconds between each tap during stress taps process +${WAIT_TIME_STRESS_TAP} 0.25s + +# The default duration for a long tap, in milliseconds +${DEFAULT_DURATION_LONG_TAP} 1500 + +# The default duration for a double or triple tap, duration between each tap, in milliseconds +${DEFAULT_DURATION_MULTI_TAP} 100 + +# Deal in seconds between each operation picked and triggered from a commands file +${WAIT_BETWEEN_CASCADED_OPERATION} 0.5s + +# The escape symbol to commnt a command store din the commands files +${ESCAPE_SYMBOL} # + +# **************** +# URL of Robot API +# **************** + +${ROBOT_URL_GET_ANGLES} /angles +${ROBOT_URL_SET_ANGLES} /setAngles +${ROBOT_URL_GET_POSITION} /position +${ROBOT_URL_SET_POSITION} /setPosition +${ROBOT_URL_TAP} /tap +${ROBOT_URL_DOUBLE_TAP} /doubleTap +${ROBOT_URL_TRIPLE_TAP} /tripleTap +${ROBOT_URL_LONG_TAP} /longTap +${ROBOT_URL_RESET} /reset +${ROBOT_URL_GET_CALIBRATION} /calibrationData +${ROBOT_URL_SET_CALIBRATION} /setCalibrationData +${ROBOT_URL_STATUS} /status +${ROBOT_URL_DANCE} /dance +${ROBOT_URL_STOP_DANCE} /stopDancing +${ROBOT_URL_SWIPE} /swipe +${ROBOT_URL_POSITION_FOR_SCREEN_COORD} /positionForScreenCoordinates +${ROBOT_URL_ANGLES_FOR_POSITION} /anglesForPosition +${ROBOT_URL_CONTACT_Z} /contactZ +${ROBOT_URL_DRAW_RANDOM} /drawRandomPattern +${ROBOT_URL_DRAW_STAR} /drawStar +${ROBOT_URL_DRAW_CIRCLE} /drawCircle +${ROBOT_URL_DRAW_CROSS} /drawCross +${ROBOT_URL_DRAW_SQUARE} /drawSquare +${ROBOT_URL_DRAW_TRIANGLE} /drawTriangle +${ROBOT_URL_DRAW_SPIRAL} /drawSpiral + diff --git a/clients/robotframework/tapster_keywords.robot b/clients/robotframework/tapster_keywords.robot new file mode 100644 index 00000000..0b1f974b --- /dev/null +++ b/clients/robotframework/tapster_keywords.robot @@ -0,0 +1,514 @@ +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +# +# File.......: tapster_keywords.robot +# Brief......: File contaning Robot Framework keywords to use to as to deal with the Tapster2 bot +# Version....: 2.0.0 +# Since......: 17/01/2018 + + +*** Settings *** + +Documentation +... Here are keywords you can use in your Robot Framework tests cases. +... If you are in a TDD/BDD/ATDD method, you may need to test your mobile applications with a Tapster 2 robot. +... You can find here kewyrods to integrate so as to deal with the robot's API. +... The things you can do with another client can be done with these keywords. +... Be aware that keywords send HTTP requests to robot's server, so cascaded operations might be a mess, feel free to add wait operation between them. + +Library RequestsLibrary +Library json +Library Collections + +Resource config.robot + + +*** Keywords *** + +# ######### +# Some glue +# ######### + +Create robot session + [Documentation] Creates a network session (using RequestsLibrary) with the robot with a dedicated alias and maybe a robot's server URL. + ... You must create a session before using the robot. + ... Parameters: + ... session_alias - the alias of the session + ... roboturl - optional, the URL of the server running the robot + ... Returns: + ... the created session. + [Arguments] ${session_alias} ${roboturl}=${DEFAULT_ROBOT_URL} + ${session} = Create Session ${session_alias} ${roboturl} + [Return] ${session} + +Delete robot session + [Documentation] Deletes an existing session which have this alias + ... Parameters: + ... session_alias - the alias of the session + ... roboturl - optional, the URL of the server running the robot + ... Returns: + ... the result of the deletion request + [Arguments] ${session_alias} ${roboturl}=${DEFAULT_ROBOT_URL} + ${results} = Delete Request ${session_alias} ${roboturl} + [Return] ${results} + +Wait + [Documentation] Waits during a time so as to let the robot's server process its last received request. + ... Indeed this server cannot temporise/cache request itself yet, here is a trick to temporise in the client side. + ... Parameters: + ... duration - the duration to wait, by default WAIT_BETWEEN_CASCADED_OPERATION + [Arguments] ${duration}=${WAIT_BETWEEN_CASCADED_OPERATION} + Sleep ${duration} + +# ########### +# Robot's API +# ########### + +Check connection of robot + [Documentation] Checks if the connection of the robot with the given session has been established. + ... Parameters: + ... session - the session for this robot + ... Returns: + ... the status code sent by the robot's server. + [Arguments] ${session} + ${response} = Head Request ${session} ${ROBOT_URL_STATUS} + Should Be Equal As Strings ${response.status_code} 200 + Wait + [Return] ${response.status_code} + +Get angles of arms + [Documentation] Returns the angles the arms of the robot have using the given session. + ... Parameters: + ... session - the session for this robot + ... Returns: + ... the angles + [Arguments] ${session} + ${response} = Get Request ${session} ${ROBOT_URL_GET_ANGLES} + Wait + [Return] ${response.text} + +Set angles of arms + [Documentation] Defines the (theta1, theta2, theta3) angles of the arms the robot should have with the given session + ... Parameters: + ... session - the session for this robot + ... Returns: + ... the response of the robot's server + [Arguments] ${session} ${theta1} ${theta2} ${theta3} + &{angles_raw} = Create Dictionary theta1=${theta1} theta2=${theta2} theta3=${theta3} + ${angles} = json.dumps ${angles_raw} + ${response} = Post Request ${session} ${ROBOT_URL_SET_ANGLES} data=${angles} + Wait + [Return] ${response.text} + +Get 3D position + [Documentation] Returns the position in 3D landmark of the robot with the given session + ... Parameters: + ... session - the session for this robot + ... Returns: + ... the 3D position in robot's landmark + [Arguments] ${session} + ${response} = Get Request ${session} ${ROBOT_URL_GET_POSITION} + Wait + [Return] ${response.text} + +Set 3D position + [Documentation] Defines the (x, y, z) position the robot must have with the given session + ... Parameters: + ... session - the session for this robot + ... x - The x value + ... y - The y value + ... z - The z value, where around -155 is the value where the baseplate is reached + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${z} + &{position_raw} = Create Dictionary x=${x} y=${y} z=${z} + ${position} = json.dumps ${position_raw} + ${response} = Post Request ${session} ${ROBOT_URL_SET_POSITION} data=${position} + Wait + [Return] ${response.text} + +Tap to point + [Documentation] Makes the robot with the given session tap to the point at (x, y) + ... Parameters: + ... session - the session for this robot + ... x - The x value of the point to tap + ... y - The y value of the point to tap + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} + &{tap_raw} = Create Dictionary x=${x} y=${y} + ${tap} = json.dumps ${tap_raw} + ${response} = Post Request ${session} ${ROBOT_URL_TAP} data=${tap} + Wait + [Return] ${response.text} + +Long tap to point + [Documentation] Makes the robot with the given session tap to the point at (x, y) during duration in ms + ... Parameters: + ... session - the session for this robot + ... x - The x value of the point to tap + ... y - The y value of the point to tap + ... duration - The duration for the contact (optional, default valued to DEFAULT_DURATION_LONG_TAP) + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${duration}=${DEFAULT_DURATION_LONG_TAP} + &{long_tap_raw} = Create Dictionary x=${x} y=${y} duration=${duration} + ${long_tap} = json.dumps ${long_tap_raw} + ${response} = Post Request ${session} ${ROBOT_URL_LONG_TAP} data=${long_tap} + ${duration_in_seconds} = Evaluate ${duration}/1000 + Wait ${duration_in_seconds} + [Return] ${response.text} + +Double tap to point + [Documentation] Makes the robot with the given session tap twice to the point at (x, y) during duration in ms + ... Parameters: + ... session - the session for this robot + ... x - The x value of the point to tap + ... y - The y value of the point to tap + ... duration - The duration to wait between two contact (optional, default valued to DEFAULT_DURATION_MULTI_TAP) + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${duration}=${DEFAULT_DURATION_MULTI_TAP} + &{double_tap_raw} = Create Dictionary x=${x} y=${y} duration=${duration} + ${double_tap} = json.dumps ${double_tap_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DOUBLE_TAP} data=${double_tap} + Wait + [Return] ${response.text} + +Triple tap to point + [Documentation] Makes the robot with the given session tap three times to the point at (x, y) during duration in ms + ... Parameters: + ... session - the session for this robot + ... x - The x value of the point to tap + ... y - The y value of the point to tap + ... duration - The duration to wait between each contact (optional, default valued to DEFAULT_DURATION_MULTI_TAP) + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${duration}=${DEFAULT_DURATION_MULTI_TAP} + &{triple_tap_raw} = Create Dictionary x=${x} y=${y} duration=${duration} + ${triple_tap} = json.dumps ${triple_tap_raw} + ${response} = Post Request ${session} ${ROBOT_URL_TRIPLE_TAP} data=${triple_tap} + Wait + [Return] ${response.text} + +Reset + [Documentation] Resets the position / arms of the robot to their default values with the given session + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + &{empty_payload_raw} = Create Dictionary + ${empty_payload} = json.dumps ${empty_payload_raw} + ${response} = Post Request ${session} ${ROBOT_URL_RESET} data=${empty_payload} + Wait + [Return] ${response.text} + +Get calibration data + [Documentation] Returns the calibration data of the robot with the given session + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + ${response} = Get Request ${session} ${ROBOT_URL_GET_CALIBRATION} + Wait + [Return] ${response.text} + +Set calibration data + [Documentation] Defines the calibation data in JSON format to apply to the robot with the given session. + ... Parameters: + ... session - the session for this robot + ... calibraiton_data - The JSON object, stringigied, contaniing calibration elements + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${calibration_data} + ${response} = Post Request ${session} ${ROBOT_URL_SET_CALIBRATION} data=${calibration_data} + Wait + [Return] ${response.text} + +Get status + [Documentation] Returns the status of the robot's server with the given session + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + ${response} = Get Request ${session} ${ROBOT_URL_STATUS} + Wait + [Return] ${response.text} + +Dance + [Documentation] Make the robot dance with the given session! + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + &{empty_payload_raw} = Create Dictionary + ${empty_payload} = json.dumps ${empty_payload_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DANCE} data=${empty_payload} + Wait + [Return] ${response.text} + +Stop dance + [Documentation] Make the robot stop dancing with the given session :-( + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + &{empty_payload_raw} = Create Dictionary + ${empty_payload} = json.dumps ${empty_payload_raw} + ${response} = Post Request ${session} ${ROBOT_URL_STOP_DANCE} data=${empty_payload} + Wait + [Return] ${response.text} + +Swipe + [Documentation] Makes the robot with the given session swipe from (a,b) to (c,d) + ... Parameters: + ... session - the session for this robot + ... a - the x value of the start point + ... b - the y value of the start point + ... c - the x value of the end point + ... d - the y value of the end point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${a} ${b} ${c} ${d} + &{swipe_raw} = Create Dictionary startX=${a} startY=${b} endX=${c} endY=${d} + ${swipe} = json.dumps ${swipe_raw} + ${response} = Post Request ${session} ${ROBOT_URL_SWIPE} data=${swipe} + Wait + [Return] ${response.text} + +Tap n times + [Documentation] Makes the robot with the given session tap n times on (x,y) + ... Parameters: + ... session - the session for this robot + ... n - the number of taps to process + ... x - the x value of the point to tap on + ... y - the y value of the point to tap on + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${n} ${x} ${y} + &{tap_raw} = Create Dictionary x=${x} y=${y} + ${tap} = json.dumps ${tap_raw} + : FOR ${INDEX} IN RANGE 0 ${n} + \ ${response} = Post Request ${session} ${ROBOT_URL_TAP} data=${tap} + \ Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Swipe n times + [Documentation] Makes the robot with the given session swipes n times from (a,b) to (c,d) + ... Parameters: + ... session - the session for this robot + ... n - the number of swipes to do + ... a - the x value of the start point + ... b - the y value of the start point + ... c - the x value of the end point + ... d - the y value of the end point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${n} ${a} ${b} ${c} ${d} + &{swipe_raw} = Create Dictionary startX=${a} startY=${b} endX=${c} endY=${d} + ${swipe} = json.dumps ${swipe_raw} + : FOR ${INDEX} IN RANGE 0 ${n} + \ ${response} = Post Request ${session} ${ROBOT_URL_SWIPE} data=${swipe} + \ Wait ${WAIT_TIME_BETWEEN_SWIPE} + [Return] ${response.text} + +Position for screen + [Documentation] Gets the position of the robot (using the given session) according to an (x,y) 2D device landmark point + ... Parameters: + ... session - the session for this robot + ... x - the x value of the point + ... y - the y value of the point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} + ${url} = Catenate SEPARATOR= ${ROBOT_URL_POSITION_FOR_SCREEN_COORD} /x/ ${x} /y/ ${y} + ${response} = Get Request ${session} ${url} + Wait + [Return] ${response.text} + +Angles for position + [Documentation] Gets the angles of the robot's arms for the (x, y, z) 3D point + ... Parameters: + ... session - the session for this robot + ... x - the x value of the point + ... y - the y value of the point + ... z - the z value of the point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${z} + ${url} = Catenate SEPARATOR= ${ROBOT_URL_ANGLES_FOR_POSITION} /x/ ${x} /y/ ${y} /z/ ${z} + ${response} = Get Request ${session} ${url} + Wait + [Return] ${response.text} + +Get contact Z + [Documentation] Gets the Z-axis value of the contact point the robot has (using the given session) + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + ${response} = Get Request ${session} ${ROBOT_URL_CONTACT_Z} + Wait + [Return] ${response.text} + +Stress taps + [Documentation] Stresses the app under the robot with n quick taps on (x,y) 2D point using a session + ... Parameters: + ... session - the session for this robot + ... n - the number of very quick taps to process + ... x - the x value of the impact point + ... y - the y value of the impact point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${n} ${x} ${y} + &{tap_raw} = Create Dictionary x=${x} y=${y} + ${tap} = json.dumps ${tap_raw} + : FOR ${INDEX} IN RANGE 0 ${n} + \ ${response} = Post Request ${session} ${ROBOT_URL_TAP} data=${tap} + \ Wait ${WAIT_TIME_STRESS_TAP} + [Return] ${response.text} + +Stress swipes + [Documentation] Stresses the app under the robot with n quick swipes from (a,b) to (c,d) using a session + ... Parameters: + ... session - the session for this robot + ... n - the number of very quick swipes to process + ... a - the x value of the start point + ... b - the y value of the start point + ... c - the x value of the end point + ... d - the y value of the end point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${n} ${a} ${b} ${c} ${d} + &{swipe_raw} = Create Dictionary startX=${a} startY=${b} endX=${c} endY=${d} + ${swipe} = json.dumps ${swipe_raw} + : FOR ${INDEX} IN RANGE 0 ${n} + \ ${response} = Post Request ${session} ${ROBOT_URL_SWIPE} data=${swipe} + \ Wait ${WAIT_TIME_STRESS_SWIPE} + [Return] ${response.text} + +Draw random pattern + [Documentation] Draws a random pattern with strokes usgin n points in a defined area + ... Parameters: + ... session - the session for this robot + ... n - the number points where their x and y are picked from [minWidth, maxWidth] for and [minHeight, maxHeight] for y + ... minWidth - the x value of the start point + ... minHeight - the y value of the start point + ... maxWidth - the x value of the end point + ... maxHeight - the y value of the end point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${n} ${minWidth} ${minHeight} ${maxWidth} ${maxHeight} + &{draw_raw} = Create Dictionary n=${n} minWidth=${minWidth} minHeight=${minHeight} maxWidth=${maxWidth} maxHeight=${maxHeight} + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_RANDOM} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Draw star + [Documentation] Draws a simple star + ... Parameters: + ... session - the session for this robot + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} + &{draw_raw} = Create Dictionary + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_STAR} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Draw circle + [Documentation] Draws a circle centered on (x,y) with r radius + ... Parameters: + ... session - the session for this robot + ... x - the x value of the center point + ... y - the y value of the center point + ... r - the radius of the circle + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${r} + &{draw_raw} = Create Dictionary x=${x} y=${y} r=${r} + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_CIRCLE} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Draw cross + [Documentation] Draws a cross using 4 corner points (1, 2, 3, 4) and two storkes (1 -> 3 and 2 -> 4) + ... Parameters: + ... session - the session for this robot + ... x1 - the x value of the corner point 1 + ... y1 - the y value of the corner point 1 + ... x2 - the x value of the corner point 2 + ... y2 - the y value of the corner point 2 + ... x3 - the x value of the corner point 3 + ... y3 - the y value of the corner point 3 + ... x4 - the x value of the corner point 4 + ... y4 - the y value of the corner point 4 + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x1} ${y1} ${x2} ${y2} ${x3} ${y3} ${x4} ${y4} + &{draw_raw} = Create Dictionary x1=${x1} y1=${y1} x2=${x2} y2=${y2} x3=${x3} y3=${y3} x4=${x4} y4=${y4} + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_CROSS} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Draw square + [Documentation] Draws a square + ... Parameters: + ... session - the session for this robot + ... n - draw ech nth point + ... length - the length of the square + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${n} ${length} + &{draw_raw} = Create Dictionary n=${n} length=${length} + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_SQUARE} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Draw triangle + [Documentation] Draws a triangle using three points + ... Parameters: + ... session - the session for this robot + ... x1 - the X axis value of the 1st point + ... y1 - the Y axis value of the 1st point + ... x2 - the X axis value of the 2nd point + ... y2 - the Y axis value of the 2nd point + ... x3 - the X axis value of the 3rd point + ... y3 - the Y axis value of the 3rd point + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x1} ${y1} ${x2} ${y2} ${x3} ${y3} + &{draw_raw} = Create Dictionary x1=${x1} y1=${y1} x2=${x2} y2=${y2} x3=${x3} y3=${y3} + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_TRIANGLE} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} + +Draw spiral + [Documentation] Draws a spiral using a center point (x,y), n loops and an r radius + ... Parameters: + ... session - the session for this robot + ... x - the X axis value of the center point + ... y - the Y axis value of the center point + ... n - the number of loops to draw + ... r - the radius of the spiral + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${session} ${x} ${y} ${n} ${r} + &{draw_raw} = Create Dictionary x=${x} y=${y} n=${n} r=${r} + ${draw} = json.dumps ${draw_raw} + ${response} = Post Request ${session} ${ROBOT_URL_DRAW_SPIRAL} data=${draw} + Wait ${WAIT_TIME_BETWEEN_TAP} + [Return] ${response.text} diff --git a/clients/robotframework/tapster_wrapper.robot b/clients/robotframework/tapster_wrapper.robot new file mode 100644 index 00000000..55c50302 --- /dev/null +++ b/clients/robotframework/tapster_wrapper.robot @@ -0,0 +1,1018 @@ +# SPDX-FileCopyrightText: 2018 Orange SA +# SPDX-License-Identifier: BSD-2-Clause OR MIT + +# File: tapster_wrapper.robot +# Brief: Robot Framework file providing feature to use so as to click on items with Tapster bot +# Version: 3.0.0 +# Since: 29/05/2018 + +*** Settings *** + +Documentation +... Here are keywords so use to as to get widgets (through Appium) and click on them (with Tapster bot) + +Library AppiumLibrary + +Resource ./tapster_keywords.robot + +*** Keywords *** + +# ############### +# Useful keywords +# ############### + +Tap To Point + [Documentation] Make a tap to a 2D point, using coodinates based on the 2D smartphone screen landmark. + ... Parameters: + ... x - the value in the X axis of the target point + ... y - the value in the Y axis of the target point + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x} ${y} ${offset_x}=0 ${offset_y}=0 + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Element With Id + [Documentation] Make a tap to an element, in portrait mode, which has this id. + ... The contact point will be computed according to location and dimension of the widget. + ... Parameters: + ... id - the id of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${id} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Element With Text + [Documentation] Make a tap to an element, in portrait mode, which has this text. + ... The contact point will be computed according to location and dimension of the widget. + ... Parameters: + ... text - the text of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${text} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Element With Xpath + [Documentation] Make a tap to an element, in portrait mode, using this XPath locator. + ... The contact point will be computed according to location and dimension of the widget. + ... Parameters: + ... xpath_locator - the text of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${xpath_locator} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap Somewhere To Element With Id + [Documentation] Tap somewhere onto the element with this id + ... The contact point will be computed according to location and dimension of the widget, using a random value. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... id - the id of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${id} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Random Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap Somewhere To Element With Text + [Documentation] Tap somewhere onto the element with this text + ... The contact point will be computed according to location and dimension of the widget, using a random value. + ... If there are several widgets with this text, will keep the 1st. + ... Parameters: + ... text - the text of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${text} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Random Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap Somewhere To Element With Xpath + [Documentation] Tap somewhere onto the element using this XPath locator + ... The contact point will be computed according to location and dimension of the widget, using a random value. + ... If there are several widgets matching this XPath locator, will keep the 1st. + ... Parameters: + ... xpath_locator - the text of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${xpath_locator} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Random Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Landscape Element With Text + [Documentation] Unstable! Keyword "Get Window Width" missing in AppiumLibrary + # Tap to an element, in landscape mode, which has this text. + # The contact point will be computed according to location and dimension of the widget. + # If there are several widgets with this text, will keep the 1st. + [Arguments] ${text} ${offset_x}=0 ${offset_y}=0 + # Coordinates in landscape mode! + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + # Robot does not care of orientation, need to convert to fake portrait mode + ${screen_width} = Get Window width # Does not work O_o, unknown keyword in AppiumLibrary! + ${y} = Evaluate ${x} + ${x} = Evaluate ${screen_width}-${y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${y} ${x} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Landscape Element With Id + [Documentation] Unstable! Keyword "Get Window Width" missing in AppiumLibrary + # Tap to an element, in landscape mode, which has this id. + # The contact point will be computed according to location and dimension of the widget. + # If there are several widgets with this id, will keep the 1st. + [Arguments] ${id} ${offset_x}=0 ${offset_y}=0 + # Coordinates in landscape mode! + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + # Robot does not care of orientation, need to convert to fake portrait mode + ${screen_width} = Get Window width # Does not work O_o, unknown keyword in AppiumLibrary! + ${y} = Evaluate ${x} + ${x} = Evaluate ${screen_width}-${y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap to point my_session ${y} ${x} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Element N Times With Id + [Documentation] Tap n times to the element with this id + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... N - the number of times the tpa will be made + ... id - the id of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${id} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap n times my_session ${N} ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Element N Times With Text + [Documentation] Tap n times to this element with this text + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... N - the number of times the tpa will be made + ... text - the text of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${text} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap n times my_session ${N} ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Tap To Element N Times With XPath + [Documentation] Tap n times to this element with this XPath locator + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... N - the number of times the tpa will be made + ... xpath_locator - the XPath lcoator to use to get and tap on the element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${xpath_locator} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Tap n times my_session ${N} ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Long Tap To Point + [Documentation] Make a long tap to a point + ... Use coordinates based on the 2D device screen landmark. + ... Parameters: + ... x - the value on the X axis of the target point + ... y - the value on the Y axis of the target point + ... duration - optional, default valued to DEFAULT_DURATION_LONG_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x} ${y} ${duration}=${DEFAULT_DURATION_LONG_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Long tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Long Tap To Element With Id + [Documentation] Make a long tap to an element, in portrait mode, which has this id. + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... The duration is by default ${DEFAULT_DURATION_LONG_TAP} (in ms) + ... Parameters: + ... id - the id of the element to tap on + ... duration - optional, default valued to DEFAULT_DURATION_LONG_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${id} ${duration}=${DEFAULT_DURATION_LONG_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Long tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Long Tap To Element With Text + [Documentation] Make a long tap to an element, in portrait mode, which has this text. + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this text, will keep the 1st. + ... The duration is by default ${DEFAULT_DURATION_LONG_TAP} (in ms) + ... Parameters: + ... text - the text of the element to tap on + ... duration - optional, default valued to DEFAULT_DURATION_LONG_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${text} ${duration}=${DEFAULT_DURATION_LONG_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Long tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Long Tap To Element With Xpath + [Documentation] Make a long tap to an element, in portrait mode, with this XPath locator + ... The contact point will be computed according to location and dimension of the widget. + ... If several widgets match with this locator, will keep the 1st. + ... The duration is by default ${DEFAULT_DURATION_LONG_TAP} (in ms) + ... Parameters: + ... xpath_locator - the XPath locator to use to select the item to tap on + ... duration - optional, default valued to DEFAULT_DURATION_LONG_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${xpath_locator} ${duration}=${DEFAULT_DURATION_LONG_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Long tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Double Tap To Point + [Documentation] Make a double tap to a point + ... Use coordinates based on the 2D device screen landmark. + ... Parameters: + ... x - the value on the X axis of the target point + ... y - the value on the Y axis of the target point + ... duration - optional, default valued to DEFAULT_DURATION_LONG_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x} ${y} ${duration}=${DEFAULT_DURATION_LONG_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Double tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Double Tap To Element With Id + [Documentation] Make a double tap to an element, in portrait mode, which has this id. + ... The contact point will be computed according to location and dimension of the widget. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... id - the id of the target element + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${id} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Double tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Double Tap To Element With Text + [Documentation] Make a double tap to an element, in portrait mode, which has this text. + ... The contact point will be computed according to location and dimension of the widget. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... text - the text of the target element + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${text} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Double tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Double Tap To Element With Xpath + [Documentation] Make a double tap to an element, in portrait mode, using this XPath locator + ... The contact point will be computed according to location and dimension of the widget. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... xpath_locator - the XPath locator to find the element + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${xpath_locator} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Double tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Triple Tap To Point + [Documentation] Make a triple tap to a point. + ... Coordinates in use are based on the 2D device screen landmark. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... x - the value on the X axis of the target point + ... y - the value on the Y axis of the target point + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x} ${y} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Triple tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Triple Tap To Element With Id + [Documentation] Make a triple tap to an element, in portrait mode, which has this id. + ... The contact point will be computed according to location and dimension of the widget. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... id - the id of the target element + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${id} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Triple tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Triple Tap To Element With Text + [Documentation] Make a triple tap to an element, in portrait mode, which has this text. + ... The contact point will be computed according to location and dimension of the widget. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... xpath_locator - the XPath lcoator tor each the element and tap on it + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${xpath_locator} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Triple tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Triple Tap To Element With Xpath + [Documentation] Make a triple tap to an element, in portrait mode, using this XPath locator + ... The contact point will be computed according to location and dimension of the widget. + ... The duration is by default ${DEFAULT_DURATION_MULTI_TAP} (in ms) + ... Parameters: + ... xpath_locator - the locator to use to get the target element + ... duration - optional, default valued to DEFAULT_DURATION_MULTI_TAP, duration of the contact + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${xpath_locator} ${duration}=${DEFAULT_DURATION_MULTI_TAP} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Triple tap to point my_session ${x} ${y} ${duration} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stresstap To Element With Id + [Documentation] Tap n times very quickly to this element with this id + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... N - the number of times the tap will be made + ... id - the id of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${id} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Id ${id} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress taps my_session ${N} ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stresstap To Element With Text + [Documentation] Tap n times very quickly to this element with this text + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... N - the number of times the tap will be made + ... text - the text of the target element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${text} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Text ${text} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress taps my_session ${N} ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stresstap To Element With XPath + [Documentation] Tap n times very quickly to this element with this XPath locator + ... The contact point will be computed according to location and dimension of the widget. + ... If there are several widgets with this id, will keep the 1st. + ... Parameters: + ... N - the number of times the tap will be made + ... xpath_locator - the XPath lcoator to use to reach the element and tap on it + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${xpath_locator} ${offset_x}=0 ${offset_y}=0 + ${x} ${y} = Get Suitable Contact Point For Widget With Xpath ${xpath_locator} + ${x} = Evaluate ${x}+${offset_x} + ${y} = Evaluate ${y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress taps my_session ${N} ${x} ${y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe + [Documentation] Swipe one time from (a,b) to (c,d) points + ... Parameters: + ... a - the X value of the start point + ... b - the Y value of the start point + ... c - the X value of the end point + ... d - the Y value of the end point + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${a} ${b} ${c} ${d} ${offset_x}=0 ${offset_y}=0 + ${new_a} = Evaluate ${a}+${offset_x} + ${new_b} = Evaluate ${b}+${offset_y} + ${new_c} = Evaluate ${c}+${offset_x} + ${new_d} = Evaluate ${d}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe my_session ${new_a} ${new_b} ${new_c} ${new_d} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe Using Elements Id + [Documentation] Swipe from an element to another using their id + ... Parameters: + ... source_id - id of the start element + ... destination_id - id of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${source_id} ${destination_id} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Id ${source_id} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Id ${destination_id} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe my_session ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe Using Elements Text + [Documentation] Swipe from an element to another using their texts + ... Parameters: + ... source_text - text of the start element + ... destination_text - text of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${source_text} ${destination_text} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Text ${source_text} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Text ${destination_text} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe my_session ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe Using Elements Xpath + [Documentation] Swipe from an element to another using XPath locators + ... Parameters: + ... source_xpath - XPath locator to find the start element + ... destination_xpath - XPath lcoator to find the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${source_xpath} ${destination_xpath} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Xpath ${source_xpath} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Xpath ${destination_xpath} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe my_session ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe N Times + [Documentation] Swipe N times from (a,b) to (c,d) points + ... Parameters: + ... N - the number of swipes wich will be made + ... a - the X value of the start point + ... b - the Y value of the start point + ... c - the X value of the end point + ... d - the Y value of the end point + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${a} ${b} ${c} ${d} ${offset_x}=0 ${offset_y}=0 + ${new_a} = Evaluate ${a}+${offset_x} + ${new_b} = Evaluate ${b}+${offset_y} + ${new_c} = Evaluate ${c}+${offset_x} + ${new_d} = Evaluate ${d}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe n times my_session ${N} ${new_a} ${new_b} ${new_c} ${new_d} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe N Times Using Elements Id + [Documentation] Swipe from an element to another using their id, n times + ... Parameters: + ... N - the number of times the swipes will be made + ... source_id - id of the start element + ... destination_id - id of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${source_id} ${destination_id} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Id ${source_id} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Id ${destination_id} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe n times my_session ${N} ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe N Times Using Elements Text + [Documentation] Swipe from an element to another using their text contents, n times + ... Parameters: + ... N - the number of times the swipes will be made + ... source_text - text of the start element + ... destination_text - text of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${source_text} ${destination_text} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Text ${source_text} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Text ${destination_text} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe n times my_session ${N} ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Swipe N Times Using Elements Xpath + [Documentation] Swipe from an element to another using XPath locators, n times + ... Parameters: + ... N - the number of times the swipes will be made + ... source_xpath - XPath locator to get the start element + ... destination_xpath - XPath locator to get the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${source_xpath} ${destination_xpath} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Xpath ${source_xpath} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Xpath ${destination_xpath} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Swipe n times my_session ${N} ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stress Swipes + [Documentation] Swipe N times from (a,b) to (c,d) points very quickly + ... Parameters: + ... N - the number of swipes wich will be made + ... a - the X value of the start point + ... b - the Y value of the start point + ... c - the X value of the end point + ... d - the Y value of the end point + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${a} ${b} ${c} ${d} ${offset_x}=0 ${offset_y}=0 + ${new_a} = Evaluate ${a}+${offset_x} + ${new_b} = Evaluate ${b}+${offset_y} + ${new_c} = Evaluate ${c}+${offset_x} + ${new_d} = Evaluate ${d}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress swipes my_session ${N} ${new_a} ${new_b} ${new_c} ${new_d} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stress Swipes Using Elements Id + [Documentation] Swipe from an element to another using their id several times very quickly + ... Parameters: + ... N - the number of swipes to process + ... source_id - id of the start element + ... destination_id - id of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${source_id} ${destination_id} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Id ${source_id} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Id ${destination_id} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress swipes my_session ${N} ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stress Swipes Using Elements Text + [Documentation] Swipe from an element to another using their texts values several times very quickly + ... Parameters: + ... N - the number of swipes to process + ... source_text - text of the start element + ... destination_text - text of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${source_text} ${destination_text} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Text ${source_text} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Id ${destination_text} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress swipes my_session ${N} ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Stress Swipes Using Elements Xpath + [Documentation] Swipe from an element to another several times very quickly using XPath locators to find the elements to use + ... Parameters: + ... N - the number of swipes to process + ... source_xpath - XPath lcoator of the start element + ... destination_xpath - XPath lcoator of the end element + ... offset_x - optional, default valued to 0, an offset to apply to X axis for the contact + ... offset_y - optional, default valued to 0, an offset to apply to Y axis for the contact + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${N} ${source_xpath} ${destination_xpath} ${offset_x}=0 ${offset_y}=0 + ${source_x} ${source_y} = Get Suitable Contact Point For Widget With Text ${source_xpath} + ${source_x} = Evaluate ${source_x}+${offset_x} + ${source_y} = Evaluate ${source_y}+${offset_y} + ${destination_x} ${destination_y} = Get Suitable Contact Point For Widget With Id ${destination_xpath} + ${destination_x} = Evaluate ${destination_x}+${offset_x} + ${destination_y} = Evaluate ${destination_y}+${offset_y} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Stress swipes my_session ${N} ${source_x} ${source_y} ${destination_x} ${destination_y} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Random Pattern + [Documentation] Draws a random pattern on the screen, using strokes + ... Parameters: + ... n - the number of anchor points, definition positions of the (n-1) strokes + ... startX - the minimal value for width, in X axis + ... startY - the minimal value for height, in Y axis + ... endX - the maximal value for width, in X axis + ... endY - the maximal value for height, in Y axis + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${n} ${startX} ${startY} ${endX} ${endY} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw random pattern my_session ${n} ${startX} ${startY} ${endX} ${endY} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Star + [Documentation] Draws a simple and lovely star + ... Returns: + ... the results of the request send to the robot's server + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw star my_session + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Circle + [Documentation] Draws a circle with a defined center point on (x,y) and a radius r + ... Parameters: + ... x - the X value of the center point + ... y - the Y value of the center point + ... r - the radius of the circle + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x} ${y} ${r} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw circle my_session ${x} ${y} ${r} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Cross + [Documentation] Draws a cross using 4 points: two strokes will be made (points 1 to 4, and 2 to 3) + ... Parameters: + ... x1 - the X value of the 1st point + ... y1 - the Y value of the 1st point + ... x2 - the X value of the 2nd point + ... y2 - the Y value of the 2nd point + ... x3 - the X value of the 3rd point + ... y3 - the Y value of the 3rd point + ... x4 - the X value of the 4th point + ... y4 - the Y value of the 4th point + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x1} ${y1} ${x2} ${y2} ${x3} ${y3} ${x4} ${y4} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw cross my_session ${x1} ${y1} ${x2} ${y2} ${x3} ${y3} ${x4} ${y4} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Square + [Documentation] Draws a square with a defined length + ... The draw will be made each nth point (e.g. n=2), the smaller n is, the more precise the square will be. + ... Parameters: + ... n - optionnal, default valued to 2 + ... length - optional, default valued to 30, + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${n}=2 ${length}=30 + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw square my_session ${n} ${length} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Triangle + [Documentation] Draws a triangle using 3 points + ... Parameters: + ... x1 - the X axis value of the 1st point + ... y1 - the Y axis value of the 1st point + ... x2 - the X axis value of the 2nd point + ... y2 - the Y axis value of the 2nd point + ... x3 - the X axis value of the 3rd point + ... y3 - the Y axis value of the 3rd point + ... Returns: + ... the results of the request send to the robot's server + [Arguments] ${x1} ${y1} ${x2} ${y2} ${x3} ${y3} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw triangle my_session ${x1} ${y1} ${x2} ${y2} ${x3} ${y3} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Draw Spiral + [Documentation] Draws a spiral using a center point (x,y), n loops and an r radius + ... Parameters: + ... x - the X axis value of the center point + ... y - the Y axis value of the center point + ... n - the number of loops to draw + ... r - the radius of the spiral + ... Returns: + ... Returns the response of the robot's server. + [Arguments] ${x} ${y} ${n} ${r} + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Draw spiral my_session ${x} ${y} ${n} ${r} + tapster_keywords.Delete robot session my_session + [Return] ${response} + +Reset + [Documentation] Resets the position of the robot's finger + ... Returns: + ... the results of the request send to the robot's server + tapster_keywords.Create robot session my_session + ${response} = tapster_keywords.Reset my_session + tapster_keywords.Delete robot session my_session + [Return] ${response} + +# ######### +# Some glue +# ######### + +Get Suitable Contact Point For Widget With Text + [Documentation] According to the location and the dimension of an element, returns a point to click on + ... Parameters: + ... text - the text of the object + ... Returns: + ... x, y - coordinates to use of the targeted element + [Arguments] ${text} + ${location} = Get Element Location xpath=//*[@text=${text}] + ${size} = Get Element Size xpath=//*[@text=${text}] + ${contact_x} = Evaluate ${location['x']}+${size['width']}/2 + ${contact_y} = Evaluate ${location['y']}+${size['height']}/2 + [Return] ${contact_x} ${contact_y} + +Get Suitable Contact Point For Widget With Id + [Documentation] According to the location and the dimension of an element, returns a point to click on + ... Parameters: + ... id - the id of the object + ... Returns: + ... x, y - coordinates to use of the targeted element + [Arguments] ${id} + ${location} = Get Element Location xpath=//*[@resource-id=${id}] + ${size} = Get Element Size xpath=//*[@resource-id=${id}] + ${contact_x} = Evaluate ${location['x']}+${size['width']}/2 + ${contact_y} = Evaluate ${location['y']}+${size['height']}/2 + [Return] ${contact_x} ${contact_y} + +Get Suitable Contact Point For Widget With Xpath + [Documentation] According to the location and the dimension of an element, returns a point to click on + ... Parameters: + ... xpath_lcoator - the XPath locator to use to find the object + ... Returns: + ... x, y - coordinates to use of the targeted element + [Arguments] ${xpath_locator} + ${location} = Get Element Location xpath=${xpath_locator} + ${size} = Get Element Size xpath=${xpath_locator} + ${contact_x} = Evaluate ${location['x']}+${size['width']}/2 + ${contact_y} = Evaluate ${location['y']}+${size['height']}/2 + [Return] ${contact_x} ${contact_y} + +Get Random Contact Point For Widget With Id + [Documentation] According to the location and the dimension of an element, returns a point to click on + ... Parameters: + ... id - the id of the object + ... Returns: + ... x, y - coordinates to use of the selected random point + [Arguments] ${id} + ${location} = Get Element Location xpath=//*[@resource-id=${id}] + ${size} = Get Element Size xpath=//*[@resource-id=${id}] + ${min_x} = Convert To Integer ${location['x']} + ${max_x} = Evaluate ${location['x']}+${size['width']} + ${max_x} = Convert To Integer ${max_x} + ${min_y} = Convert To Integer ${location['y']} + ${max_y} = Evaluate ${location['y']}+${size['height']} + ${max_y} = Convert To Integer ${max_y} + ${contact_x} = Evaluate random.sample(range(${min_x},${max_x}), 1) random + ${contact_y} = Evaluate random.sample(range(${min_y},${max_y}), 1) random + [Return] ${contact_x}[0] ${contact_y}[0] + +Get Random Contact Point For Widget With Text + [Documentation] According to the location and the dimension of an element, returns a point to click on + ... Parameters: + ... text - the text of the object + ... Returns: + ... x, y - coordinates to use of the selected random point + [Arguments] ${text} + ${location} = Get Element Location xpath=//*[@text=${text}] + ${size} = Get Element Size xpath=//*[@text=${text}] + ${min_x} = Convert To Integer ${location['x']} + ${max_x} = Evaluate ${location['x']}+${size['width']} + ${max_x} = Convert To Integer ${max_x} + ${min_y} = Convert To Integer ${location['y']} + ${max_y} = Evaluate ${location['y']}+${size['height']} + ${max_y} = Convert To Integer ${max_y} + ${contact_x} = Evaluate random.sample(range(${min_x},${max_x}), 1) random + ${contact_y} = Evaluate random.sample(range(${min_y},${max_y}), 1) random + [Return] ${contact_x}[0] ${contact_y}[0] + +Get Random Contact Point For Widget With Xpath + [Documentation] According to the location and the dimension of an element, returns a point to click on + ... Parameters: + ... xpath_locator - the XPath lcoator to use to find the object + ... Returns: + ... x, y - coordinates to use of the selected random point + [Arguments] ${xpath_locator} + ${location} = Get Element Location xpath=${xpath_locator} + ${size} = Get Element Size xpath=${xpath_locator} + ${min_x} = Convert To Integer ${location['x']} + ${max_x} = Evaluate ${location['x']}+${size['width']} + ${max_x} = Convert To Integer ${max_x} + ${min_y} = Convert To Integer ${location['y']} + ${max_y} = Evaluate ${location['y']}+${size['height']} + ${max_y} = Convert To Integer ${max_y} + ${contact_x} = Evaluate random.sample(range(${min_x},${max_x}), 1) random + ${contact_y} = Evaluate random.sample(range(${min_y},${max_y}), 1) random + [Return] ${contact_x}[0] ${contact_y}[0] diff --git a/hardware/LICENSE b/hardware/LICENSE new file mode 100644 index 00000000..531067a4 --- /dev/null +++ b/hardware/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2011-2016, Tapster Committers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] diff --git a/hardware/README.md b/hardware/README.md new file mode 100644 index 00000000..cc19e3dc --- /dev/null +++ b/hardware/README.md @@ -0,0 +1,3 @@ +# hardware folder + +Here are the assets (OpenSCAD, STL, ...) and specifications to build some Tapser bots, including the great Tapster 2 bot. diff --git a/hardware/tapster-2/BOM.md b/hardware/tapster-2/BOM.md index 843a29e3..5769e089 100644 --- a/hardware/tapster-2/BOM.md +++ b/hardware/tapster-2/BOM.md @@ -19,7 +19,7 @@ 3 Side plate 1 Arduino plate -### IndigoInstruments.com +### Indigo.com Qty Description Part # Unit Price 24 Rod magnet, D5 x 7.5mm, Nd rare earth, N42 44201-7.5 $0.44 @@ -28,10 +28,8 @@ Qty Description Long Description: Part # Unit Price 5 4-40 1/2 in Black-Oxide Alloy Steel Socket Head Cap Screw 91251A110 $8.34 per pack of 100 6 6-32 3/4 in Black-Oxide Alloy Steel Socket Head Cap Screw 91251A151 $8.50 per pack of 100 - 30 10-32 7/8 in Black-Oxide Alloy Steel Socket Head Cap Screw 91251A346 $6.68 per pack of 100 - 4 10-32 1 in Black-Oxide Alloy Steel Socket Head Cap Screw 91251A347 $8.85 per pack of 50 - ? #10 Washer For #10 Screw, 18-8 Stainless Steel Washer 92141A011 $2.30 per pack of 100 - ? #6 Washer For #6 Screw, 18-8 Stainless Steel Washer 92141A008 $1.17 per pack of 100 + 30 10-32 3/4 in Black-Oxide Alloy Steel Socket Head Cap Screw 91251A345 $9.93 per pack of 100 + 4 10-32 1 in Black-Oxide Alloy Steel Socket Head Cap Screw 91251A347 $7.82 per pack of 50 Hex Nuts: Qty Description Long Description: Part # Unit Price @@ -49,9 +47,9 @@ Qty Description Part # Unit Price 3 Hitec HS-311 servo (clockwise rotation) 31311S $7.99 -### Ebay +### Staples Qty Description Long Description Part # Unit Price - 1 Tablet stylus Touch Screen Stylus 4894462150535 $1.88 + 1 Tablet stylus QVS ISE-SV Extending Mini-Stylus IM1NZ0711 $3.99 ## Electronics: @@ -59,15 +57,12 @@ ### Adafruit.com Qty Description Long Description Part # Unit Price 1 Power adaptor 9 VDC 1000mA regulated switching power adapter 63 $6.95 + 1 Arduino Uno Arduino Uno R3 (Atmega328 - assembled) 50 $24.95 ### Amazon.com Qty Description Part # Unit Price 1 SainSmart Sensor Shield Digital Analog Module V4 B006TQ314G $11.80 -### Jameco - Qty Description Part # Unit Price - 1 Arduino Uno Arduino Uno R3 DIP Edition (Revision 3) 2151486 $21.95 - ### Monoprice.com Qty Description Long Description Part # Unit Price 1 USB cable 3ft USB 2.0 A Male to B Male 28/24AWG Cable 5437 $1.02 @@ -91,3 +86,22 @@ ## Materials: For 3D Printers: ABS plastic from Ultimachine + +For CNC Mills: +Plywood and Basswood from Blick Arts / Midwest Products + + +## Miscellaneous: + +### Uline + Qty Description + 1 8X8x14 box + 1 Red bag + + + + + + + + diff --git a/hardware/tapster-2/scad/stylus-holder.scad b/hardware/tapster-2/scad/stylus-holder.scad index 1dc238e0..7ea6c5b7 100644 --- a/hardware/tapster-2/scad/stylus-holder.scad +++ b/hardware/tapster-2/scad/stylus-holder.scad @@ -1,9 +1,8 @@ beam_width = 8; -hole_diameter = 5.1; +hole_diameter = 5.25; hole_radius = hole_diameter / 2; -center_hole = 10; clipping_distance = 26; @@ -11,7 +10,7 @@ difference(){ cylinder(r=56/2, h=9, $fn=3, center=true); translate([0,0,-10]) - cylinder(d = center_hole, h=20, $fn=30); + cylinder(r=4.3, h=20, $fn=30); rotate([60,90,0]) diff --git a/hardware/tapster-2/stl/stylus-holder.stl b/hardware/tapster-2/stl/stylus-holder.stl index 636988ad..2b4c3eb7 100644 --- a/hardware/tapster-2/stl/stylus-holder.stl +++ b/hardware/tapster-2/stl/stylus-holder.stl @@ -1,8710 +1,8150 @@ solid OpenSCAD_Model - facet normal 0.809072 -0.58771 0 - outer loop - vertex -12.2733 -6.6875 4.5 - vertex -11.9508 -6.24353 -4.5 - vertex -11.9508 -6.24353 4.5 - endloop - endfacet - facet normal 0.809072 -0.58771 0 - outer loop - vertex -11.9508 -6.24353 -4.5 - vertex -12.2733 -6.6875 4.5 - vertex -12.2733 -6.6875 -4.5 - endloop - endfacet - facet normal -0.104524 -0.994522 0 - outer loop - vertex -10 -5.375 -4.5 - vertex -9.45423 -5.43236 4.5 - vertex -10 -5.375 4.5 - endloop - endfacet - facet normal -0.104524 -0.994522 -0 - outer loop - vertex -9.45423 -5.43236 4.5 - vertex -10 -5.375 -4.5 - vertex -9.45423 -5.43236 -4.5 - endloop - endfacet - facet normal -0.978146 0.207918 0 - outer loop - vertex -7.50348 -8.81117 -4.5 - vertex -7.38938 -8.27439 4.5 - vertex -7.38938 -8.27439 -4.5 - endloop - endfacet - facet normal -0.978146 0.207918 0 - outer loop - vertex -7.38938 -8.27439 4.5 - vertex -7.50348 -8.81117 -4.5 - vertex -7.50348 -8.81117 4.5 - endloop - endfacet - facet normal 0.309024 -0.951054 0 - outer loop - vertex -11.0677 -5.60194 -4.5 - vertex -10.5458 -5.43236 4.5 - vertex -11.0677 -5.60194 4.5 - endloop - endfacet - facet normal 0.309024 -0.951054 0 - outer loop - vertex -10.5458 -5.43236 4.5 - vertex -11.0677 -5.60194 -4.5 - vertex -10.5458 -5.43236 -4.5 - endloop - endfacet - facet normal 0.91355 0.406727 0 - outer loop - vertex -12.2733 -9.3125 4.5 - vertex -12.4965 -8.81117 -4.5 - vertex -12.4965 -8.81117 4.5 - endloop - endfacet - facet normal 0.91355 0.406727 0 - outer loop - vertex -12.4965 -8.81117 -4.5 - vertex -12.2733 -9.3125 4.5 - vertex -12.2733 -9.3125 -4.5 - endloop - endfacet - facet normal 0.308892 0.951097 -0 - outer loop - vertex -10.5458 -10.5676 -4.5 - vertex -11.0677 -10.3981 4.5 - vertex -10.5458 -10.5676 4.5 - endloop - endfacet - facet normal 0.308892 0.951097 0 - outer loop - vertex -11.0677 -10.3981 4.5 - vertex -10.5458 -10.5676 -4.5 - vertex -11.0677 -10.3981 -4.5 - endloop - endfacet - facet normal -0.308887 0.951099 0 - outer loop - vertex -8.93232 -10.3981 -4.5 - vertex -9.45423 -10.5676 4.5 - vertex -8.93232 -10.3981 4.5 - endloop - endfacet - facet normal -0.308887 0.951099 0 - outer loop - vertex -9.45423 -10.5676 4.5 - vertex -8.93232 -10.3981 -4.5 - vertex -9.45423 -10.5676 -4.5 - endloop - endfacet - facet normal -0.500012 0.866019 0 - outer loop - vertex -8.45706 -10.1237 -4.5 - vertex -8.93232 -10.3981 4.5 - vertex -8.45706 -10.1237 4.5 - endloop - endfacet - facet normal -0.500012 0.866019 0 - outer loop - vertex -8.93232 -10.3981 4.5 - vertex -8.45706 -10.1237 -4.5 - vertex -8.93232 -10.3981 -4.5 - endloop - endfacet - facet normal 0.500045 -0.865999 0 - outer loop - vertex -11.5429 -5.87633 -4.5 - vertex -11.0677 -5.60194 4.5 - vertex -11.5429 -5.87633 4.5 - endloop - endfacet - facet normal 0.500045 -0.865999 0 - outer loop - vertex -11.0677 -5.60194 4.5 - vertex -11.5429 -5.87633 -4.5 - vertex -11.0677 -5.60194 -4.5 - endloop - endfacet - facet normal 0.669055 -0.743213 0 - outer loop - vertex -11.9508 -6.24353 -4.5 - vertex -11.5429 -5.87633 4.5 - vertex -11.9508 -6.24353 4.5 - endloop - endfacet - facet normal 0.669055 -0.743213 0 + facet normal 0 0 -1 outer loop - vertex -11.5429 -5.87633 4.5 - vertex -11.9508 -6.24353 -4.5 - vertex -11.5429 -5.87633 -4.5 + vertex -8.93232 10.3981 -4.5 + vertex -14 12.7017 -4.5 + vertex -4 18.4752 -4.5 endloop endfacet - facet normal 0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex -12.4965 -7.18883 4.5 - vertex -12.2733 -6.6875 -4.5 - vertex -12.2733 -6.6875 4.5 + vertex 0.0225521 14.4167 -4.5 + vertex -4 18.4752 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex -12.2733 -6.6875 -4.5 - vertex -12.4965 -7.18883 4.5 - vertex -12.4965 -7.18883 -4.5 + vertex 14.4247 -5.47142 -4.5 + vertex 18 5.7735 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 1 -0 0 + facet normal 0 0 -1 outer loop - vertex -12.6106 -8.27439 4.5 + vertex -14 -12.7017 -4.5 + vertex -14 12.7017 -4.5 vertex -12.6106 -7.72561 -4.5 - vertex -12.6106 -7.72561 4.5 endloop endfacet - facet normal 1 0 0 + facet normal 0 0 -1 outer loop + vertex -14 -12.7017 -4.5 vertex -12.6106 -7.72561 -4.5 - vertex -12.6106 -8.27439 4.5 vertex -12.6106 -8.27439 -4.5 endloop endfacet - facet normal -0.104596 0.994515 0 - outer loop - vertex -9.45423 -10.5676 -4.5 - vertex -10 -10.625 4.5 - vertex -9.45423 -10.5676 4.5 - endloop - endfacet - facet normal -0.104596 0.994515 0 - outer loop - vertex -10 -10.625 4.5 - vertex -9.45423 -10.5676 -4.5 - vertex -10 -10.625 -4.5 - endloop - endfacet - facet normal 0.500059 0.865991 -0 - outer loop - vertex -11.0677 -10.3981 -4.5 - vertex -11.5429 -10.1237 4.5 - vertex -11.0677 -10.3981 4.5 - endloop - endfacet - facet normal 0.500059 0.865991 0 + facet normal 0 0 -1 outer loop - vertex -11.5429 -10.1237 4.5 - vertex -11.0677 -10.3981 -4.5 - vertex -11.5429 -10.1237 -4.5 + vertex -14 -12.7017 -4.5 + vertex -12.6106 -8.27439 -4.5 + vertex -12.4965 -8.81117 -4.5 endloop endfacet - facet normal 0.809072 0.58771 0 + facet normal 0 0 -1 outer loop - vertex -11.9508 -9.75647 4.5 + vertex -14 -12.7017 -4.5 + vertex -12.4965 -8.81117 -4.5 vertex -12.2733 -9.3125 -4.5 - vertex -12.2733 -9.3125 4.5 endloop endfacet - facet normal 0.809072 0.58771 0 + facet normal 0 0 -1 outer loop + vertex -14 -12.7017 -4.5 vertex -12.2733 -9.3125 -4.5 - vertex -11.9508 -9.75647 4.5 vertex -11.9508 -9.75647 -4.5 endloop endfacet - facet normal 0.978146 0.207918 0 - outer loop - vertex -12.4965 -8.81117 4.5 - vertex -12.6106 -8.27439 -4.5 - vertex -12.6106 -8.27439 4.5 - endloop - endfacet - facet normal 0.978146 0.207918 0 - outer loop - vertex -12.6106 -8.27439 -4.5 - vertex -12.4965 -8.81117 4.5 - vertex -12.4965 -8.81117 -4.5 - endloop - endfacet - facet normal 0.669086 0.743185 -0 - outer loop - vertex -11.5429 -10.1237 -4.5 - vertex -11.9508 -9.75647 4.5 - vertex -11.5429 -10.1237 4.5 - endloop - endfacet - facet normal 0.669086 0.743185 0 + facet normal 0 0 -1 outer loop - vertex -11.9508 -9.75647 4.5 - vertex -11.5429 -10.1237 -4.5 + vertex -14 -12.7017 -4.5 vertex -11.9508 -9.75647 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal 0.104518 -0.994523 0 - outer loop - vertex -10.5458 -5.43236 -4.5 - vertex -10 -5.375 4.5 - vertex -10.5458 -5.43236 4.5 - endloop - endfacet - facet normal 0.104518 -0.994523 0 - outer loop - vertex -10 -5.375 4.5 - vertex -10.5458 -5.43236 -4.5 - vertex -10 -5.375 -4.5 - endloop - endfacet - facet normal -0.978146 -0.207918 0 - outer loop - vertex -7.38938 -7.72561 -4.5 - vertex -7.50348 -7.18883 4.5 - vertex -7.50348 -7.18883 -4.5 - endloop - endfacet - facet normal -0.978146 -0.207918 0 - outer loop - vertex -7.50348 -7.18883 4.5 - vertex -7.38938 -7.72561 -4.5 - vertex -7.38938 -7.72561 4.5 - endloop - endfacet - facet normal -0.91355 -0.406727 0 - outer loop - vertex -7.50348 -7.18883 -4.5 - vertex -7.72668 -6.6875 4.5 - vertex -7.72668 -6.6875 -4.5 - endloop - endfacet - facet normal -0.91355 -0.406727 0 - outer loop - vertex -7.72668 -6.6875 4.5 - vertex -7.50348 -7.18883 -4.5 - vertex -7.50348 -7.18883 4.5 - endloop - endfacet - facet normal -0.80902 -0.587782 0 - outer loop - vertex -7.72668 -6.6875 -4.5 - vertex -8.04924 -6.24353 4.5 - vertex -8.04924 -6.24353 -4.5 - endloop - endfacet - facet normal -0.80902 -0.587782 0 - outer loop - vertex -8.04924 -6.24353 4.5 - vertex -7.72668 -6.6875 -4.5 - vertex -7.72668 -6.6875 4.5 - endloop - endfacet - facet normal -0.499998 -0.866027 0 - outer loop - vertex -8.93232 -5.60194 -4.5 - vertex -8.45706 -5.87633 4.5 - vertex -8.93232 -5.60194 4.5 - endloop - endfacet - facet normal -0.499998 -0.866027 -0 - outer loop - vertex -8.45706 -5.87633 4.5 - vertex -8.93232 -5.60194 -4.5 - vertex -8.45706 -5.87633 -4.5 - endloop - endfacet - facet normal -1 0 0 - outer loop - vertex -7.38938 -8.27439 -4.5 - vertex -7.38938 -7.72561 4.5 - vertex -7.38938 -7.72561 -4.5 - endloop - endfacet - facet normal -1 -0 0 - outer loop - vertex -7.38938 -7.72561 4.5 - vertex -7.38938 -8.27439 -4.5 - vertex -7.38938 -8.27439 4.5 - endloop - endfacet - facet normal -0.91355 0.406727 0 - outer loop - vertex -7.72668 -9.3125 -4.5 - vertex -7.50348 -8.81117 4.5 - vertex -7.50348 -8.81117 -4.5 - endloop - endfacet - facet normal -0.91355 0.406727 0 - outer loop - vertex -7.50348 -8.81117 4.5 - vertex -7.72668 -9.3125 -4.5 - vertex -7.72668 -9.3125 4.5 - endloop - endfacet - facet normal -0.80902 0.587782 0 - outer loop - vertex -8.04924 -9.75647 -4.5 - vertex -7.72668 -9.3125 4.5 - vertex -7.72668 -9.3125 -4.5 - endloop - endfacet - facet normal -0.80902 0.587782 0 - outer loop - vertex -7.72668 -9.3125 4.5 - vertex -8.04924 -9.75647 -4.5 - vertex -8.04924 -9.75647 4.5 - endloop - endfacet - facet normal 0.978146 -0.207918 0 - outer loop - vertex -12.6106 -7.72561 4.5 - vertex -12.4965 -7.18883 -4.5 - vertex -12.4965 -7.18883 4.5 - endloop - endfacet - facet normal 0.978146 -0.207918 0 - outer loop - vertex -12.4965 -7.18883 -4.5 - vertex -12.6106 -7.72561 4.5 - vertex -12.6106 -7.72561 -4.5 - endloop - endfacet - facet normal 0.10459 0.994515 -0 - outer loop - vertex -10 -10.625 -4.5 - vertex -10.5458 -10.5676 4.5 - vertex -10 -10.625 4.5 - endloop - endfacet - facet normal 0.10459 0.994515 0 - outer loop - vertex -10.5458 -10.5676 4.5 - vertex -10 -10.625 -4.5 - vertex -10.5458 -10.5676 -4.5 - endloop - endfacet - facet normal -0.669128 -0.743147 0 - outer loop - vertex -8.45706 -5.87633 -4.5 - vertex -8.04924 -6.24353 4.5 - vertex -8.45706 -5.87633 4.5 - endloop - endfacet - facet normal -0.669128 -0.743147 -0 - outer loop - vertex -8.04924 -6.24353 4.5 - vertex -8.45706 -5.87633 -4.5 - vertex -8.04924 -6.24353 -4.5 - endloop - endfacet - facet normal -0.309019 -0.951056 0 - outer loop - vertex -9.45423 -5.43236 -4.5 - vertex -8.93232 -5.60194 4.5 - vertex -9.45423 -5.43236 4.5 - endloop - endfacet - facet normal -0.309019 -0.951056 -0 - outer loop - vertex -8.93232 -5.60194 4.5 - vertex -9.45423 -5.43236 -4.5 - vertex -8.93232 -5.60194 -4.5 - endloop - endfacet - facet normal -0.669158 0.74312 0 - outer loop - vertex -8.04924 -9.75647 -4.5 - vertex -8.45706 -10.1237 4.5 - vertex -8.04924 -9.75647 4.5 - endloop - endfacet - facet normal -0.669158 0.74312 0 - outer loop - vertex -8.45706 -10.1237 4.5 - vertex -8.04924 -9.75647 -4.5 - vertex -8.45706 -10.1237 -4.5 - endloop - endfacet - facet normal 0.809072 -0.58771 0 - outer loop - vertex -12.2733 9.3125 4.5 - vertex -11.9508 9.75647 -4.5 - vertex -11.9508 9.75647 4.5 - endloop - endfacet - facet normal 0.809072 -0.58771 0 - outer loop - vertex -11.9508 9.75647 -4.5 - vertex -12.2733 9.3125 4.5 - vertex -12.2733 9.3125 -4.5 - endloop - endfacet - facet normal 0.104518 0.994523 -0 - outer loop - vertex -10 5.375 -4.5 - vertex -10.5458 5.43236 4.5 - vertex -10 5.375 4.5 - endloop - endfacet - facet normal 0.104518 0.994523 0 - outer loop - vertex -10.5458 5.43236 4.5 - vertex -10 5.375 -4.5 - vertex -10.5458 5.43236 -4.5 - endloop - endfacet - facet normal -0.104596 -0.994515 0 - outer loop - vertex -10 10.625 -4.5 - vertex -9.45423 10.5676 4.5 - vertex -10 10.625 4.5 - endloop - endfacet - facet normal -0.104596 -0.994515 -0 - outer loop - vertex -9.45423 10.5676 4.5 - vertex -10 10.625 -4.5 - vertex -9.45423 10.5676 -4.5 - endloop - endfacet - facet normal -0.978146 0.207918 0 - outer loop - vertex -7.50348 7.18883 -4.5 - vertex -7.38938 7.72561 4.5 - vertex -7.38938 7.72561 -4.5 - endloop - endfacet - facet normal -0.978146 0.207918 0 - outer loop - vertex -7.38938 7.72561 4.5 - vertex -7.50348 7.18883 -4.5 - vertex -7.50348 7.18883 4.5 - endloop - endfacet - facet normal 0.308892 -0.951097 0 - outer loop - vertex -11.0677 10.3981 -4.5 - vertex -10.5458 10.5676 4.5 - vertex -11.0677 10.3981 4.5 - endloop - endfacet - facet normal 0.308892 -0.951097 0 - outer loop - vertex -10.5458 10.5676 4.5 - vertex -11.0677 10.3981 -4.5 - vertex -10.5458 10.5676 -4.5 - endloop - endfacet - facet normal 0.91355 0.406727 0 - outer loop - vertex -12.2733 6.6875 4.5 - vertex -12.4965 7.18883 -4.5 - vertex -12.4965 7.18883 4.5 - endloop - endfacet - facet normal 0.91355 0.406727 0 - outer loop - vertex -12.4965 7.18883 -4.5 - vertex -12.2733 6.6875 4.5 - vertex -12.2733 6.6875 -4.5 - endloop - endfacet - facet normal 0.309024 0.951054 -0 - outer loop - vertex -10.5458 5.43236 -4.5 - vertex -11.0677 5.60194 4.5 - vertex -10.5458 5.43236 4.5 - endloop - endfacet - facet normal 0.309024 0.951054 0 - outer loop - vertex -11.0677 5.60194 4.5 - vertex -10.5458 5.43236 -4.5 - vertex -11.0677 5.60194 -4.5 - endloop - endfacet - facet normal -0.309019 0.951056 0 - outer loop - vertex -8.93232 5.60194 -4.5 - vertex -9.45423 5.43236 4.5 - vertex -8.93232 5.60194 4.5 - endloop - endfacet - facet normal -0.309019 0.951056 0 - outer loop - vertex -9.45423 5.43236 4.5 - vertex -8.93232 5.60194 -4.5 - vertex -9.45423 5.43236 -4.5 - endloop - endfacet - facet normal -0.499998 0.866027 0 - outer loop - vertex -8.45706 5.87633 -4.5 - vertex -8.93232 5.60194 4.5 - vertex -8.45706 5.87633 4.5 - endloop - endfacet - facet normal -0.499998 0.866027 0 - outer loop - vertex -8.93232 5.60194 4.5 - vertex -8.45706 5.87633 -4.5 - vertex -8.93232 5.60194 -4.5 - endloop - endfacet - facet normal 0.500059 -0.865991 0 - outer loop - vertex -11.5429 10.1237 -4.5 - vertex -11.0677 10.3981 4.5 - vertex -11.5429 10.1237 4.5 - endloop - endfacet - facet normal 0.500059 -0.865991 0 - outer loop - vertex -11.0677 10.3981 4.5 - vertex -11.5429 10.1237 -4.5 - vertex -11.0677 10.3981 -4.5 - endloop - endfacet - facet normal 0.669086 -0.743185 0 - outer loop - vertex -11.9508 9.75647 -4.5 - vertex -11.5429 10.1237 4.5 - vertex -11.9508 9.75647 4.5 - endloop - endfacet - facet normal 0.669086 -0.743185 0 - outer loop - vertex -11.5429 10.1237 4.5 - vertex -11.9508 9.75647 -4.5 - vertex -11.5429 10.1237 -4.5 - endloop - endfacet - facet normal 0.91355 -0.406727 0 - outer loop - vertex -12.4965 8.81117 4.5 - vertex -12.2733 9.3125 -4.5 - vertex -12.2733 9.3125 4.5 - endloop - endfacet - facet normal 0.91355 -0.406727 0 - outer loop - vertex -12.2733 9.3125 -4.5 - vertex -12.4965 8.81117 4.5 - vertex -12.4965 8.81117 -4.5 - endloop - endfacet - facet normal 1 -0 0 - outer loop - vertex -12.6106 7.72561 4.5 - vertex -12.6106 8.27439 -4.5 - vertex -12.6106 8.27439 4.5 - endloop - endfacet - facet normal 1 0 0 - outer loop - vertex -12.6106 8.27439 -4.5 - vertex -12.6106 7.72561 4.5 - vertex -12.6106 7.72561 -4.5 - endloop - endfacet - facet normal -0.104524 0.994522 0 - outer loop - vertex -9.45423 5.43236 -4.5 - vertex -10 5.375 4.5 - vertex -9.45423 5.43236 4.5 - endloop - endfacet - facet normal -0.104524 0.994522 0 - outer loop - vertex -10 5.375 4.5 - vertex -9.45423 5.43236 -4.5 - vertex -10 5.375 -4.5 - endloop - endfacet - facet normal 0.500045 0.865999 -0 - outer loop - vertex -11.0677 5.60194 -4.5 - vertex -11.5429 5.87633 4.5 - vertex -11.0677 5.60194 4.5 - endloop - endfacet - facet normal 0.500045 0.865999 0 - outer loop - vertex -11.5429 5.87633 4.5 - vertex -11.0677 5.60194 -4.5 - vertex -11.5429 5.87633 -4.5 - endloop - endfacet - facet normal 0.809072 0.58771 0 - outer loop - vertex -11.9508 6.24353 4.5 - vertex -12.2733 6.6875 -4.5 - vertex -12.2733 6.6875 4.5 - endloop - endfacet - facet normal 0.809072 0.58771 0 - outer loop - vertex -12.2733 6.6875 -4.5 - vertex -11.9508 6.24353 4.5 - vertex -11.9508 6.24353 -4.5 - endloop - endfacet - facet normal 0.978146 0.207918 0 - outer loop - vertex -12.4965 7.18883 4.5 - vertex -12.6106 7.72561 -4.5 - vertex -12.6106 7.72561 4.5 - endloop - endfacet - facet normal 0.978146 0.207918 0 - outer loop - vertex -12.6106 7.72561 -4.5 - vertex -12.4965 7.18883 4.5 - vertex -12.4965 7.18883 -4.5 - endloop - endfacet - facet normal 0.669055 0.743213 -0 - outer loop - vertex -11.5429 5.87633 -4.5 - vertex -11.9508 6.24353 4.5 - vertex -11.5429 5.87633 4.5 - endloop - endfacet - facet normal 0.669055 0.743213 0 + facet normal 0 0 -1 outer loop - vertex -11.9508 6.24353 4.5 - vertex -11.5429 5.87633 -4.5 - vertex -11.9508 6.24353 -4.5 + vertex -11.9508 -9.75647 -4.5 + vertex -11.5429 -10.1237 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal 0.10459 -0.994515 0 + facet normal 0 0 -1 outer loop - vertex -10.5458 10.5676 -4.5 - vertex -10 10.625 4.5 - vertex -10.5458 10.5676 4.5 + vertex -10.5458 -10.5676 -4.5 + vertex -4 -18.4752 -4.5 + vertex -11.0677 -10.3981 -4.5 endloop endfacet - facet normal 0.10459 -0.994515 0 + facet normal 0 0 -1 outer loop - vertex -10 10.625 4.5 - vertex -10.5458 10.5676 -4.5 - vertex -10 10.625 -4.5 + vertex -10 -10.625 -4.5 + vertex -4 -18.4752 -4.5 + vertex -10.5458 -10.5676 -4.5 endloop endfacet - facet normal -0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex -7.38938 8.27439 -4.5 - vertex -7.50348 8.81117 4.5 - vertex -7.50348 8.81117 -4.5 + vertex -12.6106 8.27439 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.4965 8.81117 -4.5 endloop endfacet - facet normal -0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex -7.50348 8.81117 4.5 - vertex -7.38938 8.27439 -4.5 - vertex -7.38938 8.27439 4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -4 -18.4752 -4.5 + vertex -7.38938 -8.27439 -4.5 endloop endfacet - facet normal -0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex -7.50348 8.81117 -4.5 - vertex -7.72668 9.3125 4.5 - vertex -7.72668 9.3125 -4.5 + vertex -11.0677 -5.60194 -4.5 + vertex -14 12.7017 -4.5 + vertex -10.5458 -5.43236 -4.5 endloop endfacet - facet normal -0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex -7.72668 9.3125 4.5 - vertex -7.50348 8.81117 -4.5 - vertex -7.50348 8.81117 4.5 + vertex -10 -10.625 -4.5 + vertex -9.45423 -10.5676 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -0.80902 -0.587782 0 + facet normal 0 0 -1 outer loop - vertex -7.72668 9.3125 -4.5 - vertex -8.04924 9.75647 4.5 - vertex -8.04924 9.75647 -4.5 + vertex -9.45423 -10.5676 -4.5 + vertex -8.93232 -10.3981 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -0.80902 -0.587782 0 + facet normal 0 0 -1 outer loop - vertex -8.04924 9.75647 4.5 - vertex -7.72668 9.3125 -4.5 - vertex -7.72668 9.3125 4.5 + vertex -10.5458 -5.43236 -4.5 + vertex -14 12.7017 -4.5 + vertex -10 -5.375 -4.5 endloop endfacet - facet normal -0.500012 -0.866019 0 + facet normal 0 0 -1 outer loop - vertex -8.93232 10.3981 -4.5 - vertex -8.45706 10.1237 4.5 - vertex -8.93232 10.3981 4.5 + vertex -8.93232 -10.3981 -4.5 + vertex -8.45706 -10.1237 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -0.500012 -0.866019 -0 + facet normal 0 0 -1 outer loop - vertex -8.45706 10.1237 4.5 - vertex -8.93232 10.3981 -4.5 - vertex -8.45706 10.1237 -4.5 + vertex -10 -5.375 -4.5 + vertex -14 12.7017 -4.5 + vertex -9.45423 -5.43236 -4.5 endloop endfacet - facet normal -1 0 0 + facet normal 0 0 -1 outer loop - vertex -7.38938 7.72561 -4.5 - vertex -7.38938 8.27439 4.5 - vertex -7.38938 8.27439 -4.5 + vertex -8.45706 -10.1237 -4.5 + vertex -8.04924 -9.75647 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -1 -0 0 + facet normal 0 0 -1 outer loop - vertex -7.38938 8.27439 4.5 - vertex -7.38938 7.72561 -4.5 - vertex -7.38938 7.72561 4.5 + vertex -9.45423 -5.43236 -4.5 + vertex -12.4965 7.18883 -4.5 + vertex -8.93232 -5.60194 -4.5 endloop endfacet - facet normal -0.91355 0.406727 0 + facet normal 0 0 -1 outer loop - vertex -7.72668 6.6875 -4.5 - vertex -7.50348 7.18883 4.5 - vertex -7.50348 7.18883 -4.5 + vertex -8.04924 -9.75647 -4.5 + vertex -7.72668 -9.3125 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -0.91355 0.406727 0 + facet normal 0 0 -1 outer loop - vertex -7.50348 7.18883 4.5 - vertex -7.72668 6.6875 -4.5 - vertex -7.72668 6.6875 4.5 + vertex -12.4965 7.18883 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.6106 7.72561 -4.5 endloop endfacet - facet normal -0.80902 0.587782 0 + facet normal 0 0 -1 outer loop - vertex -8.04924 6.24353 -4.5 - vertex -7.72668 6.6875 4.5 - vertex -7.72668 6.6875 -4.5 + vertex -7.72668 -9.3125 -4.5 + vertex -7.50348 -8.81117 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -0.80902 0.587782 0 + facet normal 0 0 -1 outer loop - vertex -7.72668 6.6875 4.5 - vertex -8.04924 6.24353 -4.5 - vertex -8.04924 6.24353 4.5 + vertex -7.50348 -8.81117 -4.5 + vertex -7.38938 -8.27439 -4.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal 0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex -12.6106 8.27439 4.5 - vertex -12.4965 8.81117 -4.5 - vertex -12.4965 8.81117 4.5 + vertex -4.53882 12.9346 -4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -4 18.4752 -4.5 endloop endfacet - facet normal 0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex -12.4965 8.81117 -4.5 - vertex -12.6106 8.27439 4.5 - vertex -12.6106 8.27439 -4.5 + vertex -8.04924 -6.24353 -4.5 + vertex -11.9508 6.24353 -4.5 + vertex -7.72668 -6.6875 -4.5 endloop endfacet - facet normal -0.669158 -0.74312 0 + facet normal 0 0 -1 outer loop - vertex -8.45706 10.1237 -4.5 - vertex -8.04924 9.75647 4.5 - vertex -8.45706 10.1237 4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -4 18.4752 -4.5 endloop endfacet - facet normal -0.669158 -0.74312 -0 + facet normal 0 0 -1 outer loop - vertex -8.04924 9.75647 4.5 - vertex -8.45706 10.1237 -4.5 - vertex -8.04924 9.75647 -4.5 + vertex -12.6106 7.72561 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.6106 8.27439 -4.5 endloop endfacet - facet normal -0.308887 -0.951099 0 + facet normal 0 0 -1 outer loop - vertex -9.45423 10.5676 -4.5 - vertex -8.93232 10.3981 4.5 - vertex -9.45423 10.5676 4.5 + vertex -11.9508 6.24353 -4.5 + vertex -8.45706 -5.87633 -4.5 + vertex -12.2733 6.6875 -4.5 endloop endfacet - facet normal -0.308887 -0.951099 -0 + facet normal 0 0 -1 outer loop - vertex -8.93232 10.3981 4.5 - vertex -9.45423 10.5676 -4.5 - vertex -8.93232 10.3981 -4.5 + vertex -12.2733 6.6875 -4.5 + vertex -8.93232 -5.60194 -4.5 + vertex -12.4965 7.18883 -4.5 endloop endfacet - facet normal -0.669128 0.743147 0 + facet normal 0 0 -1 outer loop - vertex -8.04924 6.24353 -4.5 - vertex -8.45706 5.87633 4.5 - vertex -8.04924 6.24353 4.5 + vertex -7.38938 8.27439 -4.5 + vertex -4 18.4752 -4.5 + vertex -7.38938 7.72561 -4.5 endloop endfacet - facet normal -0.669128 0.743147 0 + facet normal 0 0 -1 outer loop - vertex -8.45706 5.87633 4.5 - vertex -8.04924 6.24353 -4.5 - vertex -8.45706 5.87633 -4.5 + vertex -11.5429 -5.87633 -4.5 + vertex -14 12.7017 -4.5 + vertex -11.0677 -5.60194 -4.5 endloop endfacet - facet normal -0.104417 -0.994534 0 + facet normal 0 0 -1 outer loop - vertex -1.9282 -10.0353 -4.5 - vertex -1.38244 -10.0926 4.5 - vertex -1.9282 -10.0353 4.5 + vertex -11.9508 -6.24353 -4.5 + vertex -14 12.7017 -4.5 + vertex -11.5429 -5.87633 -4.5 endloop endfacet - facet normal -0.104417 -0.994534 -0 + facet normal 0 0 -1 outer loop - vertex -1.38244 -10.0926 4.5 - vertex -1.9282 -10.0353 -4.5 - vertex -1.38244 -10.0926 -4.5 + vertex -12.2733 -6.6875 -4.5 + vertex -14 12.7017 -4.5 + vertex -11.9508 -6.24353 -4.5 endloop endfacet - facet normal -0.913536 -0.406758 0 + facet normal 0 0 -1 outer loop - vertex 0.56832 -11.8491 -4.5 - vertex 0.345113 -11.3478 4.5 - vertex 0.345113 -11.3478 -4.5 + vertex -12.4965 -7.18883 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.2733 -6.6875 -4.5 endloop endfacet - facet normal -0.913536 -0.406758 0 + facet normal 0 0 -1 outer loop - vertex 0.345113 -11.3478 4.5 - vertex 0.56832 -11.8491 -4.5 - vertex 0.56832 -11.8491 4.5 + vertex -12.6106 -7.72561 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.4965 -7.18883 -4.5 endloop endfacet - facet normal -0.309051 0.951045 0 + facet normal 0 0 -1 outer loop - vertex -0.860519 -15.0583 -4.5 - vertex -1.38243 -15.2279 4.5 - vertex -0.860519 -15.0583 4.5 + vertex -11.9508 6.24353 -4.5 + vertex -8.04924 -6.24353 -4.5 + vertex -8.45706 -5.87633 -4.5 endloop endfacet - facet normal -0.309051 0.951045 0 + facet normal 0 0 -1 outer loop - vertex -1.38243 -15.2279 4.5 - vertex -0.860519 -15.0583 -4.5 - vertex -1.38243 -15.2279 -4.5 + vertex -8.93232 -5.60194 -4.5 + vertex -12.2733 6.6875 -4.5 + vertex -8.45706 -5.87633 -4.5 endloop endfacet - facet normal -0.669129 -0.743147 0 + facet normal 0 0 -1 outer loop - vertex -0.385267 -10.5366 -4.5 - vertex 0.0225521 -10.9038 4.5 - vertex -0.385267 -10.5366 4.5 + vertex -9.45423 -5.43236 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.4965 7.18883 -4.5 endloop endfacet - facet normal -0.669129 -0.743147 -0 + facet normal 0 0 -1 outer loop - vertex 0.0225521 -10.9038 4.5 - vertex -0.385267 -10.5366 -4.5 - vertex 0.0225521 -10.9038 -4.5 + vertex -11.5429 5.87633 -4.5 + vertex -7.72668 -6.6875 -4.5 + vertex -11.9508 6.24353 -4.5 endloop endfacet - facet normal 0.809039 -0.587756 0 + facet normal 0 0 -1 outer loop - vertex -4.20152 -11.3478 4.5 - vertex -3.87896 -10.9038 -4.5 - vertex -3.87896 -10.9038 4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -11.5429 5.87633 -4.5 + vertex -11.0677 5.60194 -4.5 endloop endfacet - facet normal 0.809039 -0.587756 0 + facet normal 0 0 -1 outer loop - vertex -3.87896 -10.9038 -4.5 - vertex -4.20152 -11.3478 4.5 + vertex -4.42473 -11.8491 -4.5 + vertex -4.20603 -0.89402 -4.5 vertex -4.20152 -11.3478 -4.5 endloop endfacet - facet normal 0.978151 0.207894 0 - outer loop - vertex -4.42473 -13.4714 4.5 - vertex -4.53882 -12.9346 -4.5 - vertex -4.53882 -12.9346 4.5 - endloop - endfacet - facet normal 0.978151 0.207894 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 -12.9346 -4.5 - vertex -4.42473 -13.4714 4.5 - vertex -4.42473 -13.4714 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -11.0677 5.60194 -4.5 + vertex -10.5458 5.43236 -4.5 endloop endfacet - facet normal 0.669128 0.743147 -0 + facet normal 0 0 -1 outer loop - vertex -3.47114 -14.7839 -4.5 - vertex -3.87896 -14.4167 4.5 - vertex -3.47114 -14.7839 4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -10.5458 5.43236 -4.5 + vertex -10 5.375 -4.5 endloop endfacet - facet normal 0.669128 0.743147 0 + facet normal 0 0 -1 outer loop - vertex -3.87896 -14.4167 4.5 - vertex -3.47114 -14.7839 -4.5 - vertex -3.87896 -14.4167 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -10 5.375 -4.5 + vertex -9.45423 5.43236 -4.5 endloop endfacet - facet normal 0.50002 0.866014 -0 + facet normal 0 0 -1 outer loop - vertex -2.99589 -15.0583 -4.5 - vertex -3.47114 -14.7839 4.5 - vertex -2.99589 -15.0583 4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -9.45423 5.43236 -4.5 + vertex -8.93232 5.60194 -4.5 endloop endfacet - facet normal 0.50002 0.866014 0 + facet normal 0 0 -1 outer loop - vertex -3.47114 -14.7839 4.5 - vertex -2.99589 -15.0583 -4.5 - vertex -3.47114 -14.7839 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -8.93232 5.60194 -4.5 + vertex -8.45706 5.87633 -4.5 endloop endfacet - facet normal -0.500017 -0.866015 0 + facet normal 0 0 -1 outer loop - vertex -0.86052 -10.2622 -4.5 - vertex -0.385267 -10.5366 4.5 - vertex -0.86052 -10.2622 4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -8.45706 5.87633 -4.5 + vertex -8.04924 6.24353 -4.5 endloop endfacet - facet normal -0.500017 -0.866015 -0 + facet normal 0 0 -1 outer loop - vertex -0.385267 -10.5366 4.5 - vertex -0.86052 -10.2622 -4.5 - vertex -0.385267 -10.5366 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -8.04924 6.24353 -4.5 + vertex -7.72668 6.6875 -4.5 endloop endfacet - facet normal -0.309047 -0.951047 0 + facet normal 0 0 -1 outer loop - vertex -1.38244 -10.0926 -4.5 - vertex -0.86052 -10.2622 4.5 - vertex -1.38244 -10.0926 4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -7.72668 6.6875 -4.5 + vertex -7.50348 7.18883 -4.5 endloop endfacet - facet normal -0.309047 -0.951047 -0 + facet normal 0 0 -1 outer loop - vertex -0.86052 -10.2622 4.5 - vertex -1.38244 -10.0926 -4.5 - vertex -0.86052 -10.2622 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -7.50348 7.18883 -4.5 + vertex -4 18.4752 -4.5 endloop endfacet - facet normal 0.104415 -0.994534 0 + facet normal 0 0 -1 outer loop - vertex -2.47397 -10.0926 -4.5 - vertex -1.9282 -10.0353 4.5 - vertex -2.47397 -10.0926 4.5 + vertex -7.50348 7.18883 -4.5 + vertex -7.38938 7.72561 -4.5 + vertex -4 18.4752 -4.5 endloop endfacet - facet normal 0.104415 -0.994534 0 + facet normal 0 0 -1 outer loop - vertex -1.9282 -10.0353 4.5 - vertex -2.47397 -10.0926 -4.5 - vertex -1.9282 -10.0353 -4.5 + vertex -7.50348 8.81117 -4.5 + vertex -4 18.4752 -4.5 + vertex -7.38938 8.27439 -4.5 endloop endfacet - facet normal 0.50002 -0.866014 0 + facet normal 0 0 -1 outer loop - vertex -3.47114 -10.5366 -4.5 - vertex -2.99589 -10.2622 4.5 - vertex -3.47114 -10.5366 4.5 + vertex -7.72668 9.3125 -4.5 + vertex -4 18.4752 -4.5 + vertex -7.50348 8.81117 -4.5 endloop endfacet - facet normal 0.50002 -0.866014 0 + facet normal 0 0 -1 outer loop - vertex -2.99589 -10.2622 4.5 - vertex -3.47114 -10.5366 -4.5 - vertex -2.99589 -10.2622 -4.5 + vertex -8.04924 9.75647 -4.5 + vertex -4 18.4752 -4.5 + vertex -7.72668 9.3125 -4.5 endloop endfacet - facet normal 0.808976 0.587842 0 + facet normal 0 0 -1 outer loop - vertex -3.87896 -14.4167 4.5 - vertex -4.20152 -13.9728 -4.5 - vertex -4.20152 -13.9728 4.5 + vertex -8.45706 10.1237 -4.5 + vertex -4 18.4752 -4.5 + vertex -8.04924 9.75647 -4.5 endloop endfacet - facet normal 0.808976 0.587842 0 + facet normal 0 0 -1 outer loop - vertex -4.20152 -13.9728 -4.5 - vertex -3.87896 -14.4167 4.5 - vertex -3.87896 -14.4167 -4.5 + vertex -8.93232 10.3981 -4.5 + vertex -4 18.4752 -4.5 + vertex -8.45706 10.1237 -4.5 endloop endfacet - facet normal 1 -0 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 -12.9346 4.5 - vertex -4.53882 -12.3859 -4.5 - vertex -4.53882 -12.3859 4.5 + vertex -9.45423 10.5676 -4.5 + vertex -14 12.7017 -4.5 + vertex -8.93232 10.3981 -4.5 endloop endfacet - facet normal 1 0 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 -12.3859 -4.5 - vertex -4.53882 -12.9346 4.5 + vertex -4.42473 -13.4714 -4.5 + vertex -4 -18.4752 -4.5 vertex -4.53882 -12.9346 -4.5 endloop endfacet - facet normal 0.913534 -0.406762 0 + facet normal 0 0 -1 outer loop - vertex -4.42473 -11.8491 4.5 - vertex -4.20152 -11.3478 -4.5 - vertex -4.20152 -11.3478 4.5 + vertex -10 10.625 -4.5 + vertex -14 12.7017 -4.5 + vertex -9.45423 10.5676 -4.5 endloop endfacet - facet normal 0.913534 -0.406762 0 + facet normal 0 0 -1 outer loop - vertex -4.20152 -11.3478 -4.5 - vertex -4.42473 -11.8491 4.5 - vertex -4.42473 -11.8491 -4.5 + vertex -10.5458 10.5676 -4.5 + vertex -14 12.7017 -4.5 + vertex -10 10.625 -4.5 endloop endfacet - facet normal 0.669128 -0.743147 0 + facet normal 0 0 -1 outer loop - vertex -3.87896 -10.9038 -4.5 - vertex -3.47114 -10.5366 4.5 - vertex -3.87896 -10.9038 4.5 + vertex -11.0677 10.3981 -4.5 + vertex -14 12.7017 -4.5 + vertex -10.5458 10.5676 -4.5 endloop endfacet - facet normal 0.669128 -0.743147 0 + facet normal 0 0 -1 outer loop - vertex -3.47114 -10.5366 4.5 - vertex -3.87896 -10.9038 -4.5 - vertex -3.47114 -10.5366 -4.5 + vertex -11.5429 10.1237 -4.5 + vertex -14 12.7017 -4.5 + vertex -11.0677 10.3981 -4.5 endloop endfacet - facet normal 0.978151 -0.207894 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 -12.3859 4.5 - vertex -4.42473 -11.8491 -4.5 - vertex -4.42473 -11.8491 4.5 + vertex -11.9508 9.75647 -4.5 + vertex -14 12.7017 -4.5 + vertex -11.5429 10.1237 -4.5 endloop endfacet - facet normal 0.978151 -0.207894 0 + facet normal 0 0 -1 outer loop - vertex -4.42473 -11.8491 -4.5 - vertex -4.53882 -12.3859 4.5 - vertex -4.53882 -12.3859 -4.5 + vertex -12.2733 9.3125 -4.5 + vertex -14 12.7017 -4.5 + vertex -11.9508 9.75647 -4.5 endloop endfacet - facet normal -0.809038 -0.587757 0 + facet normal 0 0 -1 outer loop - vertex 0.345113 -11.3478 -4.5 - vertex 0.0225521 -10.9038 4.5 - vertex 0.0225521 -10.9038 -4.5 + vertex -12.4965 8.81117 -4.5 + vertex -14 12.7017 -4.5 + vertex -12.2733 9.3125 -4.5 endloop endfacet - facet normal -0.809038 -0.587757 0 + facet normal 0 0 -1 outer loop - vertex 0.0225521 -10.9038 4.5 - vertex 0.345113 -11.3478 -4.5 - vertex 0.345113 -11.3478 4.5 + vertex -4.53882 -12.9346 -4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -4.53882 -12.3859 -4.5 endloop endfacet - facet normal -0.669129 0.743146 0 + facet normal 0 0 -1 outer loop - vertex 0.0225514 -14.4167 -4.5 - vertex -0.385267 -14.7839 4.5 - vertex 0.0225514 -14.4167 4.5 + vertex -4 -18.4752 -4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -4.53882 -12.9346 -4.5 endloop endfacet - facet normal -0.669129 0.743146 0 + facet normal 0 0 -1 outer loop - vertex -0.385267 -14.7839 4.5 - vertex 0.0225514 -14.4167 -4.5 - vertex -0.385267 -14.7839 -4.5 + vertex -3.92824 -1.74897 -4.5 + vertex -4.20152 -11.3478 -4.5 + vertex -4.20603 -0.89402 -4.5 endloop endfacet - facet normal -0.808973 0.587845 0 + facet normal 0 0 -1 outer loop - vertex 0.0225514 -14.4167 -4.5 - vertex 0.345114 -13.9728 4.5 - vertex 0.345114 -13.9728 -4.5 + vertex -3.87896 -14.4167 -4.5 + vertex -4 -18.4752 -4.5 + vertex -4.20152 -13.9728 -4.5 endloop endfacet - facet normal -0.808973 0.587845 0 + facet normal 0 0 -1 outer loop - vertex 0.345114 -13.9728 4.5 - vertex 0.0225514 -14.4167 -4.5 - vertex 0.0225514 -14.4167 4.5 + vertex -4 -18.4752 -4.5 + vertex -4.42473 -13.4714 -4.5 + vertex -4.20152 -13.9728 -4.5 endloop endfacet - facet normal -0.913566 0.40669 0 + facet normal 0 0 -1 outer loop - vertex 0.345114 -13.9728 -4.5 - vertex 0.568321 -13.4714 4.5 - vertex 0.568321 -13.4714 -4.5 + vertex -4.20152 -11.3478 -4.5 + vertex -3.92824 -1.74897 -4.5 + vertex -3.87896 -10.9038 -4.5 endloop endfacet - facet normal -0.913566 0.40669 0 + facet normal 0 0 -1 outer loop - vertex 0.568321 -13.4714 4.5 - vertex 0.345114 -13.9728 -4.5 - vertex 0.345114 -13.9728 4.5 + vertex -4 -18.4752 -4.5 + vertex -3.87896 -14.4167 -4.5 + vertex -3.47114 -14.7839 -4.5 endloop endfacet - facet normal -1 0 0 + facet normal 0 0 -1 outer loop - vertex 0.682416 -12.9346 -4.5 - vertex 0.682416 -12.3859 4.5 - vertex 0.682416 -12.3859 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 0.0225516 -10.9038 -4.5 endloop endfacet - facet normal -1 -0 0 + facet normal 0 0 -1 outer loop - vertex 0.682416 -12.3859 4.5 - vertex 0.682416 -12.9346 -4.5 - vertex 0.682416 -12.9346 4.5 + vertex -4 -18.4752 -4.5 + vertex -3.47114 -14.7839 -4.5 + vertex -2.99589 -15.0583 -4.5 endloop endfacet - facet normal -0.500018 0.866015 0 + facet normal 0 0 -1 outer loop - vertex -0.385267 -14.7839 -4.5 - vertex -0.860519 -15.0583 4.5 - vertex -0.385267 -14.7839 4.5 + vertex -4 -18.4752 -4.5 + vertex -2.99589 -15.0583 -4.5 + vertex -2.47397 -15.2279 -4.5 endloop endfacet - facet normal -0.500018 0.866015 0 + facet normal 0 0 -1 outer loop - vertex -0.860519 -15.0583 4.5 - vertex -0.385267 -14.7839 -4.5 - vertex -0.860519 -15.0583 -4.5 + vertex -4 -18.4752 -4.5 + vertex -2.47397 -15.2279 -4.5 + vertex -1.9282 -15.2853 -4.5 endloop endfacet - facet normal -0.104596 0.994515 0 + facet normal 0 0 -1 outer loop - vertex -1.38243 -15.2279 -4.5 - vertex -1.9282 -15.2853 4.5 - vertex -1.38243 -15.2279 4.5 + vertex -4 -18.4752 -4.5 + vertex -1.9282 -15.2853 -4.5 + vertex -1.38244 -15.2279 -4.5 endloop endfacet - facet normal -0.104596 0.994515 0 + facet normal 0 0 -1 outer loop - vertex -1.9282 -15.2853 4.5 - vertex -1.38243 -15.2279 -4.5 - vertex -1.9282 -15.2853 -4.5 + vertex 9.97745 -2.90379 -4.5 + vertex 18 5.7735 -4.5 + vertex 10.3853 -2.53658 -4.5 endloop endfacet - facet normal 0.104596 0.994515 -0 + facet normal 0 0 -1 outer loop - vertex -1.9282 -15.2853 -4.5 - vertex -2.47397 -15.2279 4.5 - vertex -1.9282 -15.2853 4.5 + vertex -4 -18.4752 -4.5 + vertex -0.860519 -15.0583 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.104596 0.994515 0 + facet normal 0 0 -1 outer loop - vertex -2.47397 -15.2279 4.5 - vertex -1.9282 -15.2853 -4.5 - vertex -2.47397 -15.2279 -4.5 + vertex -0.860519 -15.0583 -4.5 + vertex -0.385267 -14.7839 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.309047 -0.951047 0 + facet normal 0 0 -1 outer loop - vertex -2.99589 -10.2622 -4.5 - vertex -2.47397 -10.0926 4.5 - vertex -2.99589 -10.2622 4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 9.43168 -3.84908 -4.5 + vertex 9.31758 -4.38587 -4.5 endloop endfacet - facet normal 0.309047 -0.951047 0 + facet normal 0 0 -1 outer loop - vertex -2.47397 -10.0926 4.5 - vertex -2.99589 -10.2622 -4.5 - vertex -2.47397 -10.0926 -4.5 + vertex -0.385267 -14.7839 -4.5 + vertex 0.0225521 -14.4167 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.913564 0.406695 0 + facet normal 0 0 -1 outer loop - vertex -4.20152 -13.9728 4.5 - vertex -4.42473 -13.4714 -4.5 - vertex -4.42473 -13.4714 4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.682417 -12.3859 -4.5 + vertex 0.56832 -11.8491 -4.5 endloop endfacet - facet normal 0.913564 0.406695 0 + facet normal 0 0 -1 outer loop - vertex -4.42473 -13.4714 -4.5 - vertex -4.20152 -13.9728 4.5 - vertex -4.20152 -13.9728 -4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.56832 -13.4714 -4.5 + vertex 0.682417 -12.9346 -4.5 endloop endfacet - facet normal -0.97815 0.207902 0 + facet normal 0 0 -1 outer loop - vertex 0.568321 -13.4714 -4.5 - vertex 0.682416 -12.9346 4.5 - vertex 0.682416 -12.9346 -4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.345114 -13.9728 -4.5 + vertex 0.56832 -13.4714 -4.5 endloop endfacet - facet normal -0.97815 0.207902 0 + facet normal 0 0 -1 outer loop - vertex 0.682416 -12.9346 4.5 - vertex 0.568321 -13.4714 -4.5 - vertex 0.568321 -13.4714 4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.0225521 -14.4167 -4.5 + vertex 0.345114 -13.9728 -4.5 endloop endfacet - facet normal -0.978149 -0.207904 0 + facet normal 0 0 -1 outer loop - vertex 0.682416 -12.3859 -4.5 - vertex 0.56832 -11.8491 4.5 - vertex 0.56832 -11.8491 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal -0.978149 -0.207904 0 + facet normal 0 0 -1 outer loop - vertex 0.56832 -11.8491 4.5 - vertex 0.682416 -12.3859 -4.5 - vertex 0.682416 -12.3859 4.5 + vertex -2.47397 10.0926 -4.5 + vertex -2.15 3.72391 -4.5 + vertex -2.99589 10.2622 -4.5 endloop endfacet - facet normal 0.309047 0.951047 -0 + facet normal 0 0 -1 outer loop - vertex -2.47397 -15.2279 -4.5 - vertex -2.99589 -15.0583 4.5 - vertex -2.47397 -15.2279 4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.56832 -11.8491 -4.5 + vertex 0.345113 -11.3478 -4.5 endloop endfacet - facet normal 0.309047 0.951047 0 + facet normal 0 0 -1 outer loop - vertex -2.99589 -15.0583 4.5 - vertex -2.47397 -15.2279 -4.5 - vertex -2.99589 -15.0583 -4.5 + vertex -2.87726 3.19552 -4.5 + vertex -2.99589 10.2622 -4.5 + vertex -2.15 3.72391 -4.5 endloop endfacet - facet normal -0.104536 -0.994521 0 + facet normal 0 0 -1 outer loop - vertex 11.9282 -2.03525 -4.5 - vertex 12.474 -2.09262 4.5 - vertex 11.9282 -2.03525 4.5 + vertex -1.32877 -4.08954 -4.5 + vertex -1.38243 -10.0926 -4.5 + vertex -2.15 -3.72391 -4.5 endloop endfacet - facet normal -0.104536 -0.994521 -0 + facet normal 0 0 -1 outer loop - vertex 12.474 -2.09262 4.5 - vertex 11.9282 -2.03525 -4.5 - vertex 12.474 -2.09262 -4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 18 5.7735 -4.5 + vertex 9.97745 -2.90379 -4.5 endloop endfacet - facet normal 0.913543 0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 -5.97275 4.5 - vertex 9.43168 -5.47142 -4.5 - vertex 9.43168 -5.47142 4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 18 5.7735 -4.5 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0.913543 0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 -5.47142 -4.5 - vertex 9.65489 -5.97275 4.5 - vertex 9.65489 -5.97275 -4.5 + vertex -4.53882 12.9346 -4.5 + vertex -4 18.4752 -4.5 + vertex -4.42473 13.4714 -4.5 endloop endfacet - facet normal -0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 -3.84908 -4.5 - vertex 14.2015 -3.34775 4.5 - vertex 14.2015 -3.34775 -4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -4.53882 12.9346 -4.5 endloop endfacet - facet normal -0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 -3.34775 4.5 - vertex 14.4247 -3.84908 -4.5 - vertex 14.4247 -3.84908 4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.53882 12.9346 -4.5 + vertex -4.53882 12.3859 -4.5 endloop endfacet - facet normal -0.309024 0.951054 0 + facet normal 0 0 -1 outer loop - vertex 12.9959 -7.05831 -4.5 - vertex 12.474 -7.22789 4.5 - vertex 12.9959 -7.05831 4.5 + vertex -3.47877 -2.52748 -4.5 + vertex -3.47114 -10.5366 -4.5 + vertex -3.87896 -10.9038 -4.5 endloop endfacet - facet normal -0.309024 0.951054 0 + facet normal 0 0 -1 outer loop - vertex 12.474 -7.22789 4.5 - vertex 12.9959 -7.05831 -4.5 - vertex 12.474 -7.22789 -4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.53882 12.3859 -4.5 + vertex -4.42473 11.8491 -4.5 endloop endfacet - facet normal -0.669055 -0.743213 0 + facet normal 0 0 -1 outer loop - vertex 13.4711 -2.53659 -4.5 - vertex 13.879 -2.90379 4.5 - vertex 13.4711 -2.53659 4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.42473 11.8491 -4.5 + vertex -4.20152 11.3478 -4.5 endloop endfacet - facet normal -0.669055 -0.743213 -0 + facet normal 0 0 -1 outer loop - vertex 13.879 -2.90379 4.5 - vertex 13.4711 -2.53659 -4.5 - vertex 13.879 -2.90379 -4.5 + vertex -3.92824 1.74897 -4.5 + vertex -3.87896 10.9038 -4.5 + vertex -3.47877 2.52748 -4.5 endloop endfacet - facet normal 0.809013 -0.58779 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 -3.34775 4.5 - vertex 9.97745 -2.90379 -4.5 - vertex 9.97745 -2.90379 4.5 + vertex -3.87896 14.4167 -4.5 + vertex -4 18.4752 -4.5 + vertex -3.47114 14.7839 -4.5 endloop endfacet - facet normal 0.809013 -0.58779 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 -2.90379 -4.5 - vertex 9.65489 -3.34775 4.5 - vertex 9.65489 -3.34775 -4.5 + vertex -3.47114 14.7839 -4.5 + vertex -4 18.4752 -4.5 + vertex -2.99589 15.0583 -4.5 endloop endfacet - facet normal 0.978146 0.207918 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 -5.47142 4.5 - vertex 9.31758 -4.93464 -4.5 - vertex 9.31758 -4.93464 4.5 + vertex 11.9282 7.28525 -4.5 + vertex -0.385267 10.5366 -4.5 + vertex 12.474 7.22789 -4.5 endloop endfacet - facet normal 0.978146 0.207918 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 -4.93464 -4.5 - vertex 9.43168 -5.47142 4.5 - vertex 9.43168 -5.47142 -4.5 + vertex -2.99589 15.0583 -4.5 + vertex -4 18.4752 -4.5 + vertex -2.47397 15.2279 -4.5 endloop endfacet - facet normal 0.669101 0.743172 -0 + facet normal 0 0 -1 outer loop - vertex 10.3853 -6.78392 -4.5 - vertex 9.97745 -6.41672 4.5 - vertex 10.3853 -6.78392 4.5 + vertex 12.474 7.22789 -4.5 + vertex 0.0225516 10.9038 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.669101 0.743172 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 -6.41672 4.5 - vertex 10.3853 -6.78392 -4.5 - vertex 9.97745 -6.41672 -4.5 + vertex 0.0225516 10.9038 -4.5 + vertex 0.345113 11.3478 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.500045 0.865999 -0 + facet normal 0 0 -1 outer loop - vertex 10.8605 -7.05831 -4.5 - vertex 10.3853 -6.78392 4.5 - vertex 10.8605 -7.05831 4.5 + vertex -2.47397 15.2279 -4.5 + vertex -4 18.4752 -4.5 + vertex -1.9282 15.2853 -4.5 endloop endfacet - facet normal 0.500045 0.865999 0 + facet normal 0 0 -1 outer loop - vertex 10.3853 -6.78392 4.5 - vertex 10.8605 -7.05831 -4.5 - vertex 10.3853 -6.78392 -4.5 + vertex 0.345113 11.3478 -4.5 + vertex 0.56832 11.8491 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal -0.500045 -0.865999 0 + facet normal 0 0 -1 outer loop - vertex 12.9959 -2.2622 -4.5 - vertex 13.4711 -2.53659 4.5 - vertex 12.9959 -2.2622 4.5 + vertex 0.56832 11.8491 -4.5 + vertex 0.682417 12.3859 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal -0.500045 -0.865999 -0 + facet normal 0 0 -1 outer loop - vertex 13.4711 -2.53659 4.5 - vertex 12.9959 -2.2622 -4.5 - vertex 13.4711 -2.53659 -4.5 + vertex -1.9282 15.2853 -4.5 + vertex -4 18.4752 -4.5 + vertex -1.38244 15.2279 -4.5 endloop endfacet - facet normal -0.309024 -0.951054 0 + facet normal 0 0 -1 outer loop - vertex 12.474 -2.09262 -4.5 - vertex 12.9959 -2.2622 4.5 - vertex 12.474 -2.09262 4.5 + vertex 0.682417 12.3859 -4.5 + vertex 0.682417 12.9346 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal -0.309024 -0.951054 -0 + facet normal 0 0 -1 outer loop - vertex 12.9959 -2.2622 4.5 - vertex 12.474 -2.09262 -4.5 - vertex 12.9959 -2.2622 -4.5 + vertex 0.682417 12.9346 -4.5 + vertex 0.56832 13.4714 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.104536 -0.994521 0 + facet normal 0 0 -1 outer loop - vertex 11.3824 -2.09262 -4.5 - vertex 11.9282 -2.03525 4.5 - vertex 11.3824 -2.09262 4.5 + vertex -1.38244 15.2279 -4.5 + vertex -4 18.4752 -4.5 + vertex -0.860519 15.0583 -4.5 endloop endfacet - facet normal 0.104536 -0.994521 0 + facet normal 0 0 -1 outer loop - vertex 11.9282 -2.03525 4.5 - vertex 11.3824 -2.09262 -4.5 - vertex 11.9282 -2.03525 -4.5 + vertex 0.56832 13.4714 -4.5 + vertex 0.345114 13.9728 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.500032 -0.866007 0 + facet normal 0 0 -1 outer loop - vertex 10.3853 -2.53658 -4.5 - vertex 10.8605 -2.2622 4.5 - vertex 10.3853 -2.53658 4.5 + vertex -0.385267 14.7839 -4.5 + vertex -4 18.4752 -4.5 + vertex 0.0225521 14.4167 -4.5 endloop endfacet - facet normal 0.500032 -0.866007 0 + facet normal 0 0 -1 outer loop - vertex 10.8605 -2.2622 4.5 - vertex 10.3853 -2.53658 -4.5 - vertex 10.8605 -2.2622 -4.5 + vertex 0.345114 13.9728 -4.5 + vertex 0.0225521 14.4167 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.80902 0.587782 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 -6.41672 4.5 - vertex 9.65489 -5.97275 -4.5 - vertex 9.65489 -5.97275 4.5 + vertex -0.860519 15.0583 -4.5 + vertex -4 18.4752 -4.5 + vertex -0.385267 14.7839 -4.5 endloop endfacet - facet normal 0.80902 0.587782 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 -5.97275 -4.5 - vertex 9.97745 -6.41672 4.5 - vertex 9.97745 -6.41672 -4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.0225516 -10.9038 -4.5 + vertex 1.43542 -8.98622 -4.5 endloop endfacet - facet normal 1 -0 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 -4.93464 4.5 - vertex 9.31758 -4.38587 -4.5 - vertex 9.31758 -4.38587 4.5 + vertex -2.99589 10.2622 -4.5 + vertex -2.87726 3.19552 -4.5 + vertex -3.47114 10.5366 -4.5 endloop endfacet - facet normal 1 0 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 -4.38587 -4.5 - vertex 9.31758 -4.93464 4.5 - vertex 9.31758 -4.93464 -4.5 + vertex -4.42473 13.4714 -4.5 + vertex -4 18.4752 -4.5 + vertex -4.20152 13.9728 -4.5 endloop endfacet - facet normal 0.913543 -0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 -3.84908 4.5 - vertex 9.65489 -3.34775 -4.5 - vertex 9.65489 -3.34775 4.5 + vertex -4.20603 -0.89402 -4.5 + vertex -4.42473 -11.8491 -4.5 + vertex -4.3 0 -4.5 endloop endfacet - facet normal 0.913543 -0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 -3.34775 -4.5 - vertex 9.43168 -3.84908 4.5 - vertex 9.43168 -3.84908 -4.5 + vertex -4.42473 -11.8491 -4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.3 0 -4.5 endloop endfacet - facet normal 0.669111 -0.743163 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 -2.90379 -4.5 - vertex 10.3853 -2.53658 4.5 - vertex 9.97745 -2.90379 4.5 + vertex -4.20152 13.9728 -4.5 + vertex -4 18.4752 -4.5 + vertex -3.87896 14.4167 -4.5 endloop endfacet - facet normal 0.669111 -0.743163 0 + facet normal 0 0 -1 outer loop - vertex 10.3853 -2.53658 4.5 - vertex 9.97745 -2.90379 -4.5 - vertex 10.3853 -2.53658 -4.5 + vertex -4.20603 0.89402 -4.5 + vertex -3.87896 10.9038 -4.5 + vertex -3.92824 1.74897 -4.5 endloop endfacet - facet normal 0.978147 -0.207915 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 -4.38587 4.5 - vertex 9.43168 -3.84908 -4.5 - vertex 9.43168 -3.84908 4.5 + vertex -0.860519 -15.0583 -4.5 + vertex -4 -18.4752 -4.5 + vertex -1.38244 -15.2279 -4.5 endloop endfacet - facet normal 0.978147 -0.207915 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 -3.84908 -4.5 - vertex 9.31758 -4.38587 4.5 - vertex 9.31758 -4.38587 -4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.345113 -11.3478 -4.5 + vertex 0.0225516 -10.9038 -4.5 endloop endfacet - facet normal -0.809065 -0.587719 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 -3.34775 -4.5 - vertex 13.879 -2.90379 4.5 - vertex 13.879 -2.90379 -4.5 + vertex -3.47114 -10.5366 -4.5 + vertex -3.47877 -2.52748 -4.5 + vertex -2.99589 -10.2622 -4.5 endloop endfacet - facet normal -0.809065 -0.587719 0 + facet normal 0 0 -1 outer loop - vertex 13.879 -2.90379 4.5 - vertex 14.2015 -3.34775 -4.5 - vertex 14.2015 -3.34775 4.5 + vertex -3.47877 2.52748 -4.5 + vertex -3.47114 10.5366 -4.5 + vertex -2.87726 3.19552 -4.5 endloop endfacet - facet normal -0.669055 0.743213 0 - outer loop - vertex 13.879 -6.41672 -4.5 - vertex 13.4711 -6.78392 4.5 - vertex 13.879 -6.41672 4.5 + facet normal 0 0 -1 + outer loop + vertex -2.99589 -10.2622 -4.5 + vertex -2.87726 -3.19552 -4.5 + vertex -2.47397 -10.0926 -4.5 endloop endfacet - facet normal -0.669055 0.743213 0 + facet normal 0 0 -1 outer loop - vertex 13.4711 -6.78392 4.5 - vertex 13.879 -6.41672 -4.5 - vertex 13.4711 -6.78392 -4.5 + vertex -1.9282 -10.0353 -4.5 + vertex -2.15 -3.72391 -4.5 + vertex -1.38243 -10.0926 -4.5 endloop endfacet - facet normal -0.809072 0.58771 0 + facet normal 0 0 -1 outer loop - vertex 13.879 -6.41672 -4.5 - vertex 14.2015 -5.97275 4.5 - vertex 14.2015 -5.97275 -4.5 + vertex -0.449472 -4.27644 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex -1.32877 -4.08954 -4.5 endloop endfacet - facet normal -0.809072 0.58771 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 -5.97275 4.5 - vertex 13.879 -6.41672 -4.5 - vertex 13.879 -6.41672 4.5 + vertex -0.860519 -10.2622 -4.5 + vertex -1.32877 -4.08954 -4.5 + vertex -0.385267 -10.5366 -4.5 endloop endfacet - facet normal -0.91355 0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 -5.97275 -4.5 - vertex 14.4247 -5.47142 4.5 - vertex 14.4247 -5.47142 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex -0.449472 -4.27644 -4.5 + vertex 0.449472 -4.27644 -4.5 endloop endfacet - facet normal -0.91355 0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 -5.47142 4.5 - vertex 14.2015 -5.97275 -4.5 - vertex 14.2015 -5.97275 4.5 + vertex 11.9282 2.03525 -4.5 + vertex 2.15 -3.72391 -4.5 + vertex 2.87726 -3.19552 -4.5 endloop endfacet - facet normal -1 0 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 -4.93464 -4.5 - vertex 14.5388 -4.38587 4.5 - vertex 14.5388 -4.38587 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 0.449472 -4.27644 -4.5 + vertex 1.32877 -4.08954 -4.5 endloop endfacet - facet normal -1 -0 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 -4.38587 4.5 - vertex 14.5388 -4.93464 -4.5 - vertex 14.5388 -4.93464 4.5 + vertex 3.92824 -1.74897 -4.5 + vertex 11.3824 2.09262 -4.5 + vertex 3.47877 -2.52748 -4.5 endloop endfacet - facet normal -0.500045 0.865999 0 + facet normal 0 0 -1 outer loop - vertex 13.4711 -6.78392 -4.5 - vertex 12.9959 -7.05831 4.5 - vertex 13.4711 -6.78392 4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 1.32877 -4.08954 -4.5 + vertex 2.15 -3.72391 -4.5 endloop endfacet - facet normal -0.500045 0.865999 0 + facet normal 0 0 -1 outer loop - vertex 12.9959 -7.05831 4.5 - vertex 13.4711 -6.78392 -4.5 - vertex 12.9959 -7.05831 -4.5 + vertex 13.879 2.90379 -4.5 + vertex 18 5.7735 -4.5 + vertex 13.4711 2.53658 -4.5 endloop endfacet - facet normal -0.104518 0.994523 0 + facet normal 0 0 -1 outer loop - vertex 12.474 -7.22789 -4.5 - vertex 11.9282 -7.28525 4.5 - vertex 12.474 -7.22789 4.5 + vertex 14.5388 4.38587 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.4247 3.84908 -4.5 endloop endfacet - facet normal -0.104518 0.994523 0 + facet normal 0 0 -1 outer loop - vertex 11.9282 -7.28525 4.5 - vertex 12.474 -7.22789 -4.5 - vertex 11.9282 -7.28525 -4.5 + vertex -2.15 3.72391 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex -1.32877 4.08954 -4.5 endloop endfacet - facet normal 0.104518 0.994523 -0 + facet normal 0 0 -1 outer loop - vertex 11.9282 -7.28525 -4.5 - vertex 11.3824 -7.22789 4.5 - vertex 11.9282 -7.28525 4.5 + vertex 11.9282 2.03525 -4.5 + vertex 2.87726 -3.19552 -4.5 + vertex 3.47877 -2.52748 -4.5 endloop endfacet - facet normal 0.104518 0.994523 0 + facet normal 0 0 -1 outer loop - vertex 11.3824 -7.22789 4.5 - vertex 11.9282 -7.28525 -4.5 - vertex 11.3824 -7.22789 -4.5 + vertex 11.3824 2.09262 -4.5 + vertex 3.92824 -1.74897 -4.5 + vertex 10.8605 2.2622 -4.5 endloop endfacet - facet normal 0.309024 -0.951054 0 + facet normal 0 0 -1 outer loop - vertex 10.8605 -2.2622 -4.5 - vertex 11.3824 -2.09262 4.5 - vertex 10.8605 -2.2622 4.5 + vertex 0.449472 4.27644 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 1.32877 4.08954 -4.5 endloop endfacet - facet normal 0.309024 -0.951054 0 + facet normal 0 0 -1 outer loop - vertex 11.3824 -2.09262 4.5 - vertex 10.8605 -2.2622 -4.5 - vertex 11.3824 -2.09262 -4.5 + vertex 10.8605 2.2622 -4.5 + vertex 4.20603 -0.89402 -4.5 + vertex 10.3853 2.53658 -4.5 endloop endfacet - facet normal -0.978146 0.207918 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 -5.47142 -4.5 - vertex 14.5388 -4.93464 4.5 - vertex 14.5388 -4.93464 -4.5 + vertex 1.32877 4.08954 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 2.15 3.72391 -4.5 endloop endfacet - facet normal -0.978146 0.207918 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 -4.93464 4.5 - vertex 14.4247 -5.47142 -4.5 - vertex 14.4247 -5.47142 4.5 + vertex 10.3853 2.53658 -4.5 + vertex 4.3 0 -4.5 + vertex 9.97745 2.90379 -4.5 endloop endfacet - facet normal -0.978147 -0.207915 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 -4.38587 -4.5 - vertex 14.4247 -3.84908 4.5 - vertex 14.4247 -3.84908 -4.5 + vertex 9.97745 2.90379 -4.5 + vertex 4.20603 0.89402 -4.5 + vertex 9.65489 3.34775 -4.5 endloop endfacet - facet normal -0.978147 -0.207915 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 -3.84908 4.5 - vertex 14.5388 -4.38587 -4.5 - vertex 14.5388 -4.38587 4.5 + vertex 2.87726 3.19552 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 3.47877 2.52748 -4.5 endloop endfacet - facet normal 0.309024 0.951054 -0 + facet normal 0 0 -1 outer loop - vertex 11.3824 -7.22789 -4.5 - vertex 10.8605 -7.05831 4.5 - vertex 11.3824 -7.22789 4.5 + vertex 9.65489 3.34775 -4.5 + vertex 3.92824 1.74897 -4.5 + vertex 9.43168 3.84908 -4.5 endloop endfacet - facet normal 0.309024 0.951054 0 + facet normal 0 0 -1 outer loop - vertex 10.8605 -7.05831 4.5 - vertex 11.3824 -7.22789 -4.5 - vertex 10.8605 -7.05831 -4.5 + vertex -0.449472 4.27644 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 0.449472 4.27644 -4.5 endloop endfacet - facet normal 0.913543 0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 3.34775 4.5 - vertex 9.43168 3.84908 -4.5 - vertex 9.43168 3.84908 4.5 + vertex -1.32877 4.08954 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex -0.449472 4.27644 -4.5 endloop endfacet - facet normal 0.913543 0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 3.84908 -4.5 - vertex 9.65489 3.34775 4.5 - vertex 9.65489 3.34775 -4.5 + vertex -1.32877 -4.08954 -4.5 + vertex -0.860519 -10.2622 -4.5 + vertex -1.38243 -10.0926 -4.5 endloop endfacet - facet normal 0.80902 -0.587782 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 5.97275 4.5 - vertex 9.97745 6.41672 -4.5 - vertex 9.97745 6.41672 4.5 + vertex -2.15 -3.72391 -4.5 + vertex -1.9282 -10.0353 -4.5 + vertex -2.47397 -10.0926 -4.5 endloop endfacet - facet normal 0.80902 -0.587782 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 6.41672 -4.5 - vertex 9.65489 5.97275 4.5 - vertex 9.65489 5.97275 -4.5 + vertex -3.47877 -2.52748 -4.5 + vertex -3.87896 -10.9038 -4.5 + vertex -3.92824 -1.74897 -4.5 endloop endfacet - facet normal -0.669055 -0.743213 0 + facet normal 0 0 -1 outer loop - vertex 13.4711 6.78392 -4.5 - vertex 13.879 6.41672 4.5 - vertex 13.4711 6.78392 4.5 + vertex -3.47114 10.5366 -4.5 + vertex -3.47877 2.52748 -4.5 + vertex -3.87896 10.9038 -4.5 endloop endfacet - facet normal -0.669055 -0.743213 -0 + facet normal 0 0 -1 outer loop - vertex 13.879 6.41672 4.5 - vertex 13.4711 6.78392 -4.5 - vertex 13.879 6.41672 -4.5 + vertex -2.87726 -3.19552 -4.5 + vertex -2.99589 -10.2622 -4.5 + vertex -3.47877 -2.52748 -4.5 endloop endfacet - facet normal 0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 4.93464 4.5 - vertex 9.43168 5.47142 -4.5 - vertex 9.43168 5.47142 4.5 + vertex -2.15 -3.72391 -4.5 + vertex -2.47397 -10.0926 -4.5 + vertex -2.87726 -3.19552 -4.5 endloop endfacet - facet normal 0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 5.47142 -4.5 - vertex 9.31758 4.93464 4.5 - vertex 9.31758 4.93464 -4.5 + vertex 0.0225521 -14.4167 -4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.104536 0.994521 -0 + facet normal 0 0 -1 outer loop - vertex 11.9282 2.03525 -4.5 - vertex 11.3824 2.09262 4.5 - vertex 11.9282 2.03525 4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.104536 0.994521 0 + facet normal 0 0 -1 outer loop - vertex 11.3824 2.09262 4.5 - vertex 11.9282 2.03525 -4.5 - vertex 11.3824 2.09262 -4.5 + vertex 2.93542 -11.5843 -4.5 + vertex 0.682417 -12.9346 -4.5 + vertex 0.682417 -12.3859 -4.5 endloop endfacet - facet normal -0.669065 0.743204 0 + facet normal 0 0 -1 outer loop - vertex 13.879 2.90379 -4.5 - vertex 13.4711 2.53658 4.5 - vertex 13.879 2.90379 4.5 + vertex 10.8605 -2.2622 -4.5 + vertex 18 5.7735 -4.5 + vertex 11.3824 -2.09262 -4.5 endloop endfacet - facet normal -0.669065 0.743204 0 + facet normal 0 0 -1 outer loop - vertex 13.4711 2.53658 4.5 - vertex 13.879 2.90379 -4.5 - vertex 13.4711 2.53658 -4.5 + vertex 9.31758 -4.38587 -4.5 + vertex 9.31758 -4.93464 -4.5 + vertex 8.56458 -8.33429 -4.5 endloop endfacet - facet normal -0.978147 0.207915 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 3.84908 -4.5 - vertex 14.5388 4.38587 4.5 - vertex 14.5388 4.38587 -4.5 + vertex 11.3824 -2.09262 -4.5 + vertex 18 5.7735 -4.5 + vertex 11.9282 -2.03525 -4.5 endloop endfacet - facet normal -0.978147 0.207915 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 4.38587 4.5 - vertex 14.4247 3.84908 -4.5 - vertex 14.4247 3.84908 4.5 + vertex 9.31758 -4.93464 -4.5 + vertex 9.43168 -5.47142 -4.5 + vertex 8.56458 -8.33429 -4.5 endloop endfacet - facet normal -1 0 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 4.38587 -4.5 - vertex 14.5388 4.93464 4.5 - vertex 14.5388 4.93464 -4.5 + vertex 9.43168 -5.47142 -4.5 + vertex 9.65489 -5.97275 -4.5 + vertex 8.56458 -8.33429 -4.5 endloop endfacet - facet normal -1 -0 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 4.93464 4.5 - vertex 14.5388 4.38587 -4.5 - vertex 14.5388 4.38587 4.5 + vertex 13.4711 -6.78392 -4.5 + vertex 18 -5.7735 -4.5 + vertex 12.9959 -7.05831 -4.5 endloop endfacet - facet normal 1 -0 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 4.38587 4.5 - vertex 9.31758 4.93464 -4.5 - vertex 9.31758 4.93464 4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 9.97745 -6.41672 -4.5 + vertex 10.3853 -6.78392 -4.5 endloop endfacet - facet normal 1 0 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 4.93464 -4.5 - vertex 9.31758 4.38587 4.5 - vertex 9.31758 4.38587 -4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 10.3853 -6.78392 -4.5 + vertex 10.8605 -7.05831 -4.5 endloop endfacet - facet normal 0.978147 0.207915 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 3.84908 4.5 - vertex 9.31758 4.38587 -4.5 - vertex 9.31758 4.38587 4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 10.8605 -7.05831 -4.5 + vertex 11.3824 -7.22789 -4.5 endloop endfacet - facet normal 0.978147 0.207915 0 + facet normal 0 0 -1 outer loop - vertex 9.31758 4.38587 -4.5 - vertex 9.43168 3.84908 4.5 - vertex 9.43168 3.84908 -4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 11.3824 -7.22789 -4.5 + vertex 11.9282 -7.28525 -4.5 endloop endfacet - facet normal 0.809013 0.58779 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 2.90379 4.5 - vertex 9.65489 3.34775 -4.5 - vertex 9.65489 3.34775 4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 11.9282 -7.28525 -4.5 + vertex 12.474 -7.22789 -4.5 endloop endfacet - facet normal 0.809013 0.58779 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 3.34775 -4.5 - vertex 9.97745 2.90379 4.5 - vertex 9.97745 2.90379 -4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 12.474 -7.22789 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.500032 0.866007 -0 + facet normal 0 0 -1 outer loop - vertex 10.8605 2.2622 -4.5 - vertex 10.3853 2.53658 4.5 - vertex 10.8605 2.2622 4.5 + vertex 12.474 -7.22789 -4.5 + vertex 12.9959 -7.05831 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.500032 0.866007 0 + facet normal 0 0 -1 outer loop - vertex 10.3853 2.53658 4.5 - vertex 10.8605 2.2622 -4.5 - vertex 10.3853 2.53658 -4.5 + vertex 13.879 -6.41672 -4.5 + vertex 18 -5.7735 -4.5 + vertex 13.4711 -6.78392 -4.5 endloop endfacet - facet normal -0.91355 0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 3.34775 -4.5 - vertex 14.4247 3.84908 4.5 - vertex 14.4247 3.84908 -4.5 + vertex 14.2015 -5.97275 -4.5 + vertex 18 -5.7735 -4.5 + vertex 13.879 -6.41672 -4.5 endloop endfacet - facet normal -0.91355 0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 3.84908 4.5 - vertex 14.2015 3.34775 -4.5 - vertex 14.2015 3.34775 4.5 + vertex 12.474 -2.09262 -4.5 + vertex 18 5.7735 -4.5 + vertex 12.9959 -2.2622 -4.5 endloop endfacet - facet normal -0.500032 0.866007 0 + facet normal 0 0 -1 outer loop - vertex 13.4711 2.53658 -4.5 - vertex 12.9959 2.2622 4.5 - vertex 13.4711 2.53658 4.5 + vertex 14.5388 -4.38587 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.5388 -4.93464 -4.5 endloop endfacet - facet normal -0.500032 0.866007 0 + facet normal 0 0 -1 outer loop - vertex 12.9959 2.2622 4.5 - vertex 13.4711 2.53658 -4.5 - vertex 12.9959 2.2622 -4.5 + vertex 14.5388 -4.93464 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.4247 -5.47142 -4.5 endloop endfacet - facet normal -0.104536 0.994521 0 + facet normal 0 0 -1 outer loop - vertex 12.474 2.09262 -4.5 - vertex 11.9282 2.03525 4.5 - vertex 12.474 2.09262 4.5 + vertex 14.2015 -5.97275 -4.5 + vertex 14.4247 -5.47142 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.104536 0.994521 0 + facet normal 0 0 -1 outer loop - vertex 11.9282 2.03525 4.5 - vertex 12.474 2.09262 -4.5 - vertex 11.9282 2.03525 -4.5 + vertex 14.4247 -3.84908 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.5388 -4.38587 -4.5 endloop endfacet - facet normal 0.309024 0.951054 -0 + facet normal 0 0 -1 outer loop - vertex 11.3824 2.09262 -4.5 - vertex 10.8605 2.2622 4.5 - vertex 11.3824 2.09262 4.5 + vertex 14.2015 -3.34775 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.4247 -3.84908 -4.5 endloop endfacet - facet normal 0.309024 0.951054 0 + facet normal 0 0 -1 outer loop - vertex 10.8605 2.2622 4.5 - vertex 11.3824 2.09262 -4.5 - vertex 10.8605 2.2622 -4.5 + vertex 13.879 -2.90379 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.2015 -3.34775 -4.5 endloop endfacet - facet normal -0.309024 0.951054 0 + facet normal 0 0 -1 outer loop - vertex 12.9959 2.2622 -4.5 - vertex 12.474 2.09262 4.5 - vertex 12.9959 2.2622 4.5 + vertex 13.4711 -2.53658 -4.5 + vertex 18 5.7735 -4.5 + vertex 13.879 -2.90379 -4.5 endloop endfacet - facet normal -0.309024 0.951054 0 + facet normal 0 0 -1 outer loop - vertex 12.474 2.09262 4.5 - vertex 12.9959 2.2622 -4.5 - vertex 12.474 2.09262 -4.5 + vertex 12.9959 -2.2622 -4.5 + vertex 18 5.7735 -4.5 + vertex 13.4711 -2.53658 -4.5 endloop endfacet - facet normal 0.913543 -0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.43168 5.47142 4.5 - vertex 9.65489 5.97275 -4.5 - vertex 9.65489 5.97275 4.5 + vertex 10.3853 -2.53658 -4.5 + vertex 18 5.7735 -4.5 + vertex 10.8605 -2.2622 -4.5 endloop endfacet - facet normal 0.913543 -0.406742 0 + facet normal 0 0 -1 outer loop - vertex 9.65489 5.97275 -4.5 - vertex 9.43168 5.47142 4.5 - vertex 9.43168 5.47142 -4.5 + vertex 9.65489 -3.34775 -4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 9.97745 -2.90379 -4.5 endloop endfacet - facet normal -0.309024 -0.951054 0 + facet normal 0 0 -1 outer loop - vertex 12.474 7.22789 -4.5 - vertex 12.9959 7.05831 4.5 - vertex 12.474 7.22789 4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 9.31758 -4.38587 -4.5 + vertex 8.56458 -8.33429 -4.5 endloop endfacet - facet normal -0.309024 -0.951054 -0 + facet normal 0 0 -1 outer loop - vertex 12.9959 7.05831 4.5 - vertex 12.474 7.22789 -4.5 - vertex 12.9959 7.05831 -4.5 + vertex 3.47877 2.52748 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 9.31758 4.93464 -4.5 endloop endfacet - facet normal -0.104518 -0.994523 0 + facet normal 0 0 -1 outer loop - vertex 11.9282 7.28525 -4.5 - vertex 12.474 7.22789 4.5 - vertex 11.9282 7.28525 4.5 + vertex 3.47877 2.52748 -4.5 + vertex 9.31758 4.93464 -4.5 + vertex 9.31758 4.38587 -4.5 endloop endfacet - facet normal -0.104518 -0.994523 -0 + facet normal 0 0 -1 outer loop - vertex 12.474 7.22789 4.5 - vertex 11.9282 7.28525 -4.5 - vertex 12.474 7.22789 -4.5 + vertex 14.4247 5.47142 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.5388 4.93464 -4.5 endloop endfacet - facet normal 0.104518 -0.994523 0 + facet normal 0 0 -1 outer loop - vertex 11.3824 7.22789 -4.5 - vertex 11.9282 7.28525 4.5 - vertex 11.3824 7.22789 4.5 + vertex 3.92824 1.74897 -4.5 + vertex 3.47877 2.52748 -4.5 + vertex 9.43168 3.84908 -4.5 endloop endfacet - facet normal 0.104518 -0.994523 0 + facet normal 0 0 -1 outer loop - vertex 11.9282 7.28525 4.5 - vertex 11.3824 7.22789 -4.5 - vertex 11.9282 7.28525 -4.5 + vertex 10.8605 7.05831 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex -1.9282 10.0353 -4.5 endloop endfacet - facet normal 0.500045 -0.865999 0 + facet normal 0 0 -1 outer loop - vertex 10.3853 6.78392 -4.5 - vertex 10.8605 7.05831 4.5 - vertex 10.3853 6.78392 4.5 + vertex 4.20603 0.89402 -4.5 + vertex 3.92824 1.74897 -4.5 + vertex 9.65489 3.34775 -4.5 endloop endfacet - facet normal 0.500045 -0.865999 0 + facet normal 0 0 -1 outer loop - vertex 10.8605 7.05831 4.5 - vertex 10.3853 6.78392 -4.5 - vertex 10.8605 7.05831 -4.5 + vertex 14.5388 4.93464 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.5388 4.38587 -4.5 endloop endfacet - facet normal -0.500045 -0.865999 0 + facet normal 0 0 -1 outer loop - vertex 12.9959 7.05831 -4.5 - vertex 13.4711 6.78392 4.5 - vertex 12.9959 7.05831 4.5 + vertex 4.3 0 -4.5 + vertex 4.20603 0.89402 -4.5 + vertex 9.97745 2.90379 -4.5 endloop endfacet - facet normal -0.500045 -0.865999 -0 + facet normal 0 0 -1 outer loop - vertex 13.4711 6.78392 4.5 - vertex 12.9959 7.05831 -4.5 - vertex 13.4711 6.78392 -4.5 + vertex 4.20603 -0.89402 -4.5 + vertex 4.3 0 -4.5 + vertex 10.3853 2.53658 -4.5 endloop endfacet - facet normal -0.809072 -0.58771 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 5.97275 -4.5 - vertex 13.879 6.41672 4.5 - vertex 13.879 6.41672 -4.5 + vertex 3.92824 -1.74897 -4.5 + vertex 4.20603 -0.89402 -4.5 + vertex 10.8605 2.2622 -4.5 endloop endfacet - facet normal -0.809072 -0.58771 0 + facet normal 0 0 -1 outer loop - vertex 13.879 6.41672 4.5 - vertex 14.2015 5.97275 -4.5 - vertex 14.2015 5.97275 4.5 + vertex 11.9282 2.03525 -4.5 + vertex 3.47877 -2.52748 -4.5 + vertex 11.3824 2.09262 -4.5 endloop endfacet - facet normal -0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 5.47142 -4.5 - vertex 14.2015 5.97275 4.5 - vertex 14.2015 5.97275 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 2.15 -3.72391 -4.5 + vertex 11.9282 2.03525 -4.5 endloop endfacet - facet normal -0.91355 -0.406727 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 5.97275 4.5 - vertex 14.4247 5.47142 -4.5 - vertex 14.4247 5.47142 4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 11.9282 2.03525 -4.5 + vertex 12.474 2.09262 -4.5 endloop endfacet - facet normal 0.669111 0.743163 -0 + facet normal 0 0 -1 outer loop - vertex 10.3853 2.53658 -4.5 - vertex 9.97745 2.90379 4.5 - vertex 10.3853 2.53658 4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 12.474 2.09262 -4.5 + vertex 12.9959 2.2622 -4.5 endloop endfacet - facet normal 0.669111 0.743163 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 2.90379 4.5 - vertex 10.3853 2.53658 -4.5 - vertex 9.97745 2.90379 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 12.9959 2.2622 -4.5 + vertex 13.4711 2.53658 -4.5 endloop endfacet - facet normal -0.809065 0.587719 0 + facet normal 0 0 -1 outer loop - vertex 13.879 2.90379 -4.5 - vertex 14.2015 3.34775 4.5 - vertex 14.2015 3.34775 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 13.4711 2.53658 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal -0.809065 0.587719 0 + facet normal 0 0 -1 outer loop - vertex 14.2015 3.34775 4.5 + vertex 14.2015 3.34775 -4.5 + vertex 18 5.7735 -4.5 vertex 13.879 2.90379 -4.5 - vertex 13.879 2.90379 4.5 endloop endfacet - facet normal 0.309024 -0.951054 0 + facet normal 0 0 -1 outer loop - vertex 10.8605 7.05831 -4.5 - vertex 11.3824 7.22789 4.5 - vertex 10.8605 7.05831 4.5 + vertex 14.4247 3.84908 -4.5 + vertex 18 5.7735 -4.5 + vertex 14.2015 3.34775 -4.5 endloop endfacet - facet normal 0.309024 -0.951054 0 + facet normal 0 0 -1 outer loop - vertex 11.3824 7.22789 4.5 - vertex 10.8605 7.05831 -4.5 - vertex 11.3824 7.22789 -4.5 + vertex 2.15 3.72391 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 2.87726 3.19552 -4.5 endloop endfacet - facet normal 0.669101 -0.743172 0 + facet normal 0 0 -1 outer loop - vertex 9.97745 6.41672 -4.5 - vertex 10.3853 6.78392 4.5 - vertex 9.97745 6.41672 4.5 + vertex 13.4711 6.78392 -4.5 + vertex 18 5.7735 -4.5 + vertex 13.879 6.41672 -4.5 endloop endfacet - facet normal 0.669101 -0.743172 0 + facet normal 0 0 -1 outer loop - vertex 10.3853 6.78392 4.5 vertex 9.97745 6.41672 -4.5 + vertex -2.47397 10.0926 -4.5 vertex 10.3853 6.78392 -4.5 endloop endfacet - facet normal -0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex 14.5388 4.93464 -4.5 - vertex 14.4247 5.47142 4.5 vertex 14.4247 5.47142 -4.5 + vertex 14.2015 5.97275 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal -0.978146 -0.207918 0 + facet normal 0 0 -1 outer loop - vertex 14.4247 5.47142 4.5 - vertex 14.5388 4.93464 -4.5 - vertex 14.5388 4.93464 4.5 + vertex 10.3853 6.78392 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 10.8605 7.05831 -4.5 endloop endfacet - facet normal 0.913534 0.406762 0 + facet normal 0 0 -1 outer loop - vertex -4.20152 11.3478 4.5 - vertex -4.42473 11.8491 -4.5 - vertex -4.42473 11.8491 4.5 + vertex 14.2015 5.97275 -4.5 + vertex 13.879 6.41672 -4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.913534 0.406762 0 + facet normal 0 0 -1 outer loop - vertex -4.42473 11.8491 -4.5 - vertex -4.20152 11.3478 4.5 - vertex -4.20152 11.3478 -4.5 + vertex 10.8605 7.05831 -4.5 + vertex -1.9282 10.0353 -4.5 + vertex 11.3824 7.22789 -4.5 endloop endfacet - facet normal -0.809039 0.587756 0 + facet normal 0 0 -1 outer loop - vertex 0.022553 10.9038 -4.5 - vertex 0.345113 11.3478 4.5 - vertex 0.345113 11.3478 -4.5 + vertex 12.9959 7.05831 -4.5 + vertex 18 5.7735 -4.5 + vertex 13.4711 6.78392 -4.5 endloop endfacet - facet normal -0.809039 0.587756 0 + facet normal 0 0 -1 outer loop - vertex 0.345113 11.3478 4.5 - vertex 0.022553 10.9038 -4.5 - vertex 0.022553 10.9038 4.5 + vertex 11.3824 7.22789 -4.5 + vertex -0.860519 10.2622 -4.5 + vertex 11.9282 7.28525 -4.5 endloop endfacet - facet normal 0.808976 -0.587842 0 + facet normal 0 0 -1 outer loop - vertex -4.20152 13.9728 4.5 - vertex -3.87896 14.4167 -4.5 - vertex -3.87896 14.4167 4.5 + vertex 12.474 7.22789 -4.5 + vertex 18 5.7735 -4.5 + vertex 12.9959 7.05831 -4.5 endloop endfacet - facet normal 0.808976 -0.587842 0 + facet normal 0 0 -1 outer loop - vertex -3.87896 14.4167 -4.5 - vertex -4.20152 13.9728 4.5 - vertex -4.20152 13.9728 -4.5 + vertex -0.385267 10.5366 -4.5 + vertex 0.0225516 10.9038 -4.5 + vertex 12.474 7.22789 -4.5 endloop endfacet - facet normal -0.669129 -0.743147 0 + facet normal 0 0 -1 outer loop - vertex -0.385267 14.7839 -4.5 - vertex 0.0225522 14.4167 4.5 - vertex -0.385267 14.7839 4.5 + vertex 11.9282 7.28525 -4.5 + vertex -0.860519 10.2622 -4.5 + vertex -0.385267 10.5366 -4.5 endloop endfacet - facet normal -0.669129 -0.743147 -0 + facet normal 0 0 -1 outer loop - vertex 0.0225522 14.4167 4.5 - vertex -0.385267 14.7839 -4.5 - vertex 0.0225522 14.4167 -4.5 + vertex 11.3824 7.22789 -4.5 + vertex -1.38243 10.0926 -4.5 + vertex -0.860519 10.2622 -4.5 endloop endfacet - facet normal 0.978151 -0.207894 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 12.9346 4.5 - vertex -4.42473 13.4714 -4.5 - vertex -4.42473 13.4714 4.5 + vertex -1.9282 10.0353 -4.5 + vertex -1.38243 10.0926 -4.5 + vertex 11.3824 7.22789 -4.5 endloop endfacet - facet normal 0.978151 -0.207894 0 + facet normal 0 0 -1 outer loop - vertex -4.42473 13.4714 -4.5 - vertex -4.53882 12.9346 4.5 - vertex -4.53882 12.9346 -4.5 + vertex 9.65489 5.97275 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 9.97745 6.41672 -4.5 endloop endfacet - facet normal 0.104415 0.994534 -0 + facet normal 0 0 -1 outer loop - vertex -1.9282 10.0353 -4.5 - vertex -2.47397 10.0926 4.5 - vertex -1.9282 10.0353 4.5 + vertex 9.43168 5.47142 -4.5 + vertex -2.47397 10.0926 -4.5 + vertex 9.65489 5.97275 -4.5 endloop endfacet - facet normal 0.104415 0.994534 0 + facet normal 0 0 -1 outer loop - vertex -2.47397 10.0926 4.5 - vertex -1.9282 10.0353 -4.5 + vertex 9.31758 4.93464 -4.5 vertex -2.47397 10.0926 -4.5 + vertex 9.43168 5.47142 -4.5 endloop endfacet - facet normal -0.669128 0.743147 0 + facet normal 0 0 -1 outer loop - vertex 0.022553 10.9038 -4.5 - vertex -0.385267 10.5366 4.5 - vertex 0.022553 10.9038 4.5 + vertex -11.0677 -10.3981 -4.5 + vertex -4 -18.4752 -4.5 + vertex -11.5429 -10.1237 -4.5 endloop endfacet - facet normal -0.669128 0.743147 0 + facet normal 0 0 -1 outer loop - vertex -0.385267 10.5366 4.5 - vertex 0.022553 10.9038 -4.5 - vertex -0.385267 10.5366 -4.5 + vertex -11.5429 5.87633 -4.5 + vertex -7.50348 -7.18883 -4.5 + vertex -7.72668 -6.6875 -4.5 endloop endfacet - facet normal -0.978149 0.207904 0 + facet normal 0 0 -1 outer loop - vertex 0.568321 11.8491 -4.5 - vertex 0.682417 12.3859 4.5 - vertex 0.682417 12.3859 -4.5 + vertex -3.87896 10.9038 -4.5 + vertex -4.20603 0.89402 -4.5 + vertex -4.3 0 -4.5 endloop endfacet - facet normal -0.978149 0.207904 0 + facet normal 0 0 -1 outer loop - vertex 0.682417 12.3859 4.5 - vertex 0.568321 11.8491 -4.5 - vertex 0.568321 11.8491 4.5 + vertex -4.3 0 -4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.20152 11.3478 -4.5 endloop endfacet - facet normal -1 0 0 + facet normal 0 0 -1 outer loop - vertex 0.682417 12.3859 -4.5 - vertex 0.682417 12.9346 4.5 - vertex 0.682417 12.9346 -4.5 + vertex -3.87896 10.9038 -4.5 + vertex -4.3 0 -4.5 + vertex -4.20152 11.3478 -4.5 endloop endfacet - facet normal -1 -0 0 + facet normal 0 0 -1 outer loop - vertex 0.682417 12.9346 4.5 - vertex 0.682417 12.3859 -4.5 - vertex 0.682417 12.3859 4.5 + vertex 9.43168 3.84908 -4.5 + vertex 3.47877 2.52748 -4.5 + vertex 9.31758 4.38587 -4.5 endloop endfacet - facet normal 1 -0 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 12.3859 4.5 - vertex -4.53882 12.9346 -4.5 - vertex -4.53882 12.9346 4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 9.65489 -3.34775 -4.5 + vertex 9.43168 -3.84908 -4.5 endloop endfacet - facet normal 1 0 0 + facet normal 0 0 -1 outer loop - vertex -4.53882 12.9346 -4.5 - vertex -4.53882 12.3859 4.5 - vertex -4.53882 12.3859 -4.5 + vertex 11.9282 -2.03525 -4.5 + vertex 18 5.7735 -4.5 + vertex 12.474 -2.09262 -4.5 endloop endfacet - facet normal 0.978151 0.207894 0 + facet normal 0 0 -1 outer loop - vertex -4.42473 11.8491 4.5 - vertex -4.53882 12.3859 -4.5 - vertex -4.53882 12.3859 4.5 + vertex 9.97745 -6.41672 -4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 9.65489 -5.97275 -4.5 endloop endfacet - facet normal 0.978151 0.207894 0 + facet normal -1 0 0 outer loop - vertex -4.53882 12.3859 -4.5 - vertex -4.42473 11.8491 4.5 - vertex -4.42473 11.8491 -4.5 + vertex -14 -12.7017 -4.5 + vertex -14 -12.7017 4.5 + vertex -14 12.7017 -4.5 endloop endfacet - facet normal 0.809039 0.587756 0 + facet normal -1 0 0 outer loop - vertex -3.87896 10.9038 4.5 - vertex -4.20152 11.3478 -4.5 - vertex -4.20152 11.3478 4.5 + vertex -14 12.7017 -4.5 + vertex -14 -12.7017 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0.809039 0.587756 0 + facet normal -0.5 -0.866025 0 outer loop - vertex -4.20152 11.3478 -4.5 - vertex -3.87896 10.9038 4.5 - vertex -3.87896 10.9038 -4.5 + vertex -4 -18.4752 -4.5 + vertex -4 -18.4752 4.5 + vertex -14 -12.7017 4.5 endloop endfacet - facet normal 0.50002 0.866014 -0 + facet normal -0.5 -0.866025 0 outer loop - vertex -2.99589 10.2622 -4.5 - vertex -3.47114 10.5366 4.5 - vertex -2.99589 10.2622 4.5 + vertex -14 -12.7017 -4.5 + vertex -4 -18.4752 -4.5 + vertex -14 -12.7017 4.5 endloop endfacet - facet normal 0.50002 0.866014 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.47114 10.5366 4.5 - vertex -2.99589 10.2622 -4.5 - vertex -3.47114 10.5366 -4.5 + vertex 7.27009 -11.9684 -1.46722 + vertex -4 -18.4752 -4.5 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.913535 0.406759 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.345113 11.3478 -4.5 - vertex 0.568321 11.8491 4.5 - vertex 0.568321 11.8491 -4.5 + vertex 6.72991 -12.2803 1.46722 + vertex 7 -12.1244 1.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.913535 0.406759 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.568321 11.8491 4.5 - vertex 0.345113 11.3478 -4.5 - vertex 0.345113 11.3478 4.5 + vertex 7.27009 -11.9684 -1.46722 + vertex 7 -12.1244 -1.5 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal -0.500018 0.866015 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.385267 10.5366 -4.5 - vertex -0.860519 10.2622 4.5 - vertex -0.385267 10.5366 4.5 + vertex -4 -18.4752 4.5 + vertex -4 -18.4752 -4.5 + vertex 5.70808 -12.8702 -0.156793 endloop endfacet - facet normal -0.500018 0.866015 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.860519 10.2622 4.5 - vertex -0.385267 10.5366 -4.5 - vertex -0.860519 10.2622 -4.5 + vertex -4 -18.4752 4.5 + vertex 5.70808 -12.8702 -0.156793 + vertex 5.70808 -12.8702 0.156793 endloop endfacet - facet normal -0.104415 0.994534 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.38243 10.0926 -4.5 - vertex -1.9282 10.0353 4.5 - vertex -1.38243 10.0926 4.5 + vertex 8.125 -11.4748 -0.75 + vertex 7.96537 -11.567 -1.0037 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.104415 0.994534 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.9282 10.0353 4.5 - vertex -1.38243 10.0926 -4.5 - vertex -1.9282 10.0353 -4.5 + vertex -4 -18.4752 4.5 + vertex 5.70808 -12.8702 0.156793 + vertex 5.76454 -12.8376 0.463525 endloop endfacet - facet normal 0.309047 0.951047 -0 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.47397 10.0926 -4.5 - vertex -2.99589 10.2622 4.5 - vertex -2.47397 10.0926 4.5 + vertex 8.23546 -11.4111 -0.463525 + vertex 8.125 -11.4748 -0.75 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.309047 0.951047 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.99589 10.2622 4.5 - vertex -2.47397 10.0926 -4.5 - vertex -2.99589 10.2622 -4.5 + vertex 6.03463 -12.6817 1.0037 + vertex -4 -18.4752 4.5 + vertex 5.875 -12.7739 0.75 endloop endfacet - facet normal -0.309051 0.951045 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.860519 10.2622 -4.5 - vertex -1.38243 10.0926 4.5 - vertex -0.860519 10.2622 4.5 + vertex 6.23644 -12.5652 1.21353 + vertex -4 -18.4752 4.5 + vertex 6.03463 -12.6817 1.0037 endloop endfacet - facet normal -0.309051 0.951045 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.38243 10.0926 4.5 - vertex -0.860519 10.2622 -4.5 - vertex -1.38243 10.0926 -4.5 + vertex 6.47163 -12.4294 1.37032 + vertex -4 -18.4752 4.5 + vertex 6.23644 -12.5652 1.21353 endloop endfacet - facet normal 0.913564 -0.406695 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -4.42473 13.4714 4.5 - vertex -4.20152 13.9728 -4.5 - vertex -4.20152 13.9728 4.5 + vertex 6.72991 -12.2803 1.46722 + vertex -4 -18.4752 4.5 + vertex 6.47163 -12.4294 1.37032 endloop endfacet - facet normal 0.913564 -0.406695 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -4.20152 13.9728 -4.5 - vertex -4.42473 13.4714 4.5 - vertex -4.42473 13.4714 -4.5 + vertex 7 -12.1244 1.5 + vertex 7.27009 -11.9684 1.46722 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.309051 -0.951045 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.38243 15.2279 -4.5 - vertex -0.860519 15.0583 4.5 - vertex -1.38243 15.2279 4.5 + vertex 18 -5.7735 4.5 + vertex -4 -18.4752 4.5 + vertex 6.72991 -12.2803 1.46722 endloop endfacet - facet normal -0.309051 -0.951045 -0 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.860519 15.0583 4.5 - vertex -1.38243 15.2279 -4.5 - vertex -0.860519 15.0583 -4.5 + vertex 7.27009 -11.9684 1.46722 + vertex 7.52837 -11.8193 1.37032 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.104596 -0.994515 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.9282 15.2853 -4.5 - vertex -1.38243 15.2279 4.5 - vertex -1.9282 15.2853 4.5 + vertex 7.52837 -11.8193 1.37032 + vertex 7.76356 -11.6835 1.21353 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.104596 -0.994515 -0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.38243 15.2279 4.5 - vertex -1.9282 15.2853 -4.5 - vertex -1.38243 15.2279 -4.5 + vertex 8.29192 -11.3785 -0.156793 + vertex 8.23546 -11.4111 -0.463525 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.104596 -0.994515 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.47397 15.2279 -4.5 - vertex -1.9282 15.2853 4.5 - vertex -2.47397 15.2279 4.5 + vertex 18 -5.7735 4.5 + vertex 7.76356 -11.6835 1.21353 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.104596 -0.994515 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.9282 15.2853 4.5 - vertex -2.47397 15.2279 -4.5 - vertex -1.9282 15.2853 -4.5 + vertex 7.76356 -11.6835 1.21353 + vertex 7.96537 -11.567 1.0037 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.50002 -0.866014 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.47114 14.7839 -4.5 - vertex -2.99589 15.0583 4.5 - vertex -3.47114 14.7839 4.5 + vertex 7.96537 -11.567 1.0037 + vertex 8.125 -11.4748 0.75 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal 0.50002 -0.866014 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.99589 15.0583 4.5 - vertex -3.47114 14.7839 -4.5 - vertex -2.99589 15.0583 -4.5 + vertex 8.125 -11.4748 0.75 + vertex 8.23546 -11.4111 0.463525 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.500018 -0.866015 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.860519 15.0583 -4.5 - vertex -0.385267 14.7839 4.5 - vertex -0.860519 15.0583 4.5 + vertex 8.23546 -11.4111 0.463525 + vertex 8.29192 -11.3785 0.156793 + vertex 18 -5.7735 -4.5 endloop - endfacet - facet normal -0.500018 -0.866015 -0 - outer loop - vertex -0.385267 14.7839 4.5 - vertex -0.860519 15.0583 -4.5 - vertex -0.385267 14.7839 -4.5 + endfacet + facet normal 0.5 -0.866025 0 + outer loop + vertex 8.29192 -11.3785 0.156793 + vertex 8.29192 -11.3785 -0.156793 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.808974 -0.587844 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.345114 13.9728 -4.5 - vertex 0.0225522 14.4167 4.5 - vertex 0.0225522 14.4167 -4.5 + vertex 7.96537 -11.567 -1.0037 + vertex 7.76356 -11.6835 -1.21352 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.808974 -0.587844 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.0225522 14.4167 4.5 - vertex 0.345114 13.9728 -4.5 - vertex 0.345114 13.9728 4.5 + vertex 7.76356 -11.6835 -1.21352 + vertex 7.52837 -11.8193 -1.37032 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.913566 -0.40669 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.568321 13.4714 -4.5 - vertex 0.345114 13.9728 4.5 - vertex 0.345114 13.9728 -4.5 + vertex 7.52837 -11.8193 -1.37032 + vertex 7.27009 -11.9684 -1.46722 + vertex 18 -5.7735 -4.5 endloop endfacet - facet normal -0.913566 -0.40669 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.345114 13.9728 4.5 - vertex 0.568321 13.4714 -4.5 - vertex 0.568321 13.4714 4.5 + vertex 7 -12.1244 -1.5 + vertex 6.72991 -12.2803 -1.46722 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal 0.669128 0.743147 -0 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.47114 10.5366 -4.5 - vertex -3.87896 10.9038 4.5 - vertex -3.47114 10.5366 4.5 + vertex 6.72991 -12.2803 -1.46722 + vertex 6.47163 -12.4294 -1.37032 + vertex -4 -18.4752 -4.5 endloop endfacet - facet normal 0.669128 0.743147 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.87896 10.9038 4.5 - vertex -3.47114 10.5366 -4.5 - vertex -3.87896 10.9038 -4.5 + vertex 6.23644 -12.5652 -1.21352 + vertex -4 -18.4752 -4.5 + vertex 6.47163 -12.4294 -1.37032 endloop endfacet - facet normal 0.309047 -0.951047 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.99589 15.0583 -4.5 - vertex -2.47397 15.2279 4.5 - vertex -2.99589 15.0583 4.5 + vertex 6.03463 -12.6817 -1.0037 + vertex -4 -18.4752 -4.5 + vertex 6.23644 -12.5652 -1.21352 endloop endfacet - facet normal 0.309047 -0.951047 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.47397 15.2279 4.5 - vertex -2.99589 15.0583 -4.5 - vertex -2.47397 15.2279 -4.5 + vertex 5.875 -12.7739 -0.75 + vertex -4 -18.4752 -4.5 + vertex 6.03463 -12.6817 -1.0037 endloop endfacet - facet normal 0.669128 -0.743147 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.87896 14.4167 -4.5 - vertex -3.47114 14.7839 4.5 - vertex -3.87896 14.4167 4.5 + vertex 5.76454 -12.8376 -0.463525 + vertex -4 -18.4752 -4.5 + vertex 5.875 -12.7739 -0.75 endloop endfacet - facet normal 0.669128 -0.743147 0 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.47114 14.7839 4.5 - vertex -3.87896 14.4167 -4.5 - vertex -3.47114 14.7839 -4.5 + vertex 5.70808 -12.8702 -0.156793 + vertex -4 -18.4752 -4.5 + vertex 5.76454 -12.8376 -0.463525 endloop endfacet - facet normal -0.978149 -0.207904 0 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.682417 12.9346 -4.5 - vertex 0.568321 13.4714 4.5 - vertex 0.568321 13.4714 -4.5 + vertex 5.76454 -12.8376 0.463525 + vertex 5.875 -12.7739 0.75 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.978149 -0.207904 0 + facet normal 1 0 0 outer loop - vertex 0.568321 13.4714 4.5 - vertex 0.682417 12.9346 -4.5 - vertex 0.682417 12.9346 4.5 + vertex 18 5.7735 -4.5 + vertex 18 5.7735 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -1 0 0 + facet normal 1 0 0 outer loop - vertex -14 -12.7017 -4.5 - vertex -14 12.7017 4.5 - vertex -14 12.7017 -4.5 + vertex 18 -5.7735 -4.5 + vertex 18 5.7735 -4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -1 -0 0 + facet normal 0.5 0.866025 0 outer loop - vertex -14 12.7017 4.5 - vertex -14 -12.7017 -4.5 - vertex -14 -12.7017 4.5 + vertex -4 18.4752 -4.5 + vertex -4 18.4752 4.5 + vertex 18 5.7735 -4.5 endloop endfacet - facet normal 0.5 0.866026 -0 + facet normal 0.5 0.866025 0 outer loop vertex 18 5.7735 -4.5 vertex -4 18.4752 4.5 vertex 18 5.7735 4.5 endloop endfacet - facet normal 0.5 0.866026 0 + facet normal -0.5 0.866025 0 outer loop vertex -4 18.4752 4.5 - vertex 18 5.7735 -4.5 vertex -4 18.4752 -4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0.5 -0.866026 1.44338e-05 - outer loop - vertex -4 -18.4752 4.5 - vertex 7 -12.1244 1.5 - vertex 18 -5.7735 4.5 - endloop - endfacet - facet normal 0.499539 -0.866289 -0.00223299 + facet normal -0.5 0.866025 0 outer loop - vertex -4 -18.4752 4.5 - vertex 6.91897 -12.1711 1.49017 - vertex 7 -12.1244 1.5 + vertex -14 12.7017 4.5 + vertex -4 18.4752 -4.5 + vertex -14 12.7017 -4.5 endloop endfacet - facet normal 0.500124 -0.865953 0.000593172 + facet normal 1 -6.12323e-17 0 outer loop - vertex -4 -18.4752 4.5 - vertex 6.72992 -12.2803 1.46722 - vertex 6.91897 -12.1711 1.49017 + vertex -12.6106 -7.72561 -4.5 + vertex -12.6106 -7.72561 4.5 + vertex -12.6106 -8.27439 4.5 endloop endfacet - facet normal 0.499974 -0.866041 -0.000118595 + facet normal 1 -6.12323e-17 0 outer loop - vertex -4 -18.4752 4.5 - vertex 6.47163 -12.4294 1.37032 - vertex 6.72992 -12.2803 1.46722 + vertex -12.6106 -8.27439 -4.5 + vertex -12.6106 -7.72561 -4.5 + vertex -12.6106 -8.27439 4.5 endloop endfacet - facet normal 0.500011 -0.866019 4.94012e-05 + facet normal 0.978148 -0.207912 0 outer loop - vertex -4 -18.4752 4.5 - vertex 6.23644 -12.5652 1.21352 - vertex 6.47163 -12.4294 1.37032 + vertex -12.4965 -7.18883 -4.5 + vertex -12.4965 -7.18883 4.5 + vertex -12.6106 -7.72561 4.5 endloop endfacet - facet normal 0.499988 -0.866032 -4.6779e-05 + facet normal 0.978148 -0.207912 0 outer loop - vertex -4 -18.4752 4.5 - vertex 6.03463 -12.6817 1.0037 - vertex 6.23644 -12.5652 1.21352 + vertex -12.6106 -7.72561 -4.5 + vertex -12.4965 -7.18883 -4.5 + vertex -12.6106 -7.72561 4.5 endloop endfacet - facet normal 0.500028 -0.866009 0.000105041 + facet normal 0.913546 -0.406736 0 outer loop - vertex -4 -18.4752 4.5 - vertex 5.875 -12.7739 0.75 - vertex 6.03463 -12.6817 1.0037 + vertex -12.2733 -6.6875 -4.5 + vertex -12.2733 -6.6875 4.5 + vertex -12.4965 -7.18883 4.5 endloop endfacet - facet normal 0.499942 -0.866059 -0.000194432 + facet normal 0.913546 -0.406736 0 outer loop - vertex -4 -18.4752 4.5 - vertex 5.76454 -12.8376 0.463525 - vertex 5.875 -12.7739 0.75 + vertex -12.4965 -7.18883 -4.5 + vertex -12.2733 -6.6875 -4.5 + vertex -12.4965 -7.18883 4.5 endloop endfacet - facet normal 0.500005 -0.866023 6.74655e-06 + facet normal 0.809017 -0.587786 0 outer loop - vertex -4 -18.4752 4.5 - vertex 5.70808 -12.8702 0.156793 - vertex 5.76454 -12.8376 0.463525 + vertex -11.9508 -6.24353 -4.5 + vertex -11.9508 -6.24353 4.5 + vertex -12.2733 -6.6875 4.5 endloop endfacet - facet normal 0.500003 -0.866024 0 + facet normal 0.809017 -0.587786 0 outer loop - vertex -4 -18.4752 4.5 - vertex 5.70808 -12.8702 -0.156793 - vertex 5.70808 -12.8702 0.156793 + vertex -12.2733 -6.6875 -4.5 + vertex -11.9508 -6.24353 -4.5 + vertex -12.2733 -6.6875 4.5 endloop endfacet - facet normal 0.500003 -0.866024 0 + facet normal 0.669131 -0.743145 0 outer loop - vertex -4 -18.4752 -4.5 - vertex 5.70808 -12.8702 -0.156793 - vertex -4 -18.4752 4.5 + vertex -11.5429 -5.87633 -4.5 + vertex -11.5429 -5.87633 4.5 + vertex -11.9508 -6.24353 4.5 endloop endfacet - facet normal 0.500005 -0.866023 -6.74655e-06 + facet normal 0.669131 -0.743145 0 outer loop - vertex 5.70808 -12.8702 -0.156793 - vertex -4 -18.4752 -4.5 - vertex 5.76454 -12.8376 -0.463525 + vertex -11.9508 -6.24353 -4.5 + vertex -11.5429 -5.87633 -4.5 + vertex -11.9508 -6.24353 4.5 endloop endfacet - facet normal 0.499912 -0.866076 0.000291391 + facet normal 0.5 -0.866025 0 outer loop - vertex 5.76454 -12.8376 -0.463525 - vertex -4 -18.4752 -4.5 - vertex 5.79768 -12.8185 -0.549467 + vertex -11.0677 -5.60194 -4.5 + vertex -11.0677 -5.60194 4.5 + vertex -11.5429 -5.87633 4.5 endloop endfacet - facet normal 0.499954 -0.866052 0.00015241 + facet normal 0.5 -0.866025 0 outer loop - vertex 5.79768 -12.8185 -0.549467 - vertex -4 -18.4752 -4.5 - vertex 5.875 -12.7739 -0.749999 + vertex -11.5429 -5.87633 -4.5 + vertex -11.0677 -5.60194 -4.5 + vertex -11.5429 -5.87633 4.5 endloop endfacet - facet normal 0.499983 -0.866035 5.01284e-05 + facet normal 0.309016 -0.951057 0 outer loop - vertex 5.875 -12.7739 -0.749999 - vertex -4 -18.4752 -4.5 - vertex 5.98674 -12.7094 -0.927587 + vertex -10.5458 -5.43236 -4.5 + vertex -10.5458 -5.43236 4.5 + vertex -11.0677 -5.60194 4.5 endloop endfacet - facet normal 0.500124 -0.865954 -0.000472903 + facet normal 0.309016 -0.951057 0 outer loop - vertex 5.98674 -12.7094 -0.927587 - vertex -4 -18.4752 -4.5 - vertex 6.03463 -12.6817 -1.0037 + vertex -11.0677 -5.60194 -4.5 + vertex -10.5458 -5.43236 -4.5 + vertex -11.0677 -5.60194 4.5 endloop endfacet - facet normal 0.499988 -0.866032 4.6779e-05 + facet normal 0.104529 -0.994522 0 outer loop - vertex 6.03463 -12.6817 -1.0037 - vertex -4 -18.4752 -4.5 - vertex 6.23644 -12.5652 -1.21352 + vertex -10 -5.375 -4.5 + vertex -10 -5.375 4.5 + vertex -10.5458 -5.43236 4.5 endloop endfacet - facet normal 0.499871 -0.8661 0.000615259 + facet normal 0.104529 -0.994522 0 outer loop - vertex 6.81094 -12.2335 -1.47705 - vertex -4 -18.4752 -4.5 - vertex 7 -12.1244 -1.5 + vertex -10.5458 -5.43236 -4.5 + vertex -10 -5.375 -4.5 + vertex -10.5458 -5.43236 4.5 endloop endfacet - facet normal 0.500129 -0.865951 -0.000615102 + facet normal -0.104529 -0.994522 0 outer loop - vertex 6.72992 -12.2803 -1.46722 - vertex -4 -18.4752 -4.5 - vertex 6.81094 -12.2335 -1.47705 + vertex -9.45423 -5.43236 -4.5 + vertex -9.45423 -5.43236 4.5 + vertex -10 -5.375 4.5 endloop endfacet - facet normal 0.499974 -0.866041 0.000118595 + facet normal -0.104529 -0.994522 0 outer loop - vertex 6.47163 -12.4294 -1.37032 - vertex -4 -18.4752 -4.5 - vertex 6.72992 -12.2803 -1.46722 + vertex -10 -5.375 -4.5 + vertex -9.45423 -5.43236 -4.5 + vertex -10 -5.375 4.5 endloop endfacet - facet normal 0.500011 -0.866019 -4.94012e-05 + facet normal -0.309016 -0.951057 0 outer loop - vertex 6.23644 -12.5652 -1.21352 - vertex -4 -18.4752 -4.5 - vertex 6.47163 -12.4294 -1.37032 + vertex -8.93232 -5.60194 -4.5 + vertex -8.93232 -5.60194 4.5 + vertex -9.45423 -5.43236 4.5 endloop endfacet - facet normal 0.500097 -0.865969 -0.000460015 + facet normal -0.309016 -0.951057 0 outer loop - vertex 7.08103 -12.0776 1.49017 - vertex 18 -5.7735 4.5 - vertex 7 -12.1244 1.5 + vertex -9.45423 -5.43236 -4.5 + vertex -8.93232 -5.60194 -4.5 + vertex -9.45423 -5.43236 4.5 endloop endfacet - facet normal 0.500124 -0.865953 -0.000593172 + facet normal -0.5 -0.866025 0 outer loop - vertex 7.27008 -11.9684 1.46722 - vertex 18 -5.7735 4.5 - vertex 7.08103 -12.0776 1.49017 + vertex -8.45706 -5.87633 -4.5 + vertex -8.45706 -5.87633 4.5 + vertex -8.93232 -5.60194 4.5 endloop endfacet - facet normal 0.499974 -0.866041 0.000118595 + facet normal -0.5 -0.866025 0 outer loop - vertex 7.52837 -11.8193 1.37032 - vertex 18 -5.7735 4.5 - vertex 7.27008 -11.9684 1.46722 + vertex -8.93232 -5.60194 -4.5 + vertex -8.45706 -5.87633 -4.5 + vertex -8.93232 -5.60194 4.5 endloop endfacet - facet normal 0.500011 -0.866019 -4.94012e-05 + facet normal -0.669131 -0.743145 0 outer loop - vertex 7.76356 -11.6835 1.21352 - vertex 18 -5.7735 4.5 - vertex 7.52837 -11.8193 1.37032 + vertex -8.04924 -6.24353 -4.5 + vertex -8.04924 -6.24353 4.5 + vertex -8.45706 -5.87633 4.5 endloop endfacet - facet normal 0.499988 -0.866032 4.6779e-05 + facet normal -0.669131 -0.743145 0 outer loop - vertex 7.96537 -11.567 1.0037 - vertex 18 -5.7735 4.5 - vertex 7.76356 -11.6835 1.21352 + vertex -8.45706 -5.87633 -4.5 + vertex -8.04924 -6.24353 -4.5 + vertex -8.45706 -5.87633 4.5 endloop endfacet - facet normal 0.499986 -0.866033 5.26359e-05 + facet normal -0.809017 -0.587786 0 outer loop - vertex 8.07711 -11.5025 0.826109 - vertex 18 -5.7735 4.5 - vertex 7.96537 -11.567 1.0037 + vertex -7.72668 -6.6875 4.5 + vertex -8.04924 -6.24353 4.5 + vertex -7.72668 -6.6875 -4.5 endloop endfacet - facet normal 0.500131 -0.86595 -0.000467068 + facet normal -0.809017 -0.587786 0 outer loop - vertex 8.125 -11.4748 0.75 - vertex 18 -5.7735 4.5 - vertex 8.07711 -11.5025 0.826109 + vertex -7.72668 -6.6875 -4.5 + vertex -8.04924 -6.24353 4.5 + vertex -8.04924 -6.24353 -4.5 endloop endfacet - facet normal 0.499914 -0.866075 0.000292485 + facet normal -0.913546 -0.406736 0 outer loop - vertex 8.15814 -11.4557 0.664057 - vertex 18 -5.7735 4.5 - vertex 8.125 -11.4748 0.75 + vertex -7.50348 -7.18883 4.5 + vertex -7.72668 -6.6875 4.5 + vertex -7.50348 -7.18883 -4.5 endloop endfacet - facet normal 0.499955 -0.866051 0.00015288 + facet normal -0.913546 -0.406736 0 outer loop - vertex 8.23546 -11.4111 0.463525 - vertex 18 -5.7735 4.5 - vertex 8.15814 -11.4557 0.664057 + vertex -7.50348 -7.18883 -4.5 + vertex -7.72668 -6.6875 4.5 + vertex -7.72668 -6.6875 -4.5 endloop endfacet - facet normal 0.500005 -0.866023 -6.74655e-06 + facet normal -0.978148 -0.207912 0 outer loop - vertex 8.29192 -11.3785 0.156793 - vertex 18 -5.7735 4.5 - vertex 8.23546 -11.4111 0.463525 + vertex -7.38938 -7.72561 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -7.38938 -7.72561 -4.5 endloop endfacet - facet normal 0.500003 -0.866024 0 + facet normal -0.978148 -0.207912 0 outer loop - vertex 8.29192 -11.3785 -0.156793 - vertex 18 -5.7735 4.5 - vertex 8.29192 -11.3785 0.156793 + vertex -7.38938 -7.72561 -4.5 + vertex -7.50348 -7.18883 4.5 + vertex -7.50348 -7.18883 -4.5 endloop endfacet - facet normal 0.500005 -0.866023 6.74655e-06 + facet normal -1 6.12323e-17 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 8.29192 -11.3785 -0.156793 - vertex 8.23546 -11.4111 -0.463525 + vertex -7.38938 -7.72561 4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -7.38938 -8.27439 4.5 endloop endfacet - facet normal 0.499912 -0.866076 -0.000291391 + facet normal -1 6.12323e-17 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 8.23546 -11.4111 -0.463525 - vertex 8.20232 -11.4302 -0.549467 + vertex -7.38938 -8.27439 4.5 + vertex -7.38938 -7.72561 -4.5 + vertex -7.38938 -8.27439 -4.5 endloop endfacet - facet normal 0.499954 -0.866052 -0.00015241 + facet normal -0.978148 0.207912 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 8.20232 -11.4302 -0.549467 - vertex 8.125 -11.4748 -0.749999 + vertex -7.38938 -8.27439 4.5 + vertex -7.38938 -8.27439 -4.5 + vertex -7.50348 -8.81117 4.5 endloop endfacet - facet normal 0.499983 -0.866035 -5.01284e-05 + facet normal -0.978148 0.207912 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 8.125 -11.4748 -0.749999 - vertex 8.01326 -11.5393 -0.927587 + vertex -7.50348 -8.81117 4.5 + vertex -7.38938 -8.27439 -4.5 + vertex -7.50348 -8.81117 -4.5 endloop endfacet - facet normal 0.500124 -0.865954 0.000472903 + facet normal -0.913546 0.406736 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 8.01326 -11.5393 -0.927587 - vertex 7.96537 -11.567 -1.0037 + vertex -7.50348 -8.81117 4.5 + vertex -7.50348 -8.81117 -4.5 + vertex -7.72668 -9.3125 4.5 endloop endfacet - facet normal 0.499988 -0.866032 -4.6779e-05 + facet normal -0.913546 0.406736 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 7.96537 -11.567 -1.0037 - vertex 7.76356 -11.6835 -1.21352 + vertex -7.72668 -9.3125 4.5 + vertex -7.50348 -8.81117 -4.5 + vertex -7.72668 -9.3125 -4.5 endloop endfacet - facet normal 0.500011 -0.866019 4.94012e-05 + facet normal -0.809017 0.587786 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 7.76356 -11.6835 -1.21352 - vertex 7.52837 -11.8193 -1.37032 + vertex -7.72668 -9.3125 4.5 + vertex -7.72668 -9.3125 -4.5 + vertex -8.04924 -9.75647 4.5 endloop endfacet - facet normal 0.5 -0.866026 -1.44338e-05 + facet normal -0.809017 0.587786 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 7 -12.1244 -1.5 - vertex -4 -18.4752 -4.5 + vertex -8.04924 -9.75647 4.5 + vertex -7.72668 -9.3125 -4.5 + vertex -8.04924 -9.75647 -4.5 endloop endfacet - facet normal 0.500111 -0.865961 0.000527044 + facet normal -0.669131 0.743145 0 outer loop - vertex 7 -12.1244 -1.5 - vertex 18 -5.7735 -4.5 - vertex 7.18906 -12.0152 -1.47705 + vertex -8.04924 -9.75647 4.5 + vertex -8.04924 -9.75647 -4.5 + vertex -8.45706 -10.1237 4.5 endloop endfacet - facet normal 0.500003 -0.866024 0 + facet normal -0.669131 0.743145 0 outer loop - vertex 8.29192 -11.3785 -0.156793 - vertex 18 -5.7735 -4.5 - vertex 18 -5.7735 4.5 + vertex -8.45706 -10.1237 4.5 + vertex -8.04924 -9.75647 -4.5 + vertex -8.45706 -10.1237 -4.5 endloop endfacet - facet normal 0.499974 -0.866041 -0.000118595 + facet normal -0.5 0.866025 0 outer loop - vertex 7.27008 -11.9684 -1.46722 - vertex 18 -5.7735 -4.5 - vertex 7.52837 -11.8193 -1.37032 + vertex -8.45706 -10.1237 4.5 + vertex -8.45706 -10.1237 -4.5 + vertex -8.93232 -10.3981 4.5 endloop endfacet - facet normal 0.500129 -0.865951 0.000615102 + facet normal -0.5 0.866025 0 outer loop - vertex 7.18906 -12.0152 -1.47705 - vertex 18 -5.7735 -4.5 - vertex 7.27008 -11.9684 -1.46722 + vertex -8.93232 -10.3981 4.5 + vertex -8.45706 -10.1237 -4.5 + vertex -8.93232 -10.3981 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.309016 0.951057 0 outer loop - vertex -8.04924 6.24353 4.5 - vertex -4.89074 1.03956 4.5 - vertex -7.72668 6.6875 4.5 + vertex -8.93232 -10.3981 4.5 + vertex -8.93232 -10.3981 -4.5 + vertex -9.45423 -10.5676 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309016 0.951057 0 outer loop - vertex -5 0 4.5 - vertex -7.50348 -7.18883 4.5 - vertex -7.38938 -7.72561 4.5 + vertex -9.45423 -10.5676 4.5 + vertex -8.93232 -10.3981 -4.5 + vertex -9.45423 -10.5676 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex -8.45706 5.87633 4.5 - vertex -4.89074 1.03956 4.5 - vertex -8.04924 6.24353 4.5 + vertex -9.45423 -10.5676 4.5 + vertex -9.45423 -10.5676 -4.5 + vertex -10 -10.625 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex -5 0 4.5 - vertex -7.72668 -6.6875 4.5 - vertex -7.50348 -7.18883 4.5 + vertex -10 -10.625 4.5 + vertex -9.45423 -10.5676 -4.5 + vertex -10 -10.625 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex -8.93232 5.60194 4.5 - vertex -4.89074 1.03956 4.5 - vertex -8.45706 5.87633 4.5 + vertex -10 -10.625 4.5 + vertex -10 -10.625 -4.5 + vertex -10.5458 -10.5676 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex -5 0 4.5 - vertex -8.04924 -6.24353 4.5 - vertex -7.72668 -6.6875 4.5 + vertex -10.5458 -10.5676 4.5 + vertex -10 -10.625 -4.5 + vertex -10.5458 -10.5676 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309016 0.951057 0 outer loop - vertex -9.45423 5.43236 4.5 - vertex -4.89074 1.03956 4.5 - vertex -8.93232 5.60194 4.5 + vertex -10.5458 -10.5676 4.5 + vertex -10.5458 -10.5676 -4.5 + vertex -11.0677 -10.3981 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.309016 0.951057 0 outer loop - vertex -5 0 4.5 - vertex -8.45706 -5.87633 4.5 - vertex -8.04924 -6.24353 4.5 + vertex -11.0677 -10.3981 4.5 + vertex -10.5458 -10.5676 -4.5 + vertex -11.0677 -10.3981 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.5 0.866025 0 outer loop - vertex -10 5.375 4.5 - vertex -4.89074 1.03956 4.5 - vertex -9.45423 5.43236 4.5 + vertex -11.0677 -10.3981 4.5 + vertex -11.0677 -10.3981 -4.5 + vertex -11.5429 -10.1237 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866025 0 outer loop - vertex -5 0 4.5 - vertex -8.93232 -5.60194 4.5 - vertex -8.45706 -5.87633 4.5 + vertex -11.5429 -10.1237 4.5 + vertex -11.0677 -10.3981 -4.5 + vertex -11.5429 -10.1237 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 0.743145 0 outer loop - vertex -4.89074 1.03956 4.5 - vertex -10 5.375 4.5 - vertex -5 0 4.5 + vertex -11.5429 -10.1237 4.5 + vertex -11.5429 -10.1237 -4.5 + vertex -11.9508 -9.75647 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 0.743145 0 outer loop - vertex -5 0 4.5 - vertex -9.45423 -5.43236 4.5 - vertex -8.93232 -5.60194 4.5 + vertex -11.9508 -9.75647 4.5 + vertex -11.5429 -10.1237 -4.5 + vertex -11.9508 -9.75647 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 0.587786 0 outer loop - vertex -10 -5.375 4.5 - vertex -5 0 4.5 - vertex -10 5.375 4.5 + vertex -12.2733 -9.3125 4.5 + vertex -11.9508 -9.75647 4.5 + vertex -11.9508 -9.75647 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 0.587786 0 outer loop - vertex -5 0 4.5 - vertex -10 -5.375 4.5 - vertex -9.45423 -5.43236 4.5 + vertex -12.2733 -9.3125 -4.5 + vertex -12.2733 -9.3125 4.5 + vertex -11.9508 -9.75647 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex -10.5458 5.43236 4.5 - vertex -10 -5.375 4.5 - vertex -10 5.375 4.5 + vertex -12.4965 -8.81117 4.5 + vertex -12.2733 -9.3125 4.5 + vertex -12.2733 -9.3125 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex -10.5458 5.43236 4.5 - vertex -10.5458 -5.43236 4.5 - vertex -10 -5.375 4.5 + vertex -12.4965 -8.81117 -4.5 + vertex -12.4965 -8.81117 4.5 + vertex -12.2733 -9.3125 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 0.207912 0 outer loop - vertex -11.0677 5.60194 4.5 - vertex -10.5458 -5.43236 4.5 - vertex -10.5458 5.43236 4.5 + vertex -12.6106 -8.27439 4.5 + vertex -12.4965 -8.81117 4.5 + vertex -12.4965 -8.81117 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 0.207912 0 outer loop - vertex -11.0677 5.60194 4.5 - vertex -11.0677 -5.60194 4.5 - vertex -10.5458 -5.43236 4.5 + vertex -12.6106 -8.27439 -4.5 + vertex -12.6106 -8.27439 4.5 + vertex -12.4965 -8.81117 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 1 -6.12323e-17 0 outer loop - vertex -11.5429 5.87633 4.5 - vertex -11.0677 -5.60194 4.5 - vertex -11.0677 5.60194 4.5 + vertex -12.6106 8.27439 -4.5 + vertex -12.6106 8.27439 4.5 + vertex -12.6106 7.72561 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 1 -6.12323e-17 0 outer loop - vertex -11.5429 5.87633 4.5 - vertex -11.5429 -5.87633 4.5 - vertex -11.0677 -5.60194 4.5 + vertex -12.6106 7.72561 -4.5 + vertex -12.6106 8.27439 -4.5 + vertex -12.6106 7.72561 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 -0.207912 0 outer loop - vertex -11.9508 6.24353 4.5 - vertex -11.5429 -5.87633 4.5 - vertex -11.5429 5.87633 4.5 + vertex -12.4965 8.81117 -4.5 + vertex -12.4965 8.81117 4.5 + vertex -12.6106 8.27439 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 -0.207912 0 outer loop - vertex -11.9508 6.24353 4.5 - vertex -11.9508 -6.24353 4.5 - vertex -11.5429 -5.87633 4.5 + vertex -12.6106 8.27439 -4.5 + vertex -12.4965 8.81117 -4.5 + vertex -12.6106 8.27439 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 -0.406736 0 outer loop - vertex -12.2733 6.6875 4.5 - vertex -11.9508 -6.24353 4.5 - vertex -11.9508 6.24353 4.5 + vertex -12.2733 9.3125 -4.5 + vertex -12.2733 9.3125 4.5 + vertex -12.4965 8.81117 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 -0.406736 0 outer loop - vertex -12.2733 6.6875 4.5 - vertex -12.2733 -6.6875 4.5 - vertex -11.9508 -6.24353 4.5 + vertex -12.4965 8.81117 -4.5 + vertex -12.2733 9.3125 -4.5 + vertex -12.4965 8.81117 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 -0.587786 0 outer loop - vertex -12.4965 7.18883 4.5 - vertex -12.2733 -6.6875 4.5 - vertex -12.2733 6.6875 4.5 + vertex -11.9508 9.75647 -4.5 + vertex -11.9508 9.75647 4.5 + vertex -12.2733 9.3125 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 -0.587786 0 outer loop - vertex -12.4965 7.18883 4.5 - vertex -12.4965 -7.18883 4.5 - vertex -12.2733 -6.6875 4.5 + vertex -12.2733 9.3125 -4.5 + vertex -11.9508 9.75647 -4.5 + vertex -12.2733 9.3125 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 -0.743145 0 outer loop - vertex -12.6106 7.72561 4.5 - vertex -12.4965 -7.18883 4.5 - vertex -12.4965 7.18883 4.5 + vertex -11.5429 10.1237 -4.5 + vertex -11.5429 10.1237 4.5 + vertex -11.9508 9.75647 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 -0.743145 0 outer loop - vertex -12.4965 -7.18883 4.5 - vertex -12.6106 7.72561 4.5 - vertex -12.6106 -7.72561 4.5 + vertex -11.9508 9.75647 -4.5 + vertex -11.5429 10.1237 -4.5 + vertex -11.9508 9.75647 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 -0.866025 0 outer loop - vertex 18 5.7735 4.5 - vertex 14.2015 3.34775 4.5 - vertex 18 -5.7735 4.5 + vertex -11.0677 10.3981 -4.5 + vertex -11.0677 10.3981 4.5 + vertex -11.5429 10.1237 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 -0.866025 0 outer loop - vertex 18 -5.7735 4.5 - vertex 14.4247 -3.84908 4.5 - vertex 14.5388 -4.38587 4.5 + vertex -11.5429 10.1237 -4.5 + vertex -11.0677 10.3981 -4.5 + vertex -11.5429 10.1237 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309016 -0.951057 0 outer loop - vertex 14.2015 -3.34775 4.5 - vertex 18 -5.7735 4.5 - vertex 14.2015 3.34775 4.5 + vertex -10.5458 10.5676 -4.5 + vertex -10.5458 10.5676 4.5 + vertex -11.0677 10.3981 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.309016 -0.951057 0 outer loop - vertex 18 -5.7735 4.5 - vertex 14.2015 -3.34775 4.5 - vertex 14.4247 -3.84908 4.5 + vertex -11.0677 10.3981 -4.5 + vertex -10.5458 10.5676 -4.5 + vertex -11.0677 10.3981 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.104529 -0.994522 0 outer loop - vertex 13.879 2.90379 4.5 - vertex 14.2015 -3.34775 4.5 - vertex 14.2015 3.34775 4.5 + vertex -10 10.625 -4.5 + vertex -10 10.625 4.5 + vertex -10.5458 10.5676 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 -0.994522 0 outer loop - vertex 13.879 2.90379 4.5 - vertex 13.879 -2.90379 4.5 - vertex 14.2015 -3.34775 4.5 + vertex -10.5458 10.5676 -4.5 + vertex -10 10.625 -4.5 + vertex -10.5458 10.5676 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.104529 -0.994522 0 outer loop - vertex 13.4711 2.53658 4.5 - vertex 13.879 -2.90379 4.5 - vertex 13.879 2.90379 4.5 + vertex -9.45423 10.5676 -4.5 + vertex -9.45423 10.5676 4.5 + vertex -10 10.625 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 -0.994522 0 outer loop - vertex 13.4711 2.53658 4.5 - vertex 13.4711 -2.53659 4.5 - vertex 13.879 -2.90379 4.5 + vertex -10 10.625 -4.5 + vertex -9.45423 10.5676 -4.5 + vertex -10 10.625 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.309016 -0.951057 0 outer loop - vertex 12.9959 2.2622 4.5 - vertex 13.4711 -2.53659 4.5 - vertex 13.4711 2.53658 4.5 + vertex -8.93232 10.3981 -4.5 + vertex -8.93232 10.3981 4.5 + vertex -9.45423 10.5676 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309016 -0.951057 0 outer loop - vertex 12.9959 2.2622 4.5 - vertex 12.9959 -2.2622 4.5 - vertex 13.4711 -2.53659 4.5 + vertex -9.45423 10.5676 -4.5 + vertex -8.93232 10.3981 -4.5 + vertex -9.45423 10.5676 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.5 -0.866025 0 outer loop - vertex 12.474 2.09262 4.5 - vertex 12.9959 -2.2622 4.5 - vertex 12.9959 2.2622 4.5 + vertex -8.45706 10.1237 -4.5 + vertex -8.45706 10.1237 4.5 + vertex -8.93232 10.3981 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 -0.866025 0 outer loop - vertex 12.474 2.09262 4.5 - vertex 12.474 -2.09262 4.5 - vertex 12.9959 -2.2622 4.5 + vertex -8.93232 10.3981 -4.5 + vertex -8.45706 10.1237 -4.5 + vertex -8.93232 10.3981 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.669131 -0.743145 0 outer loop - vertex 11.9282 2.03525 4.5 - vertex 12.474 -2.09262 4.5 - vertex 12.474 2.09262 4.5 + vertex -8.04924 9.75647 -4.5 + vertex -8.04924 9.75647 4.5 + vertex -8.45706 10.1237 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 -0.743145 0 outer loop - vertex 11.9282 2.03525 4.5 - vertex 11.9282 -2.03525 4.5 - vertex 12.474 -2.09262 4.5 + vertex -8.45706 10.1237 -4.5 + vertex -8.04924 9.75647 -4.5 + vertex -8.45706 10.1237 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809017 -0.587786 0 outer loop - vertex 11.3824 2.09262 4.5 - vertex 11.9282 -2.03525 4.5 - vertex 11.9282 2.03525 4.5 + vertex -7.72668 9.3125 4.5 + vertex -8.04924 9.75647 4.5 + vertex -7.72668 9.3125 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809017 -0.587786 0 outer loop - vertex 11.3824 2.09262 4.5 - vertex 11.3824 -2.09262 4.5 - vertex 11.9282 -2.03525 4.5 + vertex -7.72668 9.3125 -4.5 + vertex -8.04924 9.75647 4.5 + vertex -8.04924 9.75647 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 -0.406736 0 outer loop - vertex 10.8605 2.2622 4.5 - vertex 11.3824 -2.09262 4.5 - vertex 11.3824 2.09262 4.5 + vertex -7.50348 8.81117 4.5 + vertex -7.72668 9.3125 4.5 + vertex -7.50348 8.81117 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 -0.406736 0 outer loop - vertex 10.8605 2.2622 4.5 - vertex 10.8605 -2.2622 4.5 - vertex 11.3824 -2.09262 4.5 + vertex -7.50348 8.81117 -4.5 + vertex -7.72668 9.3125 4.5 + vertex -7.72668 9.3125 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978148 -0.207912 0 outer loop - vertex 10.3853 2.53658 4.5 - vertex 10.8605 -2.2622 4.5 - vertex 10.8605 2.2622 4.5 + vertex -7.38938 8.27439 4.5 + vertex -7.50348 8.81117 4.5 + vertex -7.38938 8.27439 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978148 -0.207912 0 outer loop - vertex 10.3853 2.53658 4.5 - vertex 10.3853 -2.53658 4.5 - vertex 10.8605 -2.2622 4.5 + vertex -7.38938 8.27439 -4.5 + vertex -7.50348 8.81117 4.5 + vertex -7.50348 8.81117 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -1 6.12323e-17 0 outer loop - vertex 5 0 4.5 - vertex 10.3853 2.53658 4.5 - vertex 9.97745 2.90379 4.5 + vertex -7.38938 8.27439 4.5 + vertex -7.38938 8.27439 -4.5 + vertex -7.38938 7.72561 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -1 6.12323e-17 0 outer loop - vertex 10.3853 2.53658 4.5 - vertex 5 0 4.5 - vertex 10.3853 -2.53658 4.5 + vertex -7.38938 7.72561 4.5 + vertex -7.38938 8.27439 -4.5 + vertex -7.38938 7.72561 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978148 0.207912 0 outer loop - vertex 4.89074 1.03956 4.5 - vertex 9.97745 2.90379 4.5 - vertex 9.65489 3.34775 4.5 + vertex -7.38938 7.72561 4.5 + vertex -7.38938 7.72561 -4.5 + vertex -7.50348 7.18883 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978148 0.207912 0 outer loop - vertex 10.3853 -2.53658 4.5 - vertex 5 0 4.5 - vertex 9.97745 -2.90379 4.5 + vertex -7.50348 7.18883 4.5 + vertex -7.38938 7.72561 -4.5 + vertex -7.50348 7.18883 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 0.406736 0 outer loop - vertex 4.56773 2.03368 4.5 - vertex 9.65489 3.34775 4.5 - vertex 9.43168 3.84908 4.5 + vertex -7.50348 7.18883 4.5 + vertex -7.50348 7.18883 -4.5 + vertex -7.72668 6.6875 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.913546 0.406736 0 outer loop - vertex 4.89074 -1.03956 4.5 - vertex 9.97745 -2.90379 4.5 - vertex 5 0 4.5 + vertex -7.72668 6.6875 4.5 + vertex -7.50348 7.18883 -4.5 + vertex -7.72668 6.6875 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809017 0.587786 0 outer loop - vertex 4.56773 2.03368 4.5 - vertex 9.43168 3.84908 4.5 - vertex 9.31758 4.38587 4.5 + vertex -7.72668 6.6875 4.5 + vertex -7.72668 6.6875 -4.5 + vertex -8.04924 6.24353 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809017 0.587786 0 outer loop - vertex 9.97745 -2.90379 4.5 - vertex 4.89074 -1.03956 4.5 - vertex 9.65489 -3.34775 4.5 + vertex -8.04924 6.24353 4.5 + vertex -7.72668 6.6875 -4.5 + vertex -8.04924 6.24353 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 0.743145 0 outer loop - vertex 4.04508 2.93893 4.5 - vertex 9.31758 4.38587 4.5 - vertex 9.31758 4.93464 4.5 + vertex -8.04924 6.24353 4.5 + vertex -8.04924 6.24353 -4.5 + vertex -8.45706 5.87633 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 0.743145 0 outer loop - vertex 14.5388 4.38587 4.5 - vertex 18 5.7735 4.5 - vertex 14.5388 4.93464 4.5 + vertex -8.45706 5.87633 4.5 + vertex -8.04924 6.24353 -4.5 + vertex -8.45706 5.87633 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 5.7735 4.5 - vertex 14.4247 5.47142 4.5 - vertex 14.5388 4.93464 4.5 + vertex -8.45706 5.87633 4.5 + vertex -8.45706 5.87633 -4.5 + vertex -8.93232 5.60194 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 5.7735 4.5 - vertex 14.2015 5.97275 4.5 - vertex 14.4247 5.47142 4.5 + vertex -8.93232 5.60194 4.5 + vertex -8.45706 5.87633 -4.5 + vertex -8.93232 5.60194 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309016 0.951057 0 outer loop - vertex 18 5.7735 4.5 - vertex 13.879 6.41672 4.5 - vertex 14.2015 5.97275 4.5 + vertex -8.93232 5.60194 4.5 + vertex -8.93232 5.60194 -4.5 + vertex -9.45423 5.43236 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309016 0.951057 0 outer loop - vertex 18 5.7735 4.5 - vertex 13.4711 6.78392 4.5 - vertex 13.879 6.41672 4.5 + vertex -9.45423 5.43236 4.5 + vertex -8.93232 5.60194 -4.5 + vertex -9.45423 5.43236 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex 18 5.7735 4.5 - vertex 12.9959 7.05831 4.5 - vertex 13.4711 6.78392 4.5 + vertex -9.45423 5.43236 4.5 + vertex -9.45423 5.43236 -4.5 + vertex -10 5.375 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex -0.385267 14.7839 4.5 - vertex 12.9959 7.05831 4.5 - vertex 18 5.7735 4.5 + vertex -10 5.375 4.5 + vertex -9.45423 5.43236 -4.5 + vertex -10 5.375 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex 4.56773 -2.03368 4.5 - vertex 9.65489 -3.34775 4.5 - vertex 4.89074 -1.03956 4.5 + vertex -10 5.375 4.5 + vertex -10 5.375 -4.5 + vertex -10.5458 5.43236 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex 9.65489 -3.34775 4.5 - vertex 4.56773 -2.03368 4.5 - vertex 9.43168 -3.84908 4.5 + vertex -10.5458 5.43236 4.5 + vertex -10 5.375 -4.5 + vertex -10.5458 5.43236 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.309016 0.951057 0 outer loop - vertex 9.31758 -4.93464 4.5 - vertex 7.06458 -5.73622 4.5 - vertex 8.56458 -8.33429 4.5 + vertex -10.5458 5.43236 4.5 + vertex -10.5458 5.43236 -4.5 + vertex -11.0677 5.60194 4.5 endloop endfacet - facet normal 0 -0 1 + facet normal 0.309016 0.951057 0 outer loop - vertex 7.06458 -5.73622 4.5 - vertex 9.43168 -3.84908 4.5 - vertex 4.56773 -2.03368 4.5 + vertex -11.0677 5.60194 4.5 + vertex -10.5458 5.43236 -4.5 + vertex -11.0677 5.60194 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866025 0 outer loop - vertex 3.34565 3.71572 4.5 - vertex 9.31758 4.93464 4.5 - vertex 9.43168 5.47142 4.5 + vertex -11.0677 5.60194 4.5 + vertex -11.0677 5.60194 -4.5 + vertex -11.5429 5.87633 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866025 0 outer loop - vertex 3.34565 3.71572 4.5 - vertex 9.43168 5.47142 4.5 - vertex 9.65489 5.97275 4.5 + vertex -11.5429 5.87633 4.5 + vertex -11.0677 5.60194 -4.5 + vertex -11.5429 5.87633 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 0.743145 0 outer loop - vertex 0.345113 11.3478 4.5 - vertex 9.65489 5.97275 4.5 - vertex 9.97745 6.41672 4.5 + vertex -11.5429 5.87633 4.5 + vertex -11.5429 5.87633 -4.5 + vertex -11.9508 6.24353 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 0.743145 0 outer loop - vertex 9.97745 2.90379 4.5 - vertex 4.89074 1.03956 4.5 - vertex 5 0 4.5 + vertex -11.9508 6.24353 4.5 + vertex -11.5429 5.87633 -4.5 + vertex -11.9508 6.24353 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 0.587786 0 outer loop - vertex 9.65489 3.34775 4.5 - vertex 4.56773 2.03368 4.5 - vertex 4.89074 1.03956 4.5 + vertex -12.2733 6.6875 4.5 + vertex -11.9508 6.24353 4.5 + vertex -11.9508 6.24353 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 0.587786 0 outer loop - vertex 0.568321 11.8491 4.5 - vertex 9.97745 6.41672 4.5 - vertex 10.3853 6.78392 4.5 + vertex -12.2733 6.6875 -4.5 + vertex -12.2733 6.6875 4.5 + vertex -11.9508 6.24353 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex 9.31758 4.38587 4.5 - vertex 4.04508 2.93893 4.5 - vertex 4.56773 2.03368 4.5 + vertex -12.4965 7.18883 4.5 + vertex -12.2733 6.6875 4.5 + vertex -12.2733 6.6875 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex 9.31758 4.93464 4.5 - vertex 3.34565 3.71572 4.5 - vertex 4.04508 2.93893 4.5 + vertex -12.4965 7.18883 -4.5 + vertex -12.4965 7.18883 4.5 + vertex -12.2733 6.6875 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 0.207912 0 outer loop - vertex 0.682417 12.3859 4.5 - vertex 10.3853 6.78392 4.5 - vertex 10.8605 7.05831 4.5 + vertex -12.6106 7.72561 4.5 + vertex -12.4965 7.18883 4.5 + vertex -12.4965 7.18883 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 0.207912 0 outer loop - vertex 9.65489 5.97275 4.5 - vertex 2.5 4.33013 4.5 - vertex 3.34565 3.71572 4.5 + vertex -12.6106 7.72561 -4.5 + vertex -12.6106 7.72561 4.5 + vertex -12.4965 7.18883 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 -0.207912 0 outer loop - vertex 9.65489 5.97275 4.5 - vertex 0.345113 11.3478 4.5 - vertex 2.5 4.33013 4.5 + vertex -4.42473 -11.8491 -4.5 + vertex -4.42473 -11.8491 4.5 + vertex -4.53882 -12.3859 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 -0.207912 0 outer loop - vertex 0.682417 12.9346 4.5 - vertex 10.8605 7.05831 4.5 - vertex 11.3824 7.22789 4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.42473 -11.8491 -4.5 + vertex -4.53882 -12.3859 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 1 -2.04945e-07 0 outer loop - vertex 10.3853 6.78392 4.5 - vertex 0.682417 12.3859 4.5 - vertex 0.568321 11.8491 4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.53882 -12.3859 4.5 + vertex -4.53882 -12.9346 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 1 -2.04945e-07 0 outer loop - vertex 0.568321 13.4714 4.5 - vertex 11.3824 7.22789 4.5 - vertex 11.9282 7.28525 4.5 + vertex -4.53882 -12.9346 -4.5 + vertex -4.53882 -12.3859 -4.5 + vertex -4.53882 -12.9346 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 0.345114 13.9728 4.5 - vertex 11.9282 7.28525 4.5 - vertex 12.474 7.22789 4.5 + vertex -4.20152 -11.3478 -4.5 + vertex -4.20152 -11.3478 4.5 + vertex -4.42473 -11.8491 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 12.9959 7.05831 4.5 - vertex -0.385267 14.7839 4.5 - vertex 12.474 7.22789 4.5 + vertex -4.42473 -11.8491 -4.5 + vertex -4.20152 -11.3478 -4.5 + vertex -4.42473 -11.8491 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 -0.587786 0 outer loop - vertex 10.8605 7.05831 4.5 - vertex 0.682417 12.9346 4.5 - vertex 0.682417 12.3859 4.5 + vertex -3.87896 -10.9038 -4.5 + vertex -3.87896 -10.9038 4.5 + vertex -4.20152 -11.3478 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 -0.587786 0 outer loop - vertex 11.3824 7.22789 4.5 - vertex 0.568321 13.4714 4.5 - vertex 0.682417 12.9346 4.5 + vertex -4.20152 -11.3478 -4.5 + vertex -3.87896 -10.9038 -4.5 + vertex -4.20152 -11.3478 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 -0.743145 0 outer loop - vertex 11.9282 7.28525 4.5 - vertex 0.345114 13.9728 4.5 - vertex 0.568321 13.4714 4.5 + vertex -3.47114 -10.5366 -4.5 + vertex -3.47114 -10.5366 4.5 + vertex -3.87896 -10.9038 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 -0.743145 0 outer loop - vertex 12.474 7.22789 4.5 - vertex 0.0225522 14.4167 4.5 - vertex 0.345114 13.9728 4.5 + vertex -3.87896 -10.9038 -4.5 + vertex -3.47114 -10.5366 -4.5 + vertex -3.87896 -10.9038 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 -0.866025 0 outer loop - vertex 12.474 7.22789 4.5 - vertex -0.385267 14.7839 4.5 - vertex 0.0225522 14.4167 4.5 + vertex -2.99589 -10.2622 -4.5 + vertex -2.99589 -10.2622 4.5 + vertex -3.47114 -10.5366 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 -0.866025 0 outer loop - vertex -4 18.4752 4.5 - vertex -0.385267 14.7839 4.5 - vertex 18 5.7735 4.5 + vertex -3.47114 -10.5366 -4.5 + vertex -2.99589 -10.2622 -4.5 + vertex -3.47114 -10.5366 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.309017 -0.951057 0 outer loop - vertex -0.385267 14.7839 4.5 - vertex -4 18.4752 4.5 - vertex -0.860519 15.0583 4.5 + vertex -2.47397 -10.0926 -4.5 + vertex -2.47397 -10.0926 4.5 + vertex -2.99589 -10.2622 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.309017 -0.951057 0 outer loop - vertex -4 18.4752 4.5 - vertex -1.38243 15.2279 4.5 - vertex -0.860519 15.0583 4.5 + vertex -2.99589 -10.2622 -4.5 + vertex -2.47397 -10.0926 -4.5 + vertex -2.99589 -10.2622 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 -0.994522 0 outer loop - vertex -4 18.4752 4.5 - vertex -1.9282 15.2853 4.5 - vertex -1.38243 15.2279 4.5 + vertex -1.9282 -10.0353 -4.5 + vertex -1.9282 -10.0353 4.5 + vertex -2.47397 -10.0926 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 -0.994522 0 outer loop - vertex -4 18.4752 4.5 - vertex -2.47397 15.2279 4.5 - vertex -1.9282 15.2853 4.5 + vertex -2.47397 -10.0926 -4.5 + vertex -1.9282 -10.0353 -4.5 + vertex -2.47397 -10.0926 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 -0.994522 0 outer loop - vertex -4 18.4752 4.5 - vertex -2.99589 15.0583 4.5 - vertex -2.47397 15.2279 4.5 + vertex -1.38243 -10.0926 -4.5 + vertex -1.38243 -10.0926 4.5 + vertex -1.9282 -10.0353 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 -0.994522 0 outer loop - vertex -4 18.4752 4.5 - vertex -3.47114 14.7839 4.5 - vertex -2.99589 15.0583 4.5 + vertex -1.9282 -10.0353 -4.5 + vertex -1.38243 -10.0926 -4.5 + vertex -1.9282 -10.0353 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -4 18.4752 4.5 - vertex -3.87896 14.4167 4.5 - vertex -3.47114 14.7839 4.5 + vertex -0.860519 -10.2622 -4.5 + vertex -0.860519 -10.2622 4.5 + vertex -1.38243 -10.0926 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -4 18.4752 4.5 - vertex -4.20152 13.9728 4.5 - vertex -3.87896 14.4167 4.5 + vertex -1.38243 -10.0926 -4.5 + vertex -0.860519 -10.2622 -4.5 + vertex -1.38243 -10.0926 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 -0.866026 0 outer loop - vertex -10 10.625 4.5 - vertex -4.20152 13.9728 4.5 - vertex -4 18.4752 4.5 + vertex -0.385267 -10.5366 -4.5 + vertex -0.385267 -10.5366 4.5 + vertex -0.860519 -10.2622 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 -0.866026 0 outer loop - vertex -4.20152 13.9728 4.5 - vertex -10 10.625 4.5 - vertex -4.42473 13.4714 4.5 + vertex -0.860519 -10.2622 -4.5 + vertex -0.385267 -10.5366 -4.5 + vertex -0.860519 -10.2622 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669132 -0.743144 0 outer loop - vertex -4.42473 11.8491 4.5 - vertex -4.89074 1.03956 4.5 - vertex -4.56773 2.03368 4.5 + vertex 0.0225516 -10.9038 -4.5 + vertex 0.0225516 -10.9038 4.5 + vertex -0.385267 -10.5366 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669132 -0.743144 0 outer loop - vertex -4.53882 12.3859 4.5 - vertex -7.38938 7.72561 4.5 - vertex -4.89074 1.03956 4.5 + vertex -0.385267 -10.5366 -4.5 + vertex 0.0225516 -10.9038 -4.5 + vertex -0.385267 -10.5366 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809016 -0.587786 0 outer loop - vertex -4.53882 12.3859 4.5 - vertex -7.38938 8.27439 4.5 - vertex -7.38938 7.72561 4.5 + vertex 0.345113 -11.3478 4.5 + vertex 0.0225516 -10.9038 4.5 + vertex 0.345113 -11.3478 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809016 -0.587786 0 outer loop - vertex -4.42473 13.4714 4.5 - vertex -9.45423 10.5676 4.5 - vertex -4.53882 12.9346 4.5 + vertex 0.345113 -11.3478 -4.5 + vertex 0.0225516 -10.9038 4.5 + vertex 0.0225516 -10.9038 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -4.53882 12.3859 4.5 - vertex -7.50348 8.81117 4.5 - vertex -7.38938 8.27439 4.5 + vertex 0.56832 -11.8491 4.5 + vertex 0.345113 -11.3478 4.5 + vertex 0.56832 -11.8491 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -4.53882 12.3859 4.5 - vertex -7.72668 9.3125 4.5 - vertex -7.50348 8.81117 4.5 + vertex 0.56832 -11.8491 -4.5 + vertex 0.345113 -11.3478 4.5 + vertex 0.345113 -11.3478 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978147 -0.207913 0 outer loop - vertex -4.53882 12.3859 4.5 - vertex -8.04924 9.75647 4.5 - vertex -7.72668 9.3125 4.5 + vertex 0.682417 -12.3859 4.5 + vertex 0.56832 -11.8491 4.5 + vertex 0.682417 -12.3859 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978147 -0.207913 0 outer loop - vertex -4.53882 12.3859 4.5 - vertex -8.45706 10.1237 4.5 - vertex -8.04924 9.75647 4.5 + vertex 0.682417 -12.3859 -4.5 + vertex 0.56832 -11.8491 4.5 + vertex 0.56832 -11.8491 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -1 2.04945e-07 0 outer loop - vertex -4.53882 12.9346 4.5 - vertex -8.93232 10.3981 4.5 - vertex -8.45706 10.1237 4.5 + vertex 0.682417 -12.3859 4.5 + vertex 0.682417 -12.3859 -4.5 + vertex 0.682417 -12.9346 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -1 2.04945e-07 0 outer loop - vertex -4.53882 12.9346 4.5 - vertex -9.45423 10.5676 4.5 - vertex -8.93232 10.3981 4.5 + vertex 0.682417 -12.9346 4.5 + vertex 0.682417 -12.3859 -4.5 + vertex 0.682417 -12.9346 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978148 0.207912 0 outer loop - vertex -4.42473 13.4714 4.5 - vertex -10 10.625 4.5 - vertex -9.45423 10.5676 4.5 + vertex 0.682417 -12.9346 4.5 + vertex 0.682417 -12.9346 -4.5 + vertex 0.56832 -13.4714 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.978148 0.207912 0 outer loop - vertex -14 12.7017 4.5 - vertex -10 10.625 4.5 - vertex -4 18.4752 4.5 + vertex 0.56832 -13.4714 4.5 + vertex 0.682417 -12.9346 -4.5 + vertex 0.56832 -13.4714 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 0.406736 0 outer loop - vertex -10 10.625 4.5 - vertex -14 12.7017 4.5 - vertex -10.5458 10.5676 4.5 + vertex 0.56832 -13.4714 4.5 + vertex 0.56832 -13.4714 -4.5 + vertex 0.345114 -13.9728 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 0.406736 0 outer loop - vertex -10.5458 10.5676 4.5 - vertex -14 12.7017 4.5 - vertex -11.0677 10.3981 4.5 + vertex 0.345114 -13.9728 4.5 + vertex 0.56832 -13.4714 -4.5 + vertex 0.345114 -13.9728 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809017 0.587786 0 outer loop - vertex -11.0677 10.3981 4.5 - vertex -14 12.7017 4.5 - vertex -11.5429 10.1237 4.5 + vertex 0.345114 -13.9728 4.5 + vertex 0.345114 -13.9728 -4.5 + vertex 0.0225521 -14.4167 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809017 0.587786 0 outer loop - vertex -14 12.7017 4.5 - vertex -12.6106 7.72561 4.5 - vertex -12.6106 8.27439 4.5 + vertex 0.0225521 -14.4167 4.5 + vertex 0.345114 -13.9728 -4.5 + vertex 0.0225521 -14.4167 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 0.743145 0 outer loop - vertex -12.6106 7.72561 4.5 - vertex -14 12.7017 4.5 - vertex -12.6106 -7.72561 4.5 + vertex 0.0225521 -14.4167 4.5 + vertex 0.0225521 -14.4167 -4.5 + vertex -0.385267 -14.7839 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 0.743145 0 outer loop - vertex -14 -12.7017 4.5 - vertex -12.6106 -7.72561 4.5 - vertex -14 12.7017 4.5 + vertex -0.385267 -14.7839 4.5 + vertex 0.0225521 -14.4167 -4.5 + vertex -0.385267 -14.7839 -4.5 + endloop + endfacet + facet normal -0.5 0.866025 0 + outer loop + vertex -0.385267 -14.7839 4.5 + vertex -0.385267 -14.7839 -4.5 + vertex -0.860519 -15.0583 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 0.866025 0 outer loop - vertex -12.4965 8.81117 4.5 - vertex -14 12.7017 4.5 - vertex -12.6106 8.27439 4.5 + vertex -0.860519 -15.0583 4.5 + vertex -0.385267 -14.7839 -4.5 + vertex -0.860519 -15.0583 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 0.951057 0 outer loop - vertex -12.2733 9.3125 4.5 - vertex -14 12.7017 4.5 - vertex -12.4965 8.81117 4.5 + vertex -0.860519 -15.0583 4.5 + vertex -0.860519 -15.0583 -4.5 + vertex -1.38244 -15.2279 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 0.951057 0 outer loop - vertex -11.9508 9.75647 4.5 - vertex -14 12.7017 4.5 - vertex -12.2733 9.3125 4.5 + vertex -1.38244 -15.2279 4.5 + vertex -0.860519 -15.0583 -4.5 + vertex -1.38244 -15.2279 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex -11.5429 10.1237 4.5 - vertex -14 12.7017 4.5 - vertex -11.9508 9.75647 4.5 + vertex -1.38244 -15.2279 4.5 + vertex -1.38244 -15.2279 -4.5 + vertex -1.9282 -15.2853 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex 14.4247 3.84908 4.5 - vertex 18 5.7735 4.5 - vertex 14.5388 4.38587 4.5 + vertex -1.9282 -15.2853 4.5 + vertex -1.38244 -15.2279 -4.5 + vertex -1.9282 -15.2853 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex 14.2015 3.34775 4.5 - vertex 18 5.7735 4.5 - vertex 14.4247 3.84908 4.5 + vertex -1.9282 -15.2853 4.5 + vertex -1.9282 -15.2853 -4.5 + vertex -2.47397 -15.2279 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex 14.5388 -4.93464 4.5 - vertex 18 -5.7735 4.5 - vertex 14.5388 -4.38587 4.5 + vertex -2.47397 -15.2279 4.5 + vertex -1.9282 -15.2853 -4.5 + vertex -2.47397 -15.2279 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309017 0.951057 0 outer loop - vertex 14.4247 -5.47142 4.5 - vertex 18 -5.7735 4.5 - vertex 14.5388 -4.93464 4.5 + vertex -2.47397 -15.2279 4.5 + vertex -2.47397 -15.2279 -4.5 + vertex -2.99589 -15.0583 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.309017 0.951057 0 outer loop - vertex 14.2015 -5.97275 4.5 - vertex 18 -5.7735 4.5 - vertex 14.4247 -5.47142 4.5 + vertex -2.99589 -15.0583 4.5 + vertex -2.47397 -15.2279 -4.5 + vertex -2.99589 -15.0583 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866026 0 outer loop - vertex 13.879 -6.41672 4.5 - vertex 18 -5.7735 4.5 - vertex 14.2015 -5.97275 4.5 + vertex -2.99589 -15.0583 4.5 + vertex -2.99589 -15.0583 -4.5 + vertex -3.47114 -14.7839 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866026 0 outer loop - vertex 13.4711 -6.78392 4.5 - vertex 18 -5.7735 4.5 - vertex 13.879 -6.41672 4.5 + vertex -3.47114 -14.7839 4.5 + vertex -2.99589 -15.0583 -4.5 + vertex -3.47114 -14.7839 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669132 0.743144 0 outer loop - vertex 12.9959 -7.05831 4.5 - vertex 18 -5.7735 4.5 - vertex 13.4711 -6.78392 4.5 + vertex -3.47114 -14.7839 4.5 + vertex -3.47114 -14.7839 -4.5 + vertex -3.87896 -14.4167 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669132 0.743144 0 outer loop - vertex -0.385267 -14.7839 4.5 - vertex 12.9959 -7.05831 4.5 - vertex 12.474 -7.22789 4.5 + vertex -3.87896 -14.4167 4.5 + vertex -3.47114 -14.7839 -4.5 + vertex -3.87896 -14.4167 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809016 0.587786 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 9.43168 -5.47142 4.5 - vertex 9.31758 -4.93464 4.5 + vertex -4.20152 -13.9728 4.5 + vertex -3.87896 -14.4167 4.5 + vertex -3.87896 -14.4167 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809016 0.587786 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 9.65489 -5.97275 4.5 - vertex 9.43168 -5.47142 4.5 + vertex -4.20152 -13.9728 -4.5 + vertex -4.20152 -13.9728 4.5 + vertex -3.87896 -14.4167 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 9.97745 -6.41672 4.5 - vertex 9.65489 -5.97275 4.5 + vertex -4.42473 -13.4714 4.5 + vertex -4.20152 -13.9728 4.5 + vertex -4.20152 -13.9728 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 10.3853 -6.78392 4.5 - vertex 9.97745 -6.41672 4.5 + vertex -4.42473 -13.4714 -4.5 + vertex -4.42473 -13.4714 4.5 + vertex -4.20152 -13.9728 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978147 0.207913 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 10.8605 -7.05831 4.5 - vertex 10.3853 -6.78392 4.5 + vertex -4.53882 -12.9346 4.5 + vertex -4.42473 -13.4714 4.5 + vertex -4.42473 -13.4714 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978147 0.207913 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 11.3824 -7.22789 4.5 - vertex 10.8605 -7.05831 4.5 + vertex -4.53882 -12.9346 -4.5 + vertex -4.53882 -12.9346 4.5 + vertex -4.42473 -13.4714 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 1 2.04945e-07 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 11.9282 -7.28525 4.5 - vertex 11.3824 -7.22789 4.5 + vertex -4.53882 12.9346 4.5 + vertex -4.53882 12.3859 4.5 + vertex -4.53882 12.3859 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 1 2.04945e-07 0 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 12.474 -7.22789 4.5 - vertex 11.9282 -7.28525 4.5 + vertex -4.53882 12.9346 -4.5 + vertex -4.53882 12.9346 4.5 + vertex -4.53882 12.3859 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978147 -0.207913 0 outer loop - vertex 0.0225514 -14.4167 4.5 - vertex 12.474 -7.22789 4.5 - vertex 8.56458 -8.33429 4.5 + vertex -4.42473 13.4714 -4.5 + vertex -4.42473 13.4714 4.5 + vertex -4.53882 12.9346 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978147 -0.207913 0 outer loop - vertex 0.0225514 -14.4167 4.5 - vertex 8.56458 -8.33429 4.5 - vertex 2.93542 -11.5843 4.5 + vertex -4.53882 12.9346 -4.5 + vertex -4.42473 13.4714 -4.5 + vertex -4.53882 12.9346 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 0.345113 -11.3478 4.5 - vertex 2.93542 -11.5843 4.5 - vertex 1.43542 -8.98622 4.5 + vertex -4.20152 13.9728 -4.5 + vertex -4.20152 13.9728 4.5 + vertex -4.42473 13.4714 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 0.682416 -12.9346 4.5 - vertex 2.93542 -11.5843 4.5 - vertex 0.682416 -12.3859 4.5 + vertex -4.42473 13.4714 -4.5 + vertex -4.20152 13.9728 -4.5 + vertex -4.42473 13.4714 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809016 -0.587786 0 outer loop - vertex 0.568321 -13.4714 4.5 - vertex 2.93542 -11.5843 4.5 - vertex 0.682416 -12.9346 4.5 + vertex -3.87896 14.4167 -4.5 + vertex -3.87896 14.4167 4.5 + vertex -4.20152 13.9728 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809016 -0.587786 0 outer loop - vertex 0.345114 -13.9728 4.5 - vertex 2.93542 -11.5843 4.5 - vertex 0.568321 -13.4714 4.5 + vertex -4.20152 13.9728 -4.5 + vertex -3.87896 14.4167 -4.5 + vertex -4.20152 13.9728 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669132 -0.743144 0 outer loop - vertex 0.0225514 -14.4167 4.5 - vertex 2.93542 -11.5843 4.5 - vertex 0.345114 -13.9728 4.5 + vertex -3.47114 14.7839 -4.5 + vertex -3.47114 14.7839 4.5 + vertex -3.87896 14.4167 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669132 -0.743144 0 outer loop - vertex -0.385267 -14.7839 4.5 - vertex 12.474 -7.22789 4.5 - vertex 0.0225514 -14.4167 4.5 + vertex -3.87896 14.4167 -4.5 + vertex -3.47114 14.7839 -4.5 + vertex -3.87896 14.4167 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.5 -0.866026 0 outer loop - vertex 12.9959 -7.05831 4.5 - vertex -0.385267 -14.7839 4.5 - vertex 18 -5.7735 4.5 + vertex -2.99589 15.0583 -4.5 + vertex -2.99589 15.0583 4.5 + vertex -3.47114 14.7839 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 -0.866026 0 outer loop - vertex -4 -18.4752 4.5 - vertex -0.385267 -14.7839 4.5 - vertex -0.860519 -15.0583 4.5 + vertex -3.47114 14.7839 -4.5 + vertex -2.99589 15.0583 -4.5 + vertex -3.47114 14.7839 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309017 -0.951057 0 outer loop - vertex -0.385267 -14.7839 4.5 - vertex -4 -18.4752 4.5 - vertex 18 -5.7735 4.5 + vertex -2.47397 15.2279 -4.5 + vertex -2.47397 15.2279 4.5 + vertex -2.99589 15.0583 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309017 -0.951057 0 outer loop - vertex -1.38243 -15.2279 4.5 - vertex -4 -18.4752 4.5 - vertex -0.860519 -15.0583 4.5 + vertex -2.99589 15.0583 -4.5 + vertex -2.47397 15.2279 -4.5 + vertex -2.99589 15.0583 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.104529 -0.994522 0 outer loop - vertex -1.9282 -15.2853 4.5 - vertex -4 -18.4752 4.5 - vertex -1.38243 -15.2279 4.5 + vertex -1.9282 15.2853 -4.5 + vertex -1.9282 15.2853 4.5 + vertex -2.47397 15.2279 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 -0.994522 0 outer loop - vertex -2.47397 -15.2279 4.5 - vertex -4 -18.4752 4.5 - vertex -1.9282 -15.2853 4.5 + vertex -2.47397 15.2279 -4.5 + vertex -1.9282 15.2853 -4.5 + vertex -2.47397 15.2279 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 -0.994522 0 outer loop - vertex -2.99589 -15.0583 4.5 - vertex -4 -18.4752 4.5 - vertex -2.47397 -15.2279 4.5 + vertex -1.38244 15.2279 -4.5 + vertex -1.38244 15.2279 4.5 + vertex -1.9282 15.2853 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 -0.994522 0 outer loop - vertex -3.47114 -14.7839 4.5 - vertex -4 -18.4752 4.5 - vertex -2.99589 -15.0583 4.5 + vertex -1.9282 15.2853 -4.5 + vertex -1.38244 15.2279 -4.5 + vertex -1.9282 15.2853 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -3.87896 -14.4167 4.5 - vertex -4 -18.4752 4.5 - vertex -3.47114 -14.7839 4.5 + vertex -0.860519 15.0583 -4.5 + vertex -0.860519 15.0583 4.5 + vertex -1.38244 15.2279 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -4.20152 -13.9728 4.5 - vertex -4 -18.4752 4.5 - vertex -3.87896 -14.4167 4.5 + vertex -1.38244 15.2279 -4.5 + vertex -0.860519 15.0583 -4.5 + vertex -1.38244 15.2279 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 -0.866025 0 outer loop - vertex -10 -10.625 4.5 - vertex -4.20152 -13.9728 4.5 - vertex -4.42473 -13.4714 4.5 + vertex -0.385267 14.7839 -4.5 + vertex -0.385267 14.7839 4.5 + vertex -0.860519 15.0583 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 -0.866025 0 outer loop - vertex -9.45423 -10.5676 4.5 - vertex -4.42473 -13.4714 4.5 - vertex -4.53882 -12.9346 4.5 + vertex -0.860519 15.0583 -4.5 + vertex -0.385267 14.7839 -4.5 + vertex -0.860519 15.0583 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 -0.743145 0 outer loop - vertex -3.87896 -10.9038 4.5 - vertex -7.50348 -8.81117 4.5 - vertex -4.20152 -11.3478 4.5 + vertex 0.0225521 14.4167 -4.5 + vertex 0.0225521 14.4167 4.5 + vertex -0.385267 14.7839 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669131 -0.743145 0 outer loop - vertex -7.38938 -7.72561 4.5 - vertex -4.89074 -1.03956 4.5 - vertex -5 0 4.5 + vertex -0.385267 14.7839 -4.5 + vertex 0.0225521 14.4167 -4.5 + vertex -0.385267 14.7839 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.809017 -0.587786 0 outer loop - vertex -7.50348 7.18883 4.5 - vertex -4.89074 1.03956 4.5 - vertex -7.38938 7.72561 4.5 + vertex 0.345114 13.9728 4.5 + vertex 0.0225521 14.4167 4.5 + vertex 0.345114 13.9728 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.809017 -0.587786 0 outer loop - vertex -7.72668 6.6875 4.5 - vertex -4.89074 1.03956 4.5 - vertex -7.50348 7.18883 4.5 + vertex 0.345114 13.9728 -4.5 + vertex 0.0225521 14.4167 4.5 + vertex 0.0225521 14.4167 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -7.72668 -9.3125 4.5 - vertex -4.20152 -11.3478 4.5 - vertex -7.50348 -8.81117 4.5 + vertex 0.56832 13.4714 4.5 + vertex 0.345114 13.9728 4.5 + vertex 0.56832 13.4714 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -4.20152 -11.3478 4.5 - vertex -7.72668 -9.3125 4.5 - vertex -4.42473 -11.8491 4.5 + vertex 0.56832 13.4714 -4.5 + vertex 0.345114 13.9728 4.5 + vertex 0.345114 13.9728 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.978148 -0.207912 0 outer loop - vertex -8.04924 -9.75647 4.5 - vertex -4.42473 -11.8491 4.5 - vertex -7.72668 -9.3125 4.5 + vertex 0.682417 12.9346 4.5 + vertex 0.56832 13.4714 4.5 + vertex 0.682417 12.9346 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.978148 -0.207912 0 outer loop - vertex -4.42473 -11.8491 4.5 - vertex -8.04924 -9.75647 4.5 - vertex -4.53882 -12.3859 4.5 + vertex 0.682417 12.9346 -4.5 + vertex 0.56832 13.4714 4.5 + vertex 0.56832 13.4714 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -1 -2.04945e-07 0 outer loop - vertex -8.45706 -10.1237 4.5 - vertex -4.53882 -12.3859 4.5 - vertex -8.04924 -9.75647 4.5 + vertex 0.682417 12.3859 4.5 + vertex 0.682417 12.9346 4.5 + vertex 0.682417 12.3859 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -1 -2.04945e-07 0 outer loop - vertex -4.53882 -12.3859 4.5 - vertex -8.45706 -10.1237 4.5 - vertex -4.53882 -12.9346 4.5 + vertex 0.682417 12.3859 -4.5 + vertex 0.682417 12.9346 4.5 + vertex 0.682417 12.9346 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.978147 0.207913 0 outer loop - vertex -8.93232 -10.3981 4.5 - vertex -4.53882 -12.9346 4.5 - vertex -8.45706 -10.1237 4.5 + vertex 0.682417 12.3859 4.5 + vertex 0.682417 12.3859 -4.5 + vertex 0.56832 11.8491 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.978147 0.207913 0 outer loop - vertex -9.45423 -10.5676 4.5 - vertex -4.53882 -12.9346 4.5 - vertex -8.93232 -10.3981 4.5 + vertex 0.56832 11.8491 4.5 + vertex 0.682417 12.3859 -4.5 + vertex 0.56832 11.8491 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.913546 0.406736 0 outer loop - vertex -10 -10.625 4.5 - vertex -4.42473 -13.4714 4.5 - vertex -9.45423 -10.5676 4.5 + vertex 0.56832 11.8491 4.5 + vertex 0.56832 11.8491 -4.5 + vertex 0.345113 11.3478 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.913546 0.406736 0 outer loop - vertex -4.20152 -13.9728 4.5 - vertex -10 -10.625 4.5 - vertex -4 -18.4752 4.5 + vertex 0.345113 11.3478 4.5 + vertex 0.56832 11.8491 -4.5 + vertex 0.345113 11.3478 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809016 0.587786 0 outer loop - vertex -14 -12.7017 4.5 - vertex -10 -10.625 4.5 - vertex -10.5458 -10.5676 4.5 + vertex 0.345113 11.3478 4.5 + vertex 0.345113 11.3478 -4.5 + vertex 0.0225516 10.9038 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.809016 0.587786 0 outer loop - vertex -14 -12.7017 4.5 - vertex -10.5458 -10.5676 4.5 - vertex -11.0677 -10.3981 4.5 + vertex 0.0225516 10.9038 4.5 + vertex 0.345113 11.3478 -4.5 + vertex 0.0225516 10.9038 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669132 0.743144 0 outer loop - vertex -14 -12.7017 4.5 - vertex -11.0677 -10.3981 4.5 - vertex -11.5429 -10.1237 4.5 + vertex 0.0225516 10.9038 4.5 + vertex 0.0225516 10.9038 -4.5 + vertex -0.385267 10.5366 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.669132 0.743144 0 outer loop - vertex -14 -12.7017 4.5 - vertex -11.5429 -10.1237 4.5 - vertex -11.9508 -9.75647 4.5 + vertex -0.385267 10.5366 4.5 + vertex 0.0225516 10.9038 -4.5 + vertex -0.385267 10.5366 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 0.866026 0 outer loop - vertex -10 -10.625 4.5 - vertex -14 -12.7017 4.5 - vertex -4 -18.4752 4.5 + vertex -0.385267 10.5366 4.5 + vertex -0.385267 10.5366 -4.5 + vertex -0.860519 10.2622 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.5 0.866026 0 outer loop - vertex -12.2733 -9.3125 4.5 - vertex -14 -12.7017 4.5 - vertex -11.9508 -9.75647 4.5 + vertex -0.860519 10.2622 4.5 + vertex -0.385267 10.5366 -4.5 + vertex -0.860519 10.2622 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 0.951057 0 outer loop - vertex -12.4965 -8.81117 4.5 - vertex -14 -12.7017 4.5 - vertex -12.2733 -9.3125 4.5 + vertex -0.860519 10.2622 4.5 + vertex -0.860519 10.2622 -4.5 + vertex -1.38243 10.0926 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.309017 0.951057 0 outer loop - vertex -12.6106 -8.27439 4.5 - vertex -14 -12.7017 4.5 - vertex -12.4965 -8.81117 4.5 + vertex -1.38243 10.0926 4.5 + vertex -0.860519 10.2622 -4.5 + vertex -1.38243 10.0926 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex -12.6106 -7.72561 4.5 - vertex -14 -12.7017 4.5 - vertex -12.6106 -8.27439 4.5 + vertex -1.38243 10.0926 4.5 + vertex -1.38243 10.0926 -4.5 + vertex -1.9282 10.0353 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.104529 0.994522 0 outer loop - vertex 9.43168 -3.84908 4.5 - vertex 7.06458 -5.73622 4.5 - vertex 9.31758 -4.38587 4.5 + vertex -1.9282 10.0353 4.5 + vertex -1.38243 10.0926 -4.5 + vertex -1.9282 10.0353 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex 9.31758 -4.38587 4.5 - vertex 7.06458 -5.73622 4.5 - vertex 9.31758 -4.93464 4.5 + vertex -1.9282 10.0353 4.5 + vertex -1.9282 10.0353 -4.5 + vertex -2.47397 10.0926 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.104529 0.994522 0 outer loop - vertex 4.04508 -2.93893 4.5 - vertex 7.06458 -5.73622 4.5 - vertex 4.56773 -2.03368 4.5 + vertex -2.47397 10.0926 4.5 + vertex -1.9282 10.0353 -4.5 + vertex -2.47397 10.0926 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309017 0.951057 0 outer loop - vertex 3.34565 -3.71572 4.5 - vertex 7.06458 -5.73622 4.5 - vertex 4.04508 -2.93893 4.5 + vertex -2.47397 10.0926 4.5 + vertex -2.47397 10.0926 -4.5 + vertex -2.99589 10.2622 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.309017 0.951057 0 outer loop - vertex 2.5 -4.33013 4.5 - vertex 7.06458 -5.73622 4.5 - vertex 3.34565 -3.71572 4.5 + vertex -2.99589 10.2622 4.5 + vertex -2.47397 10.0926 -4.5 + vertex -2.99589 10.2622 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866025 0 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 2.5 -4.33013 4.5 - vertex 1.54508 -4.75528 4.5 + vertex -2.99589 10.2622 4.5 + vertex -2.99589 10.2622 -4.5 + vertex -3.47114 10.5366 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.5 0.866025 0 outer loop - vertex 2.5 -4.33013 4.5 - vertex 1.43542 -8.98622 4.5 - vertex 7.06458 -5.73622 4.5 + vertex -3.47114 10.5366 4.5 + vertex -2.99589 10.2622 -4.5 + vertex -3.47114 10.5366 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.669131 0.743145 0 outer loop - vertex 0.522642 -4.97261 4.5 - vertex 1.43542 -8.98622 4.5 - vertex 1.54508 -4.75528 4.5 + vertex -3.47114 10.5366 4.5 + vertex -3.47114 10.5366 -4.5 + vertex -3.87896 10.9038 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.669131 0.743145 0 outer loop - vertex 2.93542 -11.5843 4.5 - vertex 0.56832 -11.8491 4.5 - vertex 0.682416 -12.3859 4.5 + vertex -3.87896 10.9038 4.5 + vertex -3.47114 10.5366 -4.5 + vertex -3.87896 10.9038 -4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.809017 0.587786 0 outer loop - vertex -0.522642 -4.97261 4.5 - vertex 1.43542 -8.98622 4.5 - vertex 0.522642 -4.97261 4.5 + vertex -4.20152 11.3478 4.5 + vertex -3.87896 10.9038 4.5 + vertex -3.87896 10.9038 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.809017 0.587786 0 outer loop - vertex 2.93542 -11.5843 4.5 - vertex 0.345113 -11.3478 4.5 - vertex 0.56832 -11.8491 4.5 + vertex -4.20152 11.3478 -4.5 + vertex -4.20152 11.3478 4.5 + vertex -3.87896 10.9038 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 0.0225521 -10.9038 4.5 - vertex 0.345113 -11.3478 4.5 + vertex -4.42473 11.8491 4.5 + vertex -4.20152 11.3478 4.5 + vertex -4.20152 11.3478 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.913546 0.406736 0 outer loop - vertex 1.43542 -8.98622 4.5 - vertex -0.385267 -10.5366 4.5 - vertex 0.0225521 -10.9038 4.5 + vertex -4.42473 11.8491 -4.5 + vertex -4.42473 11.8491 4.5 + vertex -4.20152 11.3478 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 0.207912 0 outer loop - vertex -1.38244 -10.0926 4.5 - vertex 1.43542 -8.98622 4.5 - vertex -0.522642 -4.97261 4.5 + vertex -4.53882 12.3859 4.5 + vertex -4.42473 11.8491 4.5 + vertex -4.42473 11.8491 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.978148 0.207912 0 outer loop - vertex 1.43542 -8.98622 4.5 - vertex -0.86052 -10.2622 4.5 - vertex -0.385267 -10.5366 4.5 + vertex -4.53882 12.3859 -4.5 + vertex -4.53882 12.3859 4.5 + vertex -4.42473 11.8491 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.994522 0.104528 0 outer loop - vertex 1.43542 -8.98622 4.5 - vertex -1.38244 -10.0926 4.5 - vertex -0.86052 -10.2622 4.5 + vertex -4.3 0 4.5 + vertex -4.20603 -0.89402 4.5 + vertex -4.20603 -0.89402 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.994522 0.104528 0 outer loop - vertex -1.9282 -10.0353 4.5 - vertex -0.522642 -4.97261 4.5 - vertex -1.54508 -4.75528 4.5 + vertex -4.3 0 -4.5 + vertex -4.3 0 4.5 + vertex -4.20603 -0.89402 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.994522 -0.104528 0 outer loop - vertex -0.522642 -4.97261 4.5 - vertex -1.9282 -10.0353 4.5 - vertex -1.38244 -10.0926 4.5 + vertex -4.20603 0.89402 -4.5 + vertex -4.20603 0.89402 4.5 + vertex -4.3 0 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.994522 -0.104528 0 outer loop - vertex -1.54508 -4.75528 4.5 - vertex -2.47397 -10.0926 4.5 - vertex -1.9282 -10.0353 4.5 + vertex -4.3 0 -4.5 + vertex -4.20603 0.89402 -4.5 + vertex -4.3 0 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.951056 -0.309018 0 outer loop - vertex -2.5 -4.33013 4.5 - vertex -2.47397 -10.0926 4.5 - vertex -1.54508 -4.75528 4.5 + vertex -3.92824 1.74897 -4.5 + vertex -3.92824 1.74897 4.5 + vertex -4.20603 0.89402 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.951056 -0.309018 0 outer loop - vertex -2.5 -4.33013 4.5 - vertex -2.99589 -10.2622 4.5 - vertex -2.47397 -10.0926 4.5 + vertex -4.20603 0.89402 -4.5 + vertex -3.92824 1.74897 -4.5 + vertex -4.20603 0.89402 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.866026 -0.5 0 outer loop - vertex -7.38938 -7.72561 4.5 - vertex -2.5 -4.33013 4.5 - vertex -3.34565 -3.71572 4.5 + vertex -3.47877 2.52748 -4.5 + vertex -3.47877 2.52748 4.5 + vertex -3.92824 1.74897 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.866026 -0.5 0 outer loop - vertex -2.5 -4.33013 4.5 - vertex -7.38938 -7.72561 4.5 - vertex -2.99589 -10.2622 4.5 + vertex -3.92824 1.74897 -4.5 + vertex -3.47877 2.52748 -4.5 + vertex -3.92824 1.74897 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.743145 -0.66913 0 outer loop - vertex -2.99589 -10.2622 4.5 - vertex -7.38938 -7.72561 4.5 - vertex -3.47114 -10.5366 4.5 + vertex -2.87726 3.19552 -4.5 + vertex -2.87726 3.19552 4.5 + vertex -3.47877 2.52748 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.743145 -0.66913 0 outer loop - vertex -7.38938 -7.72561 4.5 - vertex -3.34565 -3.71572 4.5 - vertex -4.04508 -2.93893 4.5 + vertex -3.47877 2.52748 -4.5 + vertex -2.87726 3.19552 -4.5 + vertex -3.47877 2.52748 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.587785 -0.809017 0 outer loop - vertex -7.38938 -8.27439 4.5 - vertex -3.47114 -10.5366 4.5 - vertex -7.38938 -7.72561 4.5 + vertex -2.15 3.72391 -4.5 + vertex -2.15 3.72391 4.5 + vertex -2.87726 3.19552 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.587785 -0.809017 0 outer loop - vertex -7.38938 -7.72561 4.5 - vertex -4.04508 -2.93893 4.5 - vertex -4.56773 -2.03368 4.5 + vertex -2.87726 3.19552 -4.5 + vertex -2.15 3.72391 -4.5 + vertex -2.87726 3.19552 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.406737 -0.913545 0 outer loop - vertex -3.47114 -10.5366 4.5 - vertex -7.38938 -8.27439 4.5 - vertex -3.87896 -10.9038 4.5 + vertex -1.32877 4.08954 -4.5 + vertex -1.32877 4.08954 4.5 + vertex -2.15 3.72391 4.5 endloop endfacet - facet normal -0 0 1 + facet normal 0.406737 -0.913545 0 outer loop - vertex -7.50348 -8.81117 4.5 - vertex -3.87896 -10.9038 4.5 - vertex -7.38938 -8.27439 4.5 + vertex -2.15 3.72391 -4.5 + vertex -1.32877 4.08954 -4.5 + vertex -2.15 3.72391 4.5 + endloop + endfacet + facet normal 0.207911 -0.978148 0 + outer loop + vertex -0.449472 4.27644 -4.5 + vertex -0.449472 4.27644 4.5 + vertex -1.32877 4.08954 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0.207911 -0.978148 0 outer loop - vertex -7.38938 -7.72561 4.5 - vertex -4.56773 -2.03368 4.5 - vertex -4.89074 -1.03956 4.5 + vertex -1.32877 4.08954 -4.5 + vertex -0.449472 4.27644 -4.5 + vertex -1.32877 4.08954 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0 -1 0 outer loop - vertex 9.97745 6.41672 4.5 - vertex 0.568321 11.8491 4.5 - vertex 0.345113 11.3478 4.5 + vertex 0.449472 4.27644 -4.5 + vertex 0.449472 4.27644 4.5 + vertex -0.449472 4.27644 4.5 endloop endfacet - facet normal 0 0 1 + facet normal 0 -1 0 outer loop - vertex 2.5 4.33013 4.5 - vertex 0.345113 11.3478 4.5 - vertex 1.54508 4.75528 4.5 + vertex -0.449472 4.27644 -4.5 + vertex 0.449472 4.27644 -4.5 + vertex -0.449472 4.27644 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.207911 -0.978148 0 outer loop - vertex 0.022553 10.9038 4.5 - vertex 1.54508 4.75528 4.5 - vertex 0.345113 11.3478 4.5 + vertex 1.32877 4.08954 -4.5 + vertex 1.32877 4.08954 4.5 + vertex 0.449472 4.27644 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.207911 -0.978148 0 outer loop - vertex -0.385267 10.5366 4.5 - vertex 1.54508 4.75528 4.5 - vertex 0.022553 10.9038 4.5 + vertex 0.449472 4.27644 -4.5 + vertex 1.32877 4.08954 -4.5 + vertex 0.449472 4.27644 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.406737 -0.913545 0 outer loop - vertex 1.54508 4.75528 4.5 - vertex -0.385267 10.5366 4.5 - vertex 0.522642 4.97261 4.5 + vertex 2.15 3.72391 -4.5 + vertex 2.15 3.72391 4.5 + vertex 1.32877 4.08954 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.406737 -0.913545 0 outer loop - vertex -0.860519 10.2622 4.5 - vertex 0.522642 4.97261 4.5 - vertex -0.385267 10.5366 4.5 + vertex 1.32877 4.08954 -4.5 + vertex 2.15 3.72391 -4.5 + vertex 1.32877 4.08954 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.587785 -0.809017 0 outer loop - vertex 0.522642 4.97261 4.5 - vertex -0.860519 10.2622 4.5 - vertex -0.522642 4.97261 4.5 + vertex 2.87726 3.19552 -4.5 + vertex 2.87726 3.19552 4.5 + vertex 2.15 3.72391 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.587785 -0.809017 0 outer loop - vertex -1.38243 10.0926 4.5 - vertex -0.522642 4.97261 4.5 - vertex -0.860519 10.2622 4.5 + vertex 2.15 3.72391 -4.5 + vertex 2.87726 3.19552 -4.5 + vertex 2.15 3.72391 4.5 endloop endfacet - facet normal -0 0 1 + facet normal -0.743145 -0.66913 0 outer loop - vertex -1.9282 10.0353 4.5 - vertex -0.522642 4.97261 4.5 - vertex -1.38243 10.0926 4.5 + vertex 3.47877 2.52748 4.5 + vertex 2.87726 3.19552 4.5 + vertex 3.47877 2.52748 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.743145 -0.66913 0 outer loop - vertex -0.522642 4.97261 4.5 - vertex -1.9282 10.0353 4.5 - vertex -1.54508 4.75528 4.5 + vertex 3.47877 2.52748 -4.5 + vertex 2.87726 3.19552 4.5 + vertex 2.87726 3.19552 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.866026 -0.5 0 outer loop - vertex -2.47397 10.0926 4.5 - vertex -1.54508 4.75528 4.5 - vertex -1.9282 10.0353 4.5 + vertex 3.92824 1.74897 4.5 + vertex 3.47877 2.52748 4.5 + vertex 3.92824 1.74897 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.866026 -0.5 0 outer loop - vertex -2.47397 10.0926 4.5 - vertex -2.5 4.33013 4.5 - vertex -1.54508 4.75528 4.5 + vertex 3.92824 1.74897 -4.5 + vertex 3.47877 2.52748 4.5 + vertex 3.47877 2.52748 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.951056 -0.309018 0 outer loop - vertex -2.99589 10.2622 4.5 - vertex -2.5 4.33013 4.5 - vertex -2.47397 10.0926 4.5 + vertex 4.20603 0.89402 4.5 + vertex 3.92824 1.74897 4.5 + vertex 4.20603 0.89402 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.951056 -0.309018 0 outer loop - vertex -2.99589 10.2622 4.5 - vertex -3.34565 3.71572 4.5 - vertex -2.5 4.33013 4.5 + vertex 4.20603 0.89402 -4.5 + vertex 3.92824 1.74897 4.5 + vertex 3.92824 1.74897 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.994522 -0.104528 0 outer loop - vertex -3.47114 10.5366 4.5 - vertex -3.34565 3.71572 4.5 - vertex -2.99589 10.2622 4.5 + vertex 4.3 0 4.5 + vertex 4.20603 0.89402 4.5 + vertex 4.3 0 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.994522 -0.104528 0 outer loop - vertex -3.87896 10.9038 4.5 - vertex -3.34565 3.71572 4.5 - vertex -3.47114 10.5366 4.5 + vertex 4.3 0 -4.5 + vertex 4.20603 0.89402 4.5 + vertex 4.20603 0.89402 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.994522 0.104528 0 outer loop - vertex -3.87896 10.9038 4.5 - vertex -4.04508 2.93893 4.5 - vertex -3.34565 3.71572 4.5 + vertex 4.3 0 4.5 + vertex 4.3 0 -4.5 + vertex 4.20603 -0.89402 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.994522 0.104528 0 outer loop - vertex -4.20152 11.3478 4.5 - vertex -4.04508 2.93893 4.5 - vertex -3.87896 10.9038 4.5 + vertex 4.20603 -0.89402 4.5 + vertex 4.3 0 -4.5 + vertex 4.20603 -0.89402 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.951056 0.309018 0 outer loop - vertex -4.56773 2.03368 4.5 - vertex -4.20152 11.3478 4.5 - vertex -4.42473 11.8491 4.5 + vertex 4.20603 -0.89402 4.5 + vertex 4.20603 -0.89402 -4.5 + vertex 3.92824 -1.74897 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.951056 0.309018 0 outer loop - vertex -4.89074 1.03956 4.5 - vertex -4.42473 11.8491 4.5 - vertex -4.53882 12.3859 4.5 + vertex 3.92824 -1.74897 4.5 + vertex 4.20603 -0.89402 -4.5 + vertex 3.92824 -1.74897 -4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.866026 0.5 0 outer loop - vertex -4.20152 11.3478 4.5 - vertex -4.56773 2.03368 4.5 - vertex -4.04508 2.93893 4.5 + vertex 3.92824 -1.74897 4.5 + vertex 3.92824 -1.74897 -4.5 + vertex 3.47877 -2.52748 4.5 endloop endfacet - facet normal 0 0 1 + facet normal -0.866026 0.5 0 outer loop - vertex -8.45706 10.1237 4.5 - vertex -4.53882 12.3859 4.5 - vertex -4.53882 12.9346 4.5 + vertex 3.47877 -2.52748 4.5 + vertex 3.92824 -1.74897 -4.5 + vertex 3.47877 -2.52748 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -4.04508 -2.93893 -4.5 - vertex -8.45706 -5.87633 -4.5 - vertex -4.56773 -2.03368 -4.5 + vertex 3.03254 -3.02307 -1.0037 + vertex 3.47877 -2.52748 -4.5 + vertex 2.87726 -3.19552 -1.20241 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -5 0 -4.5 - vertex -7.50348 7.18883 -4.5 - vertex -7.38938 7.72561 -4.5 + vertex 3.03254 -3.02307 -1.0037 + vertex 3.16222 -2.87905 -0.75 + vertex 3.47877 -2.52748 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -8.93232 -5.60194 -4.5 - vertex -4.56773 -2.03368 -4.5 - vertex -8.45706 -5.87633 -4.5 + vertex 3.16222 -2.87905 -0.75 + vertex 3.25196 -2.77938 -0.463525 + vertex 3.47877 -2.52748 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -5 0 -4.5 - vertex -7.72668 6.6875 -4.5 - vertex -7.50348 7.18883 -4.5 + vertex 3.47877 -2.52748 -4.5 + vertex 3.29783 -2.72844 -0.156793 + vertex 3.47877 -2.52748 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -4.56773 -2.03368 -4.5 - vertex -8.93232 -5.60194 -4.5 - vertex -4.89074 -1.03956 -4.5 + vertex 3.47877 -2.52748 4.5 + vertex 3.29783 -2.72844 0.156793 + vertex 2.87726 -3.19552 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -5 0 -4.5 - vertex -8.04924 6.24353 -4.5 - vertex -7.72668 6.6875 -4.5 + vertex 3.29783 -2.72844 0.156793 + vertex 3.25196 -2.77938 0.463525 + vertex 2.87726 -3.19552 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -9.45423 -5.43236 -4.5 - vertex -4.89074 -1.03956 -4.5 - vertex -8.93232 -5.60194 -4.5 + vertex 3.25196 -2.77938 0.463525 + vertex 3.16222 -2.87905 0.75 + vertex 2.87726 -3.19552 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -5 0 -4.5 - vertex -8.45706 5.87633 -4.5 - vertex -8.04924 6.24353 -4.5 + vertex 2.87726 -3.19552 4.5 + vertex 3.03254 -3.02307 1.0037 + vertex 2.87726 -3.19552 1.20241 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -10 -5.375 -4.5 - vertex -4.89074 -1.03956 -4.5 - vertex -9.45423 -5.43236 -4.5 + vertex 3.16222 -2.87905 0.75 + vertex 3.03254 -3.02307 1.0037 + vertex 2.87726 -3.19552 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -5 0 -4.5 - vertex -8.93232 5.60194 -4.5 - vertex -8.45706 5.87633 -4.5 + vertex 3.29783 -2.72844 -0.156793 + vertex 3.29783 -2.72844 0.156793 + vertex 3.47877 -2.52748 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -4.89074 -1.03956 -4.5 - vertex -10 -5.375 -4.5 - vertex -5 0 -4.5 + vertex 3.25196 -2.77938 -0.463525 + vertex 3.29783 -2.72844 -0.156793 + vertex 3.47877 -2.52748 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.743145 0.66913 0 outer loop - vertex -5 0 -4.5 - vertex -9.45423 5.43236 -4.5 - vertex -8.93232 5.60194 -4.5 + vertex 3.47877 -2.52748 -4.5 + vertex 2.87726 -3.19552 -4.5 + vertex 2.87726 -3.19552 -1.20241 endloop endfacet - facet normal 0 0 -1 + facet normal -0.587785 0.809017 0 outer loop - vertex -10 5.375 -4.5 - vertex -5 0 -4.5 - vertex -10 -5.375 -4.5 + vertex 2.4037 -3.53959 -1.46722 + vertex 2.87726 -3.19552 -4.5 + vertex 2.15 -3.72391 -1.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.587785 0.809017 0 outer loop - vertex -5 0 -4.5 - vertex -10 5.375 -4.5 - vertex -9.45423 5.43236 -4.5 + vertex 2.87726 -3.19552 -4.5 + vertex 2.6463 -3.36332 -1.37032 + vertex 2.86722 -3.20282 -1.21352 endloop endfacet - facet normal 0 0 -1 + facet normal -0.587785 0.809017 0 outer loop - vertex -10.5458 -5.43236 -4.5 - vertex -10 5.375 -4.5 - vertex -10 -5.375 -4.5 + vertex 2.87726 -3.19552 -4.5 + vertex 2.86722 -3.20282 -1.21352 + vertex 2.87726 -3.19552 -1.20241 endloop endfacet - facet normal 0 0 -1 + facet normal -0.587785 0.809017 0 outer loop - vertex -10.5458 -5.43236 -4.5 - vertex -10.5458 5.43236 -4.5 - vertex -10 5.375 -4.5 + vertex 2.4037 -3.53959 -1.46722 + vertex 2.6463 -3.36332 -1.37032 + vertex 2.87726 -3.19552 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.587785 0.809017 0 outer loop - vertex -11.0677 -5.60194 -4.5 - vertex -10.5458 5.43236 -4.5 - vertex -10.5458 -5.43236 -4.5 + vertex 2.87726 -3.19552 -4.5 + vertex 2.15 -3.72391 -4.5 + vertex 2.15 -3.72391 -1.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.406737 0.913545 0 outer loop - vertex -11.0677 -5.60194 -4.5 - vertex -11.0677 5.60194 -4.5 - vertex -10.5458 5.43236 -4.5 + vertex 1.34011 -4.0845 -1.21352 + vertex 2.15 -3.72391 -4.5 + vertex 1.32877 -4.08954 -1.20241 endloop endfacet - facet normal 0 0 -1 + facet normal -0.406737 0.913545 0 outer loop - vertex -11.5429 -5.87633 -4.5 - vertex -11.0677 5.60194 -4.5 - vertex -11.0677 -5.60194 -4.5 + vertex 1.34011 -4.0845 -1.21352 + vertex 1.58957 -3.97343 -1.37032 + vertex 2.15 -3.72391 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.406737 0.913545 0 outer loop - vertex -11.5429 -5.87633 -4.5 - vertex -11.5429 5.87633 -4.5 - vertex -11.0677 5.60194 -4.5 + vertex 2.15 -3.72391 -4.5 + vertex 1.86352 -3.85146 -1.46722 + vertex 2.15 -3.72391 -1.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.406737 0.913545 0 outer loop - vertex -11.9508 -6.24353 -4.5 - vertex -11.5429 5.87633 -4.5 - vertex -11.5429 -5.87633 -4.5 + vertex 1.58957 -3.97343 -1.37032 + vertex 1.86352 -3.85146 -1.46722 + vertex 2.15 -3.72391 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.406737 0.913545 0 outer loop - vertex -11.9508 -6.24353 -4.5 - vertex -11.9508 6.24353 -4.5 - vertex -11.5429 5.87633 -4.5 + vertex 2.15 -3.72391 -4.5 + vertex 1.32877 -4.08954 -4.5 + vertex 1.32877 -4.08954 -1.20241 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -12.2733 -6.6875 -4.5 - vertex -11.9508 6.24353 -4.5 - vertex -11.9508 -6.24353 -4.5 + vertex 1.32877 -4.08954 4.5 + vertex 1.32877 -4.08954 1.20241 + vertex 0.449472 -4.27644 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -12.2733 -6.6875 -4.5 - vertex -12.2733 6.6875 -4.5 - vertex -11.9508 6.24353 -4.5 + vertex 0.449472 -4.27644 4.5 + vertex 1.32877 -4.08954 1.20241 + vertex 1.10179 -4.13779 1.0037 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -12.4965 -7.18883 -4.5 - vertex -12.2733 6.6875 -4.5 - vertex -12.2733 -6.6875 -4.5 + vertex 0.449472 -4.27644 4.5 + vertex 1.10179 -4.13779 1.0037 + vertex 0.912218 -4.17808 0.75 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -12.4965 -7.18883 -4.5 - vertex -12.4965 7.18883 -4.5 - vertex -12.2733 6.6875 -4.5 + vertex 0.912218 -4.17808 0.75 + vertex 0.781038 -4.20597 0.463525 + vertex 0.449472 -4.27644 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -12.6106 -7.72561 -4.5 - vertex -12.4965 7.18883 -4.5 - vertex -12.4965 -7.18883 -4.5 + vertex 0.781038 -4.20597 0.463525 + vertex 0.713983 -4.22022 0.156793 + vertex 0.449472 -4.27644 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -12.4965 7.18883 -4.5 - vertex -12.6106 -7.72561 -4.5 - vertex -12.6106 7.72561 -4.5 + vertex 0.713983 -4.22022 0.156793 + vertex 0.713983 -4.22022 -0.156793 + vertex 0.449472 -4.27644 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex 9.97745 6.41672 -4.5 - vertex 0.568321 11.8491 -4.5 - vertex 0.682417 12.3859 -4.5 + vertex 0.781038 -4.20597 -0.463525 + vertex 1.32877 -4.08954 -4.5 + vertex 0.713983 -4.22022 -0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -0.385267 10.5366 -4.5 - vertex 1.54508 4.75528 -4.5 - vertex 0.522642 4.97261 -4.5 + vertex 0.912218 -4.17808 -0.75 + vertex 1.32877 -4.08954 -4.5 + vertex 0.781038 -4.20597 -0.463525 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex 2.5 4.33013 -4.5 - vertex 0.345113 11.3478 -4.5 - vertex 0.568321 11.8491 -4.5 + vertex 1.10179 -4.13779 -1.0037 + vertex 1.32877 -4.08954 -1.20241 + vertex 1.32877 -4.08954 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex 1.54508 4.75528 -4.5 - vertex 0.022553 10.9038 -4.5 - vertex 0.345113 11.3478 -4.5 + vertex 1.10179 -4.13779 -1.0037 + vertex 1.32877 -4.08954 -4.5 + vertex 0.912218 -4.17808 -0.75 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex 1.54508 4.75528 -4.5 - vertex -0.385267 10.5366 -4.5 - vertex 0.022553 10.9038 -4.5 + vertex 0.713983 -4.22022 -0.156793 + vertex 1.32877 -4.08954 -4.5 + vertex 0.449472 -4.27644 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.207911 0.978148 0 outer loop - vertex -0.860519 10.2622 -4.5 - vertex 0.522642 4.97261 -4.5 - vertex -0.522642 4.97261 -4.5 + vertex 0.713983 -4.22022 -0.156793 + vertex 0.449472 -4.27644 -4.5 + vertex 0.449472 -4.27644 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0 1 0 outer loop - vertex 0.522642 4.97261 -4.5 - vertex -0.860519 10.2622 -4.5 - vertex -0.385267 10.5366 -4.5 + vertex 0.449472 -4.27644 4.5 + vertex 0.449472 -4.27644 -4.5 + vertex -0.449472 -4.27644 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0 1 0 outer loop - vertex -0.522642 4.97261 -4.5 - vertex -1.38243 10.0926 -4.5 - vertex -0.860519 10.2622 -4.5 + vertex -0.449472 -4.27644 4.5 + vertex 0.449472 -4.27644 -4.5 + vertex -0.449472 -4.27644 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.207911 0.978148 0 outer loop - vertex -1.9282 10.0353 -4.5 - vertex -0.522642 4.97261 -4.5 - vertex -1.54508 4.75528 -4.5 + vertex -0.449472 -4.27644 4.5 + vertex -0.449472 -4.27644 -4.5 + vertex -1.32877 -4.08954 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.207911 0.978148 0 outer loop - vertex -0.522642 4.97261 -4.5 - vertex -1.9282 10.0353 -4.5 - vertex -1.38243 10.0926 -4.5 + vertex -1.32877 -4.08954 4.5 + vertex -0.449472 -4.27644 -4.5 + vertex -1.32877 -4.08954 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.406737 0.913545 0 outer loop - vertex -1.54508 4.75528 -4.5 - vertex -2.47397 10.0926 -4.5 - vertex -1.9282 10.0353 -4.5 + vertex -1.32877 -4.08954 4.5 + vertex -1.32877 -4.08954 -4.5 + vertex -2.15 -3.72391 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.406737 0.913545 0 outer loop - vertex -2.5 4.33013 -4.5 - vertex -2.47397 10.0926 -4.5 - vertex -1.54508 4.75528 -4.5 + vertex -2.15 -3.72391 4.5 + vertex -1.32877 -4.08954 -4.5 + vertex -2.15 -3.72391 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.587785 0.809017 0 outer loop - vertex -2.5 4.33013 -4.5 - vertex -2.99589 10.2622 -4.5 - vertex -2.47397 10.0926 -4.5 + vertex -2.15 -3.72391 4.5 + vertex -2.15 -3.72391 -4.5 + vertex -2.87726 -3.19552 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.587785 0.809017 0 outer loop - vertex -7.38938 7.72561 -4.5 - vertex -2.5 4.33013 -4.5 - vertex -3.34565 3.71572 -4.5 + vertex -2.87726 -3.19552 4.5 + vertex -2.15 -3.72391 -4.5 + vertex -2.87726 -3.19552 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.743145 0.66913 0 outer loop - vertex -2.5 4.33013 -4.5 - vertex -7.38938 7.72561 -4.5 - vertex -2.99589 10.2622 -4.5 + vertex -3.47877 -2.52748 4.5 + vertex -2.87726 -3.19552 4.5 + vertex -2.87726 -3.19552 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.743145 0.66913 0 outer loop - vertex -2.99589 10.2622 -4.5 - vertex -7.38938 7.72561 -4.5 - vertex -3.47114 10.5366 -4.5 + vertex -3.47877 -2.52748 -4.5 + vertex -3.47877 -2.52748 4.5 + vertex -2.87726 -3.19552 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.866026 0.5 0 outer loop - vertex -7.38938 7.72561 -4.5 - vertex -3.34565 3.71572 -4.5 - vertex -4.04508 2.93893 -4.5 + vertex -3.92824 -1.74897 4.5 + vertex -3.47877 -2.52748 4.5 + vertex -3.47877 -2.52748 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.866026 0.5 0 outer loop - vertex -7.38938 8.27439 -4.5 - vertex -3.47114 10.5366 -4.5 - vertex -7.38938 7.72561 -4.5 + vertex -3.92824 -1.74897 -4.5 + vertex -3.92824 -1.74897 4.5 + vertex -3.47877 -2.52748 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.951056 0.309018 0 outer loop - vertex -3.47114 10.5366 -4.5 - vertex -7.38938 8.27439 -4.5 - vertex -3.87896 10.9038 -4.5 + vertex -4.20603 -0.89402 4.5 + vertex -3.92824 -1.74897 4.5 + vertex -3.92824 -1.74897 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.951056 0.309018 0 outer loop - vertex -7.50348 8.81117 -4.5 - vertex -3.87896 10.9038 -4.5 - vertex -7.38938 8.27439 -4.5 + vertex -4.20603 -0.89402 -4.5 + vertex -4.20603 -0.89402 4.5 + vertex -3.92824 -1.74897 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -3.87896 10.9038 -4.5 - vertex -7.50348 8.81117 -4.5 - vertex -4.20152 11.3478 -4.5 + vertex 3.72163 -7.66627 1.37032 + vertex 7.06458 -5.73622 4.5 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.38938 7.72561 -4.5 - vertex -4.04508 2.93893 -4.5 - vertex -4.56773 2.03368 -4.5 + vertex 5.54192 -6.61532 -0.156793 + vertex 5.48546 -6.64792 -0.463525 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 9.97745 -2.90379 -4.5 - vertex 4.89074 -1.03956 -4.5 - vertex 5 0 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 2.95808 -8.10711 0.156793 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 9.43168 -3.84908 -4.5 - vertex 4.56773 -2.03368 -4.5 - vertex 4.89074 -1.03956 -4.5 + vertex 2.95808 -8.10711 0.156793 + vertex 3.01454 -8.07451 0.463525 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 4.04508 -2.93893 -4.5 - vertex 4.56773 -2.03368 -4.5 + vertex 3.01454 -8.07451 0.463525 + vertex 3.125 -8.01073 0.75 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop + vertex 4.52009 -7.20528 -1.46722 + vertex 4.25 -7.36122 -1.5 vertex 7.06458 -5.73622 -4.5 - vertex 3.34565 -3.71572 -4.5 - vertex 4.04508 -2.93893 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 2.5 -4.33013 -4.5 - vertex 3.34565 -3.71572 -4.5 + vertex 3.125 -8.01073 0.75 + vertex 3.28463 -7.91857 1.0037 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 1.43542 -8.98622 -4.5 - vertex 2.5 -4.33013 -4.5 - vertex 7.06458 -5.73622 -4.5 + vertex 3.28463 -7.91857 1.0037 + vertex 3.48644 -7.80205 1.21353 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 2.5 -4.33013 -4.5 - vertex 1.43542 -8.98622 -4.5 - vertex 1.54508 -4.75528 -4.5 + vertex 3.97991 -7.51715 1.46722 + vertex 7.06458 -5.73622 4.5 + vertex 3.72163 -7.66627 1.37032 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.345113 -11.3478 -4.5 - vertex 2.93542 -11.5843 -4.5 - vertex 0.56832 -11.8491 -4.5 + vertex 4.25 -7.36122 1.5 + vertex 7.06458 -5.73622 4.5 + vertex 3.97991 -7.51715 1.46722 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 0.345113 -11.3478 -4.5 - vertex 1.43542 -8.98622 -4.5 + vertex 5.21537 -6.80386 -1.0037 + vertex 5.01356 -6.92038 -1.21352 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 0.0225521 -10.9038 -4.5 - vertex 1.43542 -8.98622 -4.5 - vertex 0.345113 -11.3478 -4.5 + vertex 4.52009 -7.20528 1.46722 + vertex 7.06458 -5.73622 4.5 + vertex 4.25 -7.36122 1.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.385267 -10.5366 -4.5 - vertex 1.43542 -8.98622 -4.5 - vertex 0.0225521 -10.9038 -4.5 + vertex 4.77837 -7.05616 1.37032 + vertex 7.06458 -5.73622 4.5 + vertex 4.52009 -7.20528 1.46722 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.86052 -10.2622 -4.5 - vertex 1.43542 -8.98622 -4.5 - vertex -0.385267 -10.5366 -4.5 + vertex 5.01356 -6.92038 1.21353 + vertex 7.06458 -5.73622 4.5 + vertex 4.77837 -7.05616 1.37032 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 1.43542 -8.98622 -4.5 - vertex 0.522642 -4.97261 -4.5 - vertex 1.54508 -4.75528 -4.5 + vertex 5.48546 -6.64792 -0.463525 + vertex 5.375 -6.7117 -0.75 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.38244 -10.0926 -4.5 - vertex 1.43542 -8.98622 -4.5 - vertex -0.86052 -10.2622 -4.5 + vertex 5.21537 -6.80386 1.0037 + vertex 7.06458 -5.73622 4.5 + vertex 5.01356 -6.92038 1.21353 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 1.43542 -8.98622 -4.5 - vertex -0.522642 -4.97261 -4.5 - vertex 0.522642 -4.97261 -4.5 + vertex 5.375 -6.7117 0.75 + vertex 7.06458 -5.73622 4.5 + vertex 5.21537 -6.80386 1.0037 endloop endfacet - facet normal -0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 1.43542 -8.98622 -4.5 - vertex -1.38244 -10.0926 -4.5 - vertex -0.522642 -4.97261 -4.5 + vertex 5.48546 -6.64792 0.463525 + vertex 7.06458 -5.73622 4.5 + vertex 5.375 -6.7117 0.75 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -1.9282 -10.0353 -4.5 - vertex -0.522642 -4.97261 -4.5 - vertex -1.38244 -10.0926 -4.5 + vertex 5.54192 -6.61532 0.156793 + vertex 5.54192 -6.61532 -0.156793 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -0.522642 -4.97261 -4.5 - vertex -1.9282 -10.0353 -4.5 - vertex -1.54508 -4.75528 -4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 7.06458 -5.73622 4.5 + vertex 5.48546 -6.64792 0.463525 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.47397 -10.0926 -4.5 - vertex -1.54508 -4.75528 -4.5 - vertex -1.9282 -10.0353 -4.5 + vertex 5.375 -6.7117 -0.75 + vertex 5.21537 -6.80386 -1.0037 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.47397 -10.0926 -4.5 - vertex -2.5 -4.33013 -4.5 - vertex -1.54508 -4.75528 -4.5 + vertex 5.01356 -6.92038 -1.21352 + vertex 4.77837 -7.05616 -1.37032 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.99589 -10.2622 -4.5 - vertex -2.5 -4.33013 -4.5 - vertex -2.47397 -10.0926 -4.5 + vertex 5.48546 -6.64792 0.463525 + vertex 5.54192 -6.61532 0.156793 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.38938 -7.72561 -4.5 - vertex -2.5 -4.33013 -4.5 - vertex -2.99589 -10.2622 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 7.06458 -5.73622 -4.5 + vertex 4.25 -7.36122 -1.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.38938 -7.72561 -4.5 - vertex -2.99589 -10.2622 -4.5 - vertex -3.47114 -10.5366 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 4.25 -7.36122 -1.5 + vertex 3.97991 -7.51715 -1.46722 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.38938 -8.27439 -4.5 - vertex -3.47114 -10.5366 -4.5 - vertex -3.87896 -10.9038 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 3.97991 -7.51715 -1.46722 + vertex 3.72163 -7.66627 -1.37032 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.50348 -7.18883 -4.5 - vertex -2.5 -4.33013 -4.5 - vertex -7.38938 -7.72561 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 3.72163 -7.66627 -1.37032 + vertex 3.48644 -7.80205 -1.21352 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.50348 -8.81117 -4.5 - vertex -3.87896 -10.9038 -4.5 - vertex -4.20152 -11.3478 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 3.48644 -7.80205 -1.21352 + vertex 3.28463 -7.91857 -1.0037 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -7.72668 -9.3125 -4.5 - vertex -4.20152 -11.3478 -4.5 - vertex -4.42473 -11.8491 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 3.28463 -7.91857 -1.0037 + vertex 3.125 -8.01073 -0.75 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -8.04924 -9.75647 -4.5 - vertex -4.42473 -11.8491 -4.5 - vertex -4.53882 -12.3859 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 3.125 -8.01073 -0.75 + vertex 3.01454 -8.07451 -0.463525 endloop endfacet - facet normal -0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -2.5 -4.33013 -4.5 - vertex -7.50348 -7.18883 -4.5 - vertex -3.34565 -3.71572 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 2.95808 -8.10711 -0.156793 + vertex 2.95808 -8.10711 0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex -8.45706 -10.1237 -4.5 - vertex -4.53882 -12.3859 -4.5 - vertex -4.53882 -12.9346 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 3.01454 -8.07451 -0.463525 + vertex 2.95808 -8.10711 -0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 18 5.7735 -4.5 - vertex 14.4247 3.84908 -4.5 - vertex 14.5388 4.38587 -4.5 + vertex 4.77837 -7.05616 -1.37032 + vertex 4.52009 -7.20528 -1.46722 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 14.2015 -3.34775 -4.5 - vertex 18 -5.7735 -4.5 - vertex 14.4247 -3.84908 -4.5 + vertex 3.48644 -7.80205 1.21353 + vertex 3.72163 -7.66627 1.37032 + vertex 1.43542 -8.98622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.866025 0.5 0 outer loop - vertex 14.2015 3.34775 -4.5 - vertex 18 -5.7735 -4.5 - vertex 14.2015 -3.34775 -4.5 + vertex 1.43542 -8.98622 4.5 + vertex 2.93542 -11.5843 4.5 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.866025 0.5 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 14.2015 3.34775 -4.5 - vertex 14.4247 3.84908 -4.5 + vertex 1.43542 -8.98622 -4.5 + vertex 1.43542 -8.98622 4.5 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.866025 -0.5 0 outer loop - vertex 14.2015 -3.34775 -4.5 - vertex 13.879 2.90379 -4.5 - vertex 14.2015 3.34775 -4.5 + vertex 8.56458 -8.33429 4.5 + vertex 7.06458 -5.73622 4.5 + vertex 8.56458 -8.33429 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.866025 -0.5 0 outer loop - vertex 13.879 -2.90379 -4.5 - vertex 13.879 2.90379 -4.5 - vertex 14.2015 -3.34775 -4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 7.06458 -5.73622 4.5 + vertex 7.06458 -5.73622 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 13.879 -2.90379 -4.5 - vertex 13.4711 2.53658 -4.5 - vertex 13.879 2.90379 -4.5 + vertex 7.04192 -9.2134 -0.156793 + vertex 8.56458 -8.33429 4.5 + vertex 6.98546 -9.246 -0.463525 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 13.4711 -2.53659 -4.5 - vertex 13.4711 2.53658 -4.5 - vertex 13.879 -2.90379 -4.5 + vertex 4.98644 -10.4001 -1.21352 + vertex 8.56458 -8.33429 -4.5 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 13.4711 -2.53659 -4.5 - vertex 12.9959 2.2622 -4.5 - vertex 13.4711 2.53658 -4.5 + vertex 6.51356 -9.51845 -1.21352 + vertex 8.56458 -8.33429 -4.5 + vertex 6.27837 -9.65424 -1.37032 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 12.9959 -2.2622 -4.5 - vertex 12.9959 2.2622 -4.5 - vertex 13.4711 -2.53659 -4.5 + vertex 2.93542 -11.5843 4.5 + vertex 4.45808 -10.7052 -0.156793 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 12.9959 -2.2622 -4.5 - vertex 12.474 2.09262 -4.5 - vertex 12.9959 2.2622 -4.5 + vertex 4.78463 -10.5167 1.0037 + vertex 2.93542 -11.5843 4.5 + vertex 4.98644 -10.4001 1.21353 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 12.474 -2.09262 -4.5 - vertex 12.474 2.09262 -4.5 - vertex 12.9959 -2.2622 -4.5 + vertex 4.45808 -10.7052 -0.156793 + vertex 4.51454 -10.6726 -0.463525 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 11.9282 -2.03525 -4.5 - vertex 12.474 2.09262 -4.5 - vertex 12.474 -2.09262 -4.5 + vertex 5.75 -9.95929 -1.5 + vertex 8.56458 -8.33429 -4.5 + vertex 5.47991 -10.1152 -1.46722 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 11.9282 -2.03525 -4.5 - vertex 11.9282 2.03525 -4.5 - vertex 12.474 2.09262 -4.5 + vertex 4.51454 -10.6726 -0.463525 + vertex 4.625 -10.6088 -0.75 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 11.3824 -2.09262 -4.5 - vertex 11.9282 2.03525 -4.5 - vertex 11.9282 -2.03525 -4.5 + vertex 5.47991 -10.1152 -1.46722 + vertex 8.56458 -8.33429 -4.5 + vertex 5.22163 -10.2643 -1.37032 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 11.3824 -2.09262 -4.5 - vertex 11.3824 2.09262 -4.5 - vertex 11.9282 2.03525 -4.5 + vertex 4.625 -10.6088 -0.75 + vertex 4.78463 -10.5167 -1.0037 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 10.8605 -2.2622 -4.5 - vertex 11.3824 2.09262 -4.5 - vertex 11.3824 -2.09262 -4.5 + vertex 4.78463 -10.5167 -1.0037 + vertex 4.98644 -10.4001 -1.21352 + vertex 2.93542 -11.5843 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 10.8605 -2.2622 -4.5 - vertex 10.8605 2.2622 -4.5 - vertex 11.3824 2.09262 -4.5 + vertex 6.02009 -9.80336 -1.46722 + vertex 8.56458 -8.33429 -4.5 + vertex 5.75 -9.95929 -1.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 10.8605 -2.2622 -4.5 - vertex 10.3853 2.53658 -4.5 - vertex 10.8605 2.2622 -4.5 + vertex 6.27837 -9.65424 -1.37032 + vertex 8.56458 -8.33429 -4.5 + vertex 6.02009 -9.80336 -1.46722 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 10.3853 -2.53658 -4.5 - vertex 10.3853 2.53658 -4.5 - vertex 10.8605 -2.2622 -4.5 + vertex 6.71537 -9.40193 -1.0037 + vertex 8.56458 -8.33429 -4.5 + vertex 6.51356 -9.51845 -1.21352 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 5 0 -4.5 - vertex 10.3853 2.53658 -4.5 - vertex 10.3853 -2.53658 -4.5 + vertex 6.875 -9.30977 -0.75 + vertex 8.56458 -8.33429 -4.5 + vertex 6.71537 -9.40193 -1.0037 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 5 0 -4.5 - vertex 10.3853 -2.53658 -4.5 - vertex 9.97745 -2.90379 -4.5 + vertex 6.98546 -9.246 -0.463525 + vertex 8.56458 -8.33429 -4.5 + vertex 6.875 -9.30977 -0.75 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 4.89074 -1.03956 -4.5 - vertex 9.97745 -2.90379 -4.5 - vertex 9.65489 -3.34775 -4.5 + vertex 8.56458 -8.33429 4.5 + vertex 8.56458 -8.33429 -4.5 + vertex 6.98546 -9.246 -0.463525 endloop endfacet - facet normal -0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 10.3853 2.53658 -4.5 - vertex 5 0 -4.5 - vertex 9.97745 2.90379 -4.5 + vertex 7.04192 -9.2134 0.156793 + vertex 8.56458 -8.33429 4.5 + vertex 7.04192 -9.2134 -0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 4.89074 1.03956 -4.5 - vertex 9.97745 2.90379 -4.5 - vertex 5 0 -4.5 + vertex 6.98546 -9.246 0.463525 + vertex 8.56458 -8.33429 4.5 + vertex 7.04192 -9.2134 0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 4.89074 -1.03956 -4.5 - vertex 9.65489 -3.34775 -4.5 - vertex 9.43168 -3.84908 -4.5 + vertex 6.27837 -9.65424 1.37032 + vertex 2.93542 -11.5843 4.5 + vertex 6.51356 -9.51845 1.21353 endloop endfacet - facet normal -0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 9.97745 2.90379 -4.5 - vertex 4.89074 1.03956 -4.5 - vertex 9.65489 3.34775 -4.5 + vertex 8.56458 -8.33429 4.5 + vertex 6.98546 -9.246 0.463525 + vertex 6.875 -9.30977 0.75 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 9.43168 -3.84908 -4.5 - vertex 9.31758 -4.38587 -4.5 + vertex 8.56458 -8.33429 4.5 + vertex 6.875 -9.30977 0.75 + vertex 6.71537 -9.40193 1.0037 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 4.56773 2.03368 -4.5 - vertex 9.65489 3.34775 -4.5 - vertex 4.89074 1.03956 -4.5 + vertex 8.56458 -8.33429 4.5 + vertex 6.71537 -9.40193 1.0037 + vertex 6.51356 -9.51845 1.21353 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 9.31758 -4.38587 -4.5 - vertex 9.31758 -4.93464 -4.5 + vertex 8.56458 -8.33429 4.5 + vertex 6.51356 -9.51845 1.21353 + vertex 2.93542 -11.5843 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 14.4247 -3.84908 -4.5 - vertex 18 -5.7735 -4.5 - vertex 14.5388 -4.38587 -4.5 + vertex 6.02009 -9.80336 1.46722 + vertex 2.93542 -11.5843 4.5 + vertex 6.27837 -9.65424 1.37032 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 14.5388 -4.93464 -4.5 - vertex 14.5388 -4.38587 -4.5 + vertex 5.75 -9.95929 1.5 + vertex 2.93542 -11.5843 4.5 + vertex 6.02009 -9.80336 1.46722 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 14.4247 -5.47142 -4.5 - vertex 14.5388 -4.93464 -4.5 + vertex 4.98644 -10.4001 1.21353 + vertex 2.93542 -11.5843 4.5 + vertex 5.22163 -10.2643 1.37032 endloop endfacet - facet normal -0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 14.2015 -5.97275 -4.5 - vertex 14.4247 -5.47142 -4.5 + vertex 5.75 -9.95929 1.5 + vertex 5.47991 -10.1152 1.46722 + vertex 2.93542 -11.5843 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 13.879 -6.41672 -4.5 - vertex 14.2015 -5.97275 -4.5 + vertex 5.47991 -10.1152 1.46722 + vertex 5.22163 -10.2643 1.37032 + vertex 2.93542 -11.5843 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 13.4711 -6.78392 -4.5 - vertex 13.879 -6.41672 -4.5 + vertex 4.625 -10.6088 0.75 + vertex 2.93542 -11.5843 4.5 + vertex 4.78463 -10.5167 1.0037 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 12.9959 -7.05831 -4.5 - vertex 13.4711 -6.78392 -4.5 + vertex 2.93542 -11.5843 4.5 + vertex 4.625 -10.6088 0.75 + vertex 4.51454 -10.6726 0.463525 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex -0.385267 -14.7839 -4.5 - vertex 12.9959 -7.05831 -4.5 - vertex 18 -5.7735 -4.5 + vertex 2.93542 -11.5843 4.5 + vertex 4.51454 -10.6726 0.463525 + vertex 4.45808 -10.7052 0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 9.65489 -5.97275 -4.5 - vertex 7.06458 -5.73622 -4.5 - vertex 9.43168 -5.47142 -4.5 + vertex 2.93542 -11.5843 4.5 + vertex 4.45808 -10.7052 0.156793 + vertex 4.45808 -10.7052 -0.156793 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 9.65489 -5.97275 -4.5 + vertex 5.22163 -10.2643 -1.37032 vertex 8.56458 -8.33429 -4.5 + vertex 4.98644 -10.4001 -1.21352 endloop endfacet - facet normal -0 0 -1 + facet normal 1 -2.04945e-07 0 outer loop - vertex 9.97745 -6.41672 -4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 9.65489 -5.97275 -4.5 + vertex 9.31758 -4.38587 -4.5 + vertex 9.31758 -4.38587 4.5 + vertex 9.31758 -4.93464 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 1 -2.04945e-07 0 outer loop - vertex 10.3853 -6.78392 -4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 9.97745 -6.41672 -4.5 + vertex 9.31758 -4.93464 -4.5 + vertex 9.31758 -4.38587 -4.5 + vertex 9.31758 -4.93464 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.978148 -0.207912 0 outer loop - vertex 10.8605 -7.05831 -4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 10.3853 -6.78392 -4.5 + vertex 9.43168 -3.84908 -4.5 + vertex 9.43168 -3.84908 4.5 + vertex 9.31758 -4.38587 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.978148 -0.207912 0 outer loop - vertex 11.3824 -7.22789 -4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 10.8605 -7.05831 -4.5 + vertex 9.31758 -4.38587 -4.5 + vertex 9.43168 -3.84908 -4.5 + vertex 9.31758 -4.38587 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 11.9282 -7.28525 -4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 11.3824 -7.22789 -4.5 + vertex 9.65489 -3.34775 -4.5 + vertex 9.65489 -3.34775 4.5 + vertex 9.43168 -3.84908 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 12.474 -7.22789 -4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 11.9282 -7.28525 -4.5 + vertex 9.43168 -3.84908 -4.5 + vertex 9.65489 -3.34775 -4.5 + vertex 9.43168 -3.84908 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809017 -0.587786 0 outer loop - vertex 12.9959 -7.05831 -4.5 - vertex -0.385267 -14.7839 -4.5 - vertex 12.474 -7.22789 -4.5 + vertex 9.97745 -2.90379 -4.5 + vertex 9.97745 -2.90379 4.5 + vertex 9.65489 -3.34775 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809017 -0.587786 0 outer loop - vertex 12.474 -7.22789 -4.5 - vertex 0.0225514 -14.4167 -4.5 - vertex 8.56458 -8.33429 -4.5 + vertex 9.65489 -3.34775 -4.5 + vertex 9.97745 -2.90379 -4.5 + vertex 9.65489 -3.34775 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669131 -0.743145 0 outer loop - vertex 0.56832 -11.8491 -4.5 - vertex 2.93542 -11.5843 -4.5 - vertex 0.682416 -12.3859 -4.5 + vertex 10.3853 -2.53658 -4.5 + vertex 10.3853 -2.53658 4.5 + vertex 9.97745 -2.90379 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669131 -0.743145 0 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 0.682416 -12.9346 -4.5 - vertex 0.682416 -12.3859 -4.5 + vertex 9.97745 -2.90379 -4.5 + vertex 10.3853 -2.53658 -4.5 + vertex 9.97745 -2.90379 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 8.56458 -8.33429 -4.5 - vertex 0.0225514 -14.4167 -4.5 - vertex 2.93542 -11.5843 -4.5 + vertex 10.8605 -2.2622 -4.5 + vertex 10.8605 -2.2622 4.5 + vertex 10.3853 -2.53658 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866025 0 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 0.568321 -13.4714 -4.5 - vertex 0.682416 -12.9346 -4.5 + vertex 10.3853 -2.53658 -4.5 + vertex 10.8605 -2.2622 -4.5 + vertex 10.3853 -2.53658 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.309017 -0.951057 0 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 0.345114 -13.9728 -4.5 - vertex 0.568321 -13.4714 -4.5 + vertex 11.3824 -2.09262 -4.5 + vertex 11.3824 -2.09262 4.5 + vertex 10.8605 -2.2622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.309017 -0.951057 0 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 0.0225514 -14.4167 -4.5 - vertex 0.345114 -13.9728 -4.5 + vertex 10.8605 -2.2622 -4.5 + vertex 11.3824 -2.09262 -4.5 + vertex 10.8605 -2.2622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.104529 -0.994522 0 outer loop - vertex 12.474 -7.22789 -4.5 - vertex -0.385267 -14.7839 -4.5 - vertex 0.0225514 -14.4167 -4.5 + vertex 11.9282 -2.03525 -4.5 + vertex 11.9282 -2.03525 4.5 + vertex 11.3824 -2.09262 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.104529 -0.994522 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -0.385267 -14.7839 -4.5 - vertex 18 -5.7735 -4.5 + vertex 11.3824 -2.09262 -4.5 + vertex 11.9282 -2.03525 -4.5 + vertex 11.3824 -2.09262 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.104529 -0.994522 0 outer loop - vertex -0.385267 -14.7839 -4.5 - vertex -4 -18.4752 -4.5 - vertex -0.860519 -15.0583 -4.5 + vertex 12.474 -2.09262 -4.5 + vertex 12.474 -2.09262 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.104529 -0.994522 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -1.38243 -15.2279 -4.5 - vertex -0.860519 -15.0583 -4.5 + vertex 11.9282 -2.03525 -4.5 + vertex 12.474 -2.09262 -4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -1.9282 -15.2853 -4.5 - vertex -1.38243 -15.2279 -4.5 + vertex 12.9959 -2.2622 -4.5 + vertex 12.9959 -2.2622 4.5 + vertex 12.474 -2.09262 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -2.47397 -15.2279 -4.5 - vertex -1.9282 -15.2853 -4.5 + vertex 12.474 -2.09262 -4.5 + vertex 12.9959 -2.2622 -4.5 + vertex 12.474 -2.09262 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 -0.866026 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -2.99589 -15.0583 -4.5 - vertex -2.47397 -15.2279 -4.5 + vertex 13.4711 -2.53658 -4.5 + vertex 13.4711 -2.53658 4.5 + vertex 12.9959 -2.2622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 -0.866026 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -3.47114 -14.7839 -4.5 - vertex -2.99589 -15.0583 -4.5 + vertex 12.9959 -2.2622 -4.5 + vertex 13.4711 -2.53658 -4.5 + vertex 12.9959 -2.2622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.669132 -0.743144 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -3.87896 -14.4167 -4.5 - vertex -3.47114 -14.7839 -4.5 + vertex 13.879 -2.90379 -4.5 + vertex 13.879 -2.90379 4.5 + vertex 13.4711 -2.53658 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.669132 -0.743144 0 outer loop - vertex -4 -18.4752 -4.5 - vertex -4.20152 -13.9728 -4.5 - vertex -3.87896 -14.4167 -4.5 + vertex 13.4711 -2.53658 -4.5 + vertex 13.879 -2.90379 -4.5 + vertex 13.4711 -2.53658 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809016 -0.587786 0 outer loop - vertex -10 -10.625 -4.5 - vertex -4.20152 -13.9728 -4.5 - vertex -4 -18.4752 -4.5 + vertex 14.2015 -3.34775 4.5 + vertex 13.879 -2.90379 4.5 + vertex 14.2015 -3.34775 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809016 -0.587786 0 outer loop - vertex -4.20152 -13.9728 -4.5 - vertex -10 -10.625 -4.5 - vertex -4.42473 -13.4714 -4.5 + vertex 14.2015 -3.34775 -4.5 + vertex 13.879 -2.90379 4.5 + vertex 13.879 -2.90379 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -7.72668 -6.6875 -4.5 - vertex -3.34565 -3.71572 -4.5 - vertex -7.50348 -7.18883 -4.5 + vertex 14.4247 -3.84908 4.5 + vertex 14.2015 -3.34775 4.5 + vertex 14.4247 -3.84908 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -3.34565 -3.71572 -4.5 - vertex -7.72668 -6.6875 -4.5 - vertex -4.04508 -2.93893 -4.5 + vertex 14.4247 -3.84908 -4.5 + vertex 14.2015 -3.34775 4.5 + vertex 14.2015 -3.34775 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978147 -0.207913 0 outer loop - vertex -3.47114 -10.5366 -4.5 - vertex -7.38938 -8.27439 -4.5 - vertex -7.38938 -7.72561 -4.5 + vertex 14.5388 -4.38587 4.5 + vertex 14.4247 -3.84908 4.5 + vertex 14.5388 -4.38587 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978147 -0.207913 0 outer loop - vertex -4.42473 -13.4714 -4.5 - vertex -9.45423 -10.5676 -4.5 - vertex -4.53882 -12.9346 -4.5 + vertex 14.5388 -4.38587 -4.5 + vertex 14.4247 -3.84908 4.5 + vertex 14.4247 -3.84908 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -1 2.04945e-07 0 outer loop - vertex -3.87896 -10.9038 -4.5 - vertex -7.50348 -8.81117 -4.5 - vertex -7.38938 -8.27439 -4.5 + vertex 14.5388 -4.38587 4.5 + vertex 14.5388 -4.38587 -4.5 + vertex 14.5388 -4.93464 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -1 2.04945e-07 0 outer loop - vertex -4.20152 -11.3478 -4.5 - vertex -7.72668 -9.3125 -4.5 - vertex -7.50348 -8.81117 -4.5 + vertex 14.5388 -4.93464 4.5 + vertex 14.5388 -4.38587 -4.5 + vertex 14.5388 -4.93464 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978148 0.207912 0 outer loop - vertex -4.42473 -11.8491 -4.5 - vertex -8.04924 -9.75647 -4.5 - vertex -7.72668 -9.3125 -4.5 + vertex 14.5388 -4.93464 4.5 + vertex 14.5388 -4.93464 -4.5 + vertex 14.4247 -5.47142 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978148 0.207912 0 outer loop - vertex -4.53882 -12.3859 -4.5 - vertex -8.45706 -10.1237 -4.5 - vertex -8.04924 -9.75647 -4.5 + vertex 14.4247 -5.47142 4.5 + vertex 14.5388 -4.93464 -4.5 + vertex 14.4247 -5.47142 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 0.406736 0 outer loop - vertex -4.53882 -12.9346 -4.5 - vertex -8.93232 -10.3981 -4.5 - vertex -8.45706 -10.1237 -4.5 + vertex 14.4247 -5.47142 4.5 + vertex 14.4247 -5.47142 -4.5 + vertex 14.2015 -5.97275 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 0.406736 0 outer loop - vertex -4.53882 -12.9346 -4.5 - vertex -9.45423 -10.5676 -4.5 - vertex -8.93232 -10.3981 -4.5 + vertex 14.2015 -5.97275 4.5 + vertex 14.4247 -5.47142 -4.5 + vertex 14.2015 -5.97275 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809017 0.587786 0 outer loop - vertex -4.42473 -13.4714 -4.5 - vertex -10 -10.625 -4.5 - vertex -9.45423 -10.5676 -4.5 + vertex 14.2015 -5.97275 4.5 + vertex 14.2015 -5.97275 -4.5 + vertex 13.879 -6.41672 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809017 0.587786 0 outer loop - vertex -14 -12.7017 -4.5 - vertex -10 -10.625 -4.5 - vertex -4 -18.4752 -4.5 + vertex 13.879 -6.41672 4.5 + vertex 14.2015 -5.97275 -4.5 + vertex 13.879 -6.41672 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.669131 0.743145 0 outer loop - vertex -10 -10.625 -4.5 - vertex -14 -12.7017 -4.5 - vertex -10.5458 -10.5676 -4.5 + vertex 13.879 -6.41672 4.5 + vertex 13.879 -6.41672 -4.5 + vertex 13.4711 -6.78392 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.669131 0.743145 0 outer loop - vertex -10.5458 -10.5676 -4.5 - vertex -14 -12.7017 -4.5 - vertex -11.0677 -10.3981 -4.5 + vertex 13.4711 -6.78392 4.5 + vertex 13.879 -6.41672 -4.5 + vertex 13.4711 -6.78392 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex -11.0677 -10.3981 -4.5 - vertex -14 -12.7017 -4.5 - vertex -11.5429 -10.1237 -4.5 + vertex 13.4711 -6.78392 4.5 + vertex 13.4711 -6.78392 -4.5 + vertex 12.9959 -7.05831 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866025 0 outer loop - vertex -14 -12.7017 -4.5 - vertex -12.6106 -7.72561 -4.5 - vertex -12.6106 -8.27439 -4.5 + vertex 12.9959 -7.05831 4.5 + vertex 13.4711 -6.78392 -4.5 + vertex 12.9959 -7.05831 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.309017 0.951057 0 outer loop - vertex -12.6106 -7.72561 -4.5 - vertex -14 -12.7017 -4.5 - vertex -12.6106 7.72561 -4.5 + vertex 12.9959 -7.05831 4.5 + vertex 12.9959 -7.05831 -4.5 + vertex 12.474 -7.22789 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.309017 0.951057 0 outer loop - vertex -12.6106 7.72561 -4.5 - vertex -14 12.7017 -4.5 - vertex -12.6106 8.27439 -4.5 + vertex 12.474 -7.22789 4.5 + vertex 12.9959 -7.05831 -4.5 + vertex 12.474 -7.22789 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.104529 0.994522 0 outer loop - vertex -12.6106 7.72561 -4.5 - vertex -14 -12.7017 -4.5 - vertex -14 12.7017 -4.5 + vertex 12.474 -7.22789 4.5 + vertex 12.474 -7.22789 -4.5 + vertex 11.9282 -7.28525 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.104529 0.994522 0 outer loop - vertex -12.4965 -8.81117 -4.5 - vertex -14 -12.7017 -4.5 - vertex -12.6106 -8.27439 -4.5 + vertex 11.9282 -7.28525 4.5 + vertex 12.474 -7.22789 -4.5 + vertex 11.9282 -7.28525 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.104529 0.994522 0 outer loop - vertex -12.2733 -9.3125 -4.5 - vertex -14 -12.7017 -4.5 - vertex -12.4965 -8.81117 -4.5 + vertex 11.9282 -7.28525 4.5 + vertex 11.9282 -7.28525 -4.5 + vertex 11.3824 -7.22789 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.104529 0.994522 0 outer loop - vertex -11.9508 -9.75647 -4.5 - vertex -14 -12.7017 -4.5 - vertex -12.2733 -9.3125 -4.5 + vertex 11.3824 -7.22789 4.5 + vertex 11.9282 -7.28525 -4.5 + vertex 11.3824 -7.22789 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.309017 0.951057 0 outer loop - vertex -11.5429 -10.1237 -4.5 - vertex -14 -12.7017 -4.5 - vertex -11.9508 -9.75647 -4.5 + vertex 11.3824 -7.22789 4.5 + vertex 11.3824 -7.22789 -4.5 + vertex 10.8605 -7.05831 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.309017 0.951057 0 outer loop - vertex 18 -5.7735 -4.5 - vertex 14.4247 3.84908 -4.5 - vertex 18 5.7735 -4.5 + vertex 10.8605 -7.05831 4.5 + vertex 11.3824 -7.22789 -4.5 + vertex 10.8605 -7.05831 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 0.866026 0 outer loop - vertex 14.5388 4.93464 -4.5 - vertex 18 5.7735 -4.5 - vertex 14.5388 4.38587 -4.5 + vertex 10.8605 -7.05831 4.5 + vertex 10.8605 -7.05831 -4.5 + vertex 10.3853 -6.78392 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 0.866026 0 outer loop - vertex 14.4247 5.47142 -4.5 - vertex 18 5.7735 -4.5 - vertex 14.5388 4.93464 -4.5 + vertex 10.3853 -6.78392 4.5 + vertex 10.8605 -7.05831 -4.5 + vertex 10.3853 -6.78392 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669132 0.743144 0 outer loop - vertex 14.2015 5.97275 -4.5 - vertex 18 5.7735 -4.5 - vertex 14.4247 5.47142 -4.5 + vertex 10.3853 -6.78392 4.5 + vertex 10.3853 -6.78392 -4.5 + vertex 9.97745 -6.41672 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669132 0.743144 0 outer loop - vertex 13.879 6.41672 -4.5 - vertex 18 5.7735 -4.5 - vertex 14.2015 5.97275 -4.5 + vertex 9.97745 -6.41672 4.5 + vertex 10.3853 -6.78392 -4.5 + vertex 9.97745 -6.41672 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809016 0.587786 0 outer loop - vertex 13.4711 6.78392 -4.5 - vertex 18 5.7735 -4.5 - vertex 13.879 6.41672 -4.5 + vertex 9.65489 -5.97275 4.5 + vertex 9.97745 -6.41672 4.5 + vertex 9.97745 -6.41672 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809016 0.587786 0 outer loop - vertex 12.9959 7.05831 -4.5 - vertex 18 5.7735 -4.5 - vertex 13.4711 6.78392 -4.5 + vertex 9.65489 -5.97275 -4.5 + vertex 9.65489 -5.97275 4.5 + vertex 9.97745 -6.41672 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.913546 0.406736 0 outer loop - vertex -0.385267 14.7839 -4.5 - vertex 12.9959 7.05831 -4.5 - vertex 12.474 7.22789 -4.5 + vertex 9.43168 -5.47142 4.5 + vertex 9.65489 -5.97275 4.5 + vertex 9.65489 -5.97275 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.913546 0.406736 0 outer loop vertex 9.43168 -5.47142 -4.5 - vertex 7.06458 -5.73622 -4.5 - vertex 9.31758 -4.93464 -4.5 + vertex 9.43168 -5.47142 4.5 + vertex 9.65489 -5.97275 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.978147 0.207913 0 outer loop - vertex 4.56773 -2.03368 -4.5 - vertex 9.43168 -3.84908 -4.5 - vertex 7.06458 -5.73622 -4.5 + vertex 9.31758 -4.93464 4.5 + vertex 9.43168 -5.47142 4.5 + vertex 9.43168 -5.47142 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.978147 0.207913 0 outer loop - vertex 9.65489 3.34775 -4.5 - vertex 4.56773 2.03368 -4.5 - vertex 9.43168 3.84908 -4.5 + vertex 9.31758 -4.93464 -4.5 + vertex 9.31758 -4.93464 4.5 + vertex 9.43168 -5.47142 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 1 2.04945e-07 0 outer loop - vertex 9.43168 3.84908 -4.5 - vertex 4.56773 2.03368 -4.5 + vertex 9.31758 4.93464 4.5 + vertex 9.31758 4.38587 4.5 vertex 9.31758 4.38587 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 1 2.04945e-07 0 outer loop - vertex 4.04508 2.93893 -4.5 + vertex 9.31758 4.93464 -4.5 + vertex 9.31758 4.93464 4.5 vertex 9.31758 4.38587 -4.5 - vertex 4.56773 2.03368 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.978147 -0.207913 0 outer loop - vertex 9.31758 4.38587 -4.5 - vertex 4.04508 2.93893 -4.5 - vertex 9.31758 4.93464 -4.5 + vertex 9.43168 5.47142 -4.5 + vertex 9.43168 5.47142 4.5 + vertex 9.31758 4.93464 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.978147 -0.207913 0 outer loop - vertex 3.34565 3.71572 -4.5 vertex 9.31758 4.93464 -4.5 - vertex 4.04508 2.93893 -4.5 + vertex 9.43168 5.47142 -4.5 + vertex 9.31758 4.93464 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.913546 -0.406736 0 outer loop - vertex 9.31758 4.93464 -4.5 - vertex 3.34565 3.71572 -4.5 - vertex 9.43168 5.47142 -4.5 + vertex 9.65489 5.97275 -4.5 + vertex 9.65489 5.97275 4.5 + vertex 9.43168 5.47142 4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.913546 -0.406736 0 outer loop vertex 9.43168 5.47142 -4.5 - vertex 3.34565 3.71572 -4.5 vertex 9.65489 5.97275 -4.5 + vertex 9.43168 5.47142 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809016 -0.587786 0 outer loop - vertex 2.5 4.33013 -4.5 - vertex 9.65489 5.97275 -4.5 - vertex 3.34565 3.71572 -4.5 + vertex 9.97745 6.41672 -4.5 + vertex 9.97745 6.41672 4.5 + vertex 9.65489 5.97275 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809016 -0.587786 0 outer loop - vertex 0.568321 11.8491 -4.5 vertex 9.65489 5.97275 -4.5 - vertex 2.5 4.33013 -4.5 + vertex 9.97745 6.41672 -4.5 + vertex 9.65489 5.97275 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669132 -0.743144 0 outer loop - vertex 0.568321 11.8491 -4.5 - vertex 9.97745 6.41672 -4.5 - vertex 9.65489 5.97275 -4.5 + vertex 10.3853 6.78392 -4.5 + vertex 10.3853 6.78392 4.5 + vertex 9.97745 6.41672 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669132 -0.743144 0 outer loop vertex 9.97745 6.41672 -4.5 - vertex 0.682417 12.3859 -4.5 vertex 10.3853 6.78392 -4.5 + vertex 9.97745 6.41672 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866026 0 outer loop - vertex 0.345113 11.3478 -4.5 - vertex 2.5 4.33013 -4.5 - vertex 1.54508 4.75528 -4.5 + vertex 10.8605 7.05831 -4.5 + vertex 10.8605 7.05831 4.5 + vertex 10.3853 6.78392 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 -0.866026 0 outer loop vertex 10.3853 6.78392 -4.5 - vertex 0.682417 12.3859 -4.5 vertex 10.8605 7.05831 -4.5 + vertex 10.3853 6.78392 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.309017 -0.951057 0 outer loop - vertex 0.682417 12.9346 -4.5 - vertex 10.8605 7.05831 -4.5 - vertex 0.682417 12.3859 -4.5 + vertex 11.3824 7.22789 -4.5 + vertex 11.3824 7.22789 4.5 + vertex 10.8605 7.05831 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.309017 -0.951057 0 outer loop vertex 10.8605 7.05831 -4.5 - vertex 0.682417 12.9346 -4.5 vertex 11.3824 7.22789 -4.5 + vertex 10.8605 7.05831 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.104529 -0.994522 0 outer loop - vertex 0.568321 13.4714 -4.5 - vertex 11.3824 7.22789 -4.5 - vertex 0.682417 12.9346 -4.5 + vertex 11.9282 7.28525 -4.5 + vertex 11.9282 7.28525 4.5 + vertex 11.3824 7.22789 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.104529 -0.994522 0 outer loop vertex 11.3824 7.22789 -4.5 - vertex 0.568321 13.4714 -4.5 vertex 11.9282 7.28525 -4.5 + vertex 11.3824 7.22789 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.104529 -0.994522 0 outer loop - vertex 0.345114 13.9728 -4.5 - vertex 11.9282 7.28525 -4.5 - vertex 0.568321 13.4714 -4.5 + vertex 12.474 7.22789 -4.5 + vertex 12.474 7.22789 4.5 + vertex 11.9282 7.28525 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.104529 -0.994522 0 outer loop vertex 11.9282 7.28525 -4.5 - vertex 0.345114 13.9728 -4.5 vertex 12.474 7.22789 -4.5 + vertex 11.9282 7.28525 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.309017 -0.951057 0 outer loop - vertex 0.0225522 14.4167 -4.5 - vertex 12.474 7.22789 -4.5 - vertex 0.345114 13.9728 -4.5 + vertex 12.9959 7.05831 -4.5 + vertex 12.9959 7.05831 4.5 + vertex 12.474 7.22789 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.309017 -0.951057 0 outer loop - vertex -0.385267 14.7839 -4.5 vertex 12.474 7.22789 -4.5 - vertex 0.0225522 14.4167 -4.5 + vertex 12.9959 7.05831 -4.5 + vertex 12.474 7.22789 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 -0.866025 0 + outer loop + vertex 13.4711 6.78392 -4.5 + vertex 13.4711 6.78392 4.5 + vertex 12.9959 7.05831 4.5 + endloop + endfacet + facet normal -0.5 -0.866025 0 outer loop vertex 12.9959 7.05831 -4.5 - vertex -0.385267 14.7839 -4.5 - vertex 18 5.7735 -4.5 + vertex 13.4711 6.78392 -4.5 + vertex 12.9959 7.05831 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.669131 -0.743145 0 outer loop - vertex -4 18.4752 -4.5 - vertex -0.385267 14.7839 -4.5 - vertex -0.860519 15.0583 -4.5 + vertex 13.879 6.41672 -4.5 + vertex 13.879 6.41672 4.5 + vertex 13.4711 6.78392 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.669131 -0.743145 0 outer loop - vertex -0.385267 14.7839 -4.5 - vertex -4 18.4752 -4.5 - vertex 18 5.7735 -4.5 + vertex 13.4711 6.78392 -4.5 + vertex 13.879 6.41672 -4.5 + vertex 13.4711 6.78392 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809017 -0.587786 0 outer loop - vertex -1.38243 15.2279 -4.5 - vertex -4 18.4752 -4.5 - vertex -0.860519 15.0583 -4.5 + vertex 14.2015 5.97275 4.5 + vertex 13.879 6.41672 4.5 + vertex 14.2015 5.97275 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809017 -0.587786 0 outer loop - vertex -1.9282 15.2853 -4.5 - vertex -4 18.4752 -4.5 - vertex -1.38243 15.2279 -4.5 + vertex 14.2015 5.97275 -4.5 + vertex 13.879 6.41672 4.5 + vertex 13.879 6.41672 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -2.47397 15.2279 -4.5 - vertex -4 18.4752 -4.5 - vertex -1.9282 15.2853 -4.5 + vertex 14.4247 5.47142 4.5 + vertex 14.2015 5.97275 4.5 + vertex 14.4247 5.47142 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 -0.406736 0 outer loop - vertex -2.99589 15.0583 -4.5 - vertex -4 18.4752 -4.5 - vertex -2.47397 15.2279 -4.5 + vertex 14.4247 5.47142 -4.5 + vertex 14.2015 5.97275 4.5 + vertex 14.2015 5.97275 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978148 -0.207912 0 outer loop - vertex -3.47114 14.7839 -4.5 - vertex -4 18.4752 -4.5 - vertex -2.99589 15.0583 -4.5 + vertex 14.5388 4.93464 4.5 + vertex 14.4247 5.47142 4.5 + vertex 14.5388 4.93464 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978148 -0.207912 0 outer loop - vertex -3.87896 14.4167 -4.5 - vertex -4 18.4752 -4.5 - vertex -3.47114 14.7839 -4.5 + vertex 14.5388 4.93464 -4.5 + vertex 14.4247 5.47142 4.5 + vertex 14.4247 5.47142 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -1 -2.04945e-07 0 outer loop - vertex -4.20152 13.9728 -4.5 - vertex -4 18.4752 -4.5 - vertex -3.87896 14.4167 -4.5 + vertex 14.5388 4.38587 4.5 + vertex 14.5388 4.93464 4.5 + vertex 14.5388 4.38587 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -1 -2.04945e-07 0 outer loop - vertex -10 10.625 -4.5 - vertex -4.20152 13.9728 -4.5 - vertex -4.42473 13.4714 -4.5 + vertex 14.5388 4.38587 -4.5 + vertex 14.5388 4.93464 4.5 + vertex 14.5388 4.93464 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978147 0.207913 0 outer loop - vertex -9.45423 10.5676 -4.5 - vertex -4.42473 13.4714 -4.5 - vertex -4.53882 12.9346 -4.5 + vertex 14.5388 4.38587 4.5 + vertex 14.5388 4.38587 -4.5 + vertex 14.4247 3.84908 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.978147 0.207913 0 outer loop - vertex -7.38938 7.72561 -4.5 - vertex -4.56773 2.03368 -4.5 - vertex -4.89074 1.03956 -4.5 + vertex 14.4247 3.84908 4.5 + vertex 14.5388 4.38587 -4.5 + vertex 14.4247 3.84908 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 0.406736 0 outer loop - vertex -7.38938 7.72561 -4.5 - vertex -4.89074 1.03956 -4.5 - vertex -5 0 -4.5 + vertex 14.4247 3.84908 4.5 + vertex 14.4247 3.84908 -4.5 + vertex 14.2015 3.34775 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.913546 0.406736 0 outer loop - vertex -8.04924 -6.24353 -4.5 - vertex -4.04508 -2.93893 -4.5 - vertex -7.72668 -6.6875 -4.5 + vertex 14.2015 3.34775 4.5 + vertex 14.4247 3.84908 -4.5 + vertex 14.2015 3.34775 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809016 0.587786 0 outer loop - vertex -8.45706 -5.87633 -4.5 - vertex -4.04508 -2.93893 -4.5 - vertex -8.04924 -6.24353 -4.5 + vertex 14.2015 3.34775 4.5 + vertex 14.2015 3.34775 -4.5 + vertex 13.879 2.90379 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.809016 0.587786 0 outer loop - vertex -7.72668 9.3125 -4.5 - vertex -4.20152 11.3478 -4.5 - vertex -7.50348 8.81117 -4.5 + vertex 13.879 2.90379 4.5 + vertex 14.2015 3.34775 -4.5 + vertex 13.879 2.90379 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.669132 0.743144 0 outer loop - vertex -4.20152 11.3478 -4.5 - vertex -7.72668 9.3125 -4.5 - vertex -4.42473 11.8491 -4.5 + vertex 13.879 2.90379 4.5 + vertex 13.879 2.90379 -4.5 + vertex 13.4711 2.53658 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.669132 0.743144 0 outer loop - vertex -8.04924 9.75647 -4.5 - vertex -4.42473 11.8491 -4.5 - vertex -7.72668 9.3125 -4.5 + vertex 13.4711 2.53658 4.5 + vertex 13.879 2.90379 -4.5 + vertex 13.4711 2.53658 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.5 0.866026 0 outer loop - vertex -4.42473 11.8491 -4.5 - vertex -8.04924 9.75647 -4.5 - vertex -4.53882 12.3859 -4.5 + vertex 13.4711 2.53658 4.5 + vertex 13.4711 2.53658 -4.5 + vertex 12.9959 2.2622 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.5 0.866026 0 outer loop - vertex -8.45706 10.1237 -4.5 - vertex -4.53882 12.3859 -4.5 - vertex -8.04924 9.75647 -4.5 + vertex 12.9959 2.2622 4.5 + vertex 13.4711 2.53658 -4.5 + vertex 12.9959 2.2622 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal -0.309017 0.951057 0 outer loop - vertex -4.53882 12.3859 -4.5 - vertex -8.45706 10.1237 -4.5 - vertex -4.53882 12.9346 -4.5 + vertex 12.9959 2.2622 4.5 + vertex 12.9959 2.2622 -4.5 + vertex 12.474 2.09262 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.309017 0.951057 0 outer loop - vertex -8.93232 10.3981 -4.5 - vertex -4.53882 12.9346 -4.5 - vertex -8.45706 10.1237 -4.5 + vertex 12.474 2.09262 4.5 + vertex 12.9959 2.2622 -4.5 + vertex 12.474 2.09262 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal -0.104529 0.994522 0 outer loop - vertex -9.45423 10.5676 -4.5 - vertex -4.53882 12.9346 -4.5 - vertex -8.93232 10.3981 -4.5 + vertex 12.474 2.09262 4.5 + vertex 12.474 2.09262 -4.5 + vertex 11.9282 2.03525 4.5 + endloop + endfacet + facet normal -0.104529 0.994522 0 + outer loop + vertex 11.9282 2.03525 4.5 + vertex 12.474 2.09262 -4.5 + vertex 11.9282 2.03525 -4.5 + endloop + endfacet + facet normal 0.104529 0.994522 0 + outer loop + vertex 11.9282 2.03525 4.5 + vertex 11.9282 2.03525 -4.5 + vertex 11.3824 2.09262 4.5 + endloop + endfacet + facet normal 0.104529 0.994522 0 + outer loop + vertex 11.3824 2.09262 4.5 + vertex 11.9282 2.03525 -4.5 + vertex 11.3824 2.09262 -4.5 + endloop + endfacet + facet normal 0.309017 0.951057 0 + outer loop + vertex 11.3824 2.09262 4.5 + vertex 11.3824 2.09262 -4.5 + vertex 10.8605 2.2622 4.5 + endloop + endfacet + facet normal 0.309017 0.951057 0 + outer loop + vertex 10.8605 2.2622 4.5 + vertex 11.3824 2.09262 -4.5 + vertex 10.8605 2.2622 -4.5 + endloop + endfacet + facet normal 0.5 0.866025 0 + outer loop + vertex 10.8605 2.2622 4.5 + vertex 10.8605 2.2622 -4.5 + vertex 10.3853 2.53658 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.5 0.866025 0 outer loop - vertex -10 10.625 -4.5 - vertex -4.42473 13.4714 -4.5 - vertex -9.45423 10.5676 -4.5 + vertex 10.3853 2.53658 4.5 + vertex 10.8605 2.2622 -4.5 + vertex 10.3853 2.53658 -4.5 endloop endfacet - facet normal -0 0 -1 + facet normal 0.669131 0.743145 0 outer loop - vertex -4.20152 13.9728 -4.5 - vertex -10 10.625 -4.5 - vertex -4 18.4752 -4.5 + vertex 10.3853 2.53658 4.5 + vertex 10.3853 2.53658 -4.5 + vertex 9.97745 2.90379 4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.669131 0.743145 0 outer loop - vertex -14 12.7017 -4.5 - vertex -10 10.625 -4.5 - vertex -10.5458 10.5676 -4.5 + vertex 9.97745 2.90379 4.5 + vertex 10.3853 2.53658 -4.5 + vertex 9.97745 2.90379 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809017 0.587786 0 outer loop - vertex -14 12.7017 -4.5 - vertex -10.5458 10.5676 -4.5 - vertex -11.0677 10.3981 -4.5 + vertex 9.65489 3.34775 4.5 + vertex 9.97745 2.90379 4.5 + vertex 9.97745 2.90379 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.809017 0.587786 0 outer loop - vertex -14 12.7017 -4.5 - vertex -11.0677 10.3981 -4.5 - vertex -11.5429 10.1237 -4.5 + vertex 9.65489 3.34775 -4.5 + vertex 9.65489 3.34775 4.5 + vertex 9.97745 2.90379 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.913546 0.406736 0 outer loop - vertex -14 12.7017 -4.5 - vertex -11.5429 10.1237 -4.5 - vertex -11.9508 9.75647 -4.5 + vertex 9.43168 3.84908 4.5 + vertex 9.65489 3.34775 4.5 + vertex 9.65489 3.34775 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.913546 0.406736 0 outer loop - vertex -10 10.625 -4.5 - vertex -14 12.7017 -4.5 - vertex -4 18.4752 -4.5 + vertex 9.43168 3.84908 -4.5 + vertex 9.43168 3.84908 4.5 + vertex 9.65489 3.34775 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.978148 0.207912 0 outer loop - vertex -12.2733 9.3125 -4.5 - vertex -14 12.7017 -4.5 - vertex -11.9508 9.75647 -4.5 + vertex 9.31758 4.38587 4.5 + vertex 9.43168 3.84908 4.5 + vertex 9.43168 3.84908 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0.978148 0.207912 0 outer loop - vertex -12.4965 8.81117 -4.5 - vertex -14 12.7017 -4.5 - vertex -12.2733 9.3125 -4.5 + vertex 9.31758 4.38587 -4.5 + vertex 9.31758 4.38587 4.5 + vertex 9.43168 3.84908 -4.5 endloop endfacet - facet normal 0 0 -1 + facet normal 0 0 1 outer loop - vertex -14 12.7017 -4.5 - vertex -12.4965 8.81117 -4.5 - vertex -12.6106 8.27439 -4.5 + vertex -11.0677 -10.3981 4.5 + vertex -14 -12.7017 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.994522 -0.104526 0 + facet normal 0 0 1 outer loop - vertex 5 0 -4.5 - vertex 4.89074 1.03956 4.5 - vertex 4.89074 1.03956 -4.5 + vertex -12.4965 7.18883 4.5 + vertex -12.6106 7.72561 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal -0.994522 -0.104526 0 + facet normal 0 0 1 outer loop - vertex 4.89074 1.03956 4.5 - vertex 5 0 -4.5 - vertex 5 0 4.5 + vertex -14 12.7017 4.5 + vertex -14 -12.7017 4.5 + vertex -12.6106 -8.27439 4.5 endloop endfacet - facet normal 0.994522 -0.104526 0 + facet normal 0 0 1 outer loop - vertex -5 0 4.5 - vertex -4.89074 1.03956 -4.5 - vertex -4.89074 1.03956 4.5 + vertex -10.5458 -10.5676 4.5 + vertex -11.0677 -10.3981 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.994522 -0.104526 0 + facet normal 0 0 1 outer loop - vertex -4.89074 1.03956 -4.5 - vertex -5 0 4.5 - vertex -5 0 -4.5 + vertex -14 12.7017 4.5 + vertex -12.6106 -8.27439 4.5 + vertex -12.6106 -7.72561 4.5 endloop endfacet - facet normal 0 -1 0 + facet normal 0 0 1 outer loop - vertex -0.522642 4.97261 -4.5 - vertex 0.522642 4.97261 4.5 - vertex -0.522642 4.97261 4.5 + vertex -10 -10.625 4.5 + vertex -10.5458 -10.5676 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0 -1 -0 + facet normal 0 0 1 outer loop - vertex 0.522642 4.97261 4.5 - vertex -0.522642 4.97261 -4.5 - vertex 0.522642 4.97261 -4.5 + vertex -14 12.7017 4.5 + vertex -12.6106 -7.72561 4.5 + vertex -12.4965 -7.18883 4.5 endloop endfacet - facet normal 0 1 -0 + facet normal 0 0 1 outer loop - vertex 0.522642 -4.97261 -4.5 - vertex -0.522642 -4.97261 4.5 - vertex 0.522642 -4.97261 4.5 + vertex -12.6106 7.72561 4.5 + vertex -12.6106 8.27439 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0 1 0 + facet normal 0 0 1 outer loop - vertex -0.522642 -4.97261 4.5 - vertex 0.522642 -4.97261 -4.5 - vertex -0.522642 -4.97261 -4.5 + vertex -14 12.7017 4.5 + vertex -12.4965 -7.18883 4.5 + vertex -12.2733 -6.6875 4.5 endloop endfacet - facet normal -0.587791 -0.809013 0 + facet normal 0 0 1 outer loop - vertex 2.5 4.33013 -4.5 - vertex 3.34565 3.71572 4.5 - vertex 2.5 4.33013 4.5 + vertex -14 12.7017 4.5 + vertex -12.2733 -6.6875 4.5 + vertex -11.9508 -6.24353 4.5 endloop endfacet - facet normal -0.587791 -0.809013 -0 + facet normal 0 0 1 outer loop - vertex 3.34565 3.71572 4.5 - vertex 2.5 4.33013 -4.5 - vertex 3.34565 3.71572 -4.5 + vertex -8.93232 -10.3981 4.5 + vertex -9.45423 -10.5676 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.40673 -0.913548 0 + facet normal 0 0 1 outer loop - vertex 1.54508 4.75528 -4.5 - vertex 2.5 4.33013 4.5 - vertex 1.54508 4.75528 4.5 + vertex -14 12.7017 4.5 + vertex -11.9508 -6.24353 4.5 + vertex -11.5429 -5.87633 4.5 endloop endfacet - facet normal -0.40673 -0.913548 -0 + facet normal 0 0 1 outer loop - vertex 2.5 4.33013 4.5 - vertex 1.54508 4.75528 -4.5 - vertex 2.5 4.33013 -4.5 + vertex -9.45423 -10.5676 4.5 + vertex -10 -10.625 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.587791 -0.809013 0 + facet normal 0 0 1 outer loop - vertex -3.34565 3.71572 -4.5 - vertex -2.5 4.33013 4.5 - vertex -3.34565 3.71572 4.5 + vertex -14 12.7017 4.5 + vertex -11.5429 -5.87633 4.5 + vertex -11.0677 -5.60194 4.5 endloop endfacet - facet normal 0.587791 -0.809013 0 + facet normal 0 0 1 outer loop - vertex -2.5 4.33013 4.5 - vertex -3.34565 3.71572 -4.5 - vertex -2.5 4.33013 -4.5 + vertex -14 12.7017 4.5 + vertex -11.0677 -5.60194 4.5 + vertex -10.5458 -5.43236 4.5 endloop endfacet - facet normal 0.207915 -0.978147 0 + facet normal 0 0 1 outer loop - vertex -1.54508 4.75528 -4.5 - vertex -0.522642 4.97261 4.5 - vertex -1.54508 4.75528 4.5 + vertex -8.04924 -9.75647 4.5 + vertex -8.45706 -10.1237 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.207915 -0.978147 0 + facet normal 0 0 1 outer loop - vertex -0.522642 4.97261 4.5 - vertex -1.54508 4.75528 -4.5 - vertex -0.522642 4.97261 -4.5 + vertex -14 12.7017 4.5 + vertex -10.5458 -5.43236 4.5 + vertex -10 -5.375 4.5 endloop endfacet - facet normal -0.866024 -0.500003 0 + facet normal 0 0 1 outer loop - vertex 4.56773 2.03368 -4.5 - vertex 4.04508 2.93893 4.5 - vertex 4.04508 2.93893 -4.5 + vertex -8.45706 -10.1237 4.5 + vertex -8.93232 -10.3981 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.866024 -0.500003 0 + facet normal 0 0 1 outer loop - vertex 4.04508 2.93893 4.5 - vertex 4.56773 2.03368 -4.5 - vertex 4.56773 2.03368 4.5 + vertex -14 12.7017 4.5 + vertex -10 -5.375 4.5 + vertex -9.45423 -5.43236 4.5 endloop endfacet - facet normal -0.951056 -0.309018 0 + facet normal 0 0 1 outer loop - vertex 4.89074 1.03956 -4.5 - vertex 4.56773 2.03368 4.5 - vertex 4.56773 2.03368 -4.5 + vertex -12.4965 7.18883 4.5 + vertex -9.45423 -5.43236 4.5 + vertex -8.93232 -5.60194 4.5 endloop endfacet - facet normal -0.951056 -0.309018 0 + facet normal 0 0 1 outer loop - vertex 4.56773 2.03368 4.5 - vertex 4.89074 1.03956 -4.5 - vertex 4.89074 1.03956 4.5 + vertex -7.50348 -8.81117 4.5 + vertex -7.72668 -9.3125 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.743142 -0.669133 0 + facet normal 0 0 1 outer loop - vertex 4.04508 2.93893 -4.5 - vertex 3.34565 3.71572 4.5 - vertex 3.34565 3.71572 -4.5 + vertex -7.38938 -7.72561 4.5 + vertex -7.38938 -8.27439 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.743142 -0.669133 0 + facet normal 0 0 1 outer loop - vertex 3.34565 3.71572 4.5 - vertex 4.04508 2.93893 -4.5 - vertex 4.04508 2.93893 4.5 + vertex -12.2733 6.6875 4.5 + vertex -8.93232 -5.60194 4.5 + vertex -8.45706 -5.87633 4.5 endloop endfacet - facet normal -0.207915 -0.978147 0 + facet normal 0 0 1 outer loop - vertex 0.522642 4.97261 -4.5 - vertex 1.54508 4.75528 4.5 - vertex 0.522642 4.97261 4.5 + vertex -7.72668 -9.3125 4.5 + vertex -8.04924 -9.75647 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.207915 -0.978147 -0 + facet normal 0 0 1 outer loop - vertex 1.54508 4.75528 4.5 - vertex 0.522642 4.97261 -4.5 - vertex 1.54508 4.75528 -4.5 + vertex -4.53882 -12.9346 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.866024 -0.500003 0 + facet normal 0 0 1 outer loop - vertex -4.56773 2.03368 4.5 - vertex -4.04508 2.93893 -4.5 - vertex -4.04508 2.93893 4.5 + vertex 13.4711 -6.78392 4.5 + vertex 12.9959 -7.05831 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal 0.866024 -0.500003 0 + facet normal 0 0 1 outer loop - vertex -4.04508 2.93893 -4.5 - vertex -4.56773 2.03368 4.5 - vertex -4.56773 2.03368 -4.5 + vertex -7.50348 -7.18883 4.5 + vertex -7.38938 -7.72561 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.743142 -0.669133 0 + facet normal 0 0 1 outer loop - vertex -4.04508 2.93893 4.5 - vertex -3.34565 3.71572 -4.5 - vertex -3.34565 3.71572 4.5 + vertex -11.5429 -10.1237 4.5 + vertex -14 -12.7017 4.5 + vertex -11.0677 -10.3981 4.5 endloop endfacet - facet normal 0.743142 -0.669133 0 + facet normal 0 0 1 outer loop - vertex -3.34565 3.71572 -4.5 - vertex -4.04508 2.93893 4.5 - vertex -4.04508 2.93893 -4.5 + vertex -11.9508 -9.75647 4.5 + vertex -14 -12.7017 4.5 + vertex -11.5429 -10.1237 4.5 endloop endfacet - facet normal 0.951056 -0.309018 0 + facet normal 0 0 1 outer loop - vertex -4.89074 1.03956 4.5 - vertex -4.56773 2.03368 -4.5 - vertex -4.56773 2.03368 4.5 + vertex -12.2733 -9.3125 4.5 + vertex -14 -12.7017 4.5 + vertex -11.9508 -9.75647 4.5 endloop endfacet - facet normal 0.951056 -0.309018 0 + facet normal 0 0 1 outer loop - vertex -4.56773 2.03368 -4.5 - vertex -4.89074 1.03956 4.5 - vertex -4.89074 1.03956 -4.5 + vertex -12.4965 -8.81117 4.5 + vertex -14 -12.7017 4.5 + vertex -12.2733 -9.3125 4.5 endloop endfacet - facet normal 0.40673 -0.913548 0 + facet normal 0 0 1 outer loop - vertex -2.5 4.33013 -4.5 - vertex -1.54508 4.75528 4.5 - vertex -2.5 4.33013 4.5 + vertex -12.6106 -8.27439 4.5 + vertex -14 -12.7017 4.5 + vertex -12.4965 -8.81117 4.5 endloop endfacet - facet normal 0.40673 -0.913548 0 + facet normal 0 0 1 outer loop - vertex -1.54508 4.75528 4.5 - vertex -2.5 4.33013 -4.5 - vertex -1.54508 4.75528 -4.5 + vertex 7.06458 -5.73622 4.5 + vertex 9.97745 -6.41672 4.5 + vertex 9.65489 -5.97275 4.5 endloop endfacet - facet normal -0.994522 0.104526 0 + facet normal 0 0 1 outer loop - vertex 4.89074 -1.03956 -4.5 - vertex 5 0 4.5 - vertex 5 0 -4.5 + vertex -11.9508 6.24353 4.5 + vertex -8.45706 -5.87633 4.5 + vertex -8.04924 -6.24353 4.5 endloop endfacet - facet normal -0.994522 0.104526 0 + facet normal 0 0 1 outer loop - vertex 5 0 4.5 - vertex 4.89074 -1.03956 -4.5 - vertex 4.89074 -1.03956 4.5 + vertex -12.2733 9.3125 4.5 + vertex -14 12.7017 4.5 + vertex -12.4965 8.81117 4.5 endloop endfacet - facet normal -0.207915 0.978147 0 + facet normal 0 0 1 outer loop - vertex 1.54508 -4.75528 1.07137 - vertex 0.522642 -4.97261 4.5 - vertex 1.54508 -4.75528 4.5 + vertex -11.9508 9.75647 4.5 + vertex -14 12.7017 4.5 + vertex -12.2733 9.3125 4.5 endloop endfacet - facet normal -0.207927 0.978144 -3.57273e-06 + facet normal 0 0 1 outer loop - vertex 1.46779 -4.77171 1.0037 - vertex 0.522642 -4.97261 4.5 - vertex 1.54508 -4.75528 1.07137 + vertex -11.5429 10.1237 4.5 + vertex -14 12.7017 4.5 + vertex -11.9508 9.75647 4.5 endloop endfacet - facet normal -0.207925 0.978145 -3.08026e-06 + facet normal 0 0 1 outer loop - vertex 1.27821 -4.81201 0.75 - vertex 0.522642 -4.97261 4.5 - vertex 1.46779 -4.77171 1.0037 + vertex -11.0677 10.3981 4.5 + vertex -14 12.7017 4.5 + vertex -11.5429 10.1237 4.5 endloop endfacet - facet normal -0.207896 0.978151 3.13748e-06 + facet normal 0 0 1 outer loop - vertex 1.14703 -4.83989 0.463525 - vertex 0.522642 -4.97261 4.5 - vertex 1.27821 -4.81201 0.75 + vertex -10.5458 10.5676 4.5 + vertex -14 12.7017 4.5 + vertex -11.0677 10.3981 4.5 endloop endfacet - facet normal -0.207897 0.978151 2.85086e-06 + facet normal 0 0 1 outer loop - vertex 1.07998 -4.85414 0.156793 - vertex 0.522642 -4.97261 4.5 - vertex 1.14703 -4.83989 0.463525 + vertex -8.45706 10.1237 4.5 + vertex -8.04924 9.75647 4.5 + vertex 2.15 3.72391 4.5 endloop endfacet - facet normal -0.207919 0.978146 0 + facet normal 0 0 1 outer loop - vertex 1.07998 -4.85414 -0.156793 - vertex 0.522642 -4.97261 4.5 - vertex 1.07998 -4.85414 0.156793 + vertex 8.56458 -8.33429 4.5 + vertex 2.93542 -11.5843 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.207915 0.978147 0 + facet normal 0 0 1 outer loop - vertex 0.522642 -4.97261 -4.5 - vertex 1.54508 -4.75528 -1.07137 - vertex 1.54508 -4.75528 -4.5 + vertex -9.45423 10.5676 4.5 + vertex -14 12.7017 4.5 + vertex -10 10.625 4.5 endloop endfacet - facet normal -0.207927 0.978144 3.57273e-06 + facet normal 0 0 1 outer loop - vertex 1.54508 -4.75528 -1.07137 - vertex 0.522642 -4.97261 -4.5 - vertex 1.46779 -4.77171 -1.0037 + vertex 13.4711 -2.53658 4.5 + vertex 13.879 -2.90379 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.2079 0.97815 -4.09255e-06 + facet normal 0 0 1 outer loop - vertex 1.46779 -4.77171 -1.0037 - vertex 0.522642 -4.97261 -4.5 - vertex 1.32391 -4.80229 -0.811152 + vertex -2.47397 10.0926 4.5 + vertex -14 12.7017 4.5 + vertex -9.45423 10.5676 4.5 endloop endfacet - facet normal -0.208011 0.978127 2.11331e-05 + facet normal 0 0 1 outer loop - vertex 1.32391 -4.80229 -0.811152 - vertex 0.522642 -4.97261 -4.5 - vertex 1.27821 -4.81201 -0.75 + vertex 14.2015 -3.34775 4.5 + vertex 14.4247 -3.84908 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.207766 0.978179 -3.04117e-05 + facet normal 0 0 1 outer loop - vertex 1.27821 -4.81201 -0.75 - vertex 0.522642 -4.97261 -4.5 - vertex 1.24675 -4.81869 -0.681296 + vertex -2.15 3.72391 4.5 + vertex -7.50348 7.18883 4.5 + vertex -7.72668 6.6875 4.5 endloop endfacet - facet normal -0.20794 0.978142 3.97294e-06 + facet normal 0 0 1 outer loop - vertex 1.24675 -4.81869 -0.681296 - vertex 0.522642 -4.97261 -4.5 - vertex 1.14703 -4.83989 -0.463525 + vertex -1.32877 4.08954 4.5 + vertex -7.38938 8.27439 4.5 + vertex -7.38938 7.72561 4.5 endloop endfacet - facet normal -0.207897 0.978151 -2.85086e-06 + facet normal 0 0 1 outer loop - vertex 1.14703 -4.83989 -0.463525 - vertex 0.522642 -4.97261 -4.5 - vertex 1.07998 -4.85414 -0.156793 + vertex -0.449472 4.27644 4.5 + vertex 0.449472 4.27644 4.5 + vertex -7.50348 8.81117 4.5 endloop endfacet - facet normal -0.207919 0.978146 0 + facet normal 0 0 1 outer loop - vertex 1.07998 -4.85414 -0.156793 - vertex 0.522642 -4.97261 -4.5 - vertex 0.522642 -4.97261 4.5 + vertex -4.20603 -0.89402 4.5 + vertex -8.04924 6.24353 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743143 0.669132 0 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.66382 -3.36236 -0.156793 - vertex 4.04508 -2.93893 4.5 + vertex -8.04924 6.24353 4.5 + vertex -8.45706 5.87633 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.74317 0.669103 -5.21222e-06 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.61795 -3.41331 -0.463525 - vertex 3.66382 -3.36236 -0.156793 + vertex -8.45706 5.87633 4.5 + vertex -8.93232 5.60194 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743162 0.669111 -3.46777e-06 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.54974 -3.48907 -0.681296 - vertex 3.61795 -3.41331 -0.463525 + vertex -8.93232 5.60194 4.5 + vertex -9.45423 5.43236 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743033 0.669254 3.3899e-05 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.52821 -3.51297 -0.75 - vertex 3.54974 -3.48907 -0.681296 + vertex -9.45423 5.43236 4.5 + vertex -10 5.375 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743162 0.669112 -5.55673e-06 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.49695 -3.54769 -0.811152 - vertex 3.52821 -3.51297 -0.75 + vertex -10 5.375 4.5 + vertex -10.5458 5.43236 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743153 0.669121 -2.75746e-06 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.39853 -3.657 -1.0037 - vertex 3.49695 -3.54769 -0.811152 + vertex -10.5458 5.43236 4.5 + vertex -11.0677 5.60194 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743142 0.669133 0 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 -1.07137 - vertex 4.04508 -2.93893 -4.5 - vertex 3.34565 -3.71572 -4.5 + vertex -11.0677 5.60194 4.5 + vertex -11.5429 5.87633 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.743103 0.669177 1.79285e-05 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 3.34565 -3.71572 -1.07137 - vertex 3.39853 -3.657 -1.0037 + vertex -10.5458 10.5676 4.5 + vertex -10 10.625 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal -0.743143 0.669132 0 + facet normal 0 0 1 outer loop - vertex 3.66382 -3.36236 0.156793 - vertex 4.04508 -2.93893 4.5 - vertex 3.66382 -3.36236 -0.156793 + vertex -12.2733 6.6875 4.5 + vertex -12.4965 7.18883 4.5 + vertex -8.93232 -5.60194 4.5 endloop endfacet - facet normal -0.74317 0.669103 5.21222e-06 + facet normal 0 0 1 outer loop - vertex 3.61795 -3.41331 0.463525 - vertex 4.04508 -2.93893 4.5 - vertex 3.66382 -3.36236 0.156793 + vertex -14 12.7017 4.5 + vertex -9.45423 -5.43236 4.5 + vertex -12.4965 7.18883 4.5 endloop endfacet - facet normal -0.743153 0.669122 1.17484e-06 + facet normal 0 0 1 outer loop - vertex 3.59653 -3.4371 0.531919 - vertex 4.04508 -2.93893 4.5 - vertex 3.61795 -3.41331 0.463525 + vertex -4.42473 -13.4714 4.5 + vertex -4.53882 -12.9346 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.743123 0.669155 -6.32281e-06 + facet normal 0 0 1 outer loop - vertex 3.52821 -3.51297 0.749999 - vertex 4.04508 -2.93893 4.5 - vertex 3.59653 -3.4371 0.531919 + vertex -4.53882 -12.3859 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -4.53882 -12.9346 4.5 endloop endfacet - facet normal -0.743158 0.669116 4.49208e-06 + facet normal 0 0 1 outer loop - vertex 3.42999 -3.62206 0.942152 - vertex 4.04508 -2.93893 4.5 - vertex 3.52821 -3.51297 0.749999 + vertex -4.42473 -11.8491 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -4.53882 -12.3859 4.5 endloop endfacet - facet normal -0.743146 0.669129 -1.12573e-07 + facet normal 0 0 1 outer loop - vertex 3.39853 -3.657 1.0037 - vertex 4.04508 -2.93893 4.5 - vertex 3.42999 -3.62206 0.942152 + vertex -4.20152 -11.3478 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -4.42473 -11.8491 4.5 endloop endfacet - facet normal -0.743103 0.669177 -1.79285e-05 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 1.07137 - vertex 4.04508 -2.93893 4.5 - vertex 3.39853 -3.657 1.0037 + vertex -3.87896 -10.9038 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -4.20152 -11.3478 4.5 endloop endfacet - facet normal -0.743142 0.669133 0 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 4.5 - vertex 3.34565 -3.71572 1.07137 - vertex 3.34565 -3.71572 4.5 + vertex -3.47114 -10.5366 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -3.87896 -10.9038 4.5 endloop endfacet - facet normal -0.951056 0.309018 0 + facet normal 0 0 1 outer loop - vertex 4.56773 -2.03368 -4.5 - vertex 4.89074 -1.03956 4.5 - vertex 4.89074 -1.03956 -4.5 + vertex -2.99589 -10.2622 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -3.47114 -10.5366 4.5 endloop endfacet - facet normal -0.951056 0.309018 0 + facet normal 0 0 1 outer loop - vertex 4.89074 -1.03956 4.5 - vertex 4.56773 -2.03368 -4.5 - vertex 4.56773 -2.03368 4.5 + vertex -2.47397 -10.0926 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -2.99589 -10.2622 4.5 endloop endfacet - facet normal -0.866024 0.500003 0 + facet normal 0 0 1 outer loop - vertex 4.04508 -2.93893 -4.5 - vertex 4.56773 -2.03368 4.5 - vertex 4.56773 -2.03368 -4.5 + vertex 1.43542 -8.98622 4.5 + vertex -7.50348 -7.18883 4.5 + vertex -2.47397 -10.0926 4.5 endloop endfacet - facet normal -0.866024 0.500003 0 + facet normal 0 0 1 outer loop - vertex 4.56773 -2.03368 4.5 - vertex 4.04508 -2.93893 -4.5 - vertex 4.04508 -2.93893 4.5 + vertex -0.385267 -14.7839 4.5 + vertex -0.860519 -15.0583 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.866024 0.500003 0 + facet normal 0 0 1 outer loop - vertex -4.04508 -2.93893 4.5 - vertex -4.56773 -2.03368 -4.5 - vertex -4.56773 -2.03368 4.5 + vertex -4.53882 12.9346 4.5 + vertex -4.42473 13.4714 4.5 + vertex -4 18.4752 4.5 endloop endfacet - facet normal 0.866024 0.500003 0 + facet normal 0 0 1 outer loop - vertex -4.56773 -2.03368 -4.5 - vertex -4.04508 -2.93893 4.5 - vertex -4.04508 -2.93893 -4.5 + vertex 0.345114 13.9728 4.5 + vertex 0.56832 13.4714 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal 0.994522 0.104526 0 + facet normal 0 0 1 outer loop - vertex -4.89074 -1.03956 4.5 - vertex -5 0 -4.5 - vertex -5 0 4.5 + vertex 2.93542 -11.5843 4.5 + vertex 0.682417 -12.3859 4.5 + vertex 0.682417 -12.9346 4.5 endloop endfacet - facet normal 0.994522 0.104526 0 + facet normal 0 0 1 outer loop - vertex -5 0 -4.5 - vertex -4.89074 -1.03956 4.5 - vertex -4.89074 -1.03956 -4.5 + vertex -1.38244 -15.2279 4.5 + vertex -1.9282 -15.2853 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587791 0.809013 9.16531e-07 + facet normal 0 0 1 outer loop - vertex 2.69058 -4.19166 1.47538 - vertex 2.5 -4.33013 4.5 - vertex 3.34565 -3.71572 4.5 + vertex 18 -5.7735 4.5 + vertex 0.682417 -12.9346 4.5 + vertex 0.56832 -13.4714 4.5 endloop endfacet - facet normal -0.587801 0.809006 0 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 4.5 - vertex 2.69058 -4.19166 1.47538 - vertex 2.5 -4.33013 1.5 + vertex 18 -5.7735 4.5 + vertex 0.56832 -13.4714 4.5 + vertex 0.345114 -13.9728 4.5 endloop endfacet - facet normal -0.587709 0.809072 -2.62737e-05 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 4.5 - vertex 2.7537 -4.14581 1.46722 - vertex 2.69058 -4.19166 1.47538 + vertex 18 -5.7735 4.5 + vertex 0.0225521 -14.4167 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587808 0.809001 3.25645e-06 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 4.5 - vertex 2.9963 -3.96954 1.37032 - vertex 2.7537 -4.14581 1.46722 + vertex 18 -5.7735 4.5 + vertex 0.345114 -13.9728 4.5 + vertex 0.0225521 -14.4167 4.5 endloop endfacet - facet normal -0.587768 0.809029 -3.51222e-06 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 4.5 - vertex 3.21722 -3.80904 1.21352 - vertex 2.9963 -3.96954 1.37032 + vertex 0.0225521 -14.4167 4.5 + vertex -0.385267 -14.7839 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587827 0.808987 0 + facet normal 0 0 1 outer loop - vertex 3.21722 -3.80904 1.21352 - vertex 3.34565 -3.71572 4.5 - vertex 3.34565 -3.71572 1.07137 + vertex -1.9282 -15.2853 4.5 + vertex -2.47397 -15.2279 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.58776 0.809036 -2.2588e-06 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 -4.5 - vertex 2.56332 -4.28412 -1.49182 - vertex 2.7537 -4.14581 -1.46722 + vertex -2.47397 -15.2279 4.5 + vertex -2.99589 -15.0583 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587827 0.808987 0 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 -4.5 - vertex 3.21722 -3.80904 -1.21352 - vertex 3.34565 -3.71572 -1.07137 + vertex -2.99589 -15.0583 4.5 + vertex -3.47114 -14.7839 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587768 0.809029 3.51222e-06 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 -4.5 - vertex 2.9963 -3.96954 -1.37032 - vertex 3.21722 -3.80904 -1.21352 + vertex -3.47114 -14.7839 4.5 + vertex -3.87896 -14.4167 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587808 0.809001 -3.25645e-06 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 -4.5 - vertex 2.7537 -4.14581 -1.46722 - vertex 2.9963 -3.96954 -1.37032 + vertex -3.87896 -14.4167 4.5 + vertex -4.20152 -13.9728 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.587791 0.809013 1.76933e-06 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 -4.5 - vertex 2.7537 -4.14581 -1.46722 - vertex 3.34565 -3.71572 -4.5 + vertex -4.20152 -13.9728 4.5 + vertex -4.42473 -13.4714 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal -0.58783 0.808985 0 + facet normal 0 0 1 outer loop - vertex 2.56332 -4.28412 -1.49182 - vertex 2.5 -4.33013 -4.5 - vertex 2.5 -4.33013 -1.5 + vertex -4.53882 12.9346 4.5 + vertex -14 12.7017 4.5 + vertex -4.53882 12.3859 4.5 endloop endfacet - facet normal -0.406709 0.913558 0 + facet normal 0 0 1 outer loop - vertex 2.28479 -4.42594 1.47538 - vertex 2.5 -4.33013 4.5 - vertex 2.5 -4.33013 1.5 + vertex -0.385267 14.7839 4.5 + vertex 0.0225521 14.4167 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.406769 0.913531 5.09672e-06 + facet normal 0 0 1 outer loop - vertex 2.21353 -4.45767 1.46722 - vertex 2.5 -4.33013 4.5 - vertex 2.28479 -4.42594 1.47538 + vertex -4 18.4752 4.5 + vertex -14 12.7017 4.5 + vertex -4.53882 12.9346 4.5 endloop endfacet - facet normal -0.40673 0.913548 7.01455e-07 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 4.5 - vertex 2.21353 -4.45767 1.46722 - vertex 1.54508 -4.75528 4.5 + vertex 0.345113 11.3478 4.5 + vertex 0.0225516 10.9038 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.40675 0.91354 -4.38128e-06 + facet normal 0 0 1 outer loop - vertex 1.93957 -4.57965 1.37032 - vertex 1.54508 -4.75528 4.5 - vertex 2.21353 -4.45767 1.46722 + vertex 0.56832 11.8491 4.5 + vertex 0.345113 11.3478 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.406716 0.913554 6.5097e-07 + facet normal 0 0 1 outer loop - vertex 1.69011 -4.69071 1.21352 - vertex 1.54508 -4.75528 4.5 - vertex 1.93957 -4.57965 1.37032 + vertex -4 18.4752 4.5 + vertex -4.42473 13.4714 4.5 + vertex -4.20152 13.9728 4.5 endloop endfacet - facet normal -0.406729 0.913549 0 + facet normal 0 0 1 outer loop - vertex 1.54508 -4.75528 4.5 - vertex 1.69011 -4.69071 1.21352 - vertex 1.54508 -4.75528 1.07137 + vertex 0.682417 12.3859 4.5 + vertex 0.56832 11.8491 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.406696 0.913564 0 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 -4.5 - vertex 2.4285 -4.36196 -1.49182 - vertex 2.5 -4.33013 -1.5 + vertex -4 18.4752 4.5 + vertex -4.20152 13.9728 4.5 + vertex -3.87896 14.4167 4.5 endloop endfacet - facet normal -0.406734 0.913547 -1.0906e-06 + facet normal 0 0 1 outer loop - vertex 2.4285 -4.36196 -1.49182 - vertex 2.5 -4.33013 -4.5 - vertex 2.21353 -4.45767 -1.46722 + vertex 0.682417 12.9346 4.5 + vertex 0.682417 12.3859 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.40673 0.913548 -7.01455e-07 + facet normal 0 0 1 outer loop - vertex 1.54508 -4.75528 -4.5 - vertex 2.21353 -4.45767 -1.46722 - vertex 2.5 -4.33013 -4.5 + vertex -4 18.4752 4.5 + vertex -3.87896 14.4167 4.5 + vertex -3.47114 14.7839 4.5 endloop endfacet - facet normal -0.40675 0.91354 4.38128e-06 + facet normal 0 0 1 outer loop - vertex 2.21353 -4.45767 -1.46722 - vertex 1.54508 -4.75528 -4.5 - vertex 1.93957 -4.57965 -1.37032 + vertex 0.56832 13.4714 4.5 + vertex 0.682417 12.9346 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.406716 0.913554 -6.5097e-07 + facet normal 0 0 1 outer loop - vertex 1.93957 -4.57965 -1.37032 - vertex 1.54508 -4.75528 -4.5 - vertex 1.69011 -4.69071 -1.21352 + vertex -4 18.4752 4.5 + vertex -3.47114 14.7839 4.5 + vertex -2.99589 15.0583 4.5 endloop endfacet - facet normal -0.406729 0.913549 0 + facet normal 0 0 1 outer loop - vertex 1.69011 -4.69071 -1.21352 - vertex 1.54508 -4.75528 -4.5 - vertex 1.54508 -4.75528 -1.07137 + vertex -1.38243 10.0926 4.5 + vertex -1.9282 10.0353 4.5 + vertex 11.3824 7.22789 4.5 endloop endfacet - facet normal 0.207915 0.978147 -0 + facet normal 0 0 1 outer loop - vertex -0.522642 -4.97261 -4.5 - vertex -1.54508 -4.75528 4.5 - vertex -0.522642 -4.97261 4.5 + vertex -4 18.4752 4.5 + vertex -2.99589 15.0583 4.5 + vertex -2.47397 15.2279 4.5 endloop endfacet - facet normal 0.207915 0.978147 0 + facet normal 0 0 1 outer loop - vertex -1.54508 -4.75528 4.5 - vertex -0.522642 -4.97261 -4.5 - vertex -1.54508 -4.75528 -4.5 + vertex -4 18.4752 4.5 + vertex -2.47397 15.2279 4.5 + vertex -1.9282 15.2853 4.5 endloop endfacet - facet normal 0.587791 0.809013 -0 + facet normal 0 0 1 outer loop - vertex -2.5 -4.33013 -4.5 - vertex -3.34565 -3.71572 4.5 - vertex -2.5 -4.33013 4.5 + vertex 0.0225521 14.4167 4.5 + vertex 0.345114 13.9728 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal 0.587791 0.809013 0 + facet normal 0 0 1 outer loop - vertex -3.34565 -3.71572 4.5 - vertex -2.5 -4.33013 -4.5 - vertex -3.34565 -3.71572 -4.5 + vertex -4 18.4752 4.5 + vertex -1.9282 15.2853 4.5 + vertex -1.38244 15.2279 4.5 endloop endfacet - facet normal 0.743142 0.669133 0 + facet normal 0 0 1 outer loop - vertex -3.34565 -3.71572 4.5 - vertex -4.04508 -2.93893 -4.5 - vertex -4.04508 -2.93893 4.5 + vertex -4 18.4752 4.5 + vertex -0.860519 15.0583 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal 0.743142 0.669133 0 + facet normal 0 0 1 outer loop - vertex -4.04508 -2.93893 -4.5 - vertex -3.34565 -3.71572 4.5 - vertex -3.34565 -3.71572 -4.5 + vertex -4 18.4752 4.5 + vertex -1.38244 15.2279 4.5 + vertex -0.860519 15.0583 4.5 endloop endfacet - facet normal 0.951056 0.309018 0 + facet normal 0 0 1 outer loop - vertex -4.56773 -2.03368 4.5 - vertex -4.89074 -1.03956 -4.5 - vertex -4.89074 -1.03956 4.5 + vertex -0.860519 15.0583 4.5 + vertex -0.385267 14.7839 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal 0.951056 0.309018 0 + facet normal 0 0 1 outer loop - vertex -4.89074 -1.03956 -4.5 - vertex -4.56773 -2.03368 4.5 - vertex -4.56773 -2.03368 -4.5 + vertex -3.47114 10.5366 4.5 + vertex -3.87896 10.9038 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0.40673 0.913548 -0 + facet normal 0 0 1 outer loop - vertex -1.54508 -4.75528 -4.5 - vertex -2.5 -4.33013 4.5 - vertex -1.54508 -4.75528 4.5 + vertex 10.8605 -2.2622 4.5 + vertex 11.3824 -2.09262 4.5 + vertex 3.92824 1.74897 4.5 endloop endfacet - facet normal 0.40673 0.913548 0 + facet normal 0 0 1 outer loop - vertex -2.5 -4.33013 4.5 - vertex -1.54508 -4.75528 -4.5 - vertex -2.5 -4.33013 -4.5 + vertex 12.474 7.22789 4.5 + vertex 12.9959 7.05831 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.0904866 -0.052243 0.994526 + facet normal 0 0 1 outer loop - vertex 6.02008 -9.80336 -1.46722 - vertex 7.18906 -12.0152 -1.47705 - vertex 7.27008 -11.9684 -1.46722 + vertex 10.8605 7.05831 4.5 + vertex -1.9282 10.0353 4.5 + vertex -9.45423 10.5676 4.5 endloop endfacet - facet normal -0.0905233 -0.0522624 0.994522 + facet normal 0 0 1 outer loop - vertex 7.18906 -12.0152 -1.47705 - vertex 6.02008 -9.80336 -1.46722 - vertex 5.9053 -9.86963 -1.48115 + vertex -1.9282 10.0353 4.5 + vertex -2.47397 10.0926 4.5 + vertex -9.45423 10.5676 4.5 endloop endfacet - facet normal -0.0905337 -0.0522695 0.994521 + facet normal 0 0 1 outer loop - vertex 2.56332 -4.28412 -1.49182 - vertex 4.52008 -7.20528 -1.46722 - vertex 2.7537 -4.14581 -1.46722 + vertex -2.99589 10.2622 4.5 + vertex -14 12.7017 4.5 + vertex -2.47397 10.0926 4.5 endloop endfacet - facet normal -0.0905395 -0.0522733 0.99452 + facet normal 0 0 1 outer loop - vertex 4.52008 -7.20528 -1.46722 - vertex 2.56332 -4.28412 -1.49182 - vertex 4.36479 -7.29494 -1.48607 + vertex -3.87896 10.9038 4.5 + vertex -4.20152 11.3478 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0.791135 0.456754 0.406794 + facet normal 0 0 1 outer loop - vertex 4.56149 -10.6455 -0.585277 - vertex 5.875 -12.7739 -0.749999 - vertex 4.625 -10.6088 -0.749999 + vertex -4.20152 11.3478 4.5 + vertex -4.42473 11.8491 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0.791183 0.456795 0.406655 + facet normal 0 0 1 outer loop - vertex 5.875 -12.7739 -0.749999 - vertex 4.56149 -10.6455 -0.585277 - vertex 5.79768 -12.8185 -0.549467 + vertex -2.87726 3.19552 4.5 + vertex -2.15 3.72391 4.5 + vertex -8.04924 6.24353 4.5 endloop endfacet - facet normal 0.791169 0.456784 0.406694 + facet normal 0 0 1 outer loop - vertex 1.24675 -4.81869 -0.681296 - vertex 3.125 -8.01073 -0.75 - vertex 1.27821 -4.81201 -0.75 + vertex -4.53882 12.3859 4.5 + vertex -14 12.7017 4.5 + vertex -4.42473 11.8491 4.5 endloop endfacet - facet normal 0.791156 0.456775 0.406729 + facet normal 0 0 1 outer loop - vertex 3.125 -8.01073 -0.75 - vertex 1.24675 -4.81869 -0.681296 - vertex 3.07806 -8.03784 -0.628248 + vertex -3.92824 -1.74897 4.5 + vertex -4.20603 -0.89402 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.0905081 -0.0522546 0.994524 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 -1.5 - vertex 4.36479 -7.29494 -1.48607 - vertex 2.56332 -4.28412 -1.49182 + vertex -4.3 0 4.5 + vertex -8.04924 6.24353 4.5 + vertex -4.20603 -0.89402 4.5 endloop endfacet - facet normal -0.0905135 -0.052258 0.994523 + facet normal 0 0 1 outer loop - vertex 4.36479 -7.29494 -1.48607 - vertex 2.5 -4.33013 -1.5 - vertex 4.25 -7.36122 -1.5 + vertex -4.20603 0.89402 4.5 + vertex -8.04924 6.24353 4.5 + vertex -4.3 0 4.5 endloop endfacet - facet normal -0.0905345 -0.0522691 0.994521 + facet normal 0 0 1 outer loop - vertex 5.9053 -9.86963 -1.48115 - vertex 7 -12.1244 -1.5 - vertex 7.18906 -12.0152 -1.47705 + vertex -3.92824 1.74897 4.5 + vertex -8.04924 6.24353 4.5 + vertex -4.20603 0.89402 4.5 endloop endfacet - facet normal -0.0905358 -0.0522697 0.994521 + facet normal 0 0 1 outer loop - vertex 7 -12.1244 -1.5 - vertex 5.9053 -9.86963 -1.48115 - vertex 5.75 -9.95929 -1.5 + vertex 9.97745 -2.90379 4.5 + vertex 10.3853 -2.53658 4.5 + vertex 4.3 0 4.5 endloop endfacet - facet normal -0.700628 -0.404514 -0.587783 + facet normal 0 0 1 outer loop - vertex 8.125 -11.4748 0.75 - vertex 6.80716 -9.34894 0.857821 - vertex 6.875 -9.30977 0.75 + vertex -3.47877 2.52748 4.5 + vertex -8.04924 6.24353 4.5 + vertex -3.92824 1.74897 4.5 endloop endfacet - facet normal -0.700512 -0.404433 -0.587977 + facet normal 0 0 1 outer loop - vertex 6.80716 -9.34894 0.857821 - vertex 8.125 -11.4748 0.75 - vertex 8.07711 -11.5025 0.826109 + vertex -2.87726 3.19552 4.5 + vertex -8.04924 6.24353 4.5 + vertex -3.47877 2.52748 4.5 endloop endfacet - facet normal -0.700631 -0.40451 -0.587782 + facet normal 0 0 1 outer loop - vertex 5.375 -6.7117 0.749999 - vertex 3.42999 -3.62206 0.942152 - vertex 3.52821 -3.51297 0.749999 + vertex 14.5388 -4.38587 4.5 + vertex 14.5388 -4.93464 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.700624 -0.404505 -0.587794 + facet normal 0 0 1 outer loop - vertex 3.42999 -3.62206 0.942152 - vertex 5.375 -6.7117 0.749999 - vertex 5.28321 -6.76469 0.895875 + vertex -11.5429 5.87633 4.5 + vertex -11.9508 6.24353 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal -0.866029 -0.499994 0 + facet normal 0 0 1 outer loop - vertex 8.29192 -11.3785 -0.156793 - vertex 7.04192 -9.2134 0.156793 - vertex 7.04192 -9.2134 -0.156793 + vertex -7.72668 6.6875 4.5 + vertex -8.04924 6.24353 4.5 + vertex -2.15 3.72391 4.5 endloop endfacet - facet normal -0.866029 -0.499994 0 + facet normal 0 0 1 outer loop - vertex 7.04192 -9.2134 0.156793 - vertex 8.29192 -11.3785 -0.156793 - vertex 8.29192 -11.3785 0.156793 + vertex 12.9959 -7.05831 4.5 + vertex 12.474 -7.22789 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.866025 -0.500001 0 + facet normal 0 0 1 outer loop - vertex 5.54192 -6.61532 -0.156793 - vertex 3.66382 -3.36236 0.156793 - vertex 3.66382 -3.36236 -0.156793 + vertex 10.3853 6.78392 4.5 + vertex 10.8605 7.05831 4.5 + vertex -9.45423 10.5676 4.5 endloop endfacet - facet normal -0.866025 -0.500001 0 + facet normal 0 0 1 outer loop - vertex 3.66382 -3.36236 0.156793 - vertex 5.54192 -6.61532 -0.156793 - vertex 5.54192 -6.61532 0.156793 + vertex 10.8605 7.05831 4.5 + vertex 11.3824 7.22789 4.5 + vertex -1.9282 10.0353 4.5 endloop endfacet - facet normal -0.433017 -0.250006 0.866021 + facet normal 0 0 1 outer loop - vertex 6.51355 -9.51845 -1.21352 - vertex 7.52837 -11.8193 -1.37032 - vertex 7.76356 -11.6835 -1.21352 + vertex -8.04924 9.75647 4.5 + vertex -7.72668 9.3125 4.5 + vertex 1.32877 4.08954 4.5 endloop endfacet - facet normal -0.433035 -0.250013 0.86601 + facet normal 0 0 1 outer loop - vertex 7.52837 -11.8193 -1.37032 - vertex 6.51355 -9.51845 -1.21352 - vertex 6.27837 -9.65424 -1.37032 + vertex 14.5388 -4.93464 4.5 + vertex 14.4247 -5.47142 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.433029 -0.250009 0.866015 + facet normal 0 0 1 outer loop - vertex 2.9963 -3.96954 -1.37032 - vertex 5.01355 -6.92038 -1.21352 - vertex 3.21722 -3.80904 -1.21352 + vertex 0.449472 4.27644 4.5 + vertex 1.32877 4.08954 4.5 + vertex -7.72668 9.3125 4.5 endloop endfacet - facet normal -0.433041 -0.250017 0.866006 + facet normal 0 0 1 outer loop - vertex 5.01355 -6.92038 -1.21352 - vertex 2.9963 -3.96954 -1.37032 - vertex 4.77837 -7.05616 -1.37032 + vertex 3.92824 1.74897 4.5 + vertex 4.20603 0.89402 4.5 + vertex 10.8605 -2.2622 4.5 endloop endfacet - facet normal 0.0905373 0.0522725 -0.99452 + facet normal 0 0 1 outer loop - vertex 6.72992 -12.2803 1.46722 - vertex 5.63521 -10.0256 1.48607 - vertex 6.91897 -12.1711 1.49017 + vertex 4.20603 0.89402 4.5 + vertex 4.3 0 4.5 + vertex 10.3853 -2.53658 4.5 endloop endfacet - facet normal 0.0905505 0.0522789 -0.994519 + facet normal 0 0 1 outer loop - vertex 5.63521 -10.0256 1.48607 - vertex 6.72992 -12.2803 1.46722 - vertex 5.47991 -10.1152 1.46722 + vertex -11.9508 6.24353 4.5 + vertex -12.2733 6.6875 4.5 + vertex -8.45706 -5.87633 4.5 endloop endfacet - facet normal 0.0905219 0.0522649 -0.994522 + facet normal 0 0 1 outer loop - vertex 3.97992 -7.51715 1.46722 - vertex 2.28479 -4.42594 1.47538 - vertex 4.0947 -7.45088 1.48115 + vertex -0.449472 4.27644 4.5 + vertex -7.50348 8.81117 4.5 + vertex -7.38938 8.27439 4.5 endloop endfacet - facet normal 0.0905927 0.0523037 -0.994514 + facet normal 0 0 1 outer loop - vertex 2.28479 -4.42594 1.47538 - vertex 3.97992 -7.51715 1.46722 - vertex 2.21353 -4.45767 1.46722 + vertex 4.20603 -0.89402 4.5 + vertex 3.92824 -1.74897 4.5 + vertex 9.65489 -3.34775 4.5 endloop endfacet - facet normal -0.26761 -0.154505 0.951059 + facet normal 0 0 1 outer loop - vertex 6.27837 -9.65424 -1.37032 - vertex 7.27008 -11.9684 -1.46722 - vertex 7.52837 -11.8193 -1.37032 + vertex 3.92824 -1.74897 4.5 + vertex 3.47877 -2.52748 4.5 + vertex 9.43168 -3.84908 4.5 endloop endfacet - facet normal -0.267601 -0.154501 0.951062 + facet normal 0 0 1 outer loop - vertex 7.27008 -11.9684 -1.46722 - vertex 6.27837 -9.65424 -1.37032 - vertex 6.02008 -9.80336 -1.46722 + vertex 2.93542 -11.5843 4.5 + vertex 0.345113 -11.3478 4.5 + vertex 0.56832 -11.8491 4.5 endloop endfacet - facet normal -0.267612 -0.154507 0.951058 + facet normal 0 0 1 outer loop - vertex 2.7537 -4.14581 -1.46722 - vertex 4.77837 -7.05616 -1.37032 - vertex 2.9963 -3.96954 -1.37032 + vertex 2.93542 -11.5843 4.5 + vertex 0.0225516 -10.9038 4.5 + vertex 0.345113 -11.3478 4.5 endloop endfacet - facet normal -0.267602 -0.1545 0.951062 + facet normal 0 0 1 outer loop - vertex 4.77837 -7.05616 -1.37032 - vertex 2.7537 -4.14581 -1.46722 - vertex 4.52008 -7.20528 -1.46722 + vertex 9.31758 -4.38587 4.5 + vertex 2.87726 -3.19552 4.5 + vertex 2.15 -3.72391 4.5 endloop endfacet - facet normal 0.847096 0.489085 -0.207905 + facet normal 0 0 1 outer loop - vertex 5.76454 -12.8376 0.463525 - vertex 4.45808 -10.7052 0.156793 - vertex 4.51454 -10.6726 0.463525 + vertex 7.06458 -5.73622 4.5 + vertex 1.32877 -4.08954 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.847096 0.489085 -0.207905 + facet normal 0 0 1 outer loop - vertex 4.45808 -10.7052 0.156793 - vertex 5.76454 -12.8376 0.463525 - vertex 5.70808 -12.8702 0.156793 + vertex 9.31758 -4.38587 4.5 + vertex 3.47877 -2.52748 4.5 + vertex 2.87726 -3.19552 4.5 endloop endfacet - facet normal 0.847104 0.489076 -0.207894 + facet normal 0 0 1 outer loop - vertex 3.01454 -8.07451 0.463525 - vertex 1.07998 -4.85414 0.156793 - vertex 1.14703 -4.83989 0.463525 + vertex 1.32877 -4.08954 4.5 + vertex 0.449472 -4.27644 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.847102 0.489074 -0.207905 + facet normal 0 0 1 outer loop - vertex 1.07998 -4.85414 0.156793 - vertex 3.01454 -8.07451 0.463525 - vertex 2.95808 -8.10711 0.156793 + vertex 2.93542 -11.5843 4.5 + vertex 0.56832 -11.8491 4.5 + vertex 0.682417 -12.3859 4.5 endloop endfacet - facet normal 0.0905233 0.0522625 0.994522 + facet normal 0 0 1 outer loop - vertex 5.5947 -10.049 -1.48115 - vertex 7 -12.1244 -1.5 - vertex 5.75 -9.95929 -1.5 + vertex -0.449472 -4.27644 4.5 + vertex -1.32877 -4.08954 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.0905538 0.0522832 0.994518 + facet normal 0 0 1 outer loop - vertex 7 -12.1244 -1.5 - vertex 5.5947 -10.049 -1.48115 - vertex 6.81094 -12.2335 -1.47705 + vertex -1.32877 -4.08954 4.5 + vertex -2.15 -3.72391 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.0905169 0.0522599 0.994523 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 -1.5 - vertex 4.13521 -7.42749 -1.48607 - vertex 4.25 -7.36122 -1.5 + vertex -2.15 -3.72391 4.5 + vertex -2.87726 -3.19552 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.0905147 0.0522588 0.994523 + facet normal 0 0 1 outer loop - vertex 4.13521 -7.42749 -1.48607 - vertex 2.5 -4.33013 -1.5 - vertex 2.4285 -4.36196 -1.49182 + vertex -2.87726 -3.19552 4.5 + vertex -3.47877 -2.52748 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.267611 0.154504 0.951059 + facet normal 0 0 1 outer loop - vertex 5.47991 -10.1152 -1.46722 - vertex 6.47163 -12.4294 -1.37032 - vertex 6.72992 -12.2803 -1.46722 + vertex -3.47877 -2.52748 4.5 + vertex -3.92824 -1.74897 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.267618 0.154507 0.951056 + facet normal 0 0 1 outer loop - vertex 6.47163 -12.4294 -1.37032 - vertex 5.47991 -10.1152 -1.46722 - vertex 5.22163 -10.2643 -1.37032 + vertex 18 -5.7735 4.5 + vertex 2.93542 -11.5843 4.5 + vertex 0.682417 -12.9346 4.5 endloop endfacet - facet normal 0.267602 0.1545 0.951062 + facet normal 0 0 1 outer loop - vertex 2.21353 -4.45767 -1.46722 - vertex 3.72163 -7.66627 -1.37032 - vertex 3.97992 -7.51715 -1.46722 + vertex 2.15 3.72391 4.5 + vertex 11.9282 -2.03525 4.5 + vertex -8.45706 10.1237 4.5 endloop endfacet - facet normal 0.267601 0.1545 0.951062 + facet normal 0 0 1 outer loop - vertex 3.72163 -7.66627 -1.37032 - vertex 2.21353 -4.45767 -1.46722 - vertex 1.93957 -4.57965 -1.37032 + vertex 9.31758 -4.93464 4.5 + vertex 1.32877 -4.08954 4.5 + vertex 7.06458 -5.73622 4.5 endloop endfacet - facet normal -0.791159 -0.456775 0.406724 + facet normal 0 0 1 outer loop - vertex 6.875 -9.30977 -0.749999 - vertex 8.20232 -11.4302 -0.549467 - vertex 6.93851 -9.2731 -0.585277 + vertex 9.31758 -4.93464 4.5 + vertex 9.31758 -4.38587 4.5 + vertex 2.15 -3.72391 4.5 endloop endfacet - facet normal -0.791182 -0.456796 0.406655 + facet normal 0 0 1 outer loop - vertex 8.20232 -11.4302 -0.549467 - vertex 6.875 -9.30977 -0.749999 - vertex 8.125 -11.4748 -0.749999 + vertex 9.43168 -5.47142 4.5 + vertex 9.31758 -4.93464 4.5 + vertex 7.06458 -5.73622 4.5 endloop endfacet - facet normal -0.791127 -0.456754 0.406809 + facet normal 0 0 1 outer loop - vertex 3.52821 -3.51297 -0.75 - vertex 5.42194 -6.68459 -0.628248 - vertex 3.54974 -3.48907 -0.681296 + vertex 9.31758 -4.38587 4.5 + vertex 9.43168 -3.84908 4.5 + vertex 3.47877 -2.52748 4.5 endloop endfacet - facet normal -0.791156 -0.456775 0.406729 + facet normal 0 0 1 outer loop - vertex 5.42194 -6.68459 -0.628248 - vertex 3.52821 -3.51297 -0.75 - vertex 5.375 -6.7117 -0.75 + vertex 14.4247 -5.47142 4.5 + vertex 14.2015 -5.97275 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.700631 -0.404505 -0.587786 + facet normal 0 0 1 outer loop - vertex 8.07711 -11.5025 0.826109 - vertex 6.71537 -9.40193 1.0037 - vertex 6.80716 -9.34894 0.857821 + vertex 9.43168 -3.84908 4.5 + vertex 9.65489 -3.34775 4.5 + vertex 3.92824 -1.74897 4.5 endloop endfacet - facet normal -0.700644 -0.404516 -0.587762 + facet normal 0 0 1 outer loop - vertex 6.71537 -9.40193 1.0037 - vertex 8.07711 -11.5025 0.826109 - vertex 7.96537 -11.567 1.0037 + vertex 9.65489 -3.34775 4.5 + vertex 9.97745 -2.90379 4.5 + vertex 4.20603 -0.89402 4.5 endloop endfacet - facet normal -0.700641 -0.404515 -0.587767 + facet normal 0 0 1 outer loop - vertex 5.28321 -6.76469 0.895875 - vertex 3.39853 -3.657 1.0037 - vertex 3.42999 -3.62206 0.942152 + vertex -1.32877 4.08954 4.5 + vertex -0.449472 4.27644 4.5 + vertex -7.38938 8.27439 4.5 endloop endfacet - facet normal -0.700639 -0.404514 -0.587769 + facet normal 0 0 1 outer loop - vertex 3.39853 -3.657 1.0037 - vertex 5.28321 -6.76469 0.895875 - vertex 5.21537 -6.80386 1.0037 + vertex 4.3 0 4.5 + vertex 4.20603 -0.89402 4.5 + vertex 9.97745 -2.90379 4.5 endloop endfacet - facet normal 0.847096 0.489085 0.207905 + facet normal 0 0 1 outer loop - vertex 4.45808 -10.7052 -0.156793 - vertex 5.76454 -12.8376 -0.463525 - vertex 4.51454 -10.6726 -0.463525 + vertex 3.47877 2.52748 4.5 + vertex 3.92824 1.74897 4.5 + vertex 11.3824 -2.09262 4.5 endloop endfacet - facet normal 0.847096 0.489085 0.207905 + facet normal 0 0 1 outer loop - vertex 5.76454 -12.8376 -0.463525 - vertex 4.45808 -10.7052 -0.156793 - vertex 5.70808 -12.8702 -0.156793 + vertex 11.3824 -2.09262 4.5 + vertex 2.87726 3.19552 4.5 + vertex 3.47877 2.52748 4.5 endloop endfacet - facet normal 0.847104 0.489076 0.207894 + facet normal 0 0 1 outer loop - vertex 1.07998 -4.85414 -0.156793 - vertex 3.01454 -8.07451 -0.463525 - vertex 1.14703 -4.83989 -0.463525 + vertex 14.4247 -3.84908 4.5 + vertex 14.5388 -4.38587 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal 0.847102 0.489074 0.207905 + facet normal 0 0 1 outer loop - vertex 3.01454 -8.07451 -0.463525 - vertex 1.07998 -4.85414 -0.156793 - vertex 2.95808 -8.10711 -0.156793 + vertex 9.65489 3.34775 4.5 + vertex -8.45706 10.1237 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.791151 -0.456764 0.406752 + facet normal 0 0 1 outer loop - vertex 6.93851 -9.2731 -0.585277 - vertex 8.23546 -11.4111 -0.463525 - vertex 6.98546 -9.246 -0.463525 + vertex 18 5.7735 4.5 + vertex 11.9282 -2.03525 4.5 + vertex 12.474 -2.09262 4.5 endloop endfacet - facet normal -0.7912 -0.456801 0.406615 + facet normal 0 0 1 outer loop - vertex 8.23546 -11.4111 -0.463525 - vertex 6.93851 -9.2731 -0.585277 - vertex 8.20232 -11.4302 -0.549467 + vertex 13.879 -2.90379 4.5 + vertex 14.2015 -3.34775 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.791161 -0.456779 0.406715 + facet normal 0 0 1 outer loop - vertex 3.54974 -3.48907 -0.681296 - vertex 5.48546 -6.64792 -0.463525 - vertex 3.61795 -3.41331 -0.463525 + vertex 18 5.7735 4.5 + vertex 12.474 -2.09262 4.5 + vertex 12.9959 -2.2622 4.5 endloop endfacet - facet normal -0.791145 -0.456765 0.406762 + facet normal 0 0 1 outer loop - vertex 5.48546 -6.64792 -0.463525 - vertex 3.54974 -3.48907 -0.681296 - vertex 5.42194 -6.68459 -0.628248 + vertex 18 5.7735 4.5 + vertex 13.4711 -2.53658 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal 0.0905269 0.0522646 -0.994522 + facet normal 0 0 1 outer loop - vertex 6.91897 -12.1711 1.49017 - vertex 5.75 -9.95929 1.5 - vertex 7 -12.1244 1.5 + vertex 18 5.7735 4.5 + vertex 12.9959 -2.2622 4.5 + vertex 13.4711 -2.53658 4.5 endloop endfacet - facet normal 0.0905034 0.0522522 -0.994524 + facet normal 0 0 1 outer loop - vertex 5.75 -9.95929 1.5 - vertex 6.91897 -12.1711 1.49017 - vertex 5.63521 -10.0256 1.48607 + vertex -7.38938 7.72561 4.5 + vertex -7.50348 7.18883 4.5 + vertex -1.32877 4.08954 4.5 endloop endfacet - facet normal 0.0905353 0.0522706 -0.994521 + facet normal 0 0 1 outer loop - vertex 4.0947 -7.45088 1.48115 - vertex 2.5 -4.33013 1.5 - vertex 4.25 -7.36122 1.5 + vertex 11.3824 -2.09262 4.5 + vertex 2.15 3.72391 4.5 + vertex 2.87726 3.19552 4.5 endloop endfacet - facet normal 0.0905089 0.0522571 -0.994524 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 1.5 - vertex 4.0947 -7.45088 1.48115 - vertex 2.28479 -4.42594 1.47538 + vertex 10.3853 -2.53658 4.5 + vertex 10.8605 -2.2622 4.5 + vertex 4.20603 0.89402 4.5 endloop endfacet - facet normal 0.791145 0.456775 0.406752 + facet normal 0 0 1 outer loop - vertex 4.51454 -10.6726 -0.463525 - vertex 5.79768 -12.8185 -0.549467 - vertex 4.56149 -10.6455 -0.585277 + vertex 10.3853 6.78392 4.5 + vertex -9.45423 10.5676 4.5 + vertex -8.93232 10.3981 4.5 endloop endfacet - facet normal 0.791195 0.45681 0.406615 + facet normal 0 0 1 outer loop - vertex 5.79768 -12.8185 -0.549467 - vertex 4.51454 -10.6726 -0.463525 - vertex 5.76454 -12.8376 -0.463525 + vertex 0.449472 -4.27644 4.5 + vertex -0.449472 -4.27644 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.79115 0.456772 0.406744 + facet normal 0 0 1 outer loop - vertex 1.14703 -4.83989 -0.463525 - vertex 3.07806 -8.03784 -0.628248 - vertex 1.24675 -4.81869 -0.681296 + vertex 13.879 -6.41672 4.5 + vertex 13.4711 -6.78392 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal 0.791144 0.456767 0.406762 + facet normal 0 0 1 outer loop - vertex 3.07806 -8.03784 -0.628248 - vertex 1.14703 -4.83989 -0.463525 - vertex 3.01454 -8.07451 -0.463525 + vertex 10.3853 6.78392 4.5 + vertex -8.93232 10.3981 4.5 + vertex -8.45706 10.1237 4.5 endloop endfacet - facet normal 0.433021 0.25 0.866021 + facet normal 0 0 1 outer loop - vertex 5.22163 -10.2643 -1.37032 - vertex 6.23644 -12.5652 -1.21352 - vertex 6.47163 -12.4294 -1.37032 + vertex 11.9282 -7.28525 4.5 + vertex 8.56458 -8.33429 4.5 + vertex 12.474 -7.22789 4.5 endloop endfacet - facet normal 0.433021 0.25 0.866021 + facet normal 0 0 1 outer loop - vertex 6.23644 -12.5652 -1.21352 - vertex 5.22163 -10.2643 -1.37032 - vertex 4.98644 -10.4001 -1.21352 + vertex 7.06458 -5.73622 4.5 + vertex 10.8605 -7.05831 4.5 + vertex 10.3853 -6.78392 4.5 endloop endfacet - facet normal 0.433031 0.25001 0.866013 + facet normal 0 0 1 outer loop - vertex 1.93957 -4.57965 -1.37032 - vertex 3.48644 -7.80205 -1.21352 - vertex 3.72163 -7.66627 -1.37032 + vertex 10.8605 -7.05831 4.5 + vertex 8.56458 -8.33429 4.5 + vertex 11.3824 -7.22789 4.5 endloop endfacet - facet normal 0.433033 0.250011 0.866012 + facet normal 0 0 1 outer loop - vertex 3.48644 -7.80205 -1.21352 - vertex 1.93957 -4.57965 -1.37032 - vertex 1.69011 -4.69071 -1.21352 + vertex 7.06458 -5.73622 4.5 + vertex 10.3853 -6.78392 4.5 + vertex 9.97745 -6.41672 4.5 endloop endfacet - facet normal 0.700636 0.404504 0.587781 + facet normal 0 0 1 outer loop - vertex 4.625 -10.6088 -0.749999 - vertex 5.98674 -12.7094 -0.927587 - vertex 4.71678 -10.5558 -0.895875 + vertex 12.474 -7.22789 4.5 + vertex 8.56458 -8.33429 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal 0.700643 0.404509 0.587769 + facet normal 0 0 1 outer loop - vertex 5.98674 -12.7094 -0.927587 - vertex 4.625 -10.6088 -0.749999 - vertex 5.875 -12.7739 -0.749999 + vertex -0.860519 -15.0583 4.5 + vertex -1.38244 -15.2279 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.700588 0.404481 0.587853 + facet normal 0 0 1 outer loop - vertex 1.27821 -4.81201 -0.75 - vertex 3.19284 -7.97157 -0.857821 - vertex 1.32391 -4.80229 -0.811152 + vertex 1.43542 -8.98622 4.5 + vertex 7.06458 -5.73622 4.5 + vertex -7.72668 -6.6875 4.5 endloop endfacet - facet normal 0.700645 0.404519 0.587759 + facet normal 0 0 1 outer loop - vertex 3.19284 -7.97157 -0.857821 - vertex 1.27821 -4.81201 -0.75 - vertex 3.125 -8.01073 -0.75 + vertex 1.43542 -8.98622 4.5 + vertex -7.72668 -6.6875 4.5 + vertex -7.50348 -7.18883 4.5 endloop endfacet - facet normal 0.791142 0.456758 -0.406775 + facet normal 0 0 1 outer loop - vertex 5.875 -12.7739 0.75 - vertex 4.51454 -10.6726 0.463525 - vertex 4.625 -10.6088 0.75 + vertex 11.3824 -2.09262 4.5 + vertex 11.9282 -2.03525 4.5 + vertex 2.15 3.72391 4.5 endloop endfacet - facet normal 0.791184 0.456804 -0.406642 + facet normal 0 0 1 outer loop - vertex 4.51454 -10.6726 0.463525 - vertex 5.875 -12.7739 0.75 - vertex 5.76454 -12.8376 0.463525 + vertex 9.65489 -5.97275 4.5 + vertex 9.43168 -5.47142 4.5 + vertex 7.06458 -5.73622 4.5 endloop endfacet - facet normal 0.791155 0.456775 -0.406732 + facet normal 0 0 1 outer loop - vertex 3.125 -8.01073 0.75 - vertex 1.14703 -4.83989 0.463525 - vertex 1.27821 -4.81201 0.75 + vertex 7.06458 -5.73622 4.5 + vertex 8.56458 -8.33429 4.5 + vertex 10.8605 -7.05831 4.5 endloop endfacet - facet normal 0.791149 0.45677 -0.406748 + facet normal 0 0 1 outer loop - vertex 1.14703 -4.83989 0.463525 - vertex 3.125 -8.01073 0.75 - vertex 3.01454 -8.07451 0.463525 + vertex 11.3824 -7.22789 4.5 + vertex 8.56458 -8.33429 4.5 + vertex 11.9282 -7.28525 4.5 endloop endfacet - facet normal -0.791167 -0.456784 -0.406698 + facet normal 0 0 1 outer loop - vertex 8.15814 -11.4557 0.664057 - vertex 6.875 -9.30977 0.75 - vertex 6.92194 -9.28267 0.628248 + vertex 14.2015 -5.97275 4.5 + vertex 13.879 -6.41672 4.5 + vertex 18 -5.7735 4.5 endloop endfacet - facet normal -0.791199 -0.456806 -0.406611 + facet normal 0 0 1 outer loop - vertex 6.875 -9.30977 0.75 - vertex 8.15814 -11.4557 0.664057 - vertex 8.125 -11.4748 0.75 + vertex 9.31758 4.93464 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.31758 4.38587 4.5 endloop endfacet - facet normal -0.791146 -0.456767 -0.406759 + facet normal 0 0 1 outer loop - vertex 5.43851 -6.67503 0.585277 - vertex 3.52821 -3.51297 0.749999 - vertex 3.59653 -3.4371 0.531919 + vertex 14.2015 3.34775 4.5 + vertex 13.879 2.90379 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.791158 -0.456776 -0.406724 + facet normal 0 0 1 outer loop - vertex 3.52821 -3.51297 0.749999 - vertex 5.43851 -6.67503 0.585277 - vertex 5.375 -6.7117 0.749999 + vertex 9.43168 5.47142 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.31758 4.93464 4.5 endloop endfacet - facet normal -0.579483 -0.334565 0.743146 + facet normal 0 0 1 outer loop - vertex 3.34565 -3.71572 -1.07137 - vertex 5.21537 -6.80386 -1.0037 - vertex 3.39853 -3.657 -1.0037 + vertex 9.65489 5.97275 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.43168 5.47142 4.5 endloop endfacet - facet normal -0.579464 -0.334553 0.743166 + facet normal 0 0 1 outer loop - vertex 3.21722 -3.80904 -1.21352 - vertex 5.21537 -6.80386 -1.0037 - vertex 3.34565 -3.71572 -1.07137 + vertex 9.97745 6.41672 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.65489 5.97275 4.5 endloop endfacet - facet normal -0.579467 -0.334555 0.743163 + facet normal 0 0 1 outer loop - vertex 5.21537 -6.80386 -1.0037 - vertex 3.21722 -3.80904 -1.21352 - vertex 5.01355 -6.92038 -1.21352 + vertex 10.3853 6.78392 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.97745 6.41672 4.5 endloop endfacet - facet normal -0.579493 -0.334569 0.743136 + facet normal 0 0 1 outer loop - vertex 6.71537 -9.40193 -1.0037 - vertex 7.76356 -11.6835 -1.21352 - vertex 7.96537 -11.567 -1.0037 + vertex 11.3824 7.22789 4.5 + vertex 11.9282 7.28525 4.5 + vertex -0.860519 10.2622 4.5 endloop endfacet - facet normal -0.579465 -0.334559 0.743163 + facet normal 0 0 1 outer loop - vertex 7.76356 -11.6835 -1.21352 - vertex 6.71537 -9.40193 -1.0037 - vertex 6.51355 -9.51845 -1.21352 + vertex 13.879 6.41672 4.5 + vertex 14.2015 5.97275 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.579467 -0.334555 -0.743163 + facet normal 0 0 1 outer loop - vertex 3.21722 -3.80904 1.21352 - vertex 5.21537 -6.80386 1.0037 - vertex 5.01355 -6.92038 1.21352 + vertex -2.99589 10.2622 4.5 + vertex -3.47114 10.5366 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal -0.579483 -0.334565 -0.743146 + facet normal 0 0 1 outer loop - vertex 5.21537 -6.80386 1.0037 - vertex 3.34565 -3.71572 1.07137 - vertex 3.39853 -3.657 1.0037 + vertex -0.385267 10.5366 4.5 + vertex -0.860519 10.2622 4.5 + vertex 11.9282 7.28525 4.5 endloop endfacet - facet normal -0.579464 -0.334553 -0.743166 + facet normal 0 0 1 outer loop - vertex 5.21537 -6.80386 1.0037 - vertex 3.21722 -3.80904 1.21352 - vertex 3.34565 -3.71572 1.07137 + vertex 0.0225516 10.9038 4.5 + vertex 12.474 7.22789 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.579493 -0.334569 -0.743136 + facet normal 0 0 1 outer loop - vertex 7.76356 -11.6835 1.21352 - vertex 6.71537 -9.40193 1.0037 - vertex 7.96537 -11.567 1.0037 + vertex 0.0225516 10.9038 4.5 + vertex -0.385267 10.5366 4.5 + vertex 12.474 7.22789 4.5 endloop endfacet - facet normal -0.579465 -0.334559 -0.743163 + facet normal 0 0 1 outer loop - vertex 6.71537 -9.40193 1.0037 - vertex 7.76356 -11.6835 1.21352 - vertex 6.51355 -9.51845 1.21352 + vertex 12.9959 7.05831 4.5 + vertex 13.4711 6.78392 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.847105 -0.489068 -0.207905 + facet normal 0 0 1 outer loop - vertex 8.29192 -11.3785 0.156793 - vertex 6.98546 -9.246 0.463525 - vertex 7.04192 -9.2134 0.156793 + vertex 13.4711 6.78392 4.5 + vertex 13.879 6.41672 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.847105 -0.489068 -0.207905 + facet normal 0 0 1 outer loop - vertex 6.98546 -9.246 0.463525 - vertex 8.29192 -11.3785 0.156793 - vertex 8.23546 -11.4111 0.463525 + vertex 11.9282 7.28525 4.5 + vertex 12.474 7.22789 4.5 + vertex -0.385267 10.5366 4.5 endloop endfacet - facet normal -0.847099 -0.489074 -0.207917 + facet normal 0 0 1 outer loop - vertex 5.54192 -6.61532 0.156793 - vertex 3.61795 -3.41331 0.463525 - vertex 3.66382 -3.36236 0.156793 + vertex 14.2015 5.97275 4.5 + vertex 14.4247 5.47142 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.847101 -0.489076 -0.207905 + facet normal 0 0 1 outer loop - vertex 3.61795 -3.41331 0.463525 - vertex 5.54192 -6.61532 0.156793 - vertex 5.48546 -6.64792 0.463525 + vertex 11.3824 7.22789 4.5 + vertex -0.860519 10.2622 4.5 + vertex -1.38243 10.0926 4.5 endloop endfacet - facet normal -0.0905328 -0.0522691 -0.994521 + facet normal 0 0 1 outer loop - vertex 2.5 -4.33013 1.5 - vertex 4.4053 -7.27155 1.48115 - vertex 4.25 -7.36122 1.5 + vertex 14.4247 5.47142 4.5 + vertex 14.5388 4.93464 4.5 + vertex 18 5.7735 4.5 endloop endfacet - facet normal -0.0905104 -0.0522546 -0.994524 + facet normal 0 0 1 outer loop - vertex 4.4053 -7.27155 1.48115 - vertex 2.5 -4.33013 1.5 - vertex 2.69058 -4.19166 1.47538 + vertex 9.97745 2.90379 4.5 + vertex 9.65489 3.34775 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.090479 -0.052237 -0.994527 + facet normal 0 0 1 outer loop - vertex 5.75 -9.95929 1.5 - vertex 7.08103 -12.0776 1.49017 - vertex 7 -12.1244 1.5 + vertex 13.879 2.90379 4.5 + vertex 13.4711 2.53658 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.0905165 -0.0522606 -0.994523 + facet normal 0 0 1 outer loop - vertex 7.08103 -12.0776 1.49017 - vertex 5.75 -9.95929 1.5 - vertex 5.86479 -9.89302 1.48607 + vertex 18 5.7735 4.5 + vertex 14.5388 4.93464 4.5 + vertex 14.5388 4.38587 4.5 endloop endfacet - facet normal -0.433017 -0.250006 -0.866021 + facet normal 0 0 1 outer loop - vertex 7.52837 -11.8193 1.37032 - vertex 6.51355 -9.51845 1.21352 - vertex 7.76356 -11.6835 1.21352 + vertex 18 5.7735 4.5 + vertex 14.4247 3.84908 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.433035 -0.250013 -0.86601 + facet normal 0 0 1 outer loop - vertex 6.51355 -9.51845 1.21352 - vertex 7.52837 -11.8193 1.37032 - vertex 6.27837 -9.65424 1.37032 + vertex 18 5.7735 4.5 + vertex 14.5388 4.38587 4.5 + vertex 14.4247 3.84908 4.5 endloop endfacet - facet normal -0.433041 -0.250017 -0.866006 + facet normal 0 0 1 outer loop - vertex 2.9963 -3.96954 1.37032 - vertex 5.01355 -6.92038 1.21352 - vertex 4.77837 -7.05616 1.37032 + vertex 14.4247 3.84908 4.5 + vertex 14.2015 3.34775 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.433029 -0.250009 -0.866015 + facet normal 0 0 1 outer loop - vertex 5.01355 -6.92038 1.21352 - vertex 2.9963 -3.96954 1.37032 - vertex 3.21722 -3.80904 1.21352 + vertex 13.4711 2.53658 4.5 + vertex 12.9959 2.2622 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.700621 -0.40451 0.587794 + facet normal 0 0 1 outer loop - vertex 6.78321 -9.36276 -0.895875 - vertex 8.125 -11.4748 -0.749999 - vertex 6.875 -9.30977 -0.749999 + vertex 12.9959 2.2622 4.5 + vertex 12.474 2.09262 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.700636 -0.404521 0.587769 + facet normal 0 0 1 outer loop - vertex 8.125 -11.4748 -0.749999 - vertex 6.78321 -9.36276 -0.895875 - vertex 8.01326 -11.5393 -0.927587 + vertex 12.474 2.09262 4.5 + vertex 11.9282 2.03525 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.700616 -0.404501 0.587806 + facet normal 0 0 1 outer loop - vertex 3.49695 -3.54769 -0.811152 - vertex 5.375 -6.7117 -0.75 - vertex 3.52821 -3.51297 -0.75 + vertex 11.9282 2.03525 4.5 + vertex 11.3824 2.09262 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal -0.700645 -0.40452 0.587759 + facet normal 0 0 1 outer loop - vertex 5.375 -6.7117 -0.75 - vertex 3.49695 -3.54769 -0.811152 - vertex 5.30716 -6.75086 -0.857821 + vertex 11.3824 2.09262 4.5 + vertex 10.8605 2.2622 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal 0.0905396 0.0522753 0.99452 + facet normal 0 0 1 outer loop - vertex 5.47991 -10.1152 -1.46722 - vertex 6.81094 -12.2335 -1.47705 - vertex 5.5947 -10.049 -1.48115 + vertex 10.8605 2.2622 4.5 + vertex 10.3853 2.53658 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal 0.090487 0.0522422 0.994526 + facet normal 0 0 1 outer loop - vertex 6.81094 -12.2335 -1.47705 - vertex 5.47991 -10.1152 -1.46722 - vertex 6.72992 -12.2803 -1.46722 + vertex 10.3853 2.53658 4.5 + vertex 9.97745 2.90379 4.5 + vertex 11.9282 -2.03525 4.5 endloop endfacet - facet normal 0.0905398 0.0522728 0.99452 + facet normal 0 0 1 outer loop - vertex 2.4285 -4.36196 -1.49182 - vertex 3.97992 -7.51715 -1.46722 - vertex 4.13521 -7.42749 -1.48607 + vertex 9.43168 3.84908 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.65489 3.34775 4.5 endloop endfacet - facet normal 0.0905354 0.0522706 0.994521 + facet normal 0 0 1 outer loop - vertex 3.97992 -7.51715 -1.46722 - vertex 2.4285 -4.36196 -1.49182 - vertex 2.21353 -4.45767 -1.46722 + vertex 9.31758 4.38587 4.5 + vertex -8.45706 10.1237 4.5 + vertex 9.43168 3.84908 4.5 endloop endfacet - facet normal 0.579479 0.334562 0.74315 + facet normal 0 0 1 outer loop - vertex 1.69011 -4.69071 -1.21352 - vertex 3.28463 -7.91857 -1.0037 - vertex 3.48644 -7.80205 -1.21352 + vertex -7.38938 -8.27439 4.5 + vertex -7.50348 -8.81117 4.5 + vertex -4 -18.4752 4.5 endloop endfacet - facet normal 0.579461 0.334554 0.743168 + facet normal 0 0 1 outer loop - vertex 1.54508 -4.75528 -1.07137 - vertex 3.28463 -7.91857 -1.0037 - vertex 1.69011 -4.69071 -1.21352 + vertex 1.32877 4.08954 4.5 + vertex 2.15 3.72391 4.5 + vertex -8.04924 9.75647 4.5 endloop endfacet - facet normal 0.579506 0.334578 0.743122 + facet normal 0 0 1 outer loop - vertex 3.28463 -7.91857 -1.0037 - vertex 1.54508 -4.75528 -1.07137 - vertex 1.46779 -4.77171 -1.0037 + vertex -8.04924 -6.24353 4.5 + vertex -7.72668 -6.6875 4.5 + vertex -11.9508 6.24353 4.5 endloop endfacet - facet normal 0.579495 0.334566 0.743136 + facet normal 0 0 1 outer loop - vertex 4.98644 -10.4001 -1.21352 - vertex 6.03463 -12.6817 -1.0037 - vertex 6.23644 -12.5652 -1.21352 + vertex -12.6106 8.27439 4.5 + vertex -12.4965 8.81117 4.5 + vertex -14 12.7017 4.5 endloop endfacet - facet normal 0.57942 0.334538 0.743207 + facet normal 0 0 1 outer loop - vertex 6.03463 -12.6817 -1.0037 - vertex 4.98644 -10.4001 -1.21352 - vertex 4.78463 -10.5167 -1.0037 + vertex -7.72668 9.3125 4.5 + vertex -7.50348 8.81117 4.5 + vertex 0.449472 4.27644 4.5 endloop endfacet - facet normal 0.700716 0.40457 0.58764 + facet normal 0 0 1 outer loop - vertex 4.71678 -10.5558 -0.895875 - vertex 6.03463 -12.6817 -1.0037 - vertex 4.78463 -10.5167 -1.0037 + vertex -2.15 3.72391 4.5 + vertex -1.32877 4.08954 4.5 + vertex -7.50348 7.18883 4.5 endloop endfacet - facet normal 0.700527 0.404437 0.587957 + facet normal 0 0 1 outer loop - vertex 6.03463 -12.6817 -1.0037 - vertex 4.71678 -10.5558 -0.895875 - vertex 5.98674 -12.7094 -0.927587 + vertex 9.31758 -4.93464 4.5 + vertex 2.15 -3.72391 4.5 + vertex 1.32877 -4.08954 4.5 endloop endfacet - facet normal 0.70063 0.404509 0.587784 + facet normal 0 0 1 outer loop - vertex 1.32391 -4.80229 -0.811152 - vertex 3.28463 -7.91857 -1.0037 - vertex 1.46779 -4.77171 -1.0037 + vertex 2.93542 -11.5843 4.5 + vertex -0.385267 -10.5366 4.5 + vertex 0.0225516 -10.9038 4.5 endloop endfacet - facet normal 0.700618 0.4045 0.587804 + facet normal 0 0 1 outer loop - vertex 3.28463 -7.91857 -1.0037 - vertex 1.32391 -4.80229 -0.811152 - vertex 3.19284 -7.97157 -0.857821 + vertex 2.93542 -11.5843 4.5 + vertex -0.860519 -10.2622 4.5 + vertex -0.385267 -10.5366 4.5 endloop endfacet - facet normal 0.433021 0.25 -0.866021 + facet normal 0 0 1 outer loop - vertex 6.23644 -12.5652 1.21352 - vertex 5.22163 -10.2643 1.37032 - vertex 6.47163 -12.4294 1.37032 + vertex -1.9282 -10.0353 4.5 + vertex 1.43542 -8.98622 4.5 + vertex -2.47397 -10.0926 4.5 endloop endfacet - facet normal 0.433021 0.25 -0.866021 + facet normal 0 0 1 outer loop - vertex 5.22163 -10.2643 1.37032 - vertex 6.23644 -12.5652 1.21352 - vertex 4.98644 -10.4001 1.21352 + vertex -1.38243 -10.0926 4.5 + vertex 1.43542 -8.98622 4.5 + vertex -1.9282 -10.0353 4.5 endloop endfacet - facet normal 0.433031 0.25001 -0.866013 + facet normal 0 0 1 outer loop - vertex 3.48644 -7.80205 1.21352 - vertex 1.93957 -4.57965 1.37032 - vertex 3.72163 -7.66627 1.37032 + vertex -0.860519 -10.2622 4.5 + vertex 1.43542 -8.98622 4.5 + vertex -1.38243 -10.0926 4.5 endloop endfacet - facet normal 0.433033 0.250011 -0.866012 + facet normal 0 0 1 outer loop - vertex 1.93957 -4.57965 1.37032 - vertex 3.48644 -7.80205 1.21352 - vertex 1.69011 -4.69071 1.21352 + vertex 2.93542 -11.5843 4.5 + vertex 1.43542 -8.98622 4.5 + vertex -0.860519 -10.2622 4.5 endloop endfacet - facet normal 0.579479 0.334562 -0.74315 + facet normal 0.847101 0.489074 0.207912 outer loop - vertex 3.28463 -7.91857 1.0037 - vertex 1.69011 -4.69071 1.21352 - vertex 3.48644 -7.80205 1.21352 + vertex 5.70808 -12.8702 -0.156793 + vertex 5.76454 -12.8376 -0.463525 + vertex 4.51454 -10.6726 -0.463525 endloop endfacet - facet normal 0.579461 0.334554 -0.743168 + facet normal 0.847101 0.489074 0.207912 outer loop - vertex 3.28463 -7.91857 1.0037 - vertex 1.54508 -4.75528 1.07137 - vertex 1.69011 -4.69071 1.21352 + vertex 4.45808 -10.7052 -0.156793 + vertex 5.70808 -12.8702 -0.156793 + vertex 4.51454 -10.6726 -0.463525 endloop endfacet - facet normal 0.579506 0.334578 -0.743122 + facet normal 0.866025 0.5 1.92296e-16 outer loop - vertex 1.54508 -4.75528 1.07137 - vertex 3.28463 -7.91857 1.0037 - vertex 1.46779 -4.77171 1.0037 + vertex 5.70808 -12.8702 0.156793 + vertex 5.70808 -12.8702 -0.156793 + vertex 4.45808 -10.7052 -0.156793 endloop endfacet - facet normal 0.579495 0.334566 -0.743136 + facet normal 0.866025 0.5 1.92296e-16 outer loop - vertex 6.03463 -12.6817 1.0037 - vertex 4.98644 -10.4001 1.21352 - vertex 6.23644 -12.5652 1.21352 + vertex 4.45808 -10.7052 0.156793 + vertex 5.70808 -12.8702 0.156793 + vertex 4.45808 -10.7052 -0.156793 endloop endfacet - facet normal 0.57942 0.334538 -0.743207 + facet normal 0.791153 0.456773 0.406737 outer loop - vertex 4.98644 -10.4001 1.21352 - vertex 6.03463 -12.6817 1.0037 - vertex 4.78463 -10.5167 1.0037 + vertex 5.76454 -12.8376 -0.463525 + vertex 5.875 -12.7739 -0.75 + vertex 4.625 -10.6088 -0.75 endloop endfacet - facet normal 0.700664 0.40454 -0.587722 + facet normal 0.791153 0.456773 0.406737 outer loop - vertex 6.03463 -12.6817 1.0037 - vertex 4.625 -10.6088 0.75 - vertex 4.78463 -10.5167 1.0037 + vertex 4.51454 -10.6726 -0.463525 + vertex 5.76454 -12.8376 -0.463525 + vertex 4.625 -10.6088 -0.75 endloop endfacet - facet normal 0.700606 0.404488 -0.587827 + facet normal 0.700629 0.404508 0.587785 outer loop - vertex 4.625 -10.6088 0.75 - vertex 6.03463 -12.6817 1.0037 - vertex 5.875 -12.7739 0.75 + vertex 5.875 -12.7739 -0.75 + vertex 6.03463 -12.6817 -1.0037 + vertex 4.78463 -10.5167 -1.0037 endloop endfacet - facet normal 0.70062 0.404503 -0.5878 + facet normal 0.700629 0.404508 0.587785 outer loop - vertex 3.28463 -7.91857 1.0037 - vertex 1.27821 -4.81201 0.75 - vertex 1.46779 -4.77171 1.0037 + vertex 4.625 -10.6088 -0.75 + vertex 5.875 -12.7739 -0.75 + vertex 4.78463 -10.5167 -1.0037 endloop endfacet - facet normal 0.700629 0.40451 -0.587785 + facet normal 0.579484 0.334565 0.743145 outer loop - vertex 1.27821 -4.81201 0.75 - vertex 3.28463 -7.91857 1.0037 - vertex 3.125 -8.01073 0.75 + vertex 6.03463 -12.6817 -1.0037 + vertex 6.23644 -12.5652 -1.21352 + vertex 4.98644 -10.4001 -1.21352 endloop endfacet - facet normal -0.847105 -0.489068 0.207905 + facet normal 0.579484 0.334565 0.743145 outer loop - vertex 6.98546 -9.246 -0.463525 - vertex 8.29192 -11.3785 -0.156793 - vertex 7.04192 -9.2134 -0.156793 + vertex 4.78463 -10.5167 -1.0037 + vertex 6.03463 -12.6817 -1.0037 + vertex 4.98644 -10.4001 -1.21352 endloop endfacet - facet normal -0.847105 -0.489068 0.207905 + facet normal 0.433013 0.25 0.866025 outer loop - vertex 8.29192 -11.3785 -0.156793 - vertex 6.98546 -9.246 -0.463525 - vertex 8.23546 -11.4111 -0.463525 + vertex 6.23644 -12.5652 -1.21352 + vertex 6.47163 -12.4294 -1.37032 + vertex 5.22163 -10.2643 -1.37032 endloop endfacet - facet normal -0.847099 -0.489074 0.207917 + facet normal 0.433013 0.25 0.866025 outer loop - vertex 3.61795 -3.41331 -0.463525 - vertex 5.54192 -6.61532 -0.156793 - vertex 3.66382 -3.36236 -0.156793 + vertex 4.98644 -10.4001 -1.21352 + vertex 6.23644 -12.5652 -1.21352 + vertex 5.22163 -10.2643 -1.37032 endloop endfacet - facet normal -0.847101 -0.489076 0.207905 + facet normal 0.267616 0.154508 0.951057 outer loop - vertex 5.54192 -6.61532 -0.156793 - vertex 3.61795 -3.41331 -0.463525 - vertex 5.48546 -6.64792 -0.463525 + vertex 6.47163 -12.4294 -1.37032 + vertex 6.72991 -12.2803 -1.46722 + vertex 5.47991 -10.1152 -1.46722 endloop endfacet - facet normal -0.700636 -0.404521 0.587769 + facet normal 0.267616 0.154508 0.951057 outer loop - vertex 6.71537 -9.40193 -1.0037 - vertex 8.01326 -11.5393 -0.927587 - vertex 6.78321 -9.36276 -0.895875 + vertex 5.22163 -10.2643 -1.37032 + vertex 6.47163 -12.4294 -1.37032 + vertex 5.47991 -10.1152 -1.46722 endloop endfacet - facet normal -0.700522 -0.404445 0.587957 + facet normal 0.0905253 0.0522648 0.994522 outer loop - vertex 8.01326 -11.5393 -0.927587 - vertex 6.71537 -9.40193 -1.0037 - vertex 7.96537 -11.567 -1.0037 + vertex 6.72991 -12.2803 -1.46722 + vertex 7 -12.1244 -1.5 + vertex 5.75 -9.95929 -1.5 endloop endfacet - facet normal -0.700637 -0.404515 0.587772 + facet normal 0.0905253 0.0522648 0.994522 outer loop - vertex 3.39853 -3.657 -1.0037 - vertex 5.30716 -6.75086 -0.857821 - vertex 3.49695 -3.54769 -0.811152 + vertex 5.47991 -10.1152 -1.46722 + vertex 6.72991 -12.2803 -1.46722 + vertex 5.75 -9.95929 -1.5 endloop endfacet - facet normal -0.700617 -0.404502 0.587804 + facet normal -0.0905253 -0.0522648 0.994522 outer loop - vertex 5.30716 -6.75086 -0.857821 - vertex 3.39853 -3.657 -1.0037 - vertex 5.21537 -6.80386 -1.0037 + vertex 7 -12.1244 -1.5 + vertex 7.27009 -11.9684 -1.46722 + vertex 6.02009 -9.80336 -1.46722 endloop endfacet - facet normal 0.866019 0.500011 0 + facet normal -0.0905253 -0.0522648 0.994522 outer loop - vertex 5.70808 -12.8702 0.156793 - vertex 4.45808 -10.7052 -0.156793 - vertex 4.45808 -10.7052 0.156793 + vertex 5.75 -9.95929 -1.5 + vertex 7 -12.1244 -1.5 + vertex 6.02009 -9.80336 -1.46722 endloop endfacet - facet normal 0.866019 0.500011 0 + facet normal -0.267616 -0.154508 0.951057 outer loop - vertex 4.45808 -10.7052 -0.156793 - vertex 5.70808 -12.8702 0.156793 - vertex 5.70808 -12.8702 -0.156793 + vertex 7.27009 -11.9684 -1.46722 + vertex 7.52837 -11.8193 -1.37032 + vertex 6.27837 -9.65424 -1.37032 endloop endfacet - facet normal 0.866026 0.499999 0 + facet normal -0.267616 -0.154508 0.951057 outer loop - vertex 2.95808 -8.10711 0.156793 - vertex 1.07998 -4.85414 -0.156793 - vertex 1.07998 -4.85414 0.156793 + vertex 6.02009 -9.80336 -1.46722 + vertex 7.27009 -11.9684 -1.46722 + vertex 6.27837 -9.65424 -1.37032 endloop endfacet - facet normal 0.866026 0.499999 0 + facet normal -0.433013 -0.25 0.866025 outer loop - vertex 1.07998 -4.85414 -0.156793 - vertex 2.95808 -8.10711 0.156793 - vertex 2.95808 -8.10711 -0.156793 + vertex 7.52837 -11.8193 -1.37032 + vertex 7.76356 -11.6835 -1.21352 + vertex 6.51356 -9.51845 -1.21352 endloop endfacet - facet normal 0.267611 0.154504 -0.951059 + facet normal -0.433013 -0.25 0.866025 outer loop - vertex 6.47163 -12.4294 1.37032 - vertex 5.47991 -10.1152 1.46722 - vertex 6.72992 -12.2803 1.46722 + vertex 6.27837 -9.65424 -1.37032 + vertex 7.52837 -11.8193 -1.37032 + vertex 6.51356 -9.51845 -1.21352 endloop endfacet - facet normal 0.267618 0.154507 -0.951056 + facet normal -0.579484 -0.334565 0.743145 outer loop - vertex 5.47991 -10.1152 1.46722 - vertex 6.47163 -12.4294 1.37032 - vertex 5.22163 -10.2643 1.37032 + vertex 7.76356 -11.6835 -1.21352 + vertex 7.96537 -11.567 -1.0037 + vertex 6.71537 -9.40193 -1.0037 endloop endfacet - facet normal 0.267602 0.1545 -0.951062 + facet normal -0.579484 -0.334565 0.743145 outer loop - vertex 3.72163 -7.66627 1.37032 - vertex 2.21353 -4.45767 1.46722 - vertex 3.97992 -7.51715 1.46722 + vertex 6.51356 -9.51845 -1.21352 + vertex 7.76356 -11.6835 -1.21352 + vertex 6.71537 -9.40193 -1.0037 endloop endfacet - facet normal 0.267601 0.1545 -0.951062 + facet normal -0.700629 -0.404508 0.587785 outer loop - vertex 2.21353 -4.45767 1.46722 - vertex 3.72163 -7.66627 1.37032 - vertex 1.93957 -4.57965 1.37032 + vertex 8.125 -11.4748 -0.75 + vertex 6.875 -9.30977 -0.75 + vertex 7.96537 -11.567 -1.0037 endloop endfacet - facet normal -0.0905375 -0.0522722 -0.99452 + facet normal -0.700629 -0.404508 0.587785 outer loop - vertex 5.86479 -9.89302 1.48607 - vertex 7.27008 -11.9684 1.46722 - vertex 7.08103 -12.0776 1.49017 + vertex 7.96537 -11.567 -1.0037 + vertex 6.875 -9.30977 -0.75 + vertex 6.71537 -9.40193 -1.0037 endloop endfacet - facet normal -0.0905394 -0.0522735 -0.99452 + facet normal -0.791153 -0.456773 0.406737 outer loop - vertex 7.27008 -11.9684 1.46722 - vertex 5.86479 -9.89302 1.48607 - vertex 6.02008 -9.80336 1.46722 + vertex 8.23546 -11.4111 -0.463525 + vertex 6.98546 -9.246 -0.463525 + vertex 8.125 -11.4748 -0.75 endloop endfacet - facet normal -0.0905236 -0.0522619 -0.994522 + facet normal -0.791153 -0.456773 0.406737 outer loop - vertex 2.69058 -4.19166 1.47538 - vertex 4.52008 -7.20528 1.46722 - vertex 4.4053 -7.27155 1.48115 + vertex 8.125 -11.4748 -0.75 + vertex 6.98546 -9.246 -0.463525 + vertex 6.875 -9.30977 -0.75 endloop endfacet - facet normal -0.0905806 -0.0522965 -0.994515 + facet normal -0.847101 -0.489074 0.207912 outer loop - vertex 4.52008 -7.20528 1.46722 - vertex 2.69058 -4.19166 1.47538 - vertex 2.7537 -4.14581 1.46722 + vertex 8.29192 -11.3785 -0.156793 + vertex 7.04192 -9.2134 -0.156793 + vertex 8.23546 -11.4111 -0.463525 endloop endfacet - facet normal -0.26761 -0.154505 -0.951059 + facet normal -0.847101 -0.489074 0.207912 outer loop - vertex 7.27008 -11.9684 1.46722 - vertex 6.27837 -9.65424 1.37032 - vertex 7.52837 -11.8193 1.37032 + vertex 8.23546 -11.4111 -0.463525 + vertex 7.04192 -9.2134 -0.156793 + vertex 6.98546 -9.246 -0.463525 endloop endfacet - facet normal -0.267601 -0.154501 -0.951062 + facet normal -0.866025 -0.5 -1.92296e-16 outer loop - vertex 6.27837 -9.65424 1.37032 - vertex 7.27008 -11.9684 1.46722 - vertex 6.02008 -9.80336 1.46722 + vertex 8.29192 -11.3785 -0.156793 + vertex 8.29192 -11.3785 0.156793 + vertex 7.04192 -9.2134 -0.156793 endloop endfacet - facet normal -0.267602 -0.1545 -0.951062 + facet normal -0.866025 -0.5 -1.92296e-16 outer loop - vertex 2.7537 -4.14581 1.46722 - vertex 4.77837 -7.05616 1.37032 - vertex 4.52008 -7.20528 1.46722 + vertex 7.04192 -9.2134 -0.156793 + vertex 8.29192 -11.3785 0.156793 + vertex 7.04192 -9.2134 0.156793 endloop endfacet - facet normal -0.267612 -0.154507 -0.951058 + facet normal -0.847101 -0.489074 -0.207912 outer loop - vertex 4.77837 -7.05616 1.37032 - vertex 2.7537 -4.14581 1.46722 - vertex 2.9963 -3.96954 1.37032 + vertex 8.29192 -11.3785 0.156793 + vertex 8.23546 -11.4111 0.463525 + vertex 7.04192 -9.2134 0.156793 endloop endfacet - facet normal -0.791147 -0.456761 -0.406762 + facet normal -0.847101 -0.489074 -0.207912 outer loop + vertex 7.04192 -9.2134 0.156793 vertex 8.23546 -11.4111 0.463525 - vertex 6.92194 -9.28267 0.628248 vertex 6.98546 -9.246 0.463525 endloop endfacet - facet normal -0.791184 -0.456793 -0.406655 + facet normal -0.791153 -0.456773 -0.406737 outer loop - vertex 6.92194 -9.28267 0.628248 vertex 8.23546 -11.4111 0.463525 - vertex 8.15814 -11.4557 0.664057 - endloop - endfacet - facet normal -0.791177 -0.456788 -0.406673 - outer loop - vertex 5.48546 -6.64792 0.463525 - vertex 3.59653 -3.4371 0.531919 - vertex 3.61795 -3.41331 0.463525 + vertex 8.125 -11.4748 0.75 + vertex 6.98546 -9.246 0.463525 endloop endfacet - facet normal -0.791136 -0.456762 -0.406783 + facet normal -0.791153 -0.456773 -0.406737 outer loop - vertex 3.59653 -3.4371 0.531919 - vertex 5.48546 -6.64792 0.463525 - vertex 5.43851 -6.67503 0.585277 + vertex 6.98546 -9.246 0.463525 + vertex 8.125 -11.4748 0.75 + vertex 6.875 -9.30977 0.75 endloop endfacet - facet normal 0.5 -0.866025 9.10953e-17 + facet normal -0.700629 -0.404508 -0.587785 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 4.25 -7.36122 1.5 - vertex 7.06458 -5.73622 4.5 + vertex 8.125 -11.4748 0.75 + vertex 7.96537 -11.567 1.0037 + vertex 6.875 -9.30977 0.75 endloop endfacet - facet normal 0.499991 -0.866031 -1.21108e-05 + facet normal -0.700629 -0.404508 -0.587785 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 4.0947 -7.45088 1.48115 - vertex 4.25 -7.36122 1.5 + vertex 6.875 -9.30977 0.75 + vertex 7.96537 -11.567 1.0037 + vertex 6.71537 -9.40193 1.0037 endloop endfacet - facet normal 0.500009 -0.86602 9.39386e-06 + facet normal -0.579484 -0.334565 -0.743145 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 3.97992 -7.51715 1.46722 - vertex 4.0947 -7.45088 1.48115 + vertex 7.96537 -11.567 1.0037 + vertex 7.76356 -11.6835 1.21353 + vertex 6.71537 -9.40193 1.0037 endloop endfacet - facet normal 0.499993 -0.86603 -8.61935e-06 + facet normal -0.579484 -0.334565 -0.743145 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 3.72163 -7.66627 1.37032 - vertex 3.97992 -7.51715 1.46722 + vertex 6.71537 -9.40193 1.0037 + vertex 7.76356 -11.6835 1.21353 + vertex 6.51356 -9.51845 1.21353 endloop endfacet - facet normal 0.499988 -0.866033 -1.38043e-05 + facet normal -0.433013 -0.25 -0.866025 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 3.48644 -7.80205 1.21352 - vertex 3.72163 -7.66627 1.37032 + vertex 7.76356 -11.6835 1.21353 + vertex 7.52837 -11.8193 1.37032 + vertex 6.51356 -9.51845 1.21353 endloop endfacet - facet normal 0.500011 -0.866019 5.94142e-06 + facet normal -0.433013 -0.25 -0.866025 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 3.28463 -7.91857 1.0037 - vertex 3.48644 -7.80205 1.21352 + vertex 6.51356 -9.51845 1.21353 + vertex 7.52837 -11.8193 1.37032 + vertex 6.27837 -9.65424 1.37032 endloop endfacet - facet normal 0.499996 -0.866028 -4.86936e-06 + facet normal -0.267616 -0.154508 -0.951057 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 3.125 -8.01073 0.75 - vertex 3.28463 -7.91857 1.0037 + vertex 7.52837 -11.8193 1.37032 + vertex 7.27009 -11.9684 1.46722 + vertex 6.27837 -9.65424 1.37032 endloop endfacet - facet normal 0.500018 -0.866015 8.47169e-06 + facet normal -0.267616 -0.154508 -0.951057 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 3.01454 -8.07451 0.463525 - vertex 3.125 -8.01073 0.75 + vertex 6.27837 -9.65424 1.37032 + vertex 7.27009 -11.9684 1.46722 + vertex 6.02009 -9.80336 1.46722 endloop endfacet - facet normal 0.500012 -0.866019 5.06456e-06 + facet normal -0.0905253 -0.0522648 -0.994522 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 2.95808 -8.10711 0.156793 - vertex 3.01454 -8.07451 0.463525 + vertex 7.27009 -11.9684 1.46722 + vertex 7 -12.1244 1.5 + vertex 6.02009 -9.80336 1.46722 endloop endfacet - facet normal 0.500001 -0.866025 0 + facet normal -0.0905253 -0.0522648 -0.994522 outer loop - vertex 1.43542 -8.98622 4.5 - vertex 2.95808 -8.10711 -0.156793 - vertex 2.95808 -8.10711 0.156793 + vertex 6.02009 -9.80336 1.46722 + vertex 7 -12.1244 1.5 + vertex 5.75 -9.95929 1.5 endloop endfacet - facet normal 0.500001 -0.866025 0 + facet normal 0.0905253 0.0522648 -0.994522 outer loop - vertex 1.43542 -8.98622 -4.5 - vertex 2.95808 -8.10711 -0.156793 - vertex 1.43542 -8.98622 4.5 + vertex 7 -12.1244 1.5 + vertex 6.72991 -12.2803 1.46722 + vertex 5.75 -9.95929 1.5 endloop endfacet - facet normal 0.49998 -0.866037 2.604e-05 + facet normal 0.0905253 0.0522648 -0.994522 outer loop - vertex 4.13521 -7.42749 -1.48607 - vertex 1.43542 -8.98622 -4.5 - vertex 4.25 -7.36122 -1.5 + vertex 5.75 -9.95929 1.5 + vertex 6.72991 -12.2803 1.46722 + vertex 5.47991 -10.1152 1.46722 endloop endfacet - facet normal 0.500012 -0.866018 -1.33338e-05 + facet normal 0.267616 0.154508 -0.951057 outer loop - vertex 3.97992 -7.51715 -1.46722 - vertex 1.43542 -8.98622 -4.5 - vertex 4.13521 -7.42749 -1.48607 + vertex 6.72991 -12.2803 1.46722 + vertex 6.47163 -12.4294 1.37032 + vertex 5.47991 -10.1152 1.46722 endloop endfacet - facet normal 0.499993 -0.86603 8.61935e-06 + facet normal 0.267616 0.154508 -0.951057 outer loop - vertex 3.72163 -7.66627 -1.37032 - vertex 1.43542 -8.98622 -4.5 - vertex 3.97992 -7.51715 -1.46722 + vertex 5.47991 -10.1152 1.46722 + vertex 6.47163 -12.4294 1.37032 + vertex 5.22163 -10.2643 1.37032 endloop endfacet - facet normal 0.499988 -0.866033 1.38043e-05 + facet normal 0.433013 0.25 -0.866025 outer loop - vertex 3.48644 -7.80205 -1.21352 - vertex 1.43542 -8.98622 -4.5 - vertex 3.72163 -7.66627 -1.37032 + vertex 6.47163 -12.4294 1.37032 + vertex 6.23644 -12.5652 1.21353 + vertex 5.22163 -10.2643 1.37032 endloop endfacet - facet normal 0.500011 -0.866019 -5.94142e-06 + facet normal 0.433013 0.25 -0.866025 outer loop - vertex 3.28463 -7.91857 -1.0037 - vertex 1.43542 -8.98622 -4.5 - vertex 3.48644 -7.80205 -1.21352 + vertex 5.22163 -10.2643 1.37032 + vertex 6.23644 -12.5652 1.21353 + vertex 4.98644 -10.4001 1.21353 endloop endfacet - facet normal 0.500021 -0.866014 -1.25155e-05 + facet normal 0.579484 0.334565 -0.743145 outer loop - vertex 3.19284 -7.97157 -0.857821 - vertex 1.43542 -8.98622 -4.5 - vertex 3.28463 -7.91857 -1.0037 + vertex 6.23644 -12.5652 1.21353 + vertex 6.03463 -12.6817 1.0037 + vertex 4.98644 -10.4001 1.21353 endloop endfacet - facet normal 0.49996 -0.866048 2.63616e-05 + facet normal 0.579484 0.334565 -0.743145 outer loop - vertex 3.125 -8.01073 -0.75 - vertex 1.43542 -8.98622 -4.5 - vertex 3.19284 -7.97157 -0.857821 + vertex 4.98644 -10.4001 1.21353 + vertex 6.03463 -12.6817 1.0037 + vertex 4.78463 -10.5167 1.0037 endloop endfacet - facet normal 0.500061 -0.86599 -3.40584e-05 + facet normal 0.700629 0.404508 -0.587785 outer loop - vertex 3.07806 -8.03784 -0.628248 - vertex 1.43542 -8.98622 -4.5 - vertex 3.125 -8.01073 -0.75 + vertex 4.78463 -10.5167 1.0037 + vertex 6.03463 -12.6817 1.0037 + vertex 5.875 -12.7739 0.75 endloop endfacet - facet normal 0.499984 -0.866034 9.20302e-06 + facet normal 0.700629 0.404508 -0.587785 outer loop - vertex 3.01454 -8.07451 -0.463525 - vertex 1.43542 -8.98622 -4.5 - vertex 3.07806 -8.03784 -0.628248 + vertex 4.625 -10.6088 0.75 + vertex 4.78463 -10.5167 1.0037 + vertex 5.875 -12.7739 0.75 endloop endfacet - facet normal 0.500012 -0.866019 -5.06456e-06 + facet normal 0.791153 0.456773 -0.406737 outer loop - vertex 2.95808 -8.10711 -0.156793 - vertex 1.43542 -8.98622 -4.5 - vertex 3.01454 -8.07451 -0.463525 + vertex 4.625 -10.6088 0.75 + vertex 5.875 -12.7739 0.75 + vertex 5.76454 -12.8376 0.463525 endloop endfacet - facet normal 0.500028 -0.866009 -3.4858e-05 + facet normal 0.791153 0.456773 -0.406737 outer loop - vertex 4.4053 -7.27155 1.48115 - vertex 7.06458 -5.73622 4.5 - vertex 4.25 -7.36122 1.5 + vertex 4.51454 -10.6726 0.463525 + vertex 4.625 -10.6088 0.75 + vertex 5.76454 -12.8376 0.463525 endloop endfacet - facet normal 0.500009 -0.86602 -1.19855e-05 + facet normal 0.847101 0.489074 -0.207912 outer loop - vertex 4.52008 -7.20528 1.46722 - vertex 7.06458 -5.73622 4.5 - vertex 4.4053 -7.27155 1.48115 + vertex 4.51454 -10.6726 0.463525 + vertex 5.76454 -12.8376 0.463525 + vertex 5.70808 -12.8702 0.156793 endloop endfacet - facet normal 0.499992 -0.86603 6.44743e-06 + facet normal 0.847101 0.489074 -0.207912 outer loop - vertex 4.77837 -7.05616 1.37032 - vertex 7.06458 -5.73622 4.5 - vertex 4.52008 -7.20528 1.46722 + vertex 4.45808 -10.7052 0.156793 + vertex 4.51454 -10.6726 0.463525 + vertex 5.70808 -12.8702 0.156793 endloop endfacet - facet normal 0.499997 -0.866027 1.49972e-06 + facet normal -0.579484 -0.334565 0.743145 outer loop - vertex 5.01355 -6.92038 1.21352 - vertex 7.06458 -5.73622 4.5 - vertex 4.77837 -7.05616 1.37032 + vertex 5.01356 -6.92038 -1.21352 + vertex 5.21537 -6.80386 -1.0037 + vertex 3.03254 -3.02307 -1.0037 endloop endfacet - facet normal 0.499998 -0.866027 9.15104e-07 + facet normal -0.579484 -0.334565 0.743145 outer loop - vertex 5.21537 -6.80386 1.0037 - vertex 7.06458 -5.73622 4.5 - vertex 5.01355 -6.92038 1.21352 + vertex 2.86722 -3.20282 -1.21352 + vertex 5.01356 -6.92038 -1.21352 + vertex 2.87726 -3.19552 -1.20241 endloop endfacet - facet normal 0.500013 -0.866018 -9.63672e-06 + facet normal -0.579484 -0.334565 0.743145 outer loop - vertex 5.28321 -6.76469 0.895875 - vertex 7.06458 -5.73622 4.5 - vertex 5.21537 -6.80386 1.0037 + vertex 2.87726 -3.19552 -1.20241 + vertex 5.01356 -6.92038 -1.21352 + vertex 3.03254 -3.02307 -1.0037 endloop endfacet - facet normal 0.49998 -0.866037 1.24111e-05 + facet normal -0.587785 0.809017 0 outer loop - vertex 5.375 -6.7117 0.749999 - vertex 7.06458 -5.73622 4.5 - vertex 5.28321 -6.76469 0.895875 + vertex 2.87726 -3.19552 4.5 + vertex 2.87726 -3.19552 1.20241 + vertex 2.15 -3.72391 4.5 endloop endfacet - facet normal 0.500012 -0.866019 -6.98183e-06 + facet normal -0.587785 0.809017 0 outer loop - vertex 5.43851 -6.67503 0.585277 - vertex 7.06458 -5.73622 4.5 - vertex 5.375 -6.7117 0.749999 + vertex 2.15 -3.72391 4.5 + vertex 2.87726 -3.19552 1.20241 + vertex 2.86722 -3.20282 1.21353 endloop endfacet - facet normal 0.500022 -0.866013 -1.2767e-05 + facet normal -0.587785 0.809017 0 outer loop - vertex 5.48546 -6.64792 0.463525 - vertex 7.06458 -5.73622 4.5 - vertex 5.43851 -6.67503 0.585277 + vertex 2.15 -3.72391 4.5 + vertex 2.86722 -3.20282 1.21353 + vertex 2.6463 -3.36332 1.37032 endloop endfacet - facet normal 0.500009 -0.86602 -5.75105e-06 + facet normal -0.587785 0.809017 0 outer loop - vertex 5.54192 -6.61532 0.156793 - vertex 7.06458 -5.73622 4.5 - vertex 5.48546 -6.64792 0.463525 + vertex 2.6463 -3.36332 1.37032 + vertex 2.4037 -3.53959 1.46722 + vertex 2.15 -3.72391 4.5 endloop endfacet - facet normal 0.499997 -0.866027 0 + facet normal -0.587785 0.809017 0 outer loop - vertex 5.54192 -6.61532 -0.156793 - vertex 7.06458 -5.73622 4.5 - vertex 5.54192 -6.61532 0.156793 + vertex 2.4037 -3.53959 1.46722 + vertex 2.15 -3.72391 1.5 + vertex 2.15 -3.72391 4.5 endloop endfacet - facet normal 0.500009 -0.86602 5.75105e-06 + facet normal -0.579484 -0.334565 -0.743145 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 5.54192 -6.61532 -0.156793 - vertex 5.48546 -6.64792 -0.463525 + vertex 3.03254 -3.02307 1.0037 + vertex 5.21537 -6.80386 1.0037 + vertex 2.87726 -3.19552 1.20241 endloop endfacet - facet normal 0.500059 -0.865992 3.51233e-05 + facet normal -0.579484 -0.334565 -0.743145 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 5.42194 -6.68459 -0.628248 - vertex 5.375 -6.7117 -0.75 + vertex 2.87726 -3.19552 1.20241 + vertex 5.21537 -6.80386 1.0037 + vertex 5.01356 -6.92038 1.21353 endloop endfacet - facet normal 0.5 -0.866025 -1.82191e-16 + facet normal -0.579484 -0.334565 -0.743145 outer loop - vertex 7.06458 -5.73622 -4.5 - vertex 4.25 -7.36122 -1.5 - vertex 1.43542 -8.98622 -4.5 + vertex 2.87726 -3.19552 1.20241 + vertex 5.01356 -6.92038 1.21353 + vertex 2.86722 -3.20282 1.21353 endloop endfacet - facet normal 0.50003 -0.866008 3.75061e-05 + facet normal -0.700629 -0.404508 -0.587785 outer loop - vertex 4.25 -7.36122 -1.5 - vertex 7.06458 -5.73622 -4.5 - vertex 4.36479 -7.29494 -1.48607 + vertex 5.375 -6.7117 0.75 + vertex 5.21537 -6.80386 1.0037 + vertex 3.16222 -2.87905 0.75 endloop endfacet - facet normal 0.500012 -0.866018 1.59254e-05 + facet normal -0.700629 -0.404508 -0.587785 outer loop - vertex 4.36479 -7.29494 -1.48607 - vertex 7.06458 -5.73622 -4.5 - vertex 4.52008 -7.20528 -1.46722 + vertex 3.16222 -2.87905 0.75 + vertex 5.21537 -6.80386 1.0037 + vertex 3.03254 -3.02307 1.0037 endloop endfacet - facet normal 0.499992 -0.86603 -6.44743e-06 + facet normal -0.791153 -0.456773 -0.406737 outer loop - vertex 4.52008 -7.20528 -1.46722 - vertex 7.06458 -5.73622 -4.5 - vertex 4.77837 -7.05616 -1.37032 + vertex 5.48546 -6.64792 0.463525 + vertex 5.375 -6.7117 0.75 + vertex 3.25196 -2.77938 0.463525 endloop endfacet - facet normal 0.499997 -0.866027 0 + facet normal -0.791153 -0.456773 -0.406737 outer loop - vertex 5.54192 -6.61532 -0.156793 - vertex 7.06458 -5.73622 -4.5 - vertex 7.06458 -5.73622 4.5 + vertex 3.25196 -2.77938 0.463525 + vertex 5.375 -6.7117 0.75 + vertex 3.16222 -2.87905 0.75 endloop endfacet - facet normal 0.499982 -0.866036 -8.138e-06 + facet normal -0.847101 -0.489074 -0.207912 outer loop - vertex 5.42194 -6.68459 -0.628248 - vertex 7.06458 -5.73622 -4.5 - vertex 5.48546 -6.64792 -0.463525 + vertex 5.54192 -6.61532 0.156793 + vertex 5.48546 -6.64792 0.463525 + vertex 3.29783 -2.72844 0.156793 endloop endfacet - facet normal 0.499959 -0.866049 -2.50159e-05 + facet normal -0.847101 -0.489074 -0.207912 outer loop - vertex 5.30716 -6.75086 -0.857821 - vertex 7.06458 -5.73622 -4.5 - vertex 5.375 -6.7117 -0.75 + vertex 3.29783 -2.72844 0.156793 + vertex 5.48546 -6.64792 0.463525 + vertex 3.25196 -2.77938 0.463525 endloop endfacet - facet normal 0.500019 -0.866014 1.38612e-05 + facet normal -0.866025 -0.5 -1.92296e-16 outer loop - vertex 5.21537 -6.80386 -1.0037 - vertex 7.06458 -5.73622 -4.5 - vertex 5.30716 -6.75086 -0.857821 + vertex 5.54192 -6.61532 -0.156793 + vertex 5.54192 -6.61532 0.156793 + vertex 3.29783 -2.72844 -0.156793 endloop endfacet - facet normal 0.499998 -0.866027 -9.15104e-07 + facet normal -0.866025 -0.5 -1.92296e-16 outer loop - vertex 5.01355 -6.92038 -1.21352 - vertex 7.06458 -5.73622 -4.5 - vertex 5.21537 -6.80386 -1.0037 + vertex 3.29783 -2.72844 -0.156793 + vertex 5.54192 -6.61532 0.156793 + vertex 3.29783 -2.72844 0.156793 endloop endfacet - facet normal 0.499997 -0.866027 -1.49972e-06 + facet normal -0.847101 -0.489074 0.207912 outer loop - vertex 4.77837 -7.05616 -1.37032 - vertex 7.06458 -5.73622 -4.5 - vertex 5.01355 -6.92038 -1.21352 + vertex 5.54192 -6.61532 -0.156793 + vertex 3.29783 -2.72844 -0.156793 + vertex 5.48546 -6.64792 -0.463525 endloop endfacet - facet normal -0.500001 0.866025 1.44337e-06 + facet normal -0.847101 -0.489074 0.207912 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 5.75 -9.95929 1.5 - vertex 2.93542 -11.5843 4.5 + vertex 5.48546 -6.64792 -0.463525 + vertex 3.29783 -2.72844 -0.156793 + vertex 3.25196 -2.77938 -0.463525 endloop endfacet - facet normal -0.49998 0.866037 -2.604e-05 + facet normal -0.791153 -0.456773 0.406737 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 5.86479 -9.89302 1.48607 - vertex 5.75 -9.95929 1.5 + vertex 5.48546 -6.64792 -0.463525 + vertex 3.25196 -2.77938 -0.463525 + vertex 5.375 -6.7117 -0.75 endloop endfacet - facet normal -0.500012 0.866018 1.33338e-05 + facet normal -0.791153 -0.456773 0.406737 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.02008 -9.80336 1.46722 - vertex 5.86479 -9.89302 1.48607 + vertex 5.375 -6.7117 -0.75 + vertex 3.25196 -2.77938 -0.463525 + vertex 3.16222 -2.87905 -0.75 endloop endfacet - facet normal -0.499993 0.86603 -8.61935e-06 + facet normal -0.700629 -0.404508 0.587785 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.27837 -9.65424 1.37032 - vertex 6.02008 -9.80336 1.46722 + vertex 5.375 -6.7117 -0.75 + vertex 3.16222 -2.87905 -0.75 + vertex 5.21537 -6.80386 -1.0037 endloop endfacet - facet normal -0.500017 0.866016 1.47287e-05 + facet normal -0.700629 -0.404508 0.587785 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.51355 -9.51845 1.21352 - vertex 6.27837 -9.65424 1.37032 + vertex 5.21537 -6.80386 -1.0037 + vertex 3.16222 -2.87905 -0.75 + vertex 3.03254 -3.02307 -1.0037 endloop endfacet - facet normal -0.499998 0.866027 -9.15104e-07 + facet normal -0.0905253 -0.0522648 0.994522 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.71537 -9.40193 1.0037 - vertex 6.51355 -9.51845 1.21352 + vertex 4.25 -7.36122 -1.5 + vertex 4.52009 -7.20528 -1.46722 + vertex 2.4037 -3.53959 -1.46722 endloop endfacet - facet normal -0.499981 0.866037 -1.32507e-05 + facet normal -0.0905253 -0.0522648 0.994522 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.80716 -9.34894 0.857821 - vertex 6.71537 -9.40193 1.0037 + vertex 2.15 -3.72391 -1.5 + vertex 4.25 -7.36122 -1.5 + vertex 2.4037 -3.53959 -1.46722 endloop endfacet - facet normal -0.500014 0.866017 8.50084e-06 + facet normal -0.433013 -0.25 0.866025 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.875 -9.30977 0.75 - vertex 6.80716 -9.34894 0.857821 + vertex 4.77837 -7.05616 -1.37032 + vertex 5.01356 -6.92038 -1.21352 + vertex 2.86722 -3.20282 -1.21352 endloop endfacet - facet normal -0.499995 0.866028 -3.20608e-06 + facet normal -0.433013 -0.25 0.866025 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.92194 -9.28267 0.628248 - vertex 6.875 -9.30977 0.75 + vertex 2.6463 -3.36332 -1.37032 + vertex 4.77837 -7.05616 -1.37032 + vertex 2.86722 -3.20282 -1.21352 endloop endfacet - facet normal -0.499984 0.866034 -9.20302e-06 + facet normal -0.267616 -0.154508 0.951057 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 6.98546 -9.246 0.463525 - vertex 6.92194 -9.28267 0.628248 + vertex 4.52009 -7.20528 -1.46722 + vertex 4.77837 -7.05616 -1.37032 + vertex 2.6463 -3.36332 -1.37032 endloop endfacet - facet normal -0.500012 0.866019 5.06456e-06 + facet normal -0.267616 -0.154508 0.951057 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 7.04192 -9.2134 0.156793 - vertex 6.98546 -9.246 0.463525 + vertex 2.4037 -3.53959 -1.46722 + vertex 4.52009 -7.20528 -1.46722 + vertex 2.6463 -3.36332 -1.37032 endloop endfacet - facet normal -0.500001 0.866025 0 + facet normal 0.579484 0.334565 0.743145 outer loop - vertex 8.56458 -8.33429 4.5 - vertex 7.04192 -9.2134 -0.156793 - vertex 7.04192 -9.2134 0.156793 + vertex 3.28463 -7.91857 -1.0037 + vertex 3.48644 -7.80205 -1.21352 + vertex 1.34011 -4.0845 -1.21352 endloop endfacet - facet normal -0.500001 0.866025 0 + facet normal 0.579484 0.334565 0.743145 outer loop - vertex 8.56458 -8.33429 -4.5 - vertex 7.04192 -9.2134 -0.156793 - vertex 8.56458 -8.33429 4.5 + vertex 1.10179 -4.13779 -1.0037 + vertex 3.28463 -7.91857 -1.0037 + vertex 1.32877 -4.08954 -1.20241 endloop endfacet - facet normal -0.499956 0.866051 2.41198e-05 + facet normal 0.579484 0.334565 0.743145 outer loop - vertex 8.56458 -8.33429 -4.5 - vertex 6.93851 -9.2731 -0.585277 - vertex 6.98546 -9.246 -0.463525 + vertex 1.32877 -4.08954 -1.20241 + vertex 3.28463 -7.91857 -1.0037 + vertex 1.34011 -4.0845 -1.21352 endloop endfacet - facet normal -0.500009 0.86602 -9.39386e-06 + facet normal 0.0905253 0.0522648 0.994522 outer loop - vertex 8.56458 -8.33429 -4.5 - vertex 5.9053 -9.86963 -1.48115 - vertex 6.02008 -9.80336 -1.46722 + vertex 3.97991 -7.51715 -1.46722 + vertex 4.25 -7.36122 -1.5 + vertex 2.15 -3.72391 -1.5 endloop endfacet - facet normal -0.499991 0.866031 1.21108e-05 + facet normal 0.0905253 0.0522648 0.994522 outer loop - vertex 5.9053 -9.86963 -1.48115 - vertex 8.56458 -8.33429 -4.5 - vertex 5.75 -9.95929 -1.5 + vertex 1.86352 -3.85146 -1.46722 + vertex 3.97991 -7.51715 -1.46722 + vertex 2.15 -3.72391 -1.5 endloop endfacet - facet normal -0.499993 0.86603 8.61935e-06 + facet normal 0.267616 0.154508 0.951057 outer loop - vertex 6.27837 -9.65424 -1.37032 - vertex 8.56458 -8.33429 -4.5 - vertex 6.02008 -9.80336 -1.46722 + vertex 3.72163 -7.66627 -1.37032 + vertex 3.97991 -7.51715 -1.46722 + vertex 1.86352 -3.85146 -1.46722 endloop endfacet - facet normal -0.500017 0.866016 -1.47287e-05 + facet normal 0.267616 0.154508 0.951057 outer loop - vertex 6.51355 -9.51845 -1.21352 - vertex 8.56458 -8.33429 -4.5 - vertex 6.27837 -9.65424 -1.37032 + vertex 1.58957 -3.97343 -1.37032 + vertex 3.72163 -7.66627 -1.37032 + vertex 1.86352 -3.85146 -1.46722 endloop endfacet - facet normal -0.499998 0.866027 9.15104e-07 + facet normal 0.433013 0.25 0.866025 outer loop - vertex 6.71537 -9.40193 -1.0037 - vertex 8.56458 -8.33429 -4.5 - vertex 6.51355 -9.51845 -1.21352 + vertex 3.48644 -7.80205 -1.21352 + vertex 3.72163 -7.66627 -1.37032 + vertex 1.58957 -3.97343 -1.37032 endloop endfacet - facet normal -0.500013 0.866018 -9.63672e-06 + facet normal 0.433013 0.25 0.866025 outer loop - vertex 6.78321 -9.36276 -0.895875 - vertex 8.56458 -8.33429 -4.5 - vertex 6.71537 -9.40193 -1.0037 + vertex 1.34011 -4.0845 -1.21352 + vertex 3.48644 -7.80205 -1.21352 + vertex 1.58957 -3.97343 -1.37032 endloop endfacet - facet normal -0.49998 0.866037 1.24111e-05 + facet normal 0.700629 0.404508 0.587785 outer loop - vertex 6.875 -9.30977 -0.749999 - vertex 8.56458 -8.33429 -4.5 - vertex 6.78321 -9.36276 -0.895875 + vertex 3.125 -8.01073 -0.75 + vertex 3.28463 -7.91857 -1.0037 + vertex 1.10179 -4.13779 -1.0037 endloop endfacet - facet normal -0.500012 0.866019 -6.98183e-06 + facet normal 0.700629 0.404508 0.587785 outer loop - vertex 6.93851 -9.2731 -0.585277 - vertex 8.56458 -8.33429 -4.5 - vertex 6.875 -9.30977 -0.749999 + vertex 0.912218 -4.17808 -0.75 + vertex 3.125 -8.01073 -0.75 + vertex 1.10179 -4.13779 -1.0037 endloop endfacet - facet normal -0.500012 0.866019 -5.06456e-06 + facet normal 0.791153 0.456773 0.406737 outer loop - vertex 7.04192 -9.2134 -0.156793 - vertex 8.56458 -8.33429 -4.5 - vertex 6.98546 -9.246 -0.463525 + vertex 3.01454 -8.07451 -0.463525 + vertex 3.125 -8.01073 -0.75 + vertex 0.912218 -4.17808 -0.75 endloop endfacet - facet normal -0.500183 0.86592 -0.000225527 + facet normal 0.791153 0.456773 0.406737 outer loop - vertex 5.63521 -10.0256 1.48607 - vertex 2.93542 -11.5843 4.5 - vertex 5.75 -9.95929 1.5 + vertex 0.781038 -4.20597 -0.463525 + vertex 3.01454 -8.07451 -0.463525 + vertex 0.912218 -4.17808 -0.75 endloop endfacet - facet normal -0.499764 0.866162 0.00027527 + facet normal 0.847101 0.489074 0.207912 outer loop - vertex 5.47991 -10.1152 1.46722 - vertex 2.93542 -11.5843 4.5 - vertex 5.63521 -10.0256 1.48607 + vertex 2.95808 -8.10711 -0.156793 + vertex 3.01454 -8.07451 -0.463525 + vertex 0.781038 -4.20597 -0.463525 endloop endfacet - facet normal -0.499968 0.866044 4.68304e-05 + facet normal 0.847101 0.489074 0.207912 outer loop - vertex 5.22163 -10.2643 1.37032 - vertex 2.93542 -11.5843 4.5 - vertex 5.47991 -10.1152 1.46722 + vertex 0.713983 -4.22022 -0.156793 + vertex 2.95808 -8.10711 -0.156793 + vertex 0.781038 -4.20597 -0.463525 endloop endfacet - facet normal -0.500029 0.866008 -1.30691e-05 + facet normal 0.866025 0.5 1.92296e-16 outer loop - vertex 4.98644 -10.4001 1.21352 - vertex 2.93542 -11.5843 4.5 - vertex 5.22163 -10.2643 1.37032 + vertex 2.95808 -8.10711 0.156793 + vertex 2.95808 -8.10711 -0.156793 + vertex 0.713983 -4.22022 -0.156793 endloop endfacet - facet normal -0.500171 0.865927 -0.00013107 + facet normal 0.866025 0.5 1.92296e-16 outer loop - vertex 4.78463 -10.5167 1.0037 - vertex 2.93542 -11.5843 4.5 - vertex 4.98644 -10.4001 1.21352 + vertex 0.713983 -4.22022 0.156793 + vertex 2.95808 -8.10711 0.156793 + vertex 0.713983 -4.22022 -0.156793 endloop endfacet - facet normal -0.499855 0.866109 9.16874e-05 + facet normal 0.847101 0.489074 -0.207912 outer loop - vertex 4.625 -10.6088 0.75 - vertex 2.93542 -11.5843 4.5 - vertex 4.78463 -10.5167 1.0037 + vertex 0.781038 -4.20597 0.463525 + vertex 3.01454 -8.07451 0.463525 + vertex 2.95808 -8.10711 0.156793 endloop endfacet - facet normal -0.500074 0.865982 -3.99843e-05 + facet normal 0.847101 0.489074 -0.207912 outer loop - vertex 4.51454 -10.6726 0.463525 - vertex 2.93542 -11.5843 4.5 - vertex 4.625 -10.6088 0.75 + vertex 0.713983 -4.22022 0.156793 + vertex 0.781038 -4.20597 0.463525 + vertex 2.95808 -8.10711 0.156793 endloop endfacet - facet normal -0.500009 0.86602 -5.75105e-06 + facet normal 0.791153 0.456773 -0.406737 outer loop - vertex 4.45808 -10.7052 0.156793 - vertex 2.93542 -11.5843 4.5 - vertex 4.51454 -10.6726 0.463525 + vertex 0.912218 -4.17808 0.75 + vertex 3.125 -8.01073 0.75 + vertex 3.01454 -8.07451 0.463525 endloop endfacet - facet normal -0.499997 0.866027 0 + facet normal 0.791153 0.456773 -0.406737 outer loop - vertex 4.45808 -10.7052 -0.156793 - vertex 2.93542 -11.5843 4.5 - vertex 4.45808 -10.7052 0.156793 + vertex 0.781038 -4.20597 0.463525 + vertex 0.912218 -4.17808 0.75 + vertex 3.01454 -8.07451 0.463525 endloop endfacet - facet normal -0.500009 0.86602 5.75105e-06 + facet normal 0.700629 0.404508 -0.587785 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 4.45808 -10.7052 -0.156793 - vertex 4.51454 -10.6726 -0.463525 + vertex 1.10179 -4.13779 1.0037 + vertex 3.28463 -7.91857 1.0037 + vertex 3.125 -8.01073 0.75 endloop endfacet - facet normal -0.500179 0.865922 0.000220118 + facet normal 0.700629 0.404508 -0.587785 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 5.5947 -10.049 -1.48115 - vertex 5.75 -9.95929 -1.5 + vertex 0.912218 -4.17808 0.75 + vertex 1.10179 -4.13779 1.0037 + vertex 3.125 -8.01073 0.75 endloop endfacet - facet normal -0.500001 0.866025 -1.44337e-06 + facet normal 0.579484 0.334565 -0.743145 outer loop - vertex 2.93542 -11.5843 -4.5 - vertex 5.75 -9.95929 -1.5 - vertex 8.56458 -8.33429 -4.5 + vertex 1.34011 -4.0845 1.21353 + vertex 3.48644 -7.80205 1.21353 + vertex 1.32877 -4.08954 1.20241 endloop endfacet - facet normal -0.49962 0.866244 -0.000435295 + facet normal 0.579484 0.334565 -0.743145 outer loop - vertex 5.5947 -10.049 -1.48115 - vertex 2.93542 -11.5843 -4.5 - vertex 5.47991 -10.1152 -1.46722 + vertex 1.32877 -4.08954 1.20241 + vertex 3.48644 -7.80205 1.21353 + vertex 3.28463 -7.91857 1.0037 endloop endfacet - facet normal -0.499968 0.866044 -4.68304e-05 + facet normal 0.579484 0.334565 -0.743145 outer loop - vertex 5.47991 -10.1152 -1.46722 - vertex 2.93542 -11.5843 -4.5 - vertex 5.22163 -10.2643 -1.37032 + vertex 1.32877 -4.08954 1.20241 + vertex 3.28463 -7.91857 1.0037 + vertex 1.10179 -4.13779 1.0037 endloop endfacet - facet normal -0.499997 0.866027 0 + facet normal -0.406737 0.913545 0 outer loop - vertex 4.45808 -10.7052 -0.156793 - vertex 2.93542 -11.5843 -4.5 - vertex 2.93542 -11.5843 4.5 + vertex 2.15 -3.72391 4.5 + vertex 2.15 -3.72391 1.5 + vertex 1.32877 -4.08954 4.5 endloop endfacet - facet normal -0.499954 0.866052 -2.30547e-05 + facet normal -0.406737 0.913545 0 outer loop - vertex 4.56149 -10.6455 -0.585277 - vertex 2.93542 -11.5843 -4.5 - vertex 4.51454 -10.6726 -0.463525 + vertex 1.32877 -4.08954 4.5 + vertex 2.15 -3.72391 1.5 + vertex 1.86352 -3.85146 1.46722 endloop endfacet - facet normal -0.500157 0.865934 8.98355e-05 + facet normal -0.406737 0.913545 0 outer loop - vertex 4.625 -10.6088 -0.749999 - vertex 2.93542 -11.5843 -4.5 - vertex 4.56149 -10.6455 -0.585277 + vertex 1.86352 -3.85146 1.46722 + vertex 1.58957 -3.97343 1.37032 + vertex 1.32877 -4.08954 4.5 endloop endfacet - facet normal -0.500048 0.865998 2.39722e-05 + facet normal -0.406737 0.913545 0 outer loop - vertex 4.71678 -10.5558 -0.895875 - vertex 2.93542 -11.5843 -4.5 - vertex 4.625 -10.6088 -0.749999 + vertex 1.58957 -3.97343 1.37032 + vertex 1.34011 -4.0845 1.21353 + vertex 1.32877 -4.08954 4.5 endloop endfacet - facet normal -0.499612 0.866249 -0.000262979 + facet normal -0.406737 0.913545 0 outer loop - vertex 4.78463 -10.5167 -1.0037 - vertex 2.93542 -11.5843 -4.5 - vertex 4.71678 -10.5558 -0.895875 + vertex 1.34011 -4.0845 1.21353 + vertex 1.32877 -4.08954 1.20241 + vertex 1.32877 -4.08954 4.5 endloop endfacet - facet normal -0.500171 0.865927 0.00013107 + facet normal -0.433013 -0.25 -0.866025 outer loop - vertex 4.98644 -10.4001 -1.21352 - vertex 2.93542 -11.5843 -4.5 - vertex 4.78463 -10.5167 -1.0037 + vertex 5.01356 -6.92038 1.21353 + vertex 4.77837 -7.05616 1.37032 + vertex 2.86722 -3.20282 1.21353 endloop endfacet - facet normal -0.500029 0.866008 1.30691e-05 + facet normal -0.433013 -0.25 -0.866025 outer loop - vertex 5.22163 -10.2643 -1.37032 - vertex 2.93542 -11.5843 -4.5 - vertex 4.98644 -10.4001 -1.21352 + vertex 2.86722 -3.20282 1.21353 + vertex 4.77837 -7.05616 1.37032 + vertex 2.6463 -3.36332 1.37032 endloop endfacet - facet normal -0.866025 -0.500001 0 + facet normal -0.267616 -0.154508 -0.951057 outer loop - vertex 8.56458 -8.33429 -4.5 - vertex 7.06458 -5.73622 4.5 - vertex 7.06458 -5.73622 -4.5 + vertex 4.77837 -7.05616 1.37032 + vertex 4.52009 -7.20528 1.46722 + vertex 2.6463 -3.36332 1.37032 endloop endfacet - facet normal -0.866025 -0.500001 0 + facet normal -0.267616 -0.154508 -0.951057 outer loop - vertex 7.06458 -5.73622 4.5 - vertex 8.56458 -8.33429 -4.5 - vertex 8.56458 -8.33429 4.5 + vertex 2.6463 -3.36332 1.37032 + vertex 4.52009 -7.20528 1.46722 + vertex 2.4037 -3.53959 1.46722 endloop endfacet - facet normal 0.866026 0.499999 0 + facet normal -0.0905253 -0.0522648 -0.994522 outer loop - vertex 2.93542 -11.5843 4.5 - vertex 1.43542 -8.98622 -4.5 - vertex 1.43542 -8.98622 4.5 + vertex 2.4037 -3.53959 1.46722 + vertex 4.52009 -7.20528 1.46722 + vertex 2.15 -3.72391 1.5 endloop endfacet - facet normal 0.866026 0.499999 0 + facet normal -0.0905253 -0.0522648 -0.994522 outer loop - vertex 1.43542 -8.98622 -4.5 - vertex 2.93542 -11.5843 4.5 - vertex 2.93542 -11.5843 -4.5 + vertex 2.15 -3.72391 1.5 + vertex 4.52009 -7.20528 1.46722 + vertex 4.25 -7.36122 1.5 endloop endfacet - facet normal 1 -0 0 + facet normal 0.0905253 0.0522648 -0.994522 outer loop - vertex 18 -5.7735 4.5 - vertex 18 5.7735 -4.5 - vertex 18 5.7735 4.5 + vertex 4.25 -7.36122 1.5 + vertex 3.97991 -7.51715 1.46722 + vertex 2.15 -3.72391 1.5 endloop endfacet - facet normal 1 0 0 + facet normal 0.0905253 0.0522648 -0.994522 outer loop - vertex 18 5.7735 -4.5 - vertex 18 -5.7735 4.5 - vertex 18 -5.7735 -4.5 + vertex 2.15 -3.72391 1.5 + vertex 3.97991 -7.51715 1.46722 + vertex 1.86352 -3.85146 1.46722 endloop endfacet - facet normal -0.5 0.866026 0 + facet normal 0.267616 0.154508 -0.951057 outer loop - vertex -4 18.4752 -4.5 - vertex -14 12.7017 4.5 - vertex -4 18.4752 4.5 + vertex 3.97991 -7.51715 1.46722 + vertex 3.72163 -7.66627 1.37032 + vertex 1.86352 -3.85146 1.46722 endloop endfacet - facet normal -0.5 0.866026 0 + facet normal 0.267616 0.154508 -0.951057 outer loop - vertex -14 12.7017 4.5 - vertex -4 18.4752 -4.5 - vertex -14 12.7017 -4.5 + vertex 1.86352 -3.85146 1.46722 + vertex 3.72163 -7.66627 1.37032 + vertex 1.58957 -3.97343 1.37032 endloop endfacet - facet normal -0.5 -0.866026 0 + facet normal 0.433013 0.25 -0.866025 outer loop - vertex -14 -12.7017 -4.5 - vertex -4 -18.4752 4.5 - vertex -14 -12.7017 4.5 + vertex 3.72163 -7.66627 1.37032 + vertex 3.48644 -7.80205 1.21353 + vertex 1.58957 -3.97343 1.37032 endloop endfacet - facet normal -0.5 -0.866026 -0 + facet normal 0.433013 0.25 -0.866025 outer loop - vertex -4 -18.4752 4.5 - vertex -14 -12.7017 -4.5 - vertex -4 -18.4752 -4.5 + vertex 1.58957 -3.97343 1.37032 + vertex 3.48644 -7.80205 1.21353 + vertex 1.34011 -4.0845 1.21353 endloop endfacet endsolid OpenSCAD_Model diff --git a/licenses/LICENSE-RobotCalibration b/licenses/LICENSE-RobotCalibration new file mode 100644 index 00000000..24d2f4b9 --- /dev/null +++ b/licenses/LICENSE-RobotCalibration @@ -0,0 +1,203 @@ +Copyright 2012 Appium Committers + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/licenses/LICENSE-SVG-edit b/licenses/LICENSE-SVG-edit new file mode 100644 index 00000000..7d5de6e8 --- /dev/null +++ b/licenses/LICENSE-SVG-edit @@ -0,0 +1,21 @@ +Copyright (c) 2009-2018 by SVG-edit authors (see AUTHORS file) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +[This is the MIT License, https://opensource.org/licenses/MIT] \ No newline at end of file diff --git a/licenses/LICENSE-arduino.scad b/licenses/LICENSE-arduino.scad new file mode 100644 index 00000000..2e86fa17 --- /dev/null +++ b/licenses/LICENSE-arduino.scad @@ -0,0 +1,482 @@ + Copyright (C) Jestin Stoffel 2012 + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, see . + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Moe Ghoul, President of Vice + +That's all there is to it! diff --git a/licenses/LICENSE-tapster b/licenses/LICENSE-tapster new file mode 100644 index 00000000..531067a4 --- /dev/null +++ b/licenses/LICENSE-tapster @@ -0,0 +1,24 @@ +Copyright (c) 2011-2016, Tapster Committers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] diff --git a/software/README.md b/software/README.md new file mode 100644 index 00000000..1fb28e48 --- /dev/null +++ b/software/README.md @@ -0,0 +1,3 @@ +# software folder + +Here are pieces of softwares to use so as to use/drive/update/improve/fix the bot, run it and make things with it. diff --git a/software/config.js b/software/config.js deleted file mode 100644 index fc2a48c5..00000000 --- a/software/config.js +++ /dev/null @@ -1,55 +0,0 @@ -var config = {} - -//Side of end effector -//~~Do not touch~~ -config.e = 34.64101615137754; // Math.sqrt(3) * 10 * 2 - -//Side of top triangle -//~~Do not touch~~ -config.f = 110.85125168440814; // Math.sqrt(3) * 32 * 2 - -//Length of parallelogram joint -//~~Do not touch~~ -config.re = 153.5; // 145 + 8.5 - -//Length of upper joint -//~~Do not touch~~ -config.rf = 52.690131903421914; // Math.sqrt(52**2 + 8.5**2) - -//Input ranges for servos -//~~Do not touch~~ -config.servo1 = {in_min: 0, in_max: 90}; -config.servo2 = {in_min: 0, in_max: 90}; -config.servo3 = {in_min: 0, in_max: 90}; - -//Default output ranges for servos -//CHANGE THESE -config.servo1.out_min = 12; -config.servo1.out_max = 93; -config.servo2.out_min = 8; -config.servo2.out_max = 90; -config.servo3.out_min = 14; -config.servo3.out_max = 96; - -//Dimensions of the base plate -config.baseHeight = 95; -config.baseWidth = 80; - -//Default Z-Level of the pen -config.penHeight = -140; - -//Default drawing height of the pen -config.drawHeight = -152.75; - -//Delay for commands in SVGReader -//Note that some commands will take longer than this -//Default value is 150 -config.delay = 200; - -//The default easing type to be used -//When no easing is specified, this is the type that will be used -//"none" means that if no easing is specified, do not ease -//For a list of possible easing types, look in motion.js -config.defaultEaseType = "linear"; - -module.exports = config; \ No newline at end of file diff --git a/software/doc/json-api.md b/software/doc/json-api.md deleted file mode 100644 index 2d68eb77..00000000 --- a/software/doc/json-api.md +++ /dev/null @@ -1,59 +0,0 @@ -## Go to any point: - HTTP POST /go - - x: Center of circle, millimeters (Number, float) - y: Center of circle, millimeters (Number, float) - z: Center of circle, millimeters (Number, float) - - Example: - { x: 0, - y: 0, - z: -144 } - -## Draw a Circle: - HTTP POST /circle - - x: Center of circle, millimeters (Number, float) - y: Center of circle, millimeters (Number, float) - z: Center of circle, millimeters (Number, float) - radius: Radius of circle, millimeters (Number, float) - startAngle: Starting angle, radians (Number, float) - anticlockwise: Set to true to go anticlockwise, false to go clockwise (Boolean) - delay: Number of milliseconds of delay to add between each point (Number, integer) - rotations: Number of rotations (Number, integer) - - Note: This will draw complete circles. The end angle will be the same as the start angle. - - Example: - { x: 0, - y: 0, - z: -158, - radius: 20, - startAngle: 0, - anticlockwise: true, - delay: 5, - rotations: 5 } - -## Draw an Arc: - HTTP POST /arc - - x: Center of circle, millimeters (Number, float) - y: Center of circle, millimeters (Number, float) - z: Center of circle, millimeters (Number, float) - radius: Radius of circle, millimeters (Number, float) - startAngle: Starting angle, radians (Number, float) - endAngle: Ending angle, radians (Number, float) - anticlockwise: Set to true to go anticlockwise, false to go clockwise (Boolean) - delay: Number of milliseconds of delay to add between each point (Number, integer) - - Note: This will draw one arc. If startAngle and endAngle are the same, it will draw one complete circle. - If you want to draw more than one complete circle, use the "/circle" command. - - { x: 0, - y: 0, - z: -158, - radius: 20, - startAngle: 1.57, - endAngle: 3.14, - anticlockwise: false, - delay: 5 } diff --git a/software/package.json b/software/package.json old mode 100755 new mode 100644 index da413d31..8821f9b9 --- a/software/package.json +++ b/software/package.json @@ -1,26 +1,36 @@ { - "name":"tapster", - "description":"Mobile automation robot", - "version":"2.0.0", - "homepage":"", - "author":[ + "name": "tapster", + "description": "Mobile automation robot", + "version": "2.0.0", + "homepage": "", + "authors": [ { - "name":"Jason Huggins", - "email":"jrhuggins@gmail.com" + "name": "Jason Huggins", + "email": "jrhuggins@gmail.com" + }, + { + "name": "Orange", + "email": "pierreyves.lapersonne@orange.com" } ], - "repository":{ - "type":"git", - "url":"https://github.com/tapsterbot/tapsterbot.git" + "repository": { + "type": "git", + "url": "https://github.com/Orange-OpenSource/tapsterbot" }, - "engines":{ - "node":"*" + "engines": { + "node": "*" }, "dependencies": { - "johnny-five": "*", - "svg-path-parser": "*", - "xml2js": "*", - "express": "*", - "body-parser": "*" + "prompt": "1.0.0", + "fs": "0.0.2", + "os": "0.1.1", + "argparse": "1.0.9", + "wd": "1.5.0", + "hapi": "17.2.0", + "path": "0.12.7", + "johnny-five": "0.13.0", + "sylvester": "0.0.21", + "xml2js": "0.4.19", + "svg-path-parser": "1.1.0" } } diff --git a/software/recorder/index.html b/software/recorder/index.html deleted file mode 100644 index 46020822..00000000 --- a/software/recorder/index.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - -Tracing a line with d3.js - - - - -
-
- - - - - - - - - - diff --git a/software/recorder/simplify.js b/software/recorder/simplify.js deleted file mode 100644 index fa867462..00000000 --- a/software/recorder/simplify.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - (c) 2013, Vladimir Agafonkin - Simplify.js, a high-performance JS polyline simplification library - mourner.github.io/simplify-js -*/ - -(function () { 'use strict'; - -// to suit your point format, run search/replace for '.x' and '.y'; -// for 3D version, see 3d branch (configurability would draw significant performance overhead) - -// square distance between 2 points -function getSqDist(p1, p2) { - - var dx = p1.x - p2.x, - dy = p1.y - p2.y; - - return dx * dx + dy * dy; -} - -// square distance from a point to a segment -function getSqSegDist(p, p1, p2) { - - var x = p1.x, - y = p1.y, - dx = p2.x - x, - dy = p2.y - y; - - if (dx !== 0 || dy !== 0) { - - var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy); - - if (t > 1) { - x = p2.x; - y = p2.y; - - } else if (t > 0) { - x += dx * t; - y += dy * t; - } - } - - dx = p.x - x; - dy = p.y - y; - - return dx * dx + dy * dy; -} -// rest of the code doesn't care about point format - -// basic distance-based simplification -function simplifyRadialDist(points, sqTolerance) { - - var prevPoint = points[0], - newPoints = [prevPoint], - point; - - for (var i = 1, len = points.length; i < len; i++) { - point = points[i]; - - if (getSqDist(point, prevPoint) > sqTolerance) { - newPoints.push(point); - prevPoint = point; - } - } - - if (prevPoint !== point) newPoints.push(point); - - return newPoints; -} - -// simplification using optimized Douglas-Peucker algorithm with recursion elimination -function simplifyDouglasPeucker(points, sqTolerance) { - - var len = points.length, - MarkerArray = typeof Uint8Array !== 'undefined' ? Uint8Array : Array, - markers = new MarkerArray(len), - first = 0, - last = len - 1, - stack = [], - newPoints = [], - i, maxSqDist, sqDist, index; - - markers[first] = markers[last] = 1; - - while (last) { - - maxSqDist = 0; - - for (i = first + 1; i < last; i++) { - sqDist = getSqSegDist(points[i], points[first], points[last]); - - if (sqDist > maxSqDist) { - index = i; - maxSqDist = sqDist; - } - } - - if (maxSqDist > sqTolerance) { - markers[index] = 1; - stack.push(first, index, index, last); - } - - last = stack.pop(); - first = stack.pop(); - } - - for (i = 0; i < len; i++) { - if (markers[i]) newPoints.push(points[i]); - } - - return newPoints; -} - -// both algorithms combined for awesome performance -function simplify(points, tolerance, highestQuality) { - - if (points.length <= 1) return points; - - var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1; - - points = highestQuality ? points : simplifyRadialDist(points, sqTolerance); - points = simplifyDouglasPeucker(points, sqTolerance); - - return points; -} - -// export as AMD module / Node module / browser or worker variable -if (typeof define === 'function' && define.amd) define(function() { return simplify; }); -else if (typeof module !== 'undefined') module.exports = simplify; -else if (typeof self !== 'undefined') self.simplify = simplify; -else window.simplify = simplify; - -})(); diff --git a/software/src/README.md b/software/src/README.md new file mode 100644 index 00000000..dbe8f608 --- /dev/null +++ b/software/src/README.md @@ -0,0 +1,6 @@ +# src folder + +Here scripts and libraries to use so as to drive the Tapster 2 bot. +The documentation is available in the root _doc_ folder. +Some clients defined in the root _clients_ folder can be used so as to drive the robot. +You may need to calibrate the robot using the tools available in the root _calibration_ folder. diff --git a/software/src/SVGReader.js b/software/src/SVGReader.js deleted file mode 100644 index 52e2fdc1..00000000 --- a/software/src/SVGReader.js +++ /dev/null @@ -1,901 +0,0 @@ -//Draws stuff from SVG files -//Built with InkScape in mind, but should support: -//http://svg-edit.googlecode.com/svn/branches/stable/editor/svg-editor.html -//> To test: -//> svgRead.drawSVG(filepath) - -var parse = require('svg-path-parser'); -var fs = require('fs'); -var draw = require("./draw"); -var parseString = require('xml2js').parseString; - -function SVGReader(args) { - this.baseWidth = 80; - this.baseHeight = 95; - this.drawHeight = -140; - this.delay = 150; - this.defaultEaseType = "linear"; - - if (args) { - var keys = Object.keys(args) - keys.forEach(function(key){ - this[key] = args[key] - }, this) - } - objRef = this; - defaultEaseType = this.defaultEaseType; -} - -//Draws from an SVG image specified by filepath -//> Usage: -//> drawSVG("C:/Projects/Tapsterbot/software/src/drawing.svg"); -//Note: filePath can be relative -//connect is a special flag that indicates that each path should be drawn connected to each other -//It is really only used for drawing in cursive and does not need to be specified otherwise -SVGReader.prototype.drawSVG = function(filePath, connect) { - resetTimer(); - var parsed; - - if (connect) - connected = connect; - else - connected = null; - - objRef = this; - - //Create a JSON string out of the SVG image data - //parseString strips away the XML data - try { - parseString(fs.readFileSync(filePath, "utf8"), function(err, result) { - parsed = JSON.stringify(result, null, 1); - }); - } catch (e) { - if (e.code === "ENOENT") - console.log("File not found."); - else - throw e; - - return; //If the file is not found stop execution - } - - //Parse the JSON string into an array - objArr = JSON.parse(parsed); - - //Extract width and height data from the drawing - var svgDimensions = dimensionConversion(objArr.svg.$.width, objArr.svg.$.height); - width = svgDimensions.width; - height = svgDimensions.height; - - //Check for translation and account for it - //Commented out because going to stop supporting transformations - /* - transformX = 0; - transformY = 0; - - if (objArr.svg.g[0].$ && objArr.svg.g[0].$.transform) { //Done in multiple checks to avoid errors being thrown - var transString = objArr.svg.g[0].$.transform; - var subX = transString.indexOf("("); - transformX = parseInt(transString.substring(subX + 1)); - var subY = transString.indexOf(","); - transformY = parseInt(transString.substring(subY + 1)); - } - */ - - var phoneWidth = this.baseWidth; - var phoneHeight = this.baseHeight; - penHeight = this.drawHeight; - - widthRatio = width / phoneWidth; - heightRatio = height / phoneHeight; - - halfway = {x:width / 2, y:height / 2}; - currentPoint = {x:halfway.x, y:halfway.y}; //Start at the center of the canvas, which corresponds to (0,0) on the Tapster - - if (objArr.svg.g[0].g && objArr.svg.g[0].g[0].path) { //If there are multiple groups. Additional check to make sure that there is actually path data - for (var i = 0; i < objArr.svg.g[0].g.length; i++) { - pathArray = objArr.svg.g[0].g[i].path; - drawImage(pathArray); - } - } - - else if (objArr.svg.g.length > 0) { //Depending on how the paths are grouped, it is possible that this value can be greater than zero - for (var i = 0; i < objArr.svg.g.length; i++) { //If this is the case, loop through the array to get the path data - pathArray = objArr.svg.g[i].path; - drawImage(pathArray); - } - } - - else if (objArr.svg.g[0].path) { //If there is only one group - pathArray = objArr.svg.g[0].path; - drawImage(pathArray); - } - - doSetTimeout(0, 48, -130, delay); - //setTimeout(function() { resetTimer() }, timer + 5); -} - -drawImage = function(pathArray) { - var d = ""; - firstMove = null; //After a group is done being drawn, firstMove is reset as there has not yet been a first move made in the next group - for (var i = 0; i < pathArray.length; i++) { //When drawing multiple lines, there are multiple paths - firstPoint = null; - d = pathArray[i].$.d; - var commands = parse(d); - objRef.interpretCommands(commands); - /* if (i < (pathArray.length - 1)) { //Smooth transition to the next path - doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, 300); //Moves the pen up and over so no line is drawn between the two - doSetTimeout(mapX(parse(pathArray[i+1].$.d)[0].x), mapY(parse(pathArray[i+1].$.d)[0].y), penHeight + 10, 300); - doSetTimeout(mapX(parse(pathArray[i+1].$.d)[0].x), mapY(parse(pathArray[i+1].$.d)[0].y), penHeight, 300); - } */ - } - doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, delay); -} - -//Move from one point to (x, y) -move = function(x, y) { - var ptArray = []; - if (!connected) { //If the paths should not be connected, lift up the pen and move over so that a line is not drawn - doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, delay, "none"); - doSetTimeout(mapX(x), mapY(y), penHeight + 10, delay, "none"); - doSetTimeout(mapX(x), mapY(y), penHeight, delay, "none"); - //svg.drawSVG("C:/Projects/Tapsterbot/software/src/hello/helloChF.svg") - //ptArray.push({x:mapX(currentPoint.x), y:mapY(currentPoint.y), z:penHeight + 10}); - //ptArray.push({x:mapX(x), y:mapY(y), z:penHeight + 10}); - //ptArray.push({x:mapX(x), y:mapY(y), z:penHeight}); - } - else if (connected && !firstMove) { //If the paths should be connected and a move has not been made, lift up the pen and move to the first point - doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, delay, "none"); - doSetTimeout(mapX(x), mapY(y), penHeight + 10, delay, "none"); - doSetTimeout(mapX(x), mapY(y), penHeight, delay, "none"); - //ptArray.push({x:mapX(currentPoint.x), y:mapY(currentPoint.y), z:penHeight + 10}); - //ptArray.push({x:mapX(x), y:mapY(y), z:penHeight + 10}); - //ptArray.push({x:mapX(x), y:mapY(y), z:penHeight}); - } - else //If the paths should be connected and a move has been made, just draw a line between the two paths - doSetTimeout(mapX(x), mapY(y), penHeight, delay); - //ptArray.push({x:mapX(x), y:mapY(y), z:penHeight}); - - currentPoint = {x:x, y:y}; //Update the current point (done every time an SVG command is called) - - if (!firstMove) //Keeps track of if a move has been made or not. - firstMove = true; - - if (!firstPoint) //Keeps track of the first point, for use with the Z/z command - firstPoint = {x:currentPoint.x, y:currentPoint.y}; //Since the first command of a path is always to Move, this check only occurs here - - //return ptArray; -} - -//Move from one point to that that point + x, y -relMove = function(x, y) { - x = currentPoint.x + x; - y = currentPoint.y + y; - - //return move(x, y); - move(x, y); -} - -//Draw a line from one point to (x, y) -line = function(x, y) { - var ptArray = []; - doSetTimeout(mapX(x), mapY(y), penHeight, delay, "linear"); - //ptArray.push({x:mapX(x), y:mapY(y), z:penHeight}); - currentPoint = {x:x, y:y}; - -} - -//Draw a line from one point to that point + x, y -relLine = function(x, y) { - x = currentPoint.x + x; - y = currentPoint.y + y; - - //return line(x, y); - line(x, y); -} - -//Draws a cubic Bezier curve. -//(x1,y1) is the first control point -//(x2, y2) is the second -//(x, y) is the end point -cubicCurve = function(x1, y1, x2, y2, x, y) { - - //Function for calculating the coordinates of points on the curve - //Calculates t+1 points - b = function(x1, y1, x2, y2, x, y, t) { - var ptArray = new Array(); - for (var i = 0; i <= t; i++) { - var newI = i/t; //Converts i to a decimal, to satisfy 0 <= i <= 1 - var ptX = (Math.pow((1-newI), 3) * currentPoint.x) + (3 * Math.pow((1-newI), 2) * newI * x1) //From https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves - + (3 * (1-newI) * Math.pow(newI, 2) * x2) + (Math.pow(newI, 3) * x); - var ptY = (Math.pow((1-newI), 3) * currentPoint.y) + (3 * Math.pow((1-newI), 2) * newI * y1) - + (3 * (1-newI) * Math.pow(newI, 2) * y2) + (Math.pow(newI, 3) * y); - var newPt = {x:ptX, y:ptY, z:penHeight}; - ptArray.push(newPt); //Populates the array with points - } - currentPoint = {x:ptArray[t].x, y:ptArray[t].y}; - return ptArray; - } - - var curvePts = new Array(); - curvePts = b(x1, y1, x2, y2, x, y, 5); //Arbitrarily-chosen value. It creates a smooth-looking curve without calculating too many points - for (var i = 0;i < curvePts.length; i++) - doSetTimeout(mapX(curvePts[i].x), mapY(curvePts[i].y), penHeight, delay*2 / curvePts.length, "none"); //The cubic curve command takes 2*delay ms to complete so that an accurate curve is created - //return b(x1, y1, x2, y2, x, y, 8); -} - -//Draws a relative cubic Bezier curve -relCubicCurve = function(x1, y1, x2, y2, x, y) -{ - var tempX = currentPoint.x; - var tempY = currentPoint.y; - //return cubicCurve(tempX + x1, tempY + y1, tempX + x2, tempY + y2, tempX + x, tempY + y); - cubicCurve(tempX + x1, tempY + y1, tempX + x2, tempY + y2, tempX + x, tempY + y); -} - -//Draws a quadratic Bezier curve -//(x1, y1) is the control point -//(x, y) is the end point -quadraticCurve = function(x1, y1, x, y) { - - //Helper function for generating the points - q = function(x1, y1, x, y, t) { - var ptArray = new Array(); - for (var i = 0; i <= t; i++) { - var newI = i/t; //Converts i to a decimal, to satisfy 0 <= i <= 1 - var ptX = Math.pow((1-newI), 2)*currentPoint.x + (2 * (1-newI) * newI * x1) + (Math.pow(newI, 2) * x); //From https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Quadratic_B.C3.A9zier_curves - var ptY = Math.pow((1-newI), 2)*currentPoint.y + (2 * (1-newI) * newI * y1) + (Math.pow(newI, 2) * y); - var newPt = {x:ptX, y:ptY, z:penHeight}; - ptArray.push(newPt); - } - currentPoint = {x:ptArray[t].x, y:ptArray[t].y}; - return ptArray; - } - - var curvePts = new Array(); - curvePts = q(x1, y1, x, y, 5); - for (var i = 0; i < curvePts.length; i++) - doSetTimeout(mapX(curvePts[i].x), mapY(curvePts[i].y), penHeight, delay*2 / curvePts.length, "none"); - //return q(x1, y1, x, y, 8); -} - -//Draws a relative quadratic Bezier curve -relQuadraticCurve = function(x1, y1, x, y) { - var tempX = currentPoint.x; - var tempY = currentPoint.y; - //return quadraticCurve(tempX + x1, tempY + y1, tempX + x, tempY + y); - quadraticCurve(tempX + x1, tempY + y1, tempX + x, tempY + y); -} - -//Draws an elliptical arc -//rx and ry are the radii -//rotation is the angle (in degrees) between the rotated x-axis and the original x-axis -//largeArc is a flag that determines if the arc is greater than or less than or equal to 180 degrees -//sweep is a flag that determines if the arc is drawn in a positive direction or a negative direction -//(x, y) is the final point of the arc -//From: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes -arc = function(rx, ry, rotation, largeArc, sweep, x, y) { - - //Helper function for calculating the points - a = function(rx, ry, largeArc, sweep, x, y, t) { - var ptArray = new Array(); - - for (var i = 0; i <= t; i++) { - var newI = i / t; - var angle = startAngle + sweepAngle * newI; - var newPt = {x: cx + rx * cos(angle), y: cy + ry * sin(angle), z:penHeight}; - ptArray.push(newPt); - } - - currentPoint = {x: ptArray[t].x, y: ptArray[t].y}; - return ptArray; - } - - //Helper function for calculating the angle between two vectors - angleBetween = function(v1, v2) { - var p = v1.x*v2.x + v1.y*v2.y; - var n = Math.sqrt((Math.pow(v1.x, 2)+Math.pow(v1.y, 2)) * (Math.pow(v2.x, 2)+Math.pow(v2.y, 2))); - var sign = v1.x*v2.y - v1.y*v2.x < 0 ? -1 : 1; - var angle = sign*Math.acos(p/n) * 180 / Math.PI; - - return angle; - } - - tempX = currentPoint.x; - tempY = currentPoint.y; - - var xPrime = (cos(rotation) * ((tempX - x) / 2)) + (sin(rotation) * ((tempY - y) / 2)); - var yPrime = (-sin(rotation) * ((tempX - x) / 2)) + (cos(rotation) * ((tempY - y) / 2)); - - //Checks to ensure radii are as they should be - rx = Math.abs(rx); //Ensures they are non-zero and positive - ry = Math.abs(ry); - - var lambda = (Math.pow(xPrime, 2) / Math.pow(rx, 2)) + (Math.pow(yPrime, 2) / Math.pow(ry, 2)); - - if (lambda > 1) { //Ensures they are large enough - rx = Math.sqrt(lambda) * rx; - ry = Math.sqrt(lambda) * ry; - } - - var sign = 1; - - if (largeArc == sweep) //If they are equal, cPrime is negative - sign = -1; - - //For some reason this would occasionally result in NaN - //Implemented this check at the suggestion of: - //http://users.ecs.soton.ac.uk/rfp07r/interactive-svg-examples/arc.html - var cPrimeNumerator = ((Math.pow(rx, 2) * Math.pow(ry, 2)) - (Math.pow(rx, 2) * Math.pow(yPrime, 2)) - (Math.pow(ry, 2) * Math.pow(xPrime, 2))); - var cPrimeDenom = ((Math.pow(rx, 2) * Math.pow(yPrime, 2)) + (Math.pow(ry, 2) * Math.pow(xPrime, 2))); - - if ((cPrimeNumerator / cPrimeDenom) < 1e-7) - cPrime = 0; - else - cPrime = Math.sqrt(cPrimeNumerator / cPrimeDenom); - - //Calculates the transformed center - var cxPrime = sign * cPrime * ((rx * yPrime) / ry); - var cyPrime = sign * cPrime * (-(ry * xPrime) / rx); - - //Calculates the original center - var cx = ((cos(rotation) * cxPrime) + (-sin(rotation) * cyPrime)) + ((tempX + x) / 2); - var cy = ((sin(rotation) * cxPrime) + (cos(rotation) * cyPrime)) + ((tempY + y) / 2); - - //Calculates the start angle of the arc and the total change in the angle - var startVector = {x: (xPrime - cxPrime) / rx, y: (yPrime - cyPrime) / ry}; - var startAngle = angleBetween({x:1, y:0}, startVector); - var endVector = {x: (-xPrime - cxPrime) / rx, y: (-yPrime - cyPrime) / ry}; - var sweepAngle = angleBetween(startVector, endVector); - - if (!sweep && sweepAngle > 0) { - sweepAngle -= 360; - } - - else if (sweep && sweepAngle < 0) { - sweepAngle += 360; - } - - sweepAngle %= 360; - - var ptArray = a(rx, ry, largeArc, sweep, x, y, 5); - - for (var i = 0; i < ptArray.length; i++) { - doSetTimeout(mapX(ptArray[i].x), mapY(ptArray[i].y), penHeight, delay*2 / ptArray.length, "none"); - } - - //return a(rx, ry, largeArc, sweep, x, y, 10); -} - -//Function for drawing a relative elliptical arc -relArc = function(rx, ry, rotation, largeArc, sweep, x, y) { - x = currentPoint.x + x; - y = currentPoint.y + y; - - //return arc(rx, ry, rotation, largeArc, sweep, x, y); - arc(rx, ry, rotation, largeArc, sweep, x, y); -} - -//A function for setting the penHeight from the command line -setPenHeight = function(penHeight) { - penHeight = penHeight; -} - -//Reflects the point (x,y) across the point (x1, y1) -//For use with smooth curves -reflect = function(x, y, x1, y1) { - var tempX = x; - var tempY = y; - - tempX = x1 - (tempX - x1); - tempY = y1 - (tempY - y1); - - var point = {x:tempX, y:tempY}; - - return point; -} - -//Convert points pixel coordinates to Tapster coordinates -//Done in two methods for ease of use -mapX = function(x) { - var newX = x; - newX = (newX - halfway.x) / widthRatio; //The center of the canvas corresponds to (0, 0) on the Tapster - return newX; -}; - -mapY = function(y) { - var newY = y; - newY = (halfway.y - newY) / heightRatio; - return newY; -} - -// A sine function for working with degrees, not radians -sin = function(degree) { - return Math.sin(Math.PI * (degree/180)); -} - -// A cosine function for working with degrees, not radians -cos = function(degree) { - return Math.cos(Math.PI * (degree/180)); -} - -//Function for converting Inkscape dimensions into Tapster-friendly pixels -//Should switch to switch statements -dimensionConversion = function(width, height) { - width = String(width); - if (width.search("mm") != -1) { - var dimension = {width: parseInt(width) * 3.779527559, height: parseInt(height) * 3.779527559}; //The px:mm ratio is ~ 3.8:1 - } - else if (width.search("in") != -1) { - var dimension = {width: parseInt(width) * 96, height: parseInt(height) * 96}; //The px:in ratio is 96:1 - } - else if (width.search("ft") != -1) { - var dimension = {width: parseInt(width) * 96 * 12, height: parseInt(height) * 96 * 12}; //The px:ft ratio is 96*12:1 - } - else if (width.search("m") != -1) { - var dimension = {width: parseInt(width) * 3.779527559 * 1000, height: parseInt(height) * 3.779527559 * 1000}; //The px:m ratio is ~3.8*1000:1 - } - else if (width.search("cm") != -1) { - var dimension = {width: parseInt(width) * 3.779527559 * 100, height: parseInt(height) * 3.779527559 * 100}; //The px:cm ratio is ~3.8*100:1 - } - else if (width.search("pt") != -1) { - var dimension = {width: parseInt(width) * 1.3333, height: parseInt(height) * 1.3333}; //The px:pt ratio is ~1.3:1 - } - else if (width.search("pc") != -1) { - var dimension = {width: parseInt(width) * 16, height: parseInt(height) * 16}; //The px:pc ratio is 16:1 - } - else //No unit specified == pixels - var dimension = {width: width, height: height}; - - return dimension; -} - -//Goes through the list of commands an generated by the SVG-Path-Parser and calls the corresponding functions -//Should switch to switch statements -SVGReader.prototype.interpretCommands = function(commands) { - delay = this.delay; - for (var i = 0; i < commands.length; i++) { - var cmdCode = commands[i].code; - switch (cmdCode) { - case 'M': - move(commands[i].x, commands[i].y); - break; - - case 'm': - relMove(commands[i].x, commands[i].y); - break; - - case 'L': - line(commands[i].x, commands[i].y); - break; - - case 'l': - relLine(commands[i].x, commands[i].y); - break; - - case 'V': - line(currentPoint.x, commands[i].y); - break; - - case 'v': - relLine(currentPoint.x, commands[i].y); - break; - - case 'H': - line(commands[i].x, currentPoint.y); - break; - - case 'h': - relLine(commands[i].x, currentPoint.y); - break; - - case 'C': - cubicCurve(commands[i].x1, commands[i].y1, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); - break; - - case 'c': - relCubicCurve(commands[i].x1, commands[i].y1, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); - break; - - //Smooth cubic curve - case 'S': - if (i > 1 && (commands[i-1].code == 's' || commands[i-1].code == 'c' || commands[i-1].code == 'C' || commands[i-1].code == 'S')) { - var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); - var ctrl = {x:reflected.x, y:reflected.y}; - } - else - var ctrl = {x:currentPoint.x, y:currentPoint.y}; - - cubicCurve(ctrl.x, ctrl.y, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); - break; - - //Smooth relative cubic curve - case 's': - if (i > 1 && (commands[i-1].code == 's' || commands[i-1].code == 'c' || commands[i-1].code == 'C' || commands[i-1].code == 'S')) { - var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); - var ctrl = {x:reflect(commands[i-1].x2).x, y:reflect(commands[i-1].y2).y}; - } - else - var ctrl = {x:currentPoint.x, y:currentPoint.y}; - - relCubicCurve(ctrl.x, ctrl.y, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); - break; - - case 'Q': - quadraticCurve(commands[i].x1, commands[i].y1, commands[i].x, commands[i].y); - break; - - case 'q': - relQuadraticCurve(commands[i].x1, commands[i].y1, commands[i].x, commands[i].y); - break; - - //Smooth quadratic curve - case 'T': - if (i > 1 && (commands[i-1].code == 't' || commands[i-1].code == 'q' || commands[i-1].code == 'Q' || commands[i-1].code == 'T')) { - var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); - var ctrl = {x:reflect(commands[i-1].x1).x, y:reflect(commands[i-1].y1).y}; - } - else - var ctrl = {x:currentPoint.x, y:currentPoint.y}; - - quadraticCurve(ctrl.x, ctrl.y, commands[i].x, commands[i].y); - break; - - //Smooth relative quadratic curve - case 't': - if (i > 1 && (commands[i-1].code == 't' || commands[i-1].code == 'q' || commands[i-1].code == 'Q' || commands[i-1].code == 'T')) { - var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); - var ctrl = {x:reflect(commands[i-1].x1).x, y:reflect(commands[i-1].y1).y}; - } - else - var ctrl = {x:currentPoint.x, y:currentPoint.y}; - - relQuadraticCurve(ctrl.x, ctrl.y, commands[i].x, commands[i].y); - break; - - case 'A': - arc(commands[i].rx, commands[i].ry, commands[i].xAxisRotation, commands[i].largeArc, commands[i].sweep, commands[i].x, commands[i].y); - break; - - case 'a': - relArc(commands[i].rx, commands[i].ry, commands[i].xAxisRotation, commands[i].largeArc, commands[i].sweep, commands[i].x, commands[i].y); - break; - - case 'Z': - line(firstPoint.x, firstPoint.y); - firstPoint = null; - break; - - case 'z': - line(firstPoint.x, firstPoint.y); - firstPoint = null; - break; - } - } - } - -//Creates a working clock -SVGReader.prototype.clock = function() { - var dimensions = dimensionConversion("80mm", "95mm"); //Since no dimensions are specified, assume the default - //To-do: Pull this from a config file - width = dimensions.width; - height = dimensions.height; - - objRef = this; - - resetTimer(); - connected = false; - - //Used to access the erase functions - var drawing = new draw.Draw({ - baseWidth: objRef.baseWidth, - baseHeight: objRef.baseHeight, - drawHeight: objRef.drawHeight - }); - - var phoneWidth = this.baseWidth; - var phoneHeight = this.baseHeight; - - widthRatio = width / phoneWidth; - heightRatio = height / phoneHeight; - - penHeight = this.drawHeight; - halfway = {x:width / 2, y:height / 2}; - currentPoint = {x:halfway.x, y:halfway.y}; //Start at the center of the canvas, which corresponds to (0,0) on the Tapster - - //Currently hardcoded path data - var zero = "M 40.890286,241.44557 30.687127,245.57254 23.885021,257.95342 20.483968,278.58823 20.483968,290.96912 23.885021,311.60393 30.687127,323.98482 40.890286,328.11178 47.692392,328.11178 57.895551,323.98482 64.697657,311.60393 68.09871,290.96912 68.09871,278.58823 64.697657,257.95342 57.895551,245.57254 47.692392,241.44557 40.890286,241.44557"; - var one = "M 50.289453,243.07635 50.289453,329.52761"; - var two = "M 27.618803,262.08031 27.618803,257.95271 30.945521,249.69749 34.27224,245.56989 40.925676,241.44228 54.23255,241.44228 60.885986,245.56989 64.212704,249.69749 67.539423,257.95271 67.539423,266.20792 64.212704,274.46313 57.559268,286.84595 24.292085,328.12202 70.866141,328.12202"; - var three = "M 33.809127,248.8729 C 45.779077,241.87747 46.887418,243.5556 53.186196,243.05913 61.663816,242.39092 65.286579,246.55715 64.812967,252.72615 64.140416,261.48642 55.207358,274.28536 40.185777,283.01419 L 52.623884,281.94331 59.295192,285.47169 62.630846,289.00007 65.9665,299.58523 65.9665,306.64193 62.630846,317.22713 55.959538,324.28383 45.952576,327.81223 35.945614,327.81223 25.938652,324.28383 22.602998,320.75553 19.267344,313.69873"; - var four = "M 54.845427,241.51709 22.803997,300.19076 70.866142,300.19076 M 54.845427,241.51709 54.845427,329.5276"; - var five = "M 61.700462,246.77512 26.654546,246.77512 23.149954,281.56734 26.654546,277.70154 37.168321,273.83574 47.682096,273.83574 58.19587,277.70154 65.205054,285.43315 68.709645,297.03055 68.709645,304.76216 65.205054,316.35956 58.19587,324.09117 47.682096,327.95697 37.168321,327.95697 26.654546,324.09117 23.149954,320.22537 19.645363,312.49376"; - var six = "M 64.294901,253.7887 60.65789,245.53396 49.746856,241.40659 42.472833,241.40659 31.561799,245.53396 24.287776,257.91607 20.650765,278.55291 20.650765,299.18976 24.287776,315.69923 31.561799,323.95397 42.472833,328.08134 46.109844,328.08134 57.020878,323.95397 64.294901,315.69923 67.931912,303.31713 67.931912,299.18976 64.294901,286.80765 57.020878,278.55291 46.109844,274.42554 42.472833,274.42554 31.561799,278.55291 24.287776,286.80765 20.650765,299.18976"; - var seven = "M 68.262659,241.73033 32.158284,328.90301 M 17.716535,241.73033 68.262659,241.73033"; - var eight = "M 37.489233,241.44557 27.286074,245.57254 23.885021,253.82646 23.885021,262.08039 27.286074,270.33431 34.08818,274.46127 47.692392,278.58823 57.895551,282.7152 64.697657,290.96912 68.09871,299.22304 68.09871,311.60393 64.697657,319.85785 61.296604,323.98482 51.093445,328.11178 37.489233,328.11178 27.286074,323.98482 23.885021,319.85785 20.483968,311.60393 20.483968,299.22304 23.885021,290.96912 30.687127,282.7152 40.890286,278.58823 54.494498,274.46127 61.296604,270.33431 64.697657,262.08039 64.697657,253.82646 61.296604,245.57254 51.093445,241.44557 37.489233,241.44557"; - var nine = "M 67.931912,270.29818 64.2949,282.68028 57.020878,290.93502 46.109844,295.06239 42.472833,295.06239 31.561799,290.93502 24.287776,282.68028 20.650765,270.29818 20.650765,266.17081 24.287776,253.7887 31.561799,245.53396 42.472833,241.40659 46.109844,241.40659 57.020878,245.53396 64.2949,253.7887 67.931912,270.29818 67.931912,290.93502 64.2949,311.57186 57.020878,323.95397 46.109844,328.08134 38.835821,328.08134 27.924787,323.95397 24.287776,315.69923"; - - pathData = [zero, one, two, three, four, five, six, seven, eight, nine]; - - var colon = "M 165.73227,300.21546 Z M 165.73227,253.34648 Z"; - var arrayTime = new Array(); - - objRef = this; - - //Simple function for converting units in millimeters to units in pixels - //Based on the fixed ratio between mm and px - toPixels = function(mm) { - return mm * 3.779527559; - } - - //Draws the time - //Takes an array of path data and a callback function - drawTime = function(arrayOfPaths, callback) { - for (var i = 0; i < arrayOfPaths.length; i++) { - objRef.interpretCommands(arrayOfPaths[i]); //Interprets the path data and draws the number - - firstPoint = null; - - if (i == 1) //Inserts the colon between the second and third number - objRef.interpretCommands(parse(colon)); - } - doSetTimeout(0, 0, -140, delay); - setTimeout(function() { endTime = new Date().getTime() }, timer + 1); //Gets the time after drawTime finishes executing - //Because of the way doSetTimeout works, timer + 1 occurs (is meant to occur) a millisecond after the doSetTimeout call - setTimeout(function() { difference = endTime - startTime }, timer + 3); - setTimeout(function() { callback() }, timer + 4); - } - - //Gets the curent time and converts it into an array of four digits - //The first two digits are the hours, the last two are the minutes - getTheTime = function() { - var currentTime = new Date() - var hours = String(currentTime.getHours()); - var minutes = String(currentTime.getMinutes()); - - //Converts from 24 hour time to 12 hour time - if (hours > 12) - hours -= 12; - else if (hours === 0) - hours = 12; - - //Adds a placeholder zero to ensure that there are four digits in the time - //The zero is not actually drawn - if (hours < 10) - hours = "0" + hours; - - if (minutes < 10) - minutes = "0" + minutes; - - var timeArray = new Array(); - for (var i = 0; i < hours.length; i++) { - timeArray.push(hours.charAt(i)); - } - - for (var i = 0; i < minutes.length; i++) { - timeArray.push(minutes.charAt(i)); - } - arrayTime = timeArray; //Stores the array in another variable so it can be accessed elsewhere without calling the function again - return timeArray; - } - - //Converts the digits in the timeArray into path data - convertToPath = function(timeArray) { - var pathArray = new Array(); - var offset = toPixels(3); //The first digit is drawn three mm from the left side - var commandArray = new Array(); - //Loops through the digits in timeArray - for (var i = 0; i < timeArray.length; i++) { - if (i == 0 && timeArray[i] == 0) { //If the first digit is 0 (if the hours < 10) AND the loop is on the first digit - offset += toPixels(5); //Changes the offset so that the three digits that will be drawn will be centered - commandArray.push(["Z"]); //The Z command, without a firstPoint value, will not draw anything, but can still be interpreted without errors - colon = "M 118.73227,307.21546 Z M 118.73227,253.34648 Z"; //Changes the path data of the colon so that it will still be in the correct location - } - else { - var data = pathData[timeArray[i]]; - var commands = parse(data); - - //Loops through the commands in the array and adds the offset to each x value - for (var x = 0; x < commands.length; x++) { - if (commands[x].code != 'Z' || commands[x].code != 'z') { //Every command but the close path commands have an x value - commands[x].x += offset; - if (commands[x].x1) //Some commands (curves and arcs) have an x1 value - commands[x].x1 += offset; - if (commands[x].x2) //Some commands (cubic curves) have an x2 value - commands[x].x2 += offset; - } - } - - commandArray.push(commands); - - if (timeArray[0] != 0) - colon = "M 165.73227,300.21546 Z M 165.73227,253.34648 Z"; //Ensures that the colon has the correct path data - //Without this check, once the hours changed from single to double digits, the colon would be in the incorrect place - - offset += toPixels(18); //Adds an offset to each digit - //Each digit should be 15mm wide, with 3mm space between each digit - if (i == 1) - offset += toPixels(4); //Adds an extra 4mm of space to account for the colon - } - } - - return commandArray; - } - - //Draws a circle to indicate the amount of time left in the minute - timeCircle = function() { - resetTimer(); - - //Draws a circle, given an array of points and the amount of delay in between each point - circle = function(array, timeDelay) { - for (var i=0; i -2; degree--) { - var radians = (degree + 90) * Math.PI/180; //Add 90 to degree so that the circle starts at the top, not at the right - var x = centerX + radius * Math.cos(radians); - var y = centerY + radius * Math.sin(radians); - points.push({x:x,y:y}); - } - - setTimeout(function() { circle(points, calcDelay(calcTimeLeft(), points.length)) }, 0); - } - - //Tells the time - tellTime = function() { - resetTimer(); - - startTime = new Date().getTime(); - - drawing.erase(function() { - drawTime(convertToPath(getTheTime()), function() { - timeCircle(); - }); - }); - - //drawTime(convertToPath([0, 2, 4, 2]), console.log); - //setTimeout(function() { drawTime(convertToPath(getTheTime())) }, 12500); - //setTimeout(function() { drawTime(convertToPath([0, 8, 5, 8]))}, 12500); - //setTimeout(function() { timeCircle() }, 12501); - } - - tellTime(); - clockTimer = setInterval(function() { tellTime() }, 60000); //Repeat every 60 seconds -} - -//A function to stop the clock -//The clock will finish erasing, drawing, and moving the arms in a circle, but it will not repeat -SVGReader.prototype.clearClock = function() { - clearInterval(clockTimer); - console.log("Stopping clock."); -} - -//Says 'hello' in multiple languages -SVGReader.prototype.hello = function() { - resetTimer(); - var fileArray = fs.readdirSync("./hello"); - var fileNum; - objRef = this; - - //Used to access the erase functions - var drawing = new draw.Draw({ - baseWidth: objRef.baseWidth, - baseHeight: objRef.baseHeight, - drawHeight: objRef.drawHeight - }); - - //Picks a file at random from a folder of 'hello's - pickFile = function() { - do { - fileNum = Math.floor(Math.random() * fileArray.length); - } - while (fileNum == lastNum1 || fileNum == lastNum2); //Generates numbers until a number that has not been used in the past two calls is picked - //A language can only be used every third time - - lastNum2 = lastNum1; //Adjusts the last two numbers used - lastNum1 = fileNum; - - //Checks to see if the characters should be drawn connected or not - //Specified in file name - if (fileArray[fileNum].charAt(7) === 'T') - connect = true; - else - connect = false; - - return "./hello/" + fileArray[fileNum]; - } - - //Says hello. - sayHello = function() { - resetTimer(); - var fileChoice = pickFile(); - drawing.erase(function() { - setTimeout(function() { objRef.drawSVG(fileChoice, connect) }, 10000); - }); - } - - sayHello(); - helloTimer = setInterval(function() { sayHello() }, 60000); //Repeat every minute -} - -//A function to cancel saying hello -//The robot will finish writing/erasing if it has already started but after that it will stop -SVGReader.prototype.sayGoodbye = function() { - clearInterval(helloTimer); - console.log("Goodbye!"); -} - -//Cycles through all the languages rather than picking one at random -SVGReader.prototype.helloCycle = function() { - resetTimer(); - var fileArray = fs.readdirSync("./hello"); - objRef = this; - var fileNum = 0; - - //Used to access the erase functions - var drawing = new draw.Draw({ - baseWidth: objRef.baseWidth, - baseHeight: objRef.baseHeight, - drawHeight: objRef.drawHeight - }); - - //Function to actually write hello - sayHello = function() { - var fileChoice = "./hello/" + fileArray[fileNum]; - - if (fileChoice.charAt(15) === 'T') - connect = true; - else - connect = false; - - //drawing.erase(function() { - // setTimeout(function() { objRef.drawSVG(fileChoice, connect) }, 10000); - //}); - - fileNum++; - - if (fileNum >= fileArray.length) //Once the end of the list is reached, stop writing - clearInterval(helloTimer); - } - - sayHello(); - helloTimer = setInterval(function() { sayHello() }, 60000); - -} - -//Saves the coordinates of the first point drawn -var firstPoint; - -var objArr; -var pathArray; - -var widthRatio; -var heightRatio; -var halfway; -var currentPoint; -var penHeight; -var delay, loaded, fontFile; -var transformX, transformY, objRef, connected, startTime, endTime, difference, clockTimer, firstMove, lastNum1, lastNum2, connect, baseWidth, baseHeight, defaultEaseType; - -module.exports.SVGReader = SVGReader; diff --git a/software/src/arc.js b/software/src/arc.js deleted file mode 100644 index 0121953c..00000000 --- a/software/src/arc.js +++ /dev/null @@ -1,85 +0,0 @@ -// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc -// https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-arc - -var tau = Math.TAU = 2*Math.PI; - -function areValid(arguments) { - // Check for correct number of arguments - if (arguments.length < 6) { return false; } - if (arguments.length > 7) { return false; } - - // If any of the arguments are infinite or NaN, then abort. - for (var parameter in arguments) { - if (!isFinite(arguments[parameter])) { return false; } - if (isNaN(arguments[parameter])) { return false; } - } - return true; -} - -function calcPoint(cX, cY, r, radian) { - var pointX = cX + r * Math.cos(radian); - var pointY = cY + r * Math.sin(radian); - return {x: pointX, y: pointY} -} - -function arc(centerX, centerY, centerZ, radius, startAngle, endAngle, anticlockwise) { - var arcPoints = []; - - if (!areValid(arguments)) return; - - // Test if anticlockwise was given. If not, set to false. - if (typeof(anticlockwise) === "undefined") { - var anticlockwise = false; - } else { - // Abort if not boolean - if (typeof(anticlockwise) !== "boolean") { - return; - } - } - - // Modulo angles into range - startAngle = startAngle % tau; - endAngle = endAngle % tau; - - var clockwise = !anticlockwise; - if (clockwise === false) { - // If needed, offset startAngle by one full turn so the loop works - if (startAngle >= endAngle) { - startAngle -= tau; - } - - // Get all path points - for (var radian = startAngle; radian <= endAngle; radian += .05) { - var point = calcPoint(centerX, centerY, radius, radian);; - arcPoints.push({x:point.x, y:point.y, z:centerZ}) - } - } else { - // If needed, offset startAngle by one full turn so the loop works - if (startAngle <= endAngle) { - startAngle += tau; - } - - // Get all path points - for (var radian = startAngle; radian >= endAngle; radian -= .05) { - var point = calcPoint(centerX, centerY, radius, radian); - arcPoints.push({x:point.x, y:point.y, z:centerZ}) - } - } - return arcPoints; -} - - -//----------------------------------------------------- -// Example #1: startAngle > endAngle, clockwise -//arc(0, 0, -140, 20, tau/2, tau/4, false); - -// Example #2: startAngle > endAngle, anticlockwise -//arc(0, 0, -140, 20, tau/2, tau/4, true); - -// Example #3: startAngle < endAngle, clockwise -//arc(0, 0, -140, 20, tau/4, tau/2, false); - -// Example #4: startAngle < endAngle, anticlockwise -//arc(0, 0, -140, 20, tau/4, tau/2, true); - -module.exports = arc; \ No newline at end of file diff --git a/software/src/bot.js b/software/src/bot.js deleted file mode 100755 index 3ac1ee8d..00000000 --- a/software/src/bot.js +++ /dev/null @@ -1,371 +0,0 @@ -five = require("johnny-five"); -kinematics = require("./kinematics"); -svgRead = require("./SVGReader"); -drawing = require("./draw"); -arc = require("./arc"); -motion = require("./motion"); - -var express = require('express'); -var bodyParser = require('body-parser'); -var app = express(); - -var jsonParser = bodyParser.json(); - -app.get('/', function (req, res) { - res.send('Welcome to Tapster World!'); -}); - -var servo1; -var servo2; -var servo3; - -app.post('/go', jsonParser, function (req, res) { - console.log('Go!'); - console.log(req.body); - if ((typeof req.body.x === 'undefined') || - (typeof req.body.y === 'undefined') || - (typeof req.body.z === 'undefined')) { - - res.status(400).send('Invalid request\n'); - - } else { - var x = req.body.x; - var y = req.body.y; - var z = req.body.z; - // Move with default easing - go(x, y, z); - - // Move with no easing - //go(x, y, z, 'none'); - - setTimeout(function(){ res.send('OK\n') }, 250); - } - -}); - -app.post('/circle', jsonParser, function (req, res) { - console.log('Circle!'); - console.log(req.body); - if ((typeof req.body.x === 'undefined') || - (typeof req.body.y === 'undefined') || - (typeof req.body.z === 'undefined') || - (typeof req.body.radius === 'undefined') || - (typeof req.body.startAngle === 'undefined') || - (typeof req.body.anticlockwise === 'undefined') || - (typeof req.body.delay === 'undefined') || - (typeof req.body.rotations === 'undefined')) { - - res.status(400).send('Invalid request\n'); - - } else { - var centerX = req.body.x; - var centerY = req.body.y; - var centerZ = req.body.z; - var radius = req.body.radius; - var startAngle = req.body.startAngle; - var anticlockwise = req.body.anticlockwise; - var delay = req.body.delay; - var rotations = req.body.rotations; - - // An array to save points on the arc - var points = arc(centerX, centerY, centerZ, radius, startAngle, startAngle, anticlockwise); - - // Go to each point in the arc - for (var rotation = 0; rotation < rotations; rotation += 1) { - for (var i = 0; i < points.length; i += 1) { - setTimeout( function(point) { - go(point.x, point.y, point.z, "none") - }, - i*delay + points.length*delay*rotation, - points[i]); - } - } - - // Return - setTimeout(function(){ res.send('OK\n') }, points.length*delay*rotations ); - } -}); - - -app.post('/arc', jsonParser, function (req, res) { - console.log('Arc!'); - console.log(req.body); - if ((typeof req.body.x === 'undefined') || - (typeof req.body.y === 'undefined') || - (typeof req.body.z === 'undefined') || - (typeof req.body.radius === 'undefined') || - (typeof req.body.startAngle === 'undefined') || - (typeof req.body.endAngle === 'undefined') || - (typeof req.body.anticlockwise === 'undefined') || - (typeof req.body.delay === 'undefined')) { - - res.status(400).send('Invalid request\n'); - - } else { - var centerX = req.body.x; - var centerY = req.body.y; - var centerZ = req.body.z; - var radius = req.body.radius; - var startAngle = req.body.startAngle; - var endAngle = req.body.endAngle; - var anticlockwise = req.body.anticlockwise; - var delay = req.body.delay; - - // An array to save points on the arc - var points = arc(centerX, centerY, centerZ, radius, startAngle, endAngle, anticlockwise); - - // Go to each point in the arc - var i; - for (i = 0; i < points.length; i += 1) { - setTimeout( function(point) { go(point.x, point.y, point.z, "none") }, i*delay, points[i]); - } - - // Return - setTimeout(function(){ res.send('OK\n') }, i*delay ); - } - -}); - - - -// set the port of our application -// process.env.PORT lets the port be set by Heroku -var port = process.env.PORT || 8080; - -app.listen(port, function () { - console.log('Tapster web server listening on port ' + port); -}); - - -//If a filepath is specified, load that config -//Otherwise, resort to the default config -//> Usage: -//> node bot.js "C:\Projects\Tapsterbot\software\config.js" -if (process.argv[2]) { - try { - var config = require(process.argv[2]); - console.log("Config found and loaded."); - } catch (e) { - console.log("Config not found. Loading default."); - var config = require("../config.js"); - } -} -else { - console.log("Config not specified. Loading default."); - var config = require("../config.js"); -} - -//Alternate config loading code -//If a Tapster version is specified, load that config -//Otherwise resort to the default config -//> Usage: -//> node bot.js "Tapster-2-plus" - -/*if (process.argv[2]) { - try { - var config = require("../" + process.argv[2] + ".js"); - console.log("Config found and loaded."); - } catch (e) { - console.log("Config not found. Loading default."); - var config = require("../config.js"); - } -} -else { - console.log("Config not specified. Loading default."); - var config = require("../config.js"); -} */ - -k = new kinematics.Kinematics({ - e: config.e, - f: config.f, - re: config.re, - rf: config.rf -}); - -svg = new svgRead.SVGReader({ - baseWidth: config.baseWidth, - baseHeight: config.baseHeight, - drawHeight: config.drawHeight, - delay: config.delay, - defaultEaseType: config.defaultEaseType -}); - -draw = new drawing.Draw({ - baseWidth: config.baseWidth, - baseHeight: config.baseHeight, - drawHeight: config.drawHeight, - defaultEaseType: config.defaultEaseType -}); - -board = new five.Board({ - debug: false -}); - -var steps = 5; -var delay = config.delay / steps; -var defaultEaseType = config.defaultEaseType; - -current = [0, 0, -140]; -timer = 0; - -board.on("ready", function() { - // Setup - /*servo1 = five.Servo({ - address: 0x40, - controller: "PCA9685", - pin: 0, - range: [35, 145] //Too high of a minimum input will cause issues with the forward kinematics - }); - servo2 = five.Servo({ - address: 0x40, - controller: "PCA9685", - pin: 1, - range: [35, 145] - }); - servo3 = five.Servo({ - address: 0x40, - controller: "PCA9685", - pin: 2, - range: [35, 145] - }); */ - - servo1 = new five.Servo({ - pin: 9, - range: [0, 100] - }); - - servo2 = new five.Servo({ - pin: 10, - range: [0, 100] - }); - - servo3 = new five.Servo({ - pin: 11, - range: [0, 100] - }); - - board.repl.inject({ - servo1: servo1, - s1: servo1, - servo2: servo2, - s2: servo2, - servo3: servo3, - s3: servo3, - }); - - // Move to starting point - var max = 15; - var min = 5; - var range = max - min; - servo1.to(15); - servo2.to(15); - servo3.to(15); - - /* - var dance = function() { - servo1.to(parseInt((Math.random() * range) + min, 10)); - servo2.to(parseInt((Math.random() * range) + min, 10)); - servo3.to(parseInt((Math.random() * range) + min, 10)); - }; - - var dancer; - - start_dance = function() { - if (!dancer) dancer = setInterval(dance, 250); - } - - stop_dance = function() { - if (dancer) { - clearInterval(dancer); - dancer = null; - } - } - - board.repl.inject({ - dance: start_dance, - chill: stop_dance - }); */ - - -}); - -Number.prototype.map = function ( in_min , in_max , out_min , out_max ) { - return ( this - in_min ) * ( out_max - out_min ) / ( in_max - in_min ) + out_min; -} - -rotate = function(x,y) { - var theta = -60; - x1 = x * cos(theta) - y * sin(theta); - y1 = y * cos(theta) + x * sin(theta); - return [x1,y1] -} - -reflect = function(x,y) { - var theta = 0; - x1 = x; - y1 = x * sin(2*theta) - y * cos(2*theta); - return [x1,y1] -} - - -// A sine function for working with degrees, not radians -sin = function(degree) { - return Math.sin(Math.PI * (degree/180)); -} - -// A cosine function for working with degrees, not radians -cos = function(degree) { - return Math.cos(Math.PI * (degree/180)); -} - -moveServosTo = function(x, y, z) { - current = [x, y, z] - reflected = reflect(x,y); - rotated = rotate(reflected[0],reflected[1]); - - angles = k.inverse(rotated[0], rotated[1], z); - - servo1.to((angles[1]).map(config.servo1.in_min, config.servo1.in_max, config.servo1.out_min, config.servo1.out_max)); - servo2.to((angles[2]).map(config.servo2.in_min, config.servo2.in_max, config.servo2.out_min, config.servo2.out_max)); - servo3.to((angles[3]).map(config.servo3.in_min, config.servo3.in_max, config.servo3.out_min, config.servo3.out_max)); - console.log(angles); -} - -go = function(x, y, z, easeType) { - var pointB = [x, y, z]; - if (easeType == "none") { - moveServosTo(pointB[0], pointB[1], pointB[2]); - return; //Ensures that it doesn't move twice - } - - else if (!easeType) - easeType = defaultEaseType //If no easeType is specified, go with default (specified in config.js) - - //motion.move(current, pointB, steps, easeType, delay); - var points = motion.getPoints(current, pointB, steps, easeType); - - for (var i = 0; i < points.length; i++) { - setTimeout( function(point) { moveServosTo(point[0], point[1], point[2]) }, i * delay, points[i]); - } -} - -//Returns the coordinates of the end effector, based on the angles -//Using the map function messes up these values -//Simply passing in the original angles will return the correct coordinates -position = function() { - return k.forward(servo1.last.degrees, servo2.last.degrees, servo3.last.degrees); -} - -//A separate setTimeout method so that delays work properly -doSetTimeout = function(x, y, z, timeDelay, easing) { - if (!easing) - easing = defaultEaseType; - - setTimeout(function() { go(x, y, z, easing) }, timer); - timer = timer + timeDelay; -}; - - -resetTimer = function() { - timer = 0; -} diff --git a/software/src/calibrate.js b/software/src/calibrate.js new file mode 100644 index 00000000..5251091c --- /dev/null +++ b/software/src/calibrate.js @@ -0,0 +1,357 @@ +#! /usr/local/bin/node + +/* +Copyright (c) 2011-2016, Tapster Committers +Copyright (c) 2018, Orange + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +*/ + + +// ************************************** +// Dependencies and parameters management +// ************************************** + +var prompt = require("prompt"), + fs = require("fs"), + eol = require('os').EOL, + ArgumentParser = require('argparse').ArgumentParser, + robot = require('./lib/server/robot_http_client').client("127.0.0.1","4242"), + wd = require('wd'); + +var args = {}, + newCalibrationData = {}; + +var androidInUse = false; +var iOSInUse = false; + +var androidCoordRegex = /text[^\(,]+\((\d+\.*\d*),\s+(\d+\.*\d*)\)/ ; +var iOSCoordRegex = /label[^\(,]+\((\d+\.*\d*),\s+(\d+\.*\d*)\)/ ; + +function CalibrationManager(argv){ + args = argv; + prompt.message = ''; + prompt.delimiter = ''; + prompt.start(); +} + +exports.CalibrationManager = CalibrationManager; + +/** + * Gets the arguments of the command lines + */ +var getCommandLineArgs = function(){ + var parser = new ArgumentParser({ + version: '0.0.1', + addHelp:true, + description: 'Tapster Calibration Script' + }); + parser.addArgument( + [ '-o', '--output' ], { + defaultValue: "calibration.json" + , help: 'file to save calibration data to' + } + ); + return parser.parseArgs(); +}; + +/** + * Runs the calibrate workflow. + * Will ask to user if he or she wants yto claibrate the arms of the bot and the corddinates mapping with a dedicated device. + */ +CalibrationManager.prototype.calibrate = function(){ + robot.calibrationData(function (calibrationData) { + console.log("Receiving existing calibration data."); + newCalibrationData = calibrationData; + console.log(JSON.stringify(newCalibrationData)); + return askToCalibrateRobot(function() { + return askToCalibrateDevice(function() { + saveCalibrationData(function() { + console.log("Calibration Complete"); + }); + }) + }); + }); +}; + +/** + * Ask the user if he or she wants to calibrate the robot, here the arms of the bot + */ +var askToCalibrateRobot = function(cb){ + var schema = { + name:"answer", + description: 'Would you like to calibrate the robot arms?', + type: 'string' + }; + prompt.get(schema, function (err, result){ + if (result.answer.toLowerCase().substr(0,1) == "y") { + return calibrateRobot(cb); + } else { + return cb(); + } + }); +}; + +/** + * Ask the user if he or she wants to calibrate the robot with a dedicated device + */ +var askToCalibrateDevice = function(cb){ + var schema = { + name:"answer", + description: 'Would you like to calibrate the robot to a device? If so, plug the arms of the bot.', + type: 'string' + }; + prompt.get(schema, function (err, result){ + if (result.answer.toLowerCase().substr(0,1) == "y") { + return calibrateDevice(cb); + } else { + return cb(); + } + }); +}; + +/** + * Saves the calibration data in JSON format + */ +var saveCalibrationData = function(cb){ + console.log("New calibration data generated."); + console.log(JSON.stringify(newCalibrationData)); + return robot.setCalibrationData(newCalibrationData, function () { + console.log("Robot is now calibrated!"); + return fs.writeFile(args.output, JSON.stringify(newCalibrationData), function (err) { + if (err) { + console.log('Calibration data can not be saved: ' + err); + } else { + console.log('Calibration data saved to "' + args.output + '"'); + } + return cb(); + }); + }); +}; + +/** + * Calibrates the robot. + * Asks the user to remove the arms and to define good agngles for them. + * Will then let the suer choose the good angles for each arm. + */ +var calibrateRobot = function(cb){ + + var schema = { + description: 'Please remove the arms from the robot and press any key to continue...', + type: 'string' + }; + + return prompt.get(schema, function (){ + + var calibrateServos = function(cb) { + + var calibrateServo = function(armIndex, isMin, cb){ + robot.angles(function (angles) { + var description = 'Enter an adjustment for arm #' + (armIndex +1) + ', enter 0 when the arm is ' + + (isMin ? 'parallel to the roof.' : 'perpendicular to the roof'); + + var schema = { + name: "delta", + description: description, + type: 'number' + }; + + return prompt.get(schema, function (err, result) { + if (result.delta < 0.05 && result.delta > -0.05) { + newCalibrationData["servo" + (armIndex+1)][(isMin ? "min" : "max" ) + "imumAngle"] = angles[armIndex]; + return cb(); + } else { + console.log("Old angles: " + angles); + angles[armIndex] = angles[armIndex] + result.delta; + console.log("New angles: " + angles); + robot.setAngles(angles[0], angles[1], angles[2], function() { + return calibrateServo(armIndex, isMin, cb); + }); + } + }); + + }); + }; // End of calibrateServo = function(armIndex, isMin, cb) + + var calibrateServoMinAndMax = function(armIndex, cb){ + return robot.reset(function () { + return calibrateServo(armIndex, true, function () { + return calibrateServo(armIndex, false, cb); + }); + }); + }; + + // calibrate the servos + return calibrateServoMinAndMax(0, function() { + return calibrateServoMinAndMax(1, function() { + return calibrateServoMinAndMax(2, function() { + return robot.reset(cb); + }); + }); + }); + + }; // End of var calibrateServos = function(cb) + + return calibrateServos(function () { + return cb(); + }); + + }); + +}; // End of var calibrateRobot = function(cb) + +/** + * Reads JSON file containing desired capabilities for iOS device so as to run the calibraiton app. + * + * @return {json} capabilities - The desired capabilities to use so as to deal with the good calibration app in the good device + */ +var readIosDesiredCapabilities = function(){ + return JSON.parse(fs.readFileSync('../../calibration/capabilities/ios-desired-capabilities.json', 'utf8')); +} + +/** + * Reads JSON file containing desired capabilities for Android device so as to run the calibraiton app. + * + * @return {json} capabilities - The desired capabilities to use so as to deal with the good calibration app in the good device + */ +var readAndroidDesiredCapabilities = function(){ + return JSON.parse(fs.readFileSync('../../calibration/capabilities/android-desired-capabilities.json', 'utf8')); +} + +/** + * Asks the user the OS of its device. + * Indeed if there is an iPhone with iOS or an Android handset, the capabilities to use with Appium or the regex + * in use to retrieve the coordinates will not be the same. + * + * @param {function} cb - An error clalback + * @return {json} capabilities - The desired capabilities to use so as to deal with the good calibration app in the good device + */ +var askForTypeOfDeviceOs = function(cb){ + + var schema = { + name:"answer", + description: 'What is the operating system of the device? Android (a) or iOS (i) or something else?', + type: 'string' + }; + + prompt.get(schema, function (err, result){ + + // Android handset + if (result.answer.toLowerCase().substr(0,1) == "a") { + + console.log("Using desired capabilities for Android handset"); + androidInUse = true; + iOSInUse = false; + return readAndroidDesiredCapabilities(); + + // iPhone + } else if (result.answer.toLowerCase().substr(0,1) == "i") { + + console.log("Using desired capabilities for iPhone"); + androidInUse = false; + iOSInUse = true; + return readIosDesiredCapabilities(); + + // Not supported OS (we are in 2017 guys... ;-D) + } else { + return cb(); + } + + }); + +}; // End of var askForTypeOfDeviceOs = function(cb) + +/** + * Caliibrates the robot for a dedicated device. + * Will lower the arms of the bot so as ot have contact points. + * Then will get coordinates displayed by a dedicated app in the device. + * The task will be made for 3 points. + */ +var calibrateDevice = function(cb){ + + newCalibrationData.device = { + contactPoint: { position:{},screenCoordinates:{} }, + point1: { position:{},screenCoordinates:{} }, + point2: { position:{},screenCoordinates:{} } + }; + + var driver = wd.remote({port:4723}); + + driver.on('http', function(meth, path, data) { + console.log(' > 1' + meth.magenta, path, (data || '').grey); + }); + + var lowerAndCheckForContact = function(x,y,currentZ, cb) { + + return robot.setPosition(x,y,currentZ,function() { + + setTimeout(function() { + var coordRegex = ( androidInUse ? androidCoordRegex : iOSCoordRegex ); + return driver.source(function(err, pageSource) { + if (coordRegex.test(pageSource)) { + var match = coordRegex.exec(pageSource); + var screenX = parseFloat(match[1]); + var screenY = parseFloat(match[2]); + console.log("Found Point: (" + x + "," + y + ") => (" + screenX + "," + screenY + ")"); + return cb(x,y,screenX,screenY,currentZ); + } else { + if (currentZ < -150) { + return robot.reset(function() { + return cb(Error("Could not touch the screen.")); + }); + } else { + return lowerAndCheckForContact(x, y, currentZ - 2, cb); + } + } + }); + }, 2000); + + }); // End of return robot.setPosition(x,y,currentZ,function() + + }; // End of var lowerAndCheckForContact = function(x,y,currentZ, cb) + + var desiredCapabilities = askForTypeOfDeviceOs(function(){console.log("Not supported OS");}); + + return driver.init(desiredCapabilities, function() { + driver.setImplicitWaitTimeout(1000, function () { + return lowerAndCheckForContact(0, 0, -145, function (x, y, screenX, screenY, robotZ) { + newCalibrationData.device.contactPoint.position = {x: x, y: y, z:robotZ}; + newCalibrationData.device.contactPoint.screenCoordinates = {x: screenX, y: screenY}; + return lowerAndCheckForContact(0, 20, -145, function (x, y, screenX, screenY, robotZ) { + newCalibrationData.device.point1.position = {x: x, y: y, z:robotZ}; + newCalibrationData.device.point1.screenCoordinates = {x: screenX, y: screenY}; + return lowerAndCheckForContact(20, 0, -145, function (x, y, screenX, screenY, robotZ) { + newCalibrationData.device.point2.position = {x: x, y: y, z:robotZ}; + newCalibrationData.device.point2.screenCoordinates = {x: screenX, y: screenY}; + return robot.reset(cb); + }); + }); + }); + }); + }); // End of return driver.init + +}; // End of var calibrateDevice = function(cb) + +if(require.main === module) { + new CalibrationManager(getCommandLineArgs()).calibrate(); +} diff --git a/software/src/data.json b/software/src/data.json deleted file mode 100644 index d77a6afa..00000000 --- a/software/src/data.json +++ /dev/null @@ -1,240 +0,0 @@ -[[ - { - "x": 2.013888359069824, - "y": -0.9861116409301758 - }, - { - "x": 0.013888359069824219, - "y": -0.9861116409301758 - }, - { - "x": 0.013888359069824219, - "y": 4.013888359069824 - }, - { - "x": 9.013888359069824, - "y": 23.01388931274414 - }, - { - "x": 24.01388931274414, - "y": 36.01388931274414 - }, - { - "x": 35.01388931274414, - "y": 48.01388931274414 - }, - { - "x": 44.01388931274414, - "y": 65.01388549804688 - }, - { - "x": 47.01388931274414, - "y": 76.01388549804688 - }, - { - "x": 55.01388931274414, - "y": 93.01388549804688 - }, - { - "x": 67.01388549804688, - "y": 104.01388549804688 - }, - { - "x": 85.01388549804688, - "y": 117.01388549804688 - }, - { - "x": 106.01388549804688, - "y": 149.01388549804688 - }, - { - "x": 107.01388549804688, - "y": 154.01388549804688 - }, - { - "x": 114.01388549804688, - "y": 165.01388549804688 - }, - { - "x": 123.01388549804688, - "y": 173.01388549804688 - }, - { - "x": 132.01388549804688, - "y": 178.01388549804688 - }, - { - "x": 163.01388549804688, - "y": 214.01388549804688 - }, - { - "x": 187.01388549804688, - "y": 233.01388549804688 - }, - { - "x": 226.01388549804688, - "y": 276.0138854980469 - }, - { - "x": 252.01388549804688, - "y": 290.0138854980469 - }, - { - "x": 255.01388549804688, - "y": 294.0138854980469 - }, - { - "x": 260.0138854980469, - "y": 312.0138854980469 - }, - { - "x": 262.0138854980469, - "y": 313.0138854980469 - }, - { - "x": 266.0138854980469, - "y": 323.0138854980469 - }, - { - "x": 270.0138854980469, - "y": 326.0138854980469 - }, - { - "x": 279.0138854980469, - "y": 329.0138854980469 - }, - { - "x": 287.0138854980469, - "y": 337.0138854980469 - } -] -, [ - { - "x": 294.0138854980469, - "y": 6.013888359069824 - }, - { - "x": 255.01388549804688, - "y": 49.01388931274414 - }, - { - "x": 253.01388549804688, - "y": 53.01388931274414 - }, - { - "x": 245.01388549804688, - "y": 59.01388931274414 - }, - { - "x": 242.01388549804688, - "y": 68.01388549804688 - }, - { - "x": 239.01388549804688, - "y": 70.01388549804688 - }, - { - "x": 235.01388549804688, - "y": 82.01388549804688 - }, - { - "x": 225.01388549804688, - "y": 92.01388549804688 - }, - { - "x": 216.01388549804688, - "y": 97.01388549804688 - }, - { - "x": 209.01388549804688, - "y": 106.01388549804688 - }, - { - "x": 203.01388549804688, - "y": 123.01388549804688 - }, - { - "x": 195.01388549804688, - "y": 134.01388549804688 - }, - { - "x": 178.01388549804688, - "y": 145.01388549804688 - }, - { - "x": 169.01388549804688, - "y": 154.01388549804688 - }, - { - "x": 156.01388549804688, - "y": 176.01388549804688 - }, - { - "x": 153.01388549804688, - "y": 185.01388549804688 - }, - { - "x": 126.01388549804688, - "y": 229.01388549804688 - }, - { - "x": 115.01388549804688, - "y": 244.01388549804688 - }, - { - "x": 102.01388549804688, - "y": 258.0138854980469 - }, - { - "x": 88.01388549804688, - "y": 269.0138854980469 - }, - { - "x": 87.01388549804688, - "y": 272.0138854980469 - }, - { - "x": 68.01388549804688, - "y": 282.0138854980469 - }, - { - "x": 54.01388931274414, - "y": 287.0138854980469 - }, - { - "x": 50.01388931274414, - "y": 292.0138854980469 - }, - { - "x": 47.01388931274414, - "y": 305.0138854980469 - }, - { - "x": 43.01388931274414, - "y": 310.0138854980469 - }, - { - "x": 35.01388931274414, - "y": 315.0138854980469 - }, - { - "x": 30.01388931274414, - "y": 315.0138854980469 - }, - { - "x": 20.01388931274414, - "y": 320.0138854980469 - }, - { - "x": 20.01388931274414, - "y": 322.0138854980469 - }, - { - "x": 16.01388931274414, - "y": 326.0138854980469 - }, - { - "x": 13.013888359069824, - "y": 337.0138854980469 - } -]] diff --git a/software/src/demo/angry-birds/angrybirds.js b/software/src/demo/angry-birds/angrybirds.js deleted file mode 100644 index 86643ec3..00000000 --- a/software/src/demo/angry-birds/angrybirds.js +++ /dev/null @@ -1,244 +0,0 @@ -var five = require("johnny-five") -var kin = require("./../../kinematics.js"); -var config = require("./../../../config.js"); - -drawHeight = config.drawHeight; - -board = new five.Board({ - debug: false -}); - -k = new kin.Kinematics({ - e: config.e, - f: config.f, - re: config.re, - rf: config.rf -}) - -board.on("ready", function() { - // Setup - /*servo1 = five.Servo({ - address: 0x40, - controller: "PCA9685", - pin: 0, - range: [35, 145] //Too high of a minimum input will cause issues with the forward kinematics - }); - servo2 = five.Servo({ - address: 0x40, - controller: "PCA9685", - pin: 1, - range: [35, 145] - }); - servo3 = five.Servo({ - address: 0x40, - controller: "PCA9685", - pin: 2, - range: [35, 145] - }); */ - - servo1 = five.Servo({ - pin: 9, - range: [0, 100] - }); - - servo2 = five.Servo({ - pin: 10, - range: [0, 100] - }); - - servo3 = five.Servo({ - pin: 11, - range: [0, 100] - }); - - servo1.on("error", function() { - console.log(arguments); - }) - servo2.on("error", function() { - console.log(arguments); - }) - servo3.on("error", function() { - console.log(arguments); - }) - - board.repl.inject({ - servo1: servo1, - s1: servo1, - servo2: servo2, - s2: servo2, - servo3: servo3, - s3: servo3, - }); - - // Move to starting point - var max = 15; - var min = 5; - var range = max - min; - servo1.to(15); - servo2.to(15); - servo3.to(15); - - /* - var dance = function() { - servo1.to(parseInt((Math.random() * range) + min, 10)); - servo2.to(parseInt((Math.random() * range) + min, 10)); - servo3.to(parseInt((Math.random() * range) + min, 10)); - }; - - var dancer; - - start_dance = function() { - if (!dancer) dancer = setInterval(dance, 250); - } - - stop_dance = function() { - if (dancer) { - clearInterval(dancer); - dancer = null; - } - } - - board.repl.inject({ - dance: start_dance, - chill: stop_dance - }); */ - - -}); - -rotate = function(x,y) { - var theta = -60 * Math.PI / 180; - x1 = x * Math.cos(theta) - y * Math.sin(theta); - y1 = y * Math.cos(theta) + x * Math.sin(theta); - return [x1,y1] -} - -reflect = function(x,y) { - var theta = 0; - x1 = x; - y1 = x * Math.sin(2*theta) - y * Math.cos(2*theta); - return [x1,y1] -} - -Number.prototype.map = function ( in_min , in_max , out_min , out_max ) { - return ( this - in_min ) * ( out_max - out_min ) / ( in_max - in_min ) + out_min; -} - -moveServosTo = function(x, y, z) { - reflected = reflect(x,y); - rotated = rotate(reflected[0],reflected[1]); - - angles = k.inverse(rotated[0], rotated[1], z); - - servo1.to((angles[1]).map(config.servo1.in_min, config.servo1.in_max, config.servo1.out_min, config.servo1.out_max)); - servo2.to((angles[2]).map(config.servo2.in_min, config.servo2.in_max, config.servo2.out_min, config.servo2.out_max)); - servo3.to((angles[3]).map(config.servo3.in_min, config.servo3.in_max, config.servo3.out_min, config.servo3.out_max)); - console.log(angles); -} - -move = function(x,y,z, when) { - setTimeout(function(){ moveServosTo(x,y,z) }, moveTimer); - moveTimer += when; -} - -resetMoveTimer = function() { - moveTimer = 0; -} - -var moveTimer = 0; - -playLevelOne = function(){ - resetMoveTimer(); - move(-20, -3, drawHeight + 10, 0); - move(-20, -3, drawHeight, 500); - move(-35,-6, drawHeight,300); - move(-35,-6, drawHeight + 10,400); - move(-30,0, drawHeight + 10,400); - - move(42,-18, drawHeight + 10, 2800); - move(42,-18, drawHeight - 3, 500); - move(42, -18, drawHeight + 10, 500); - - move(9,-13, drawHeight + 10, 3000); - move(9,-13, drawHeight - 2, 300); - move(9, -13, drawHeight + 10,300); - move(0,0, drawHeight + 10,300); -} - -playLevelTwo = function() { - resetMoveTimer(); - move(-20, -3, drawHeight + 10, 500); - move(-20, -3, drawHeight, 200); - move(-35, -2, drawHeight, 300); - move(-35, -2, drawHeight + 10, 300); - move(-20, -3, drawHeight + 10, 15000); - move(-20, -3, drawHeight - 1, 300); - move(-35, -8, drawHeight, 400); - move(-35, -8, drawHeight + 10, 300); - - move(42, -18, drawHeight + 10, 6000); - move(42, -18, drawHeight - 3, 500); - move(42, -18, drawHeight + 10, 500); - - move(9, -13, drawHeight + 10, 3000); - move(9, -13, drawHeight - 2, 300); - move(9, -13, drawHeight + 10, 300); - move(0, 0, drawHeight + 10, 400); -} - -playLevelThree = function() { - resetMoveTimer(); - move(-20, -3, drawHeight + 10, 1000); - move(-20, -3, drawHeight, 200); - move(-25, -10, drawHeight, 350); - move(-23, -6.5, drawHeight, 350); - move(-23, -6.5, drawHeight + 10, 350); - - move(42, -18, drawHeight + 10, 8000); - move(42, -18, drawHeight - 3, 500); - move(42, -18, drawHeight + 10, 500); -}; - -goToLevelOne = function() { - resetMoveTimer(); - move(-14, -12, drawHeight + 10, 250); - move(-14, -12, drawHeight - 2, 250); - move(-14, -12, drawHeight + 10, 250); - move(-48, 23, drawHeight + 10, 1000); - move(-46, 23, drawHeight - 2, 1000); - move(-48, 23, drawHeight + 10, 500); - move(45, -18, drawHeight + 10, 500); - move(41, -18, drawHeight - 4, 500); - move(45, -18, drawHeight + 10, 500); - move(0, 0, drawHeight + 10, 250); -} - -repeat = function(){ - move(4,-32,-140,0); - move(4,-32,-149,300); - move(4,-32,-140,600); - move(0,0,-120,900); -} - -playLevels = function() { - resetMoveTimer(); - var objRef = this; - setTimeout(objRef.playLevelOne, 0); - setTimeout(objRef.playLevelTwo, 15000); - setTimeout(objRef.playLevelThree, 47500); - setTimeout(goToLevelOne, 65000); -} - - -play_forever = function(){ - var objRef = this; - console.log("Now playing forever...") - this.playLevels(); - interval = setInterval(objRef.playLevels, 70000); - return interval; -} - -stop_playing = function() { - clearInterval(interval); - console.log("No longer playing forever."); -} \ No newline at end of file diff --git a/software/src/demo/angry-birds/play-angry-birds.js b/software/src/demo/angry-birds/play-angry-birds.js deleted file mode 100644 index 63b1528a..00000000 --- a/software/src/demo/angry-birds/play-angry-birds.js +++ /dev/null @@ -1,29 +0,0 @@ -sleep = require('teddybear'); - -move = function(x, y, z) { - go(x, y, z); - sleep(1000); -} - -play = function() { - move(25,-10,-140); - move(25,-10,-147); - move(35,-15,-145); - move(35,-15,-145); - move(0,0,-130); -} - - -sleep = require('teddybear'); - -throw_bird = function() { - go(7,33,-155); - sleep(500); - go(7,33,-160); - sleep(500); - go(14,50,-158); - sleep(500); - go(14,50,-158); - sleep(500); - go(0,0,-130); -} \ No newline at end of file diff --git a/software/src/demo/angry-birds/play_angry_birds.txt b/software/src/demo/angry-birds/play_angry_birds.txt deleted file mode 100644 index 8fb0ee8c..00000000 --- a/software/src/demo/angry-birds/play_angry_birds.txt +++ /dev/null @@ -1,42 +0,0 @@ -throw_bird = function() { - - go(7,33,-145); - - setTimeout((function() { - go(7,33,-140); - }), 500); - - setTimeout((function() { - go(14,50,-148); - //go(18,53,-158) - }), 1000); - - setTimeout((function() { - //go(18,53,-151) - go(14,50,-148); - }), 1500); - - setTimeout((function() { - go(0,0,-130); - }), 2000); -} -throw_bird() - -repeat = function() { - setTimeout((function() { - go(22,12,-155); - }), 0); - - setTimeout((function() { - go(22,12,-161); - }), 500); - - setTimeout((function() { - go(22,12,-155); - }), 1000); - - setTimeout((function() { - go(0,0,-130); - }), 1500); -} - diff --git a/software/src/demo/hi.js b/software/src/demo/hi.js deleted file mode 100644 index 768f5bd1..00000000 --- a/software/src/demo/hi.js +++ /dev/null @@ -1,70 +0,0 @@ -five = require("johnny-five"); -bot = require("bot"); -board = new five.Board({ - debug: false -}); - -board.on("ready", function() { - // Setup - servo1 = five.Servo({ - pin: 9, - range: [0,90] - }); - servo2 = five.Servo({ - pin: 10, - range: [0,90] - }); - servo3 = five.Servo({ - pin: 11, - range: [0, 90] - }); - - servo1.on("error", function() { - console.log(arguments); - }) - servo2.on("error", function() { - console.log(arguments); - }) - servo3.on("error", function() { - console.log(arguments); - }) - - board.repl.inject({ - servo1: servo1, - s1: servo1, - servo2: servo2, - s2: servo2, - servo3: servo3, - s3: servo3, - }); - - bot.go(0, 0, -140); - }); - -hi = function() { - setTimeout(function() { go(-20, 20, -150) }, 0); - setTimeout(function() { go(-20, -20, -150) }, 250); - setTimeout(function() { go(-20, 0, -150) }, 500); - setTimeout(function() { go(-10, 0, -150) }, 750) - setTimeout(function() { go(-10, 20, -150) }, 1000); - setTimeout(function() { go(-10, -20, -150) }, 1250); - - setTimeout(function() { go(-10, -20, -140) }, 1500); - setTimeout(function() { go(-5, -20, -140) }, 1750) - setTimeout(function() { go(-5, -20, -150) }, 2000); - setTimeout(function() { go(-5, 0, -150) }, 2250); - setTimeout(function() { go(-5, 0, -140) }, 2500); - setTimeout(function() { go(-5, 10, -140) }, 2750); - setTimeout(function() { go(-5, 10, -150) }, 3000); - setTimeout(function() { go(-5, 15, -150) }, 3250); - - setTimeout(function() { go(-5, 20, -140) }, 3500); - setTimeout(function() { go(5, 20, -140) }, 3750); - setTimeout(function() { go(5, 20, -150) }, 4000); - setTimeout(function() { go(5, -10, -150) }, 4250); - setTimeout(function() { go(5, -10, -140) }, 4500); - setTimeout(function() { go(5, -15, -140) }, 4750); - setTimeout(function() { go(5, -15, -150) }, 5000); - setTimeout(function() { go(5, -20, -150) }, 5250); - setTimeout(function() { go(5, 0, -140) }, 5500); - } diff --git a/software/src/draw.js b/software/src/draw.js deleted file mode 100644 index 066eb054..00000000 --- a/software/src/draw.js +++ /dev/null @@ -1,345 +0,0 @@ -//Draws lines and shapes. - -var fs = require('fs'); -var objRef, defaultEaseType; -var calculated, spiralPts; - -function Draw(args) { - this.baseWidth = 80; - this.baseHeight = 95; - this.drawHeight = -140; - this.defaultEaseType = "linear"; - - if (args) { - var keys = Object.keys(args); - keys.forEach(function(key){ - this[key] = args[key]; - }, this) - } - penHeight = this.drawHeight; - defaultEaseType = this.defaultEaseType; - objRef = this; -} - -//Maps point from canvas to the Tapster coordinate plane -//The conversion is based on the canvas size and the size of the Tapster base -//These can be changed as needed -mapPoints = function(x, y) { - var newX = x; - var newY = y; - - newX = (newX - halfway.x) / widthRatio; - newY = (halfway.y - newY) / heightRatio; - return {x:newX, y:newY}; -}; - -//Adds delays while the Tapster is writing -//The specific delay can be changed if the bot has to go slower or faster for a particular segment -/*doSetTimeout = function(x, y, z, delay, easing) { - if (!easing) - easing = defaultEaseType; - setTimeout(function() { go(x, y, z, easing) }, timer); - currentPoint = {x: x, y: y, z: z}; - timer = timer + delay; -}; */ - -//Initialized here so that they are accessible from the mapPoints function -var baseHeight, baseWidth, canvasHeight, canvasWidth, heightRatio, widthRatio, halfway; - -var currentPoint = {x: 0, y: 0, z: -140}; -var penHeight = this.drawHeight; - -//Set the penHeight from the command line -Draw.prototype.setPenHeight = function(height) { - penHeight = height; - console.log("The pen is now set at: " + height); -} - -//Draws an image from a JSON file of coordinates -//The SVGReader drawSVG method is preferred -Draw.prototype.drawFromCoordinates = function() { - - baseHeight = this.baseHeight; - baseWidth = this.baseWidth; - canvasHeight = baseHeight * 3.779527559; //Set ratio of ~1:3.8 mm:px - canvasWidth = baseWidth * 3.779527559; - - //The ratio between the sizes of the canvas and robot. - //It will always be 3.779527559 because the canvas size is set - //according to that ratio - heightRatio = 3.779527559; - widthRatio = 3.779527559; - - //The center of the canvas - halfway = {x:canvasWidth / 2, y:canvasHeight / 2}; - - - var jFile = fs.readFileSync('.//data.json', 'utf8'); //Reads data from a JSON file of coordinates - var objArr = JSON.parse(jFile); //Creates an array out of the data - - //Loops through the JSON array - for (var i = 0; i < objArr.length; i++) { - var x = 0; - if (objArr[i].length > 0) { //If there are multiple lines - var point = objArr[i][x]; - var transMap = mapPoints(point.x, point.y); - doSetTimeout(transMap.x, transMap.y, penHeight + 20, 200); //Moves the arm vertically so that it does not draw a line between the last point of one line - //and the first point of another - - for (x = 0; x < objArr[i].length; x++) { - point = objArr[i][x]; - var mapped = mapPoints(point.x, point.y); - doSetTimeout(mapped.x, mapped.y, penHeight, 100); - } - transMap = mapPoints(point.x, point.y); - doSetTimeout(transMap.x, transMap.y, penHeight + 20, 200); - } - - else { //Only one line to be drawn - point = objArr[i]; - var mapped = mapPoints(point.x, point.y); - doSetTimeout(mapped.x, mapped.y, penHeight, 100); - } - } -}; - -//Draws a square in order to ensure that everything is working properly -//Optional args: -//sideLength: the length of each side (default: 20) -//n: draws every nth point (default: 2) -Draw.prototype.drawSquare = function(args) { - - //Default values - this.sideLength = 20; - this.n = 2; - - if (args) { - var keys = Object.keys(args) - keys.forEach(function(key){ - this[key] = args[key] - }, this) - } - - resetTimer(); //Reset the timer so that there isn't unnecessary delay when calling the function multiple times - - var halfSide = this.sideLength / 2; - var points = this.sideLength / this.n; - - doSetTimeout(-halfSide, halfSide, penHeight + 10, 0) - doSetTimeout(-halfSide, halfSide, penHeight, 500); //Top left corner - - for (var i = 0; i < points; i++) { //To bottom left - doSetTimeout(-halfSide, halfSide - (this.n * i), penHeight, i * 5); - } - - for (var i = 0; i < points; i++) { //To bottom right - doSetTimeout(-halfSide + (this.n * i), -halfSide, penHeight, i * 5); - } - - for (var i = 0; i < points; i++) { //To top right - doSetTimeout(halfSide, -halfSide + (this.n * i), penHeight, i * 5); - } - - for (var i = 0; i < points; i++) { //To top left - doSetTimeout(halfSide - (this.n * i), halfSide, penHeight, i * 5); - } - - doSetTimeout(0, 0, -140, timer + 100); - -}; - -//Draws a star to test that the Tapster bot is working properly -Draw.prototype.drawStar = function() { - resetTimer(); - doSetTimeout(-20, -20, penHeight, 1000); - doSetTimeout(0, 30, penHeight, 1000); - doSetTimeout(20, -20, penHeight, 1000); - doSetTimeout(-30, 10, penHeight, 1000); - doSetTimeout(30, 10, penHeight, 1000); - doSetTimeout(-20, -20, penHeight, 1000); - - //-20, -20, 0, 30, 20, -20 -}; - - -Draw.prototype.drawTriangle = function(x, y, x1, y1, x2, y2) { - resetTimer(); - doSetTimeout(x, y, penHeight, 1000); - doSetTimeout(x1, y1, penHeight, 1000); - doSetTimeout(x2, y2, penHeight, 1000); - doSetTimeout(x, y, penHeight, 1000); -} - -//Draws a circle -//Optional args: -//centerX: the x coordinate of the center (default: 0) -//centerY: the y coordinate of the center (default: 0) -//radius: the radius of the center (default: 20) -Draw.prototype.drawCircle = function(args) { - resetTimer(); - - this.centerX = 0; - this.centerY = 0; - this.radius = 20; - - if (args) { - var keys = Object.keys(args) - keys.forEach(function(key){ - this[key] = args[key] - }, this) - } - - // an array to save your points - var points=[]; - - // populate array with points along a circle - //Goes slightly over so that the circle is actually completed - for (var degree=0; degree < 395; degree++) { - var radians = (degree + 90) * Math.PI/180; - var x = this.centerX + this.radius * Math.cos(radians); - var y = this.centerY + this.radius * Math.sin(radians); - points.push({x:x,y:y}); - } - - circle = function() { - doSetTimeout(0, 0, -120, 50, "none"); - doSetTimeout(points[0].x, points[0].y, penHeight + 10, 150, "none"); - doSetTimeout(points[0].x, points[0].y, penHeight, 150, "none"); - for (var i=0; i - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - diff --git a/software/src/example/textTutorial.svg b/software/src/example/textTutorial.svg deleted file mode 100644 index d816475b..00000000 --- a/software/src/example/textTutorial.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/software/src/example/tutorial.svg b/software/src/example/tutorial.svg deleted file mode 100644 index 70ed47d9..00000000 --- a/software/src/example/tutorial.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/software/src/hello/helloChF.svg b/software/src/hello/helloChF.svg deleted file mode 100644 index 2fe5d962..00000000 --- a/software/src/hello/helloChF.svg +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/software/src/hello/helloEnT.svg b/software/src/hello/helloEnT.svg deleted file mode 100644 index c5fa4724..00000000 --- a/software/src/hello/helloEnT.svg +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/software/src/hello/helloFrF.svg b/software/src/hello/helloFrF.svg deleted file mode 100644 index e6997af1..00000000 --- a/software/src/hello/helloFrF.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/software/src/hello/helloItF.svg b/software/src/hello/helloItF.svg deleted file mode 100644 index b7dac35d..00000000 --- a/software/src/hello/helloItF.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/software/src/hello/helloJpF.svg b/software/src/hello/helloJpF.svg deleted file mode 100644 index aff0c36b..00000000 --- a/software/src/hello/helloJpF.svg +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/software/src/hello/helloRuF.svg b/software/src/hello/helloRuF.svg deleted file mode 100644 index d3d732e1..00000000 --- a/software/src/hello/helloRuF.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/software/src/hello/helloSpT.svg b/software/src/hello/helloSpT.svg deleted file mode 100644 index ae19b574..00000000 --- a/software/src/hello/helloSpT.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/software/src/kinematics.js b/software/src/kinematics.js deleted file mode 100644 index 400eeb12..00000000 --- a/software/src/kinematics.js +++ /dev/null @@ -1,135 +0,0 @@ -// Trigonometric constants -var s = 165 * 2; -var sqrt3 = Math.sqrt(3.0); -var pi = 3.141592653; -var sin120 = sqrt3 / 2.0; -var cos120 = -0.5; -var tan60 = sqrt3; -var sin30 = 0.5; -var tan30 = 1.0 / sqrt3; - -function Kinematics(args) { - //Side of end effector - this.e = 0; - - //Side of top triangle - this.f = 0; - - //Length of parallelogram joint - this.re = 0; - - //Length of upper joint - this.rf = 0; - - if (args) { - var keys = Object.keys(args) - keys.forEach(function(key){ - this[key] = args[key] - }, this) - } -} - -// Forward kinematics: (theta1, theta2, theta3) -> (x0, y0, z0) -// Returned {error code,theta1,theta2,theta3} -Kinematics.prototype.forward = function(theta1, theta2, theta3) { - var x0 = 0.0; - var y0 = 0.0; - var z0 = 0.0; - - var t = (this.f - this.e) * tan30 / 2.0; - var dtr = pi / 180.0; - - theta1 *= dtr; - theta2 *= dtr; - theta3 *= dtr; - - var y1 = -(t + this.rf * Math.cos(theta1)); - var z1 = -this.rf * Math.sin(theta1); - - var y2 = (t + this.rf * Math.cos(theta2)) * sin30; - var x2 = y2 * tan60; - var z2 = -this.rf * Math.sin(theta2); - - var y3 = (t + this.rf * Math.cos(theta3)) * sin30; - var x3 = -y3 * tan60; - var z3 = -this.rf * Math.sin(theta3); - - var dnm = (y2 - y1) * x3 - (y3 - y1) * x2; - - var w1 = y1 * y1 + z1 * z1; - var w2 = x2 * x2 + y2 * y2 + z2 * z2; - var w3 = x3 * x3 + y3 * y3 + z3 * z3; - - // x = (a1*z + b1)/dnm - var a1 = (z2 - z1) * (y3 - y1) - (z3 - z1) * (y2 - y1); - var b1 = -((w2 - w1) * (y3 - y1) - (w3 - w1) * (y2 - y1)) / 2.0; - - // y = (a2*z + b2)/dnm; - var a2 = -(z2 - z1) * x3 + (z3 - z1) * x2; - var b2 = ((w2 - w1) * x3 - (w3 - w1) * x2) / 2.0; - - // a*z^2 + b*z + c = 0 - var a = a1 * a1 + a2 * a2 + dnm * dnm; - var b = 2.0 * (a1 * b1 + a2 * (b2 - y1 * dnm) - z1 * dnm * dnm); - var c = (b2 - y1 * dnm) * (b2 - y1 * dnm) + b1 * b1 + dnm * dnm * (z1 * z1 - this.re * this.re); - - // discriminant - var d = b * b - 4.0 * a * c; - if (d < 0.0) { - return new Array(1, 0, 0, 0); // non-existing povar. return error,x,y,z - } - - z0 = -0.5 * (b + Math.sqrt(d)) / a; - x0 = (a1 * z0 + b1) / dnm; - y0 = (a2 * z0 + b2) / dnm; - - return new Array(0, x0, y0, z0); -}; - - - - -// Inverse kinematics - -// Helper functions, calculates angle theta1 (for YZ-pane) -Kinematics.prototype.delta_calcAngleYZ = function(x0, y0, z0) { - var y1 = -0.5 * 0.57735 * this.f; // f/2 * tg 30 - y0 -= 0.5 * 0.57735 * this.e; // shift center to edge - // z = a + b*y - var a = (x0 * x0 + y0 * y0 + z0 * z0 + this.rf * this.rf - this.re * this.re - y1 * y1) / (2.0 * z0); - var b = (y1 - y0) / z0; - - // discriminant - var d = -(a + b * y1) * (a + b * y1) + this.rf * (b * b * this.rf + this.rf); - if (d < 0) { - return new Array(1, 0); // non-existing povar. return error, theta - } - - var yj = (y1 - a * b - Math.sqrt(d)) / (b * b + 1); // choosing outer povar - var zj = a + b * yj; - var theta = Math.atan(-zj / (y1 - yj)) * 180.0 / pi + ((yj > y1) ? 180.0 : 0.0); - - return new Array(0, theta); // return error, theta - }; - - -Kinematics.prototype.inverse = function(x0, y0, z0) { - var theta1 = 0; - var theta2 = 0; - var theta3 = 0; - var status = this.delta_calcAngleYZ(x0, y0, z0); - - if (status[0] === 0) { - theta1 = status[1]; - status = this.delta_calcAngleYZ(x0 * cos120 + y0 * sin120, y0 * cos120 - x0 * sin120, z0, theta2); - } - if (status[0] === 0) { - theta2 = status[1]; - status = this.delta_calcAngleYZ(x0 * cos120 - y0 * sin120, y0 * cos120 + x0 * sin120, z0, theta3); - } - theta3 = status[1]; - - return new Array(status[0], theta1, theta2, theta3); -}; - -module.exports.Kinematics = Kinematics; \ No newline at end of file diff --git a/software/src/lib/SVGDraw.js b/software/src/lib/SVGDraw.js new file mode 100644 index 00000000..f7dfaa38 --- /dev/null +++ b/software/src/lib/SVGDraw.js @@ -0,0 +1,598 @@ +/* +Copyright (c) 2009-2018 by SVG-edit authors (see AUTHORS file) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +[This is the MIT License, https://opensource.org/licenses/MIT] +*/ + + +// Draws stuff from SVG files +// See project on GitHub: https://github.com/SVG-Edit/svgedit +// Previsouly picked from "demo" folder, and adapter for these softwares +// +// > To test: +// > svgRead.drawSVG(filepath) + + +/* ************ + * Useful tools + * ************/ + + var parse = require('svg-path-parser'); + var fs = require('fs'); + var draw = require("./draw"); + var xml2jsParseString = require('xml2js').parseString; + var motion = require("./motion"); + +/* ********* * + * Variables * + * ********* */ + +var firstPoint; + +var objArr; +var pathArray; + +var widthRatio; +var heightRatio; +var halfway; +var currentPoint; +var penHeight; +var delay, loaded, fontFile; +var transformX, transformY, objRef, connected, startTime, endTime, difference, clockTimer, firstMove, lastNum1, lastNum2, connect, baseWidth, baseHeight; + +var robotReference; +var drawer; + +/* ************************** + * Definition of super object + * **************************/ + + function SVGDraw(args, robot) { + + this.baseWidth = 80; + this.baseHeight = 95; + this.drawHeight = -150; + this.delay = 150; + this.defaultEaseType = "linear"; + + if (args) { + var keys = Object.keys(args) + keys.forEach(function(key){ + this[key] = args[key] + }, this) + } + + objRef = this; + defaultEaseType = this.defaultEaseType; + robotReference = robot; + drawer = new draw.Draw(null, robotReference); + + } + +/* ********************* * + * Defintions of methods * + * ********************* */ + +//Draws from an SVG image specified using its raw content +//Note: fconnect is a special flag that indicates that each path should be drawn connected to each other +//It is really only used for drawing in cursive and does not need to be specified otherwise +SVGDraw.prototype.drawSVG = function(content, connect) { + + drawer.resetTimer(); + var parsed; + + if (connect) connected = connect; + else connected = null; + + objRef = this; + + //Create a JSON string out of the SVG image data + //parseString strips away the XML data + try { + xml2jsParseString(content, function(err, result) { + parsed = JSON.stringify(result, null, 1); + }); + } catch (e) { + console.error(e); + throw e; + } + + //Parse the JSON string into an array + objArr = JSON.parse(parsed); + + //Extract width and height data from the drawing + var svgDimensions = dimensionConversion(objArr.svg.$.width, objArr.svg.$.height); + width = svgDimensions.width; + height = svgDimensions.height; + + var phoneWidth = this.baseWidth; + var phoneHeight = this.baseHeight; + penHeight = this.drawHeight; + + widthRatio = width / phoneWidth; + heightRatio = height / phoneHeight; + + //Start at the center of the canvas, which corresponds to (0,0) on the Tapster + halfway = {x:width / 2, y:height / 2}; + currentPoint = {x:halfway.x, y:halfway.y}; + + //If there are multiple groups. Additional check to make sure that there is actually path data + if (objArr.svg.g[0].g && objArr.svg.g[0].g[0].path) { + for (var i = 0; i < objArr.svg.g[0].g.length; i++) { + pathArray = objArr.svg.g[0].g[i].path; + drawImage(pathArray); + } + } + //Depending on how the paths are grouped, it is possible that this value can be greater than zero + else if (objArr.svg.g.length > 0) { + //If this is the case, loop through the array to get the path data + for (var i = 0; i < objArr.svg.g.length; i++) { + pathArray = objArr.svg.g[i].path; + drawImage(pathArray); + } + } + //If there is only one group + else if (objArr.svg.g[0].path) { + pathArray = objArr.svg.g[0].path; + drawImage(pathArray); + } + + drawer.doSetTimeout(0, 0, -130, delay); + +} + +drawImage = function(pathArray) { + var d = ""; + //After a group is done being drawn, firstMove is reset as there has not yet been a first move made in the next group + firstMove = null; + //When drawing multiple lines, there are multiple paths + for (var i = 0; i < pathArray.length; i++) { + firstPoint = null; + d = pathArray[i].$.d; + var commands = parse(d); + objRef.interpretCommands(commands); + } + drawer.doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, delay); +} + +//Move from one point to (x, y) +move = function(x, y) { + var ptArray = []; + //If the paths should not be connected, lift up the pen and move over so that a line is not drawn + if (!connected) { + drawer.doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, delay, "none"); + drawer.doSetTimeout(mapX(x), mapY(y), penHeight + 10, delay, "none"); + drawer.doSetTimeout(mapX(x), mapY(y), penHeight, delay, "none"); + } + //If the paths should be connected and a move has not been made, lift up the pen and move to the first point + else if (connected && !firstMove) { + drawer.doSetTimeout(mapX(currentPoint.x), mapY(currentPoint.y), penHeight + 10, delay, "none"); + drawer.doSetTimeout(mapX(x), mapY(y), penHeight + 10, delay, "none"); + drawer.doSetTimeout(mapX(x), mapY(y), penHeight, delay, "none"); + } + else //If the paths should be connected and a move has been made, just draw a line between the two paths + drawer.doSetTimeout(mapX(x), mapY(y), penHeight, delay); + + currentPoint = {x:x, y:y}; //Update the current point (done every time an SVG command is called) + + if (!firstMove) //Keeps track of if a move has been made or not. + firstMove = true; + + if (!firstPoint) //Keeps track of the first point, for use with the Z/z command + firstPoint = {x:currentPoint.x, y:currentPoint.y}; //Since the first command of a path is always to Move, this check only occurs here + +} + +//Move from one point to that that point + x, y +relMove = function(x, y) { + x = currentPoint.x + x; + y = currentPoint.y + y; + move(x, y); +} + +//Draw a line from one point to (x, y) +line = function(x, y) { + var ptArray = []; + drawer.doSetTimeout(mapX(x), mapY(y), penHeight, delay, "linear"); + currentPoint = {x:x, y:y}; +} + +//Draw a line from one point to that point + x, y +relLine = function(x, y) { + x = currentPoint.x + x; + y = currentPoint.y + y; + line(x, y); +} + +//Draws a cubic Bezier curve. +//(x1,y1) is the first control point +//(x2, y2) is the second +//(x, y) is the end point +cubicCurve = function(x1, y1, x2, y2, x, y) { + + //Function for calculating the coordinates of points on the curve + //Calculates t+1 points + b = function(x1, y1, x2, y2, x, y, t) { + var ptArray = new Array(); + for (var i = 0; i <= t; i++) { + var newI = i/t; //Converts i to a decimal, to satisfy 0 <= i <= 1 + var ptX = (Math.pow((1-newI), 3) * currentPoint.x) + (3 * Math.pow((1-newI), 2) * newI * x1) //From https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves + + (3 * (1-newI) * Math.pow(newI, 2) * x2) + (Math.pow(newI, 3) * x); + var ptY = (Math.pow((1-newI), 3) * currentPoint.y) + (3 * Math.pow((1-newI), 2) * newI * y1) + + (3 * (1-newI) * Math.pow(newI, 2) * y2) + (Math.pow(newI, 3) * y); + var newPt = {x:ptX, y:ptY, z:penHeight}; + ptArray.push(newPt); //Populates the array with points + } + currentPoint = {x:ptArray[t].x, y:ptArray[t].y}; + return ptArray; + } + + var curvePts = new Array(); + curvePts = b(x1, y1, x2, y2, x, y, 5); //Arbitrarily-chosen value. It creates a smooth-looking curve without calculating too many points + for (var i = 0;i < curvePts.length; i++) + drawer.doSetTimeout(mapX(curvePts[i].x), mapY(curvePts[i].y), penHeight, delay*2 / curvePts.length, "none"); //The cubic curve command takes 2*delay ms to complete so that an accurate curve is created +} + +//Draws a relative cubic Bezier curve +relCubicCurve = function(x1, y1, x2, y2, x, y) { + var tempX = currentPoint.x; + var tempY = currentPoint.y; + cubicCurve(tempX + x1, tempY + y1, tempX + x2, tempY + y2, tempX + x, tempY + y); +} + +//Draws a quadratic Bezier curve +//(x1, y1) is the control point +//(x, y) is the end point +quadraticCurve = function(x1, y1, x, y) { + + //Helper function for generating the points + q = function(x1, y1, x, y, t) { + var ptArray = new Array(); + for (var i = 0; i <= t; i++) { + var newI = i/t; //Converts i to a decimal, to satisfy 0 <= i <= 1 + var ptX = Math.pow((1-newI), 2)*currentPoint.x + (2 * (1-newI) * newI * x1) + (Math.pow(newI, 2) * x); //From https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Quadratic_B.C3.A9zier_curves + var ptY = Math.pow((1-newI), 2)*currentPoint.y + (2 * (1-newI) * newI * y1) + (Math.pow(newI, 2) * y); + var newPt = {x:ptX, y:ptY, z:penHeight}; + ptArray.push(newPt); + } + currentPoint = {x:ptArray[t].x, y:ptArray[t].y}; + return ptArray; + } + + var curvePts = new Array(); + curvePts = q(x1, y1, x, y, 5); + for (var i = 0; i < curvePts.length; i++) + drawer.doSetTimeout(mapX(curvePts[i].x), mapY(curvePts[i].y), penHeight, delay*2 / curvePts.length, "none"); + +} + +//Draws a relative quadratic Bezier curve +relQuadraticCurve = function(x1, y1, x, y) { + var tempX = currentPoint.x; + var tempY = currentPoint.y; + quadraticCurve(tempX + x1, tempY + y1, tempX + x, tempY + y); +} + +//Draws an elliptical arc +//rx and ry are the radii +//rotation is the angle (in degrees) between the rotated x-axis and the original x-axis +//largeArc is a flag that determines if the arc is greater than or less than or equal to 180 degrees +//sweep is a flag that determines if the arc is drawn in a positive direction or a negative direction +//(x, y) is the final point of the arc +//From: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes +arc = function(rx, ry, rotation, largeArc, sweep, x, y) { + + //Helper function for calculating the points + a = function(rx, ry, largeArc, sweep, x, y, t) { + var ptArray = new Array(); + + for (var i = 0; i <= t; i++) { + var newI = i / t; + var angle = startAngle + sweepAngle * newI; + var newPt = {x: cx + rx * cos(angle), y: cy + ry * sin(angle), z:penHeight}; + ptArray.push(newPt); + } + + currentPoint = {x: ptArray[t].x, y: ptArray[t].y}; + return ptArray; + } + + //Helper function for calculating the angle between two vectors + angleBetween = function(v1, v2) { + var p = v1.x*v2.x + v1.y*v2.y; + var n = Math.sqrt((Math.pow(v1.x, 2)+Math.pow(v1.y, 2)) * (Math.pow(v2.x, 2)+Math.pow(v2.y, 2))); + var sign = v1.x*v2.y - v1.y*v2.x < 0 ? -1 : 1; + var angle = sign*Math.acos(p/n) * 180 / Math.PI; + + return angle; + } + + tempX = currentPoint.x; + tempY = currentPoint.y; + + var xPrime = (cos(rotation) * ((tempX - x) / 2)) + (sin(rotation) * ((tempY - y) / 2)); + var yPrime = (-sin(rotation) * ((tempX - x) / 2)) + (cos(rotation) * ((tempY - y) / 2)); + + //Checks to ensure radii are as they should be + rx = Math.abs(rx); //Ensures they are non-zero and positive + ry = Math.abs(ry); + + var lambda = (Math.pow(xPrime, 2) / Math.pow(rx, 2)) + (Math.pow(yPrime, 2) / Math.pow(ry, 2)); + + if (lambda > 1) { //Ensures they are large enough + rx = Math.sqrt(lambda) * rx; + ry = Math.sqrt(lambda) * ry; + } + + var sign = 1; + + if (largeArc == sweep) //If they are equal, cPrime is negative + sign = -1; + + //For some reason this would occasionally result in NaN + //Implemented this check at the suggestion of: + //http://users.ecs.soton.ac.uk/rfp07r/interactive-svg-examples/arc.html + var cPrimeNumerator = ((Math.pow(rx, 2) * Math.pow(ry, 2)) - (Math.pow(rx, 2) * Math.pow(yPrime, 2)) - (Math.pow(ry, 2) * Math.pow(xPrime, 2))); + var cPrimeDenom = ((Math.pow(rx, 2) * Math.pow(yPrime, 2)) + (Math.pow(ry, 2) * Math.pow(xPrime, 2))); + + if ((cPrimeNumerator / cPrimeDenom) < 1e-7) + cPrime = 0; + else + cPrime = Math.sqrt(cPrimeNumerator / cPrimeDenom); + + //Calculates the transformed center + var cxPrime = sign * cPrime * ((rx * yPrime) / ry); + var cyPrime = sign * cPrime * (-(ry * xPrime) / rx); + + //Calculates the original center + var cx = ((cos(rotation) * cxPrime) + (-sin(rotation) * cyPrime)) + ((tempX + x) / 2); + var cy = ((sin(rotation) * cxPrime) + (cos(rotation) * cyPrime)) + ((tempY + y) / 2); + + //Calculates the start angle of the arc and the total change in the angle + var startVector = {x: (xPrime - cxPrime) / rx, y: (yPrime - cyPrime) / ry}; + var startAngle = angleBetween({x:1, y:0}, startVector); + var endVector = {x: (-xPrime - cxPrime) / rx, y: (-yPrime - cyPrime) / ry}; + var sweepAngle = angleBetween(startVector, endVector); + + if (!sweep && sweepAngle > 0) { + sweepAngle -= 360; + } + + else if (sweep && sweepAngle < 0) { + sweepAngle += 360; + } + + sweepAngle %= 360; + + var ptArray = a(rx, ry, largeArc, sweep, x, y, 5); + + for (var i = 0; i < ptArray.length; i++) { + drawer.doSetTimeout(mapX(ptArray[i].x), mapY(ptArray[i].y), penHeight, delay*2 / ptArray.length, "none"); + } + +} + +//Function for drawing a relative elliptical arc +relArc = function(rx, ry, rotation, largeArc, sweep, x, y) { + x = currentPoint.x + x; + y = currentPoint.y + y; + arc(rx, ry, rotation, largeArc, sweep, x, y); +} + +//A function for setting the penHeight from the command line +setPenHeight = function(penHeight) { + penHeight = penHeight; +} + +//Reflects the point (x,y) across the point (x1, y1) +//For use with smooth curves +reflect = function(x, y, x1, y1) { + var tempX = x; + var tempY = y; + + tempX = x1 - (tempX - x1); + tempY = y1 - (tempY - y1); + + var point = {x:tempX, y:tempY}; + + return point; +} + +//Convert points pixel coordinates to Tapster coordinates +//Done in two methods for ease of use +mapX = function(x) { + var newX = x; + newX = (newX - halfway.x) / widthRatio; //The center of the canvas corresponds to (0, 0) on the Tapster + return newX; +}; + +mapY = function(y) { + var newY = y; + newY = (halfway.y - newY) / heightRatio; + return newY; +} + +// A sine function for working with degrees, not radians +sin = function(degree) { + return Math.sin(Math.PI * (degree/180)); +} + +// A cosine function for working with degrees, not radians +cos = function(degree) { + return Math.cos(Math.PI * (degree/180)); +} + +//Function for converting Inkscape dimensions into Tapster-friendly pixels +//Should switch to switch statements +dimensionConversion = function(width, height) { + width = String(width); + if (width.search("mm") != -1) { + var dimension = {width: parseInt(width) * 3.779527559, height: parseInt(height) * 3.779527559}; //The px:mm ratio is ~ 3.8:1 + } + else if (width.search("in") != -1) { + var dimension = {width: parseInt(width) * 96, height: parseInt(height) * 96}; //The px:in ratio is 96:1 + } + else if (width.search("ft") != -1) { + var dimension = {width: parseInt(width) * 96 * 12, height: parseInt(height) * 96 * 12}; //The px:ft ratio is 96*12:1 + } + else if (width.search("m") != -1) { + var dimension = {width: parseInt(width) * 3.779527559 * 1000, height: parseInt(height) * 3.779527559 * 1000}; //The px:m ratio is ~3.8*1000:1 + } + else if (width.search("cm") != -1) { + var dimension = {width: parseInt(width) * 3.779527559 * 100, height: parseInt(height) * 3.779527559 * 100}; //The px:cm ratio is ~3.8*100:1 + } + else if (width.search("pt") != -1) { + var dimension = {width: parseInt(width) * 1.3333, height: parseInt(height) * 1.3333}; //The px:pt ratio is ~1.3:1 + } + else if (width.search("pc") != -1) { + var dimension = {width: parseInt(width) * 16, height: parseInt(height) * 16}; //The px:pc ratio is 16:1 + } + else //No unit specified == pixels + var dimension = {width: width, height: height}; + + return dimension; +} + +//Goes through the list of commands an generated by the SVG-Path-Parser and calls the corresponding functions +//Should switch to switch statements +SVGDraw.prototype.interpretCommands = function(commands) { + delay = this.delay; + for (var i = 0; i < commands.length; i++) { + var cmdCode = commands[i].code; + switch (cmdCode) { + case 'M': + move(commands[i].x, commands[i].y); + break; + + case 'm': + relMove(commands[i].x, commands[i].y); + break; + + case 'L': + line(commands[i].x, commands[i].y); + break; + + case 'l': + relLine(commands[i].x, commands[i].y); + break; + + case 'V': + line(currentPoint.x, commands[i].y); + break; + + case 'v': + relLine(currentPoint.x, commands[i].y); + break; + + case 'H': + line(commands[i].x, currentPoint.y); + break; + + case 'h': + relLine(commands[i].x, currentPoint.y); + break; + + case 'C': + cubicCurve(commands[i].x1, commands[i].y1, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); + break; + + case 'c': + relCubicCurve(commands[i].x1, commands[i].y1, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); + break; + + //Smooth cubic curve + case 'S': + if (i > 1 && (commands[i-1].code == 's' || commands[i-1].code == 'c' || commands[i-1].code == 'C' || commands[i-1].code == 'S')) { + var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); + var ctrl = {x:reflected.x, y:reflected.y}; + } + else + var ctrl = {x:currentPoint.x, y:currentPoint.y}; + + cubicCurve(ctrl.x, ctrl.y, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); + break; + + //Smooth relative cubic curve + case 's': + if (i > 1 && (commands[i-1].code == 's' || commands[i-1].code == 'c' || commands[i-1].code == 'C' || commands[i-1].code == 'S')) { + var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); + var ctrl = {x:reflect(commands[i-1].x2).x, y:reflect(commands[i-1].y2).y}; + } + else + var ctrl = {x:currentPoint.x, y:currentPoint.y}; + + relCubicCurve(ctrl.x, ctrl.y, commands[i].x2, commands[i].y2, commands[i].x, commands[i].y); + break; + + case 'Q': + quadraticCurve(commands[i].x1, commands[i].y1, commands[i].x, commands[i].y); + break; + + case 'q': + relQuadraticCurve(commands[i].x1, commands[i].y1, commands[i].x, commands[i].y); + break; + + //Smooth quadratic curve + case 'T': + if (i > 1 && (commands[i-1].code == 't' || commands[i-1].code == 'q' || commands[i-1].code == 'Q' || commands[i-1].code == 'T')) { + var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); + var ctrl = {x:reflect(commands[i-1].x1).x, y:reflect(commands[i-1].y1).y}; + } + else + var ctrl = {x:currentPoint.x, y:currentPoint.y}; + + quadraticCurve(ctrl.x, ctrl.y, commands[i].x, commands[i].y); + break; + + //Smooth relative quadratic curve + case 't': + if (i > 1 && (commands[i-1].code == 't' || commands[i-1].code == 'q' || commands[i-1].code == 'Q' || commands[i-1].code == 'T')) { + var reflected = reflect(commands[i].x, commands[i].y, commands[i-1].x, commands[i-1].y); + var ctrl = {x:reflect(commands[i-1].x1).x, y:reflect(commands[i-1].y1).y}; + } + else + var ctrl = {x:currentPoint.x, y:currentPoint.y}; + + relQuadraticCurve(ctrl.x, ctrl.y, commands[i].x, commands[i].y); + break; + + case 'A': + arc(commands[i].rx, commands[i].ry, commands[i].xAxisRotation, commands[i].largeArc, commands[i].sweep, commands[i].x, commands[i].y); + break; + + case 'a': + relArc(commands[i].rx, commands[i].ry, commands[i].xAxisRotation, commands[i].largeArc, commands[i].sweep, commands[i].x, commands[i].y); + break; + + case 'Z': + line(firstPoint.x, firstPoint.y); + firstPoint = null; + break; + + case 'z': + line(firstPoint.x, firstPoint.y); + firstPoint = null; + break; + } + } +} + +module.exports.SVGDraw = SVGDraw; diff --git a/software/src/lib/draw.js b/software/src/lib/draw.js new file mode 100644 index 00000000..89e3b6d7 --- /dev/null +++ b/software/src/lib/draw.js @@ -0,0 +1,422 @@ +/* + Copyright (c) 2011-2016, Tapster Committers + Copyright (c) 2018, Orange + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + [This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +*/ + +//Draws lines and shapes using if needed data.json file + +/* ************ + * Useful tools + * ************/ + +var fs = require('fs'); +var motion = require("./motion"); + +/* ********* * + * Variables * + * ********* */ + +var objRef, defaultEaseType; +var calculated, spiralPts; + +var baseHeight, baseWidth, canvasHeight, canvasWidth, heightRatio, widthRatio, halfway; + +var DRAW_HEIGHT = -152; +var currentPoint = {x: 0, y: 0, z: -140}; +var penHeight = DRAW_HEIGHT; + +var defaultEaseType = "linear"; +var timer = 0; +var current = [0, 0, DRAW_HEIGHT]; +var steps = 5; +var delay = 200 / steps; + +var robotReference; + +/* ************************** + * Definition of super object + * **************************/ + +function Draw(args, robot){ + + // FIXME Hardcoded values + this.baseWidth = 80; + this.baseHeight = 95; + this.drawHeight = DRAW_HEIGHT; // TODO Use calibration data instead! + this.defaultEaseType = "linear"; + + if (args){ + var keys = Object.keys(args); + keys.forEach(function(key){ + this[key] = args[key]; + }, this) + } + + penHeight = this.drawHeight; + defaultEaseType = this.defaultEaseType; + objRef = this; + + robotReference = robot; + +} + + +/* ********************* * + * Defintions of methods * + * ********************* */ + +//Maps point from canvas to the Tapster coordinate plane +//The conversion is based on the canvas size and the size of the Tapster base +//These can be changed as needed +mapPoints = function(x, y){ + var newX = x; + var newY = y; + newX = (newX - halfway.x) / widthRatio; + newY = (halfway.y - newY) / heightRatio; + return {x:newX, y:newY}; +}; + + +//Set the penHeight from the command line +Draw.prototype.setPenHeight = function(height){ + penHeight = height; +} + +//Draws a square in order to ensure that everything is working properly +//Optional args: +//sideLength: the length of each side (default: 20) +//n: draws every nth point (default: 2) +Draw.prototype.drawSquare = function(args){ + + //Default values + this.sideLength = 30; + this.n = 2; + + if (args) { + var keys = Object.keys(args) + keys.forEach(function(key){ + this[key] = args[key] + }, this) + } + + objRef.resetTimer(); //Reset the timer so that there isn't unnecessary delay when calling the function multiple times + + var halfSide = this.sideLength / 2; + var points = this.sideLength / this.n; + + objRef.doSetTimeout(-halfSide, halfSide, penHeight + 10, 0) + objRef.doSetTimeout(-halfSide, halfSide, penHeight, 500); //Top left corner + + for (var i = 0; i < points; i++) { //To bottom left + objRef.doSetTimeout(-halfSide, halfSide - (this.n * i), penHeight, i * 5); + } + + for (var i = 0; i < points; i++) { //To bottom right + objRef.doSetTimeout(-halfSide + (this.n * i), -halfSide, penHeight, i * 5); + } + + for (var i = 0; i < points; i++) { //To top right + objRef.doSetTimeout(halfSide, -halfSide + (this.n * i), penHeight, i * 5); + } + + for (var i = 0; i < points; i++) { //To top left + objRef.doSetTimeout(halfSide - (this.n * i), halfSide, penHeight, i * 5); + } + + objRef.doSetTimeout(0, 0, -140, timer + 100); + +}; + +//Draws a star to test that the Tapster bot is working properly +// Points are not in the 2D landmark of the device, but in the robot's landmark +// (= (0,0) at the center of the plate) +Draw.prototype.drawStar = function(){ + objRef.resetTimer(); + objRef.doSetTimeout(-20, -20, penHeight, 1000); + objRef.doSetTimeout(0, 30, penHeight, 1000); + objRef.doSetTimeout(20, -20, penHeight, 1000); + objRef.doSetTimeout(-30, 10, penHeight, 1000); + objRef.doSetTimeout(30, 10, penHeight, 1000); + objRef.doSetTimeout(-20, -20, penHeight, 1000); + objRef.doSetTimeout(0, 0, -140, timer + 100); + //-20, -20, 0, 30, 20, -20 +}; + +// Draws a triangle +// Points are not in the 2D landmark of the device, but in the robot's landmark +// (= (0,0) at the center of the plate) +Draw.prototype.drawTriangle = function(x, y, x1, y1, x2, y2){ + objRef.resetTimer(); + objRef.doSetTimeout(x, y, penHeight, 1000); + objRef.doSetTimeout(x1, y1, penHeight, 1000); + objRef.doSetTimeout(x2, y2, penHeight, 1000); + objRef.doSetTimeout(x, y, penHeight, 1000); + objRef.doSetTimeout(0, 0, -140, timer + 100); +} + +// Draws a cross with two strokes : (x1, y1) -> (x3, y3) and (x2, y2) -> (x4, y4) +// Points are not in the 2D landmark of the device, but in the robot's landmark +// (= (0,0) at the center of the plate) +Draw.prototype.drawCross = function(x1, y1, x2, y2, x3, y3, x4, y4){ + objRef.resetTimer(); + objRef.doSetTimeout(x1, y1, penHeight, 1000); + objRef.doSetTimeout(x3, y3, penHeight, 1000); + objRef.doSetTimeout(0, 0, -140, 500); + objRef.doSetTimeout(x2, y2, penHeight, 1000); + objRef.doSetTimeout(x4, y4, penHeight, 1000); + objRef.doSetTimeout(0, 0, -140, 500); +} + +//Draws a circle +//Optional args: +//centerX: the x coordinate of the center (default: 0) +//centerY: the y coordinate of the center (default: 0) +//radius: the radius of the center (default: 20) +Draw.prototype.drawCircle = function(args){ + + objRef.resetTimer(); + + this.centerX = 0; + this.centerY = 0; + this.radius = 20; + + if (args) { + var keys = Object.keys(args) + keys.forEach(function(key){ + this[key] = args[key] + }, this) + } + + // an array to save your points + var points = []; + + // populate array with points along a circle + //Goes slightly over so that the circle is actually completed + for (var degree=0; degree < 395; degree++) { + var radians = (degree + 90) * Math.PI/180; + var x = this.centerX + this.radius * Math.cos(radians); + var y = this.centerY + this.radius * Math.sin(radians); + points.push({x:x,y:y}); + } + + circle = function() { + objRef.doSetTimeout(0, 0, -120, 50, "none"); + objRef.doSetTimeout(points[0].x, points[0].y, penHeight + 10, 150, "none"); + objRef.doSetTimeout(points[0].x, points[0].y, penHeight, 150, "none"); + for (var i=0; i (x0, y0, z0) + // Returned {error code,theta1,theta2,theta3} + exports.forward = function(theta1, theta2, theta3){ + + var x0 = 0.0; + var y0 = 0.0; + var z0 = 0.0; + + var t = (f - e) * tan30 / 2.0; + var dtr = pi / 180.0; + + theta1 *= dtr; + theta2 *= dtr; + theta3 *= dtr; + + var y1 = -(t + rf * Math.cos(theta1)); + var z1 = -rf * Math.sin(theta1); + + var y2 = (t + rf * Math.cos(theta2)) * sin30; + var x2 = y2 * tan60; + var z2 = -rf * Math.sin(theta2); + + var y3 = (t + rf * Math.cos(theta3)) * sin30; + var x3 = -y3 * tan60; + var z3 = -rf * Math.sin(theta3); + + var dnm = (y2 - y1) * x3 - (y3 - y1) * x2; + + var w1 = y1 * y1 + z1 * z1; + var w2 = x2 * x2 + y2 * y2 + z2 * z2; + var w3 = x3 * x3 + y3 * y3 + z3 * z3; + + // x = (a1*z + b1)/dnm + var a1 = (z2 - z1) * (y3 - y1) - (z3 - z1) * (y2 - y1); + var b1 = -((w2 - w1) * (y3 - y1) - (w3 - w1) * (y2 - y1)) / 2.0; + + // y = (a2*z + b2)/dnm; + var a2 = -(z2 - z1) * x3 + (z3 - z1) * x2; + var b2 = ((w2 - w1) * x3 - (w3 - w1) * x2) / 2.0; + + // a*z^2 + b*z + c = 0 + var a = a1 * a1 + a2 * a2 + dnm * dnm; + var b = 2.0 * (a1 * b1 + a2 * (b2 - y1 * dnm) - z1 * dnm * dnm); + var c = (b2 - y1 * dnm) * (b2 - y1 * dnm) + b1 * b1 + dnm * dnm * (z1 * z1 - re * re); + + // discriminant + var d = b * b - 4.0 * a * c; + if (d < 0.0) { + return new Array(1, 0, 0, 0); // non-existing povar. return error,x,y,z + } + + z0 = -0.5 * (b + Math.sqrt(d)) / a; + x0 = (a1 * z0 + b1) / dnm; + y0 = (a2 * z0 + b2) / dnm; + + return new Array(0, x0, y0, z0); + + }; + + // Inverse kinematics + // Helper functions, calculates angle theta1 (for YZ-pane) + var delta_calcAngleYZ = function(x0, y0, z0){ + + var y1 = -0.5 * 0.57735 * f; // f/2 * tg 30 + y0 -= 0.5 * 0.57735 * e; // shift center to edge + // z = a + b*y + var a = (x0 * x0 + y0 * y0 + z0 * z0 + rf * rf - re * re - y1 * y1) / (2.0 * z0); + var b = (y1 - y0) / z0; + + // discriminant + var d = -(a + b * y1) * (a + b * y1) + rf * (b * b * rf + rf); + if (d < 0) { + return new Array(1, 0); // non-existing povar. return error, theta + } + + var yj = (y1 - a * b - Math.sqrt(d)) / (b * b + 1); // choosing outer povar + var zj = a + b * yj; + var theta = Math.atan(-zj / (y1 - yj)) * 180.0 / pi + ((yj > y1) ? 180.0 : 0.0); + + return new Array(0, theta); // return error, theta + + }; + + exports.inverse = function(x0, y0, z0){ + + var theta1 = 0; + var theta2 = 0; + var theta3 = 0; + var status = delta_calcAngleYZ(x0, y0, z0); + + if (status[0] === 0) { + theta1 = status[1]; + status = delta_calcAngleYZ(x0 * cos120 + y0 * sin120, y0 * cos120 - x0 * sin120, z0, theta2); + } + if (status[0] === 0) { + theta2 = status[1]; + status = delta_calcAngleYZ(x0 * cos120 - y0 * sin120, y0 * cos120 + x0 * sin120, z0, theta3); + } + theta3 = status[1]; + + return new Array(status[0], theta1, theta2, theta3); + + }; + +}(typeof exports === 'undefined' ? this.ik = {} : exports)); diff --git a/software/src/motion.js b/software/src/lib/motion.js similarity index 66% rename from software/src/motion.js rename to software/src/lib/motion.js index 1f62398c..b4507fc4 100644 --- a/software/src/motion.js +++ b/software/src/lib/motion.js @@ -1,9 +1,36 @@ -/* +/* + Copyright (c) 2011-2016, Tapster Committers + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + [This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +*/ + +/* // Usage: // motion.move(pointA, pointB, numberOfSteps, easingType, timeDeltaInMilliseconds) // Example -$ node bot.js +$ node bot.js >> motion = require('./motion') >> motion.move([0,0,-140],[-20,20,-140], 20, 'easeInOutCubic', 500) >> motion.move([-20,60,-165],[-20,-60,-165], 30, 'easeInOutCubic', 20) @@ -49,7 +76,7 @@ var EasingFunctions = { pointB[2] - pointA[2] ]; return vector; } - + // (x,y,z) = (1,6,3) + t(7,-4,4) = (1 + 7t, 6 - 4t, 3 + 4t). var parametricEquation = function(pointA, pointB) { var dv = directionVector(pointA, pointB); @@ -60,31 +87,31 @@ var EasingFunctions = { } return equation; } - + // get an array of points between (and including) two end points // numberOfSteps and easingType are required var getPoints = function(pointA, pointB, numberOfSteps, easingType) { var points = []; var point = parametricEquation(pointA, pointB); var easingFunction = EasingFunctions[easingType]; - + for (var i = 0; i <= numberOfSteps; i++) { t = easingFunction(i/numberOfSteps); points.push(point(t)) } return points; } - + var move = function(pointA, pointB, numberOfSteps, easingType, timeDelta) { var points = getPoints(pointA, pointB, numberOfSteps, easingType); for (var i=0; i': { position: {x: 160, y: 417}, size: {width: 32, height:42 }, modifiers:["numberToggle", "shift"]}, + '€': { position: {x: 192, y: 417}, size: {width: 32, height:42 }, modifiers:["numberToggle", "shift"]}, + '£': { position: {x: 224, y: 417}, size: {width: 32, height:42 }, modifiers:["numberToggle", "shift"]}, + '•': { position: {x: 256, y: 417}, size: {width: 32, height:42 }, modifiers:["numberToggle", "shift"]}, + '¥': { position: {x: 288, y: 417}, size: {width: 32, height:42 }, modifiers:["numberToggle", "shift"]}, + shift: { position: {x: 20, y: 471}, size: {width: 22, height:42 }, modifiers:[]}, + backspace: { position: {x: 278, y: 471}, size: {width: 42, height:42 }, modifiers:[]}, + numberToggle: { position: {x: 20, y: 525}, size: {width: 20, height:37 }, modifiers:[]}, + keyboardToggle: { position: {x: 40, y: 525}, size: {width: 40, height:37 }, modifiers:[]}, + dictation: { position: {x: 80, y: 525}, size: {width: 32, height:37 }, modifiers:[]}, + ' ': { position: {x: 112, y: 525}, size: {width: 128, height:37 }, modifiers:[]}, + done: { position: {x: 240, y: 525}, size: {width: 80, height:37 }, modifiers:[]} +}; + + +var keyboardModule = { + getKeyboard: function (deviceName) { + var keyboard = {}; + keyboard.keyMap = keymaps[deviceName]; + keyboard.getKeySequence = function (key) { + var sequence = []; + var postSequence = []; + var keyMapping = keyboard.keyMap[key]; + for (var modIndex=0; modIndex < keyMapping.modifiers.length; modIndex++) { + var modKeyName = keyMapping.modifiers[modIndex]; + var modKey = keyboard.keyMap[modKeyName]; + var keyPosition = { + x: modKey.position.x + (modKey.size.width / 2), + y: modKey.position.y + (modKey.size.height / 2) + }; + sequence.push(keyPosition); + if (modKeyName == "numberToggle") { + postSequence.push(keyPosition); + } + } + sequence.push({ + x: keyMapping.position.x + (keyMapping.size.width / 2), + y: keyMapping.position.y + (keyMapping.size.height / 2) + }); + sequence = sequence.concat(postSequence); + return sequence; + }; + return keyboard; + } +}; + +module.exports = keyboardModule; diff --git a/software/src/lib/server/parser.js b/software/src/lib/server/parser.js new file mode 100644 index 00000000..f146b7da --- /dev/null +++ b/software/src/lib/server/parser.js @@ -0,0 +1,59 @@ +/* +Copyright (c) 2011-2016, Tapster Committers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +*/ + +var ArgumentParser = require('argparse').ArgumentParser; + +// parse arguments +var parser = new ArgumentParser({ + version: '0.0.1', + addHelp:true, + description: 'Tapster Server' +}); + +parser.addArgument( + [ '-c', '--calibration'], { + help: 'file to load calibration data from' + }); + +parser.addArgument( + ['-p', '--port'] , { + defaultValue: 4242 + , required: false + , type: 'int' + , example: "4242" + , help: 'port to listen on' + }); + +parser.addArgument( + ['-a', '--address'], { + defaultValue: '127.0.0.1' + , required: false + , example: "127.0.0.1" + , help: 'IP address to listen on' + }); + +module.exports = parser; diff --git a/software/src/lib/server/robot.js b/software/src/lib/server/robot.js new file mode 100644 index 00000000..b30c8588 --- /dev/null +++ b/software/src/lib/server/robot.js @@ -0,0 +1,326 @@ +/* +Copyright (c) 2011-2016, Tapster Committers +Copyright © 2018 Orange + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +*/ + +// TODO Make a massive refactoring to make sources compliant to ES6 and strict mode + +var kinematics = require("./../kinematics"); +require("sylvester"); +var keyboards = require("./keyboards"); + +var method = Robot.prototype; + +function Robot(servo1, servo2, servo3, calibration){ + this._servo1 = servo1; + this._servo2 = servo2; + this._servo3 = servo3; + this._calibration = calibration; + this._dancer_interval = null; +} + +var generateTranslationMatrix = function(calibration){ + + var r1x = calibration.device.contactPoint.position.x; + var r1y = calibration.device.contactPoint.position.y; + var r2x = calibration.device.point1.position.x; + var r2y = calibration.device.point1.position.y; + var r3x = calibration.device.point2.position.x; + var r3y = calibration.device.point2.position.y; + + var d1x = calibration.device.contactPoint.screenCoordinates.x; + var d1y = calibration.device.contactPoint.screenCoordinates.y; + var d2x = calibration.device.point1.screenCoordinates.x; + var d2y = calibration.device.point1.screenCoordinates.y; + var d3x = calibration.device.point2.screenCoordinates.x; + var d3y = calibration.device.point2.screenCoordinates.y; + + var deviceXVector = $M([[(d3x-d1x) / (r3x-r1x)], [(d3y-d1y) / (r3x-r1x) ]]); + var deviceYVector = $M([[(d2x-d1x) / (r2y-r1y)], [(d2y-d1y) / (r2y-r1y) ]]); + var offset = $M([d1x-r1x, d1y-r1y]); + var r2dMatrix = $M([[deviceXVector.elements[0], deviceYVector.elements[0]], [deviceXVector.elements[1], deviceYVector.elements[1]]]); + return {offset: offset, matrix: r2dMatrix}; + +}; + +var sin = function(degree){ + return Math.sin(Math.PI * (degree/180)); +}; + +var cos = function(degree){ + return Math.cos(Math.PI * (degree/180)); +}; + +var mapNumber = function (num, in_min , in_max , out_min , out_max ){ + return ( num - in_min ) * ( out_max - out_min ) / ( in_max - in_min ) + out_min; +}; + +var rotate = function(x,y){ + var theta = -60; + var x1 = x * cos(theta) - y * sin(theta); + var y1 = y * cos(theta) + x * sin(theta); + return [x1,y1] +}; + +var reflect = function(x,y){ + var theta = 0; + var x1 = x; + var y1 = x * sin(2*theta) - y * cos(2*theta); + return [x1,y1] +}; + + +method.getAngles = function(){ + return [this._servo1.last.degrees, this._servo2.last.degrees, this._servo3.last.degrees]; +}; + +method.setAngles = function(t1,t2,t3){ + console.log("Setting Angles:" + [t1,t2,t3]); + t1 = isNaN(t1) ? this._calibration.servo1.minimumAngle : t1; + t2 = isNaN(t2) ? this._calibration.servo1.minimumAngle : t2; + t3 = isNaN(t3) ? this._calibration.servo1.minimumAngle : t3; + this._servo1.to(t1); + this._servo2.to(t2); + this._servo3.to(t3); +}; + +method.getPosition = function(){ + var angles = this.getAngles(); + return kinematics.forward(angles[0], angles[1], angles[2]); +}; + +method.setPosition = function(x, y, z){ + console.log("Setting Position:" + [x,y,z]); + var reflected = reflect(x,y); + var rotated = rotate(reflected[0],reflected[1]); + var angles = kinematics.inverse(rotated[0], rotated[1], z); + var t1 = mapNumber(angles[1], 0 , 90 , this._calibration.servo1.minimumAngle , this._calibration.servo1.maximumAngle); + var t2 = mapNumber(angles[2], 0 , 90 , this._calibration.servo2.minimumAngle , this._calibration.servo2.maximumAngle); + var t3 = mapNumber(angles[3], 0 , 90 , this._calibration.servo3.minimumAngle , this._calibration.servo3.maximumAngle); + this.setAngles(t1,t2,t3); +}; + +method.resetPosition = function(){ + this.setPosition(this._calibration.restPoint.x, this._calibration.restPoint.y, this._calibration.restPoint.z); +}; + +method.getPositionForAngles = function(t1,t2,t3){ + var points = kinematics.forward(t1,t2,t3); + return [points[1], points[2], points[3]]; +}; + +method.getAnglesForPosition = function(x,y,z){ + var angles = kinematics.inverse(x,y,z); + return [angles[1], angles[2], angles[3]]; +}; + +method.getPositionForScreenCoordinates = function(x,y){ + var calData = generateTranslationMatrix(this._calibration); + var matrix = calData.matrix; + var offset = calData.offset; + var vector = $M([ [x-offset.elements[0]],[y-offset.elements[1]] ]); + var converted = matrix.inverse().multiply(vector); + var newX = converted.elements[0]; + var newY = converted.elements[1]; + return {x:newX, y:newY}; +}; + +method.getContactZ = function(){ + return 1.01 * Math.min( + this._calibration.device.contactPoint.position.z, + this._calibration.device.point1.position.z, + this._calibration.device.point2.position.z + ); +}; + +method.tap = function(screenX, screenY, cb){ + var position = this.getPositionForScreenCoordinates(screenX, screenY); + var touchZ = this.getContactZ(); + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(cb, 400); + }.bind(this), 400); + }.bind(this), 400); +}; + +method.doubleTap = function(screenX, screenY, duration, cb){ + // Duration and temporization in ms + var minimalDuration = 100; + var tempo = 100; + duration = (duration < minimalDuration ? minimalDuration : duration); + var position = this.getPositionForScreenCoordinates(screenX, screenY); + var touchZ = this.getContactZ(); + // Be ready to tap + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + // Tap + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + // Go to initial state + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + // Tap again + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + // Go to initial state + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(cb, tempo); + }.bind(this), tempo); + }.bind(this), duration); + }.bind(this), tempo); + }.bind(this), tempo); +}; + +method.tripleTap = function(screenX, screenY, duration, cb){ + // Duration and temporization in ms + var minimalDuration = 100; + var tempo = 100; + duration = (duration < minimalDuration ? minimalDuration : duration); + var position = this.getPositionForScreenCoordinates(screenX, screenY); + var touchZ = this.getContactZ(); + // Be ready to tap + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + // Tap + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + // Go to initial state + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + // Tap again + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + // Go to initial state + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + // Tap again + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + // Go to initial state + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(cb, tempo); + }.bind(this), tempo); + }.bind(this), duration); + }.bind(this), tempo); + }.bind(this), duration); + }.bind(this), tempo); + }.bind(this), tempo); +}; + +method.longTap = function(screenX, screenY, duration, cb){ + // Duration and temporization in ms + var minimalDuration = 1000; + var tempo = 400; + duration = (duration < minimalDuration ? minimalDuration : duration); + var position = this.getPositionForScreenCoordinates(screenX, screenY); + var touchZ = this.getContactZ(); + // Be ready to tap + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(function() { + // Tap + this.setPosition(position.x, position.y, touchZ); + return setTimeout(function() { + // Go to initial state + this.setPosition(position.x, position.y, touchZ * 0.9); + return setTimeout(cb, tempo); + }.bind(this), duration); + }.bind(this), tempo); +}; + +method.swipe = function(startX, startY, endX, endY, cb){ + var startPosition = this.getPositionForScreenCoordinates(startX, startY); + var endPosition = this.getPositionForScreenCoordinates(endX, endY); + var touchZ = this.getContactZ(); + this.setPosition(startPosition.x, startPosition.y, touchZ * 0.9); + return setTimeout(function() { + this.setPosition(startPosition.x, startPosition.y, touchZ); + return setTimeout(function() { + this.setPosition(endPosition.x, endPosition.y, touchZ); + return setTimeout(function() { + this.setPosition(endPosition.x, endPosition.y, touchZ * 0.9); + return setTimeout(cb, 100); + }.bind(this), 400); + }.bind(this), 400); + }.bind(this), 400); +}; + +method.sendKeys = function(keys, cb){ + var keyboard = keyboards.getKeyboard("iPhone 6"/*this._calibration.device.name*/); + var keystrokeSequence = []; + for (var keyIndex=0; keyIndex < keys.length; keyIndex++) { + keystrokeSequence = keystrokeSequence.concat(keyboard.getKeySequence(keys[keyIndex])); + } + var tapKey = function(keystrokes, cb) { + if (keystrokes.length == 0) { + return cb(); + } else { + var currentKeyPosition = keystrokes.shift(); + this.tap(currentKeyPosition.x, currentKeyPosition.y, function() { + return tapKey(keystrokes, cb); + }); + } + }.bind(this); + return tapKey(keystrokeSequence, cb); +}; + +method.startDancing = function(){ + var _dance = function() { + var minAngle = 10; + var maxAngle = 20; + var range = maxAngle - minAngle; + var t1 = parseInt((Math.random() * range) + minAngle, 10); + var t2 = parseInt((Math.random() * range) + minAngle, 10); + var t3 = parseInt((Math.random() * range) + minAngle, 10); + this.setAngles(t1,t2,t3); + }.bind(this); + + if (!this._dancer_interval) { + this._dancer_interval = setInterval(_dance, 250); + } + +}; + +method.stopDancing = function(){ + if (this._dancer_interval) { + clearInterval(this._dancer_interval); + this._dancer_interval = null; + } +}; + +method.getCalibrationData = function(){ + return this._calibration; +}; + +method.setCalibrationData = function(newData){ + this._calibration = newData; +}; + +module.exports = {}; +module.exports.Robot = Robot; diff --git a/software/src/lib/server/robot_http_client.js b/software/src/lib/server/robot_http_client.js new file mode 100644 index 00000000..a7b5982c --- /dev/null +++ b/software/src/lib/server/robot_http_client.js @@ -0,0 +1,67 @@ +var http = require('http'); + +exports.client = function(address, port) { + var get = function(path, cb) { + return http.get({ host: address, port: port, path: path }, function(res){ + res.setEncoding('utf8'); + return res.on('data', function(chunk) { + var result = JSON.parse(chunk); + return cb(result.data); + }); + }).on("error", function(err){ + console.log("Got error: " + err.message); + return cb(null, err); + }); + }; + var post = function(path, bodyData, cb) { + var req = http.request({ host: address, port: port, path: path, method: 'POST'}, function(res) { + res.setEncoding('utf8'); + return res.on('data', function (chunk) { + var result = JSON.parse(chunk); + return cb(result.data); + }); + }).on('error', function(err) { + console.log("Got error: " + err.message); + return cb(null, err); + }); + req.setHeader('Content-Type', 'application/x-www-form-urlencoded'); + req.write(bodyData); + req.write('\n'); + req.end(); + }; + return { + address : address, + port : port, + url : function(uri) { + return 'http://' + address + ":" + port + uri; + }, + angles : function(cb) { + return get('/angles', cb); + }, + setAngles : function(theta1, theta2, theta3, cb) { + var postData = "theta1=" + theta1 + "&theta2=" +theta2 + "&theta3=" + theta3; + return post('/setAngles', postData, cb); + }, + position : function(cb) { + return get('/position', cb); + }, + setPosition : function(x, y, z, cb) { + var postData = "x=" + x + "&y=" + y + "&z=" + z; + return post('/setPosition', postData, cb); + }, + tap : function(x, y, cb) { + var postData = "x=" + x + "&y=" + y; + return post('/tap', postData, cb); + }, + reset : function(cb) { + return post('/reset', '', cb); + }, + calibrationData : function(cb) { + return get('/calibrationData', cb); + }, + setCalibrationData : function(newData, cb) { + var postData = "newData=" + JSON.stringify(newData); + return post('/setCalibrationData', postData, cb); + } + }; +}; \ No newline at end of file diff --git a/software/src/server.js b/software/src/server.js new file mode 100644 index 00000000..8a4723a1 --- /dev/null +++ b/software/src/server.js @@ -0,0 +1,737 @@ +#! /usr/local/bin/node + +/* +Copyright (c) 2011-2016, Tapster Committers +Copyright (c) 2018 Orange + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[This is the BSD 2-Clause License, http://opensource.org/licenses/BSD-2-Clause] +*/ + +/* *************************** +* Load third-party librairies +* ****************************/ + +var parser = require("./lib/server/parser"), +Hapi = require("hapi"), +path = require("path"), +five = require("johnny-five"), +calibration = require("./lib/server/calibration"), +Robot = require("./lib/server/robot").Robot, +draw = require("./lib/draw"), +svgDraw = require("./lib/SVGDraw"); + +var args = parser.parseArgs(); +var robot, servo1, servo2, servo3; + +var board = new five.Board({ debug: false}); + +board.on("ready", function(){ + + /* ************************************************** + * Step 1: Get the servomotors from the Arduino board + * **************************************************/ + + servo1 = five.Servo({ + pin: 9, + range: [0,120] + }); + + servo2 = five.Servo({ + pin: 10, + range: [0,120] + }); + + servo3 = five.Servo({ + pin: 11, + range: [0,120] + }); + + servo1.on("error", function() { + console.log(arguments); + }); + + servo2.on("error", function() { + console.log(arguments); + }); + + servo3.on("error", function() { + console.log(arguments); + }); + + /* *********************** + * Strep 2: Prepare config + * ***********************/ + + // Initialize objects + var calibrationData = calibration.getDataFromFilePath(args.calibration); + calibrationData = calibrationData == null ? calibration.defaultData : calibrationData; + robot = new Robot(servo1, servo2, servo3, calibrationData); + + // Move to starting point + robot.resetPosition(); + + // Create a server with a host and port + var server = new Hapi.Server({ + host: args.address, + port: args.port + }); + + var getCommonReponseObject = function(err, data){ + if (err) { + return { status:err.code, data: err }; + } else { + return { status: 0, data: data }; + } + }; + + /* ********************* + * Step 3: Define routes + * *********************/ + + // TODO Set up a cache of requests so as to trigger them when the previous are done + // It may prevent following newer requests to cancel the on-going aor previously-received ones. + + // Status of the robot's server + server.route({ + method: 'GET', + path:'/status', + handler: function (request, h) { + console.log("GET " + request.path + ": "); + return getCommonReponseObject(null, '"OK"'); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Reset the position of the robot's arms + server.route({ + method: 'POST', + path:'/reset', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + robot.resetPosition(); + return getCommonReponseObject(null, robot.getAngles()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Make the robot dance + server.route({ + method: 'POST', + path:'/dance', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + robot.startDancing(); + return getCommonReponseObject(null, '"Dancing!"'); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Make the robot stop dancing + server.route({ + method: 'POST', + path:'/stopDancing', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + robot.stopDancing(); + return getCommonReponseObject(null, '"No more dancing."'); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Define the gnales the robot's arms must have (angles of servomotors) + server.route({ + method: 'POST', + path:'/setAngles', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var theta1 = parseFloat(request.payload.theta1); + var theta2 = parseFloat(request.payload.theta2); + var theta3 = parseFloat(request.payload.theta3); + robot.setAngles(theta1, theta2, theta3); + return getCommonReponseObject(null, robot.getAngles()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Define the position in 3D for the robot's finger + server.route({ + method: 'POST', + path:'/setPosition', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var x = parseFloat(request.payload.x); + var y = parseFloat(request.payload.y); + var z = parseFloat(request.payload.z); + robot.setPosition(x, y, z); + return getCommonReponseObject(null, '"OK"'); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Get the angles the robot's arms have + server.route({ + method: 'GET', + path:'/angles', + handler: function (request, h) { + console.log("GET " + request.path + ": "); + return getCommonReponseObject(null, robot.getAngles()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Get the position in 3D of the robot's finger + server.route({ + method: 'GET', + path:'/position', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Return the angles of the servomotors for a dedicated 3D point + server.route({ + method: 'GET', + path:'/anglesForPosition/x/{x}/y/{y}/z/{z}', + handler: function (request, h) { + console.log("GET " + request.path + ": "); + var x = parseFloat(request.params.x); + var y = parseFloat(request.params.y); + var z = parseFloat(request.params.z); + return getCommonReponseObject(null,robot.getAnglesForPosition(x,y,z)); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Return the 3D position of the finger for a dedicated 2D point using the device landmark + server.route({ + method: 'GET', + path:'/positionForScreenCoordinates/x/{x}/y/{y}', + handler: function (request, h) { + console.log("GET " + request.path + ": "); + var x = parseFloat(request.params.x); + var y = parseFloat(request.params.y); + return getCommonReponseObject(null,robot.getPositionForScreenCoordinates(x,y)); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Tap to a 2D point using the device landmark + server.route({ + method: 'POST', + path:'/tap', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var x = parseFloat(request.payload.x); + var y = parseFloat(request.payload.y); + robot.tap( x, y, function(){return getCommonReponseObject(null, '"OK"')} ); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Tap to a 2D point using the device landmark, n times + server.route({ + method: 'POST', + path:'/nTap', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters + var n = parseFloat(request.payload.n); + var x = parseFloat(request.payload.x); + var y = parseFloat(request.payload.y); + // Convert to coordinates for the robot + var point = robot.getPositionForScreenCoordinates(x, y); + // Draw + var drawer = new draw.Draw(null, robot); + drawer.drawPoints(n, point.x, point.y); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Make a long tap to a 2D point using the device landmark with a dedicated duration in ms + server.route({ + method: 'POST', + path:'/longTap', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var x = parseFloat(request.payload.x); + var y = parseFloat(request.payload.y); + var duration = parseFloat(request.payload.duration); + robot.longTap(x, y, duration, function(){return getCommonReponseObject(null, '"OK"')} ); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Make a double tap to a 2D point using the device landmark with a dedicated duration in ms + server.route({ + method: 'POST', + path:'/doubleTap', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var x = parseFloat(request.payload.x); + var y = parseFloat(request.payload.y); + var duration = parseFloat(request.payload.duration); + robot.doubleTap(x, y, duration, function(){return getCommonReponseObject(null, '"OK"')} ); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Make a double tap to a 2D point using the device landmark with a dedicated duration in ms + server.route({ + method: 'POST', + path:'/tripleTap', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var x = parseFloat(request.payload.x); + var y = parseFloat(request.payload.y); + var duration = parseFloat(request.payload.duration); + robot.tripleTap(x, y, duration, function(){return getCommonReponseObject(null, '"OK"')} ); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Swipe from a point to another point, these points are 2D device-landmark-based + server.route({ + method: 'POST', + path:'/swipe', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var startX = parseFloat(request.payload.startX); + var startY = parseFloat(request.payload.startY); + var endX = parseFloat(request.payload.endX); + var endY = parseFloat(request.payload.endY); + robot.swipe( startX, startY, endX, endY, function(){return getCommonReponseObject(null, '"OK"')} ); + return getCommonReponseObject( null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Swipe from a point to another point, n times, these points are 2D device-landmark-based + server.route({ + method: 'POST', + path:'/nSwipe', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters + var n = parseFloat(request.payload.n); + var startX = parseFloat(request.payload.startX); + var startY = parseFloat(request.payload.startY); + var endX = parseFloat(request.payload.endX); + var endY = parseFloat(request.payload.endY); + // Convert to coordinates for the robot + var startPoint = robot.getPositionForScreenCoordinates(startX, startY); + var endPoint = robot.getPositionForScreenCoordinates(endX, endY); + // Draw + var drawer = new draw.Draw(null, robot); + drawer.drawStrokes(n, startPoint.x, startPoint.y, endPoint.x, endPoint.y); + return getCommonReponseObject(null, robot.getPosition()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Tape to a keyboard using already defined kies values, for old iPhone (legacy feature) + // WARNING: Deprecated + server.route({ + method: 'POST', + path:'/sendKeys', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var keys = decodeURIComponent(request.payload.keys); + return robot.sendKeys(keys, function() { + return getCommonReponseObject(null, '"OK"'); + }); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Get the calibration data used to calibrate the nrobot for a dedicated device + server.route({ + method: 'GET', + path:'/calibrationData', + handler: function (request, h) { + console.log("GET " + request.path + ": "); + return getCommonReponseObject(null, robot.getCalibrationData()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Set the calibration data used to calibrate the nrobot for a dedicated device + server.route({ + method: 'POST', + path:'/setCalibrationData', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var newData = JSON.parse(request.payload.newData); + robot.setCalibrationData(newData); + return getCommonReponseObject(null, robot.getCalibrationData()); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Return the Z value of the 3D point (robot landmark) where the robot's finger hits the device's screen + server.route({ + method: 'GET', + path:'/contactZ', + handler: function (request, h) { + console.log("GET " + request.path + ": "); + return getCommonReponseObject(null, {z: robot.getContactZ()} ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a square + server.route({ + method: 'POST', + path:'/drawSquare', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var n = JSON.parse(request.payload.n); + var length = JSON.parse(request.payload.length); + var params = {"n": n, "sideLength": length}; + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawSquare(params) ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a star + server.route({ + method: 'POST', + path:'/drawStar', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawStar() ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a triangle + server.route({ + method: 'POST', + path:'/drawTriangle', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters, supposed to be in 2D device landmark + var x1 = JSON.parse(request.payload.x1); + var y1 = JSON.parse(request.payload.y1); + var x2 = JSON.parse(request.payload.x2); + var y2 = JSON.parse(request.payload.y2); + var x3 = JSON.parse(request.payload.x3); + var y3 = JSON.parse(request.payload.y3); + // Compute to points in 3D robot landmark + var p1 = robot.getPositionForScreenCoordinates(x1, y1); + var p2 = robot.getPositionForScreenCoordinates(x2, y2); + var p3 = robot.getPositionForScreenCoordinates(x3, y3); + // Draw! + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawTriangle(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y) ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a circle + server.route({ + method: 'POST', + path:'/drawCircle', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters, supposed to be in 2D device landmark + var x = JSON.parse(request.payload.x); + var y = JSON.parse(request.payload.y); + var r = JSON.parse(request.payload.r); + // Compute to points in 3D robot landmark + var p = robot.getPositionForScreenCoordinates(x, y); + // Draw! + var params = {"centerX": parseInt(p.x), "centerY": parseInt(p.y), "radius": r}; + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawCircle(params) ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a cross + server.route({ + method: 'POST', + path:'/drawCross', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters, supposed to be in 2D device landmark + var x1 = JSON.parse(request.payload.x1); + var y1 = JSON.parse(request.payload.y1); + var x2 = JSON.parse(request.payload.x2); + var y2 = JSON.parse(request.payload.y2); + var x3 = JSON.parse(request.payload.x3); + var y3 = JSON.parse(request.payload.y3); + var x4 = JSON.parse(request.payload.x4); + var y4 = JSON.parse(request.payload.y4); + // Compute to points in 3D robot landmark + var p1 = robot.getPositionForScreenCoordinates(x1, y1); + var p2 = robot.getPositionForScreenCoordinates(x2, y2); + var p3 = robot.getPositionForScreenCoordinates(x3, y3); + var p4 = robot.getPositionForScreenCoordinates(x4, y4); + // Draw! + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawCross(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y)); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a spiral + server.route({ + method: 'POST', + path:'/drawSpiral', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters, supposed to be in 2D device landmark + var x = JSON.parse(request.payload.x); + var y = JSON.parse(request.payload.y); + var n = JSON.parse(request.payload.n); + var r = JSON.parse(request.payload.r); + // Compute to point in 3D robot landmark + var p = robot.getPositionForScreenCoordinates(x, y); + // Draw! + var params = {"startX": parseInt(p.x), "startY": parseInt(p.y), "spirals": n, "radius": r}; + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawSpiral(params) ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws an SVG picture + server.route({ + method: 'POST', + path:'/drawSvg', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + var content = request.payload.rawContent; + var svgDrawer = new svgDraw.SVGDraw(null, robot); + return getCommonReponseObject(null, svgDrawer.drawSVG(content, false) ); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Draws a random pattern + server.route({ + method: 'POST', + path:'/drawRandomPattern', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters, supposed to be in 2D device landmark + var n = parseFloat(request.payload.n); + var minW = parseFloat(request.payload.minWidth); + var minH = parseFloat(request.payload.minHeight); + var maxW = parseFloat(request.payload.maxWidth); + var maxH = parseFloat(request.payload.maxHeight); + // Compute to points in 3D robot landmark + var miniPoint = robot.getPositionForScreenCoordinates(minW, minH); + var maxiPoint = robot.getPositionForScreenCoordinates(maxW, maxH); + // Draw ! + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.drawRandom(n, miniPoint.x, miniPoint.y, maxiPoint.x, maxiPoint.y)); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + // Tap on several random points + server.route({ + method: 'POST', + path:'/tapRandomPoints', + handler: function (request, h) { + console.log("POST " + request.path + ": "); + // Get parameters, supposed to be in 2D device landmark + var n = parseFloat(request.payload.n); + var minW = parseFloat(request.payload.minWidth); + var minH = parseFloat(request.payload.minHeight); + var maxW = parseFloat(request.payload.maxWidth); + var maxH = parseFloat(request.payload.maxHeight); + // Compute to points in 3D robot landmark + var miniPoint = robot.getPositionForScreenCoordinates(minW, minH); + var maxiPoint = robot.getPositionForScreenCoordinates(maxW, maxH); + // Draw ! + var drawer = new draw.Draw(null, robot); + return getCommonReponseObject(null, drawer.tapRandom(n, miniPoint.x, miniPoint.y, maxiPoint.x, maxiPoint.y)); + }, + config: { + cors: { + origin: ['*'], + additionalHeaders: ['cache-control', 'x-requested-with'] + } + } + }); + + server.start(); + console.log("Robot listening on port " + args.port); + +}); // End of board.on("ready", function()) diff --git a/software/src/shrug.svg b/software/src/shrug.svg deleted file mode 100644 index 7a6ced33..00000000 --- a/software/src/shrug.svg +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - -