├── meshviewer-screenshot.jpg ├── README.md ├── meshviewer_vispy_tk.py ├── meshviewer_mpl_tk.py ├── meshviewer_plotly_cef_tk.py ├── test └── test.obj └── LICENSE /meshviewer-screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precise-simulation/mesh-viewer/HEAD/meshviewer-screenshot.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Mesh Viewer 2 | ----------- 3 | 4 | **Mesh Viewer** is a simple STL/OBJ CAD geometry and surface mesh 5 | viewer prototype with a _Model View Controller_ (MVC) type 6 | design. Three different visualization backends are compared and 7 | embedded within the same 8 | [Python](https://www.python.org)/[tkinter](https://wiki.python.org/moin/TkInter) 9 | GUI framework. 10 | 11 | - [matplotlib](https://matplotlib.org) 12 | - [plotly](https://www.featool.com/web-plots) _(WebGL with embedded webview)_ 13 | - [vispy](http://vispy.org) _(OpenGL)_ 14 | 15 | ![Mesh Viewer screenshot](https://raw.githubusercontent.com/precise-simulation/mesh-viewer/master/meshviewer-screenshot.jpg) 16 | 17 | The _vispy/opengl_ backend seems to be the best choice overall with 18 | respect to performance and packaged size (~35 MB), while _plotly_ 19 | (subjectively) looks the best but leads to large binaries due to 20 | embedding the Chromium framework (~70-90 MB), _matplotlib_ is the 21 | simplest backend but suffers from slow performance for larger 22 | visualizations. 23 | 24 | 25 | # Python Script Use 26 | 27 | Simply downloading and running the corresponding Python scripts should 28 | start both the GUI and mesh viewer application. The examples below 29 | show how to set up a new 30 | [conda](https://docs.conda.io/en/latest/miniconda.html) Python 31 | environment with the required dependencies. 32 | 33 | ## mesh-viewer with matplotlib backend 34 | 35 | conda create -n mpl python=3.7 36 | conda activate mpl 37 | conda install conda-forge::blas=*=openblas numpy 38 | pip install matplotlib==3.2.2 39 | 40 | python meshviewer_mpl_tk.py 41 | 42 | ## mesh-viewer with plotly/cefpython backend 43 | 44 | conda create -n plotly python=3.7 45 | conda activate plotly 46 | conda install conda-forge::blas=*=openblas numpy 47 | pip install cefpython3 48 | 49 | python meshviewer_plotly_cef_tk.py 50 | 51 | ## mesh-viewer with vispy/pyopengltk backend 52 | 53 | conda create -n vispy python=3.7 54 | conda activate vispy 55 | conda install conda-forge::blas=*=openblas numpy 56 | pip install cython 57 | pip install pyopengltk 58 | git clone --recurse-submodules https://github.com/Wosser1sProductions/vispy.git 59 | cd vispy 60 | git submodule update --init --recursive 61 | pip install . --no-use-pep517 62 | cd .. 63 | 64 | python meshviewer_vispy_tk.py 65 | 66 | 67 | # Pre-Built Binaries 68 | 69 | The 70 | [releases](https://github.com/precise-simulation/mesh-viewer/releases/latest) 71 | include stand-alone and pre-compiled executable _one-click_ binaries 72 | _(exe)_ for Windows systems (note that it may take several seconds to 73 | load/start due to extracting all resources, and that the _plotly_ 74 | backed required an internet connection and accepting a 75 | Microsoft/Windows certificate to download the [plotly 76 | javascript](https://github.com/plotly/plotly.js) library). Building 77 | stand-alone executables can be done with 78 | [pyinstaller](https://www.pyinstaller.org) as described below. 79 | 80 | ## build mesh-viewer with matplotlib backend 81 | 82 | conda create -n mpl python=3.7 83 | conda activate mpl 84 | conda install conda-forge::blas=*=openblas numpy 85 | pip install matplotlib==3.2.2 86 | pip install pyinstaller 87 | 88 | pyinstaller --onefile --windowed --noupx meshviewer_mpl_tk.py 89 | 90 | conda env remove -n mpl 91 | 92 | ## build mesh-viewer with plotly/cefpython backend 93 | 94 | conda create -n plotly python=3.7 95 | conda activate plotly 96 | conda install conda-forge::blas=*=openblas numpy 97 | pip install cefpython3 98 | pip install pyinstaller==3.6 99 | 100 | cd build 101 | python build.py --onefile 102 | 103 | conda env remove -n plotly 104 | 105 | ## build mesh-viewer with vispy/pyopengltk backend 106 | 107 | conda create -n vispy python=3.7 108 | conda activate vispy 109 | conda install conda-forge::blas=*=openblas numpy 110 | pip install cython 111 | pip install pyopengltk 112 | git clone --recurse-submodules https://github.com/Wosser1sProductions/vispy.git 113 | cd vispy 114 | git submodule update --init --recursive 115 | pip install . --no-use-pep517 116 | pip install pyinstaller 117 | 118 | cd ../build 119 | pyinstaller --onefile meshviewer_vispy_tk.spec 120 | 121 | conda env remove -n vispy 122 | 123 | 124 | # Note 125 | 126 | This is just a simple prototype/proof-of-concept and not intended to 127 | be a full fledged application. If you are interested in custom CAE and 128 | simulation tools such as this app and 129 | [FEATool Multiphysics](https://www.featool.com) please feel free to 130 | get in touch with [Precise Simulation](https://www.precisesimulation.com). 131 | 132 | 133 | # License 134 | 135 | AGPL v3, see LICENSE for more details. 136 | 137 | Copyright (C) 2020 Precise Simulation Ltd. 138 | -------------------------------------------------------------------------------- /meshviewer_vispy_tk.py: -------------------------------------------------------------------------------- 1 | """STL/OBJ Python Mesh Viewer prototype with Vispy/OpenGL/Tkinter 2 | using a Model View Controller (MVC) design. 3 | 4 | This is just a simple prototype/proof-of-concept and not intended to 5 | be a full fledged application. If you are interested in custom CAE and 6 | simulation tools such as this app and 7 | [FEATool Multiphysics](https://www.featool.com) please feel free to 8 | get in touch with [Precise Simulation](https://www.precisesimulation.com). 9 | 10 | :license: AGPL v3, see LICENSE for more details or contact 11 | Precise Simulation for alternative licensing options. 12 | :copyright: 2020 Precise Simulation Ltd. 13 | 14 | """ 15 | 16 | try: 17 | import tkinter as tk 18 | except ImportError: 19 | import Tkinter as tk 20 | import tkinter.ttk as ttk 21 | import tkinter.font as tkfont 22 | from tkinter.filedialog import askopenfilename 23 | 24 | import vispy 25 | import vispy.scene 26 | # import vispy.visuals 27 | vispy.use(app='tkinter') 28 | 29 | import numpy as np 30 | 31 | import sys 32 | import os 33 | if os.name == 'nt': 34 | from ctypes import windll, pointer, wintypes 35 | try: 36 | windll.shcore.SetProcessDpiAwareness(1) 37 | except Exception: 38 | pass # this will fail on Windows Server and maybe early Windows 39 | 40 | 41 | class Model(): 42 | 43 | def __init__(self, file_name=None): 44 | 45 | self.data = [] 46 | if file_name is None: 47 | # Define unit cube. 48 | vertices = [[0,1,0], [1,1,0], [1,0,0], [0,0,0], 49 | [1,0,1], [0,0,1], [1,1,1], [0,1,1]] 50 | faces = [[0,1,2], [0,2,3], [2,4,5], [2,5,3], [4,2,1], [4,1,6], 51 | [6,1,0], [6,0,7], [3,5,7], [3,7,0], [6,5,4], [6,7,5]] 52 | data = Mesh(np.asarray(vertices, dtype='float32'), np.asarray(faces,dtype='uint32')) 53 | 54 | self.data = [data] 55 | else: 56 | self.load_file(file_name) 57 | 58 | def clear(self): 59 | self.data = [] 60 | 61 | def load_file(self, file_name): 62 | '''Load mesh from file 63 | ''' 64 | vertices, faces, _, _ = vispy.io.read_mesh(file_name) 65 | self.data.append(Mesh(vertices, faces)) 66 | 67 | def get_bounding_box(self): 68 | bbox = self.data[0].bounding_box 69 | for mesh in self.data[1:]: 70 | for i in range(len(bbox)): 71 | x_i = mesh.bounding_box[i] 72 | bbox[i][0] = min([bbox[i][0], min(x_i)]) 73 | bbox[i][1] = max([bbox[i][1], max(x_i)]) 74 | 75 | return bbox 76 | 77 | 78 | class Mesh(): 79 | 80 | def __init__(self, vertices, faces): 81 | self.vertices = vertices 82 | self.faces = faces 83 | self.bounding_box = self.get_bounding_box() 84 | 85 | def get_vertices(self): 86 | vertices = [] 87 | for face in self.faces: 88 | vertices.append([self.vertices[ivt] for ivt in face]) 89 | 90 | return vertices 91 | 92 | def get_line_segments(self): 93 | line_segments = set() 94 | for face in self.faces: 95 | for i in range(len(face)): 96 | iv = face[i] 97 | jv = face[(i+1)%len(face)] 98 | if jv > iv: 99 | edge = (iv, jv) 100 | else: 101 | edge = (jv, iv) 102 | 103 | line_segments.add(edge) 104 | 105 | return [[self.vertices[edge[0]-1], self.vertices[edge[1]-1]] for edge in line_segments] 106 | 107 | def get_bounding_box(self): 108 | v = [vti for face in self.get_vertices() for vti in face] 109 | bbox = [] 110 | for i in range(len(self.vertices[0])): 111 | x_i = [p[i] for p in v] 112 | bbox.append([min(x_i), max(x_i)]) 113 | 114 | return bbox 115 | 116 | 117 | class View(): 118 | 119 | def __init__(self, model=None): 120 | 121 | if model is None: 122 | model = Model() 123 | self.model = model 124 | self.canvas = None 125 | self.vpview = None 126 | 127 | def clear(self): 128 | if self.vpview is not None: 129 | self.vpview.parent = None 130 | 131 | self.vpview = self.canvas.central_widget.add_view(bgcolor='white') 132 | # vispy.scene.visuals.XYZAxis(parent=self.vpview.scene) 133 | 134 | def plot(self, types="solid + wireframe"): 135 | self.clear() 136 | if isinstance(types, (str,)): 137 | types = [s.strip() for s in types.split('+')] 138 | 139 | for mesh in self.model.data: 140 | for type in types: 141 | 142 | if type=="solid": 143 | msh = vispy.scene.visuals.Mesh(vertices=mesh.vertices, \ 144 | shading='smooth', faces=mesh.faces) 145 | self.vpview.add(msh) 146 | 147 | elif type=="wireframe": 148 | n_faces = len(mesh.faces) 149 | ix = np.tile([0, 1, 1, 2, 2, 0], n_faces) + \ 150 | np.repeat(np.arange(0, 3*n_faces, 3), 6) 151 | edges = mesh.faces.reshape(-1)[ix] 152 | edg = vispy.scene.visuals.Line(pos=mesh.vertices[edges], connect="segments") 153 | self.vpview.add(edg) 154 | 155 | else: 156 | # Unknown plot type 157 | return None 158 | 159 | self.vpview.camera = vispy.scene.TurntableCamera(parent=self.vpview.scene) 160 | 161 | def xy(self): 162 | self.vpview.camera.elevation = 90 163 | self.vpview.camera.azimuth = -90 164 | self.vpview.camera.roll = 0 165 | 166 | def xz(self): 167 | self.vpview.camera.elevation = 0 168 | self.vpview.camera.azimuth = -90 169 | self.vpview.camera.roll = 0 170 | 171 | def yz(self): 172 | self.vpview.camera.elevation = 0 173 | self.vpview.camera.azimuth = 0 174 | self.vpview.camera.roll = 0 175 | 176 | def reset(self): 177 | self.vpview.camera.reset() 178 | 179 | class Controller(): 180 | 181 | def __init__(self, view=None): 182 | 183 | root = tk.Tk() 184 | root.geometry("600x550") 185 | root.title("Mesh Viewer") 186 | 187 | if view is None: 188 | view = View() 189 | 190 | f1 = ttk.Frame(root) 191 | f1.pack(side=tk.TOP, anchor=tk.W) 192 | 193 | toolbar = [ tk.Button(f1, text="Open"), 194 | tk.Button(f1, text="XY", command=view.xy), 195 | tk.Button(f1, text="XZ", command=view.xz), 196 | tk.Button(f1, text="YZ", command=view.yz), 197 | tk.Button(f1, text="Reset", command=view.reset) ] 198 | 199 | f2 = tk.Frame(f1, highlightthickness=1, highlightbackground="gray") 200 | options = ["solid","wireframe","solid + wireframe"] 201 | var = tk.StringVar() 202 | o1 = ttk.OptionMenu(f2, var, options[len(options)-1], *options, command=lambda val: self.view.plot(val)) 203 | o1["menu"].configure(bg="white") 204 | setMaxWidth(options, o1) 205 | o1.pack() 206 | toolbar.append(f2) 207 | 208 | toolbar[0].config(command=lambda: self.open(var)) 209 | 210 | [obj.pack(side=tk.LEFT, anchor=tk.W) for obj in toolbar] 211 | 212 | canvas = vispy.scene.SceneCanvas( 213 | keys='interactive', show=True, parent=root) 214 | canvas.native.pack(side=tk.TOP, fill=tk.BOTH, expand=True) 215 | view.canvas = canvas 216 | root.update_idletasks() 217 | 218 | menubar = tk.Menu( root ) 219 | file_menu = tk.Menu(menubar, tearoff=0) 220 | file_menu.add_command(label="Open...", command=lambda: self.open(var)) 221 | file_menu.add_command(label="Exit", command=self.exit) 222 | menubar.add_cascade(label="File", menu=file_menu) 223 | root.config(menu=menubar) 224 | 225 | self.root = root 226 | self.view = view 227 | self.model = view.model 228 | view.plot() 229 | 230 | def render(self): 231 | self.root.mainloop() 232 | 233 | def open(self, var): 234 | file_name = askopenfilename( title = "Select file to open", 235 | filetypes = (("CAD files","*.obj;*.stl"), 236 | ("all files","*.*")) ) 237 | self.model.clear() 238 | self.model.load_file(file_name) 239 | self.view.plot(var.get()) 240 | 241 | def exit(self): 242 | self.model.clear() 243 | self.view.clear() 244 | self.root.destroy() 245 | 246 | 247 | def setMaxWidth(stringList, element): 248 | try: 249 | f = tkfont.nametofont(element.cget("font")) 250 | zerowidth = f.measure("0") 251 | except: 252 | f = tkfont.nametofont(ttk.Style().lookup("TButton", "font")) 253 | zerowidth = f.measure("0") - 0.8 254 | 255 | w = max([f.measure(i) for i in stringList])/zerowidth 256 | element.config(width=int(w)) 257 | 258 | 259 | class App(): 260 | 261 | def __init__(self, model=None, view=None, controller=None): 262 | file_name = None 263 | if len(sys.argv) >= 2: 264 | file_name = sys.argv[1] 265 | 266 | if model is None: 267 | model = Model(file_name) 268 | 269 | if view is None: 270 | view = View(model) 271 | 272 | if controller is None: 273 | controller = Controller(view) 274 | 275 | self.model = model 276 | self.view = view 277 | self.controller = controller 278 | 279 | def start(self): 280 | self.controller.render() 281 | 282 | 283 | if __name__ == "__main__": 284 | 285 | app = App() 286 | app.start() 287 | -------------------------------------------------------------------------------- /meshviewer_mpl_tk.py: -------------------------------------------------------------------------------- 1 | """STL/OBJ Python Mesh Viewer prototype with Matplotlib/Tkinter 2 | using a Model View Controller (MVC) design. 3 | 4 | This is just a simple prototype/proof-of-concept and not intended to 5 | be a full fledged application. If you are interested in custom CAE and 6 | simulation tools such as this app and 7 | [FEATool Multiphysics](https://www.featool.com) please feel free to 8 | get in touch with [Precise Simulation](https://www.precisesimulation.com). 9 | 10 | :license: AGPL v3, see LICENSE for more details or contact 11 | Precise Simulation for alternative licensing options. 12 | :copyright: 2020 Precise Simulation Ltd. 13 | 14 | """ 15 | 16 | try: 17 | import tkinter as tk 18 | except ImportError: 19 | import Tkinter as tk 20 | import tkinter.ttk as ttk 21 | import tkinter.font as tkfont 22 | from tkinter.filedialog import askopenfilename 23 | 24 | import matplotlib 25 | matplotlib.use("TkAgg") 26 | from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk) 27 | from matplotlib.figure import Figure 28 | from mpl_toolkits import mplot3d 29 | 30 | import sys 31 | import os 32 | if os.name == "nt": 33 | from ctypes import windll, pointer, wintypes 34 | try: 35 | windll.shcore.SetProcessDpiAwareness(1) 36 | except Exception: 37 | pass # this will fail on Windows Server and maybe early Windows 38 | 39 | 40 | class Model(): 41 | 42 | def __init__(self, file_name=None): 43 | 44 | self.data = [] 45 | if file_name is None: 46 | # Define unit cube. 47 | vertices = [[0,0,0], [1,0,0], [1,1,0], [0,1,0], 48 | [0,0,1], [1,0,1], [1,1,1], [0,1,1]] 49 | faces = [[1,2,3,4], [1,2,6,5], [2,3,7,6], [3,4,8,7], [4,1,5,8], [5,6,7,8]] 50 | data = Mesh(vertices, faces) 51 | 52 | self.data = [data] 53 | else: 54 | self.load_file(file_name) 55 | 56 | def clear(self): 57 | self.data = [] 58 | 59 | def load_file(self, file_name): 60 | '''Load mesh from file 61 | ''' 62 | if file_name.lower().endswith(('.stl','.stla','.stlb')): 63 | self.load_stl(file_name) 64 | 65 | elif file_name.lower().endswith('.obj'): 66 | self.load_obj(file_name) 67 | 68 | def load_stl(self, file_name): 69 | '''Load STL CAD file 70 | ''' 71 | try: 72 | with open(file_name, 'r') as f: 73 | data = f.read() 74 | 75 | self.load_stl_ascii(data) 76 | 77 | except: 78 | self.load_stl_binary(file_name) 79 | 80 | def load_stl_ascii(self, data): 81 | '''Load ASCII STL CAD file 82 | ''' 83 | vertices = [] 84 | faces = [] 85 | v = [] 86 | for i, line in enumerate(data.splitlines()): 87 | if i == 0 and line.strip() != 'solid': 88 | raise ValueError('Not valid ASCII STL file.') 89 | 90 | line_data = line.split() 91 | 92 | if line_data[0]=='facet': 93 | v = [] 94 | 95 | elif line_data[0]=='vertex': 96 | v.append([float(line_data[1]), float(line_data[2]), float(line_data[3])]) 97 | 98 | elif line_data[0]=='endloop': 99 | if len(v)==3: 100 | vertices.extend(v) 101 | ind = 3*len(faces)+1 102 | faces.append([ind, ind+1, ind+2]) 103 | 104 | self.data.append(Mesh(vertices, faces)) 105 | 106 | def load_stl_binary(self, file_name): 107 | '''Load binary STL CAD file 108 | ''' 109 | from struct import unpack 110 | vertices = [] 111 | faces = [] 112 | with open(file_name, 'rb') as f: 113 | header = f.read(80) 114 | # name = header.strip() 115 | n_tri = unpack(' iv: 186 | edge = (iv, jv) 187 | else: 188 | edge = (jv, iv) 189 | 190 | line_segments.add(edge) 191 | 192 | return [[self.vertices[edge[0]-1], self.vertices[edge[1]-1]] for edge in line_segments] 193 | 194 | def get_bounding_box(self): 195 | v = [vti for face in self.get_vertices() for vti in face] 196 | bbox = [] 197 | for i in range(len(self.vertices[0])): 198 | x_i = [p[i] for p in v] 199 | bbox.append([min(x_i), max(x_i)]) 200 | 201 | return bbox 202 | 203 | 204 | class View(): 205 | 206 | def __init__(self, model=None): 207 | 208 | if model is None: 209 | model = Model() 210 | self.model = model 211 | 212 | figure = Figure() 213 | axes = mplot3d.Axes3D(figure) 214 | 215 | self.figure = figure 216 | self.axes = axes 217 | self.canvas = None 218 | self.toolbar = None 219 | 220 | self.plot() 221 | 222 | def clear(self): 223 | self.axes.clear() 224 | self.update() 225 | 226 | def update(self): 227 | if self.canvas is not None: 228 | self.canvas.draw() 229 | 230 | def plot(self, types="solid + wireframe"): 231 | self.clear() 232 | if isinstance(types, (str,)): 233 | types = [s.strip() for s in types.split('+')] 234 | 235 | for mesh in self.model.data: 236 | for type in types: 237 | 238 | if type=="solid": 239 | self.axes.add_collection3d(mplot3d.art3d.Poly3DCollection(mesh.get_vertices())) 240 | 241 | elif type=="wireframe": 242 | self.axes.add_collection3d(mplot3d.art3d.Line3DCollection(mesh.get_line_segments(), 243 | colors=(0.1, 0.1, 0.35, 1))) 244 | 245 | else: 246 | # Unknown plot type 247 | return None 248 | 249 | if len(self.model.data) >= 1: 250 | self.axes.auto_scale_xyz(*self.model.get_bounding_box()) 251 | self.update() 252 | 253 | def xy(self): 254 | self.axes.view_init(elev=90, azim=-90) 255 | self.update() 256 | 257 | def xz(self): 258 | self.axes.view_init(elev=0, azim=-90) 259 | self.update() 260 | 261 | def yz(self): 262 | self.axes.view_init(elev=0, azim=0) 263 | self.update() 264 | 265 | def reset(self): 266 | self.axes.view_init() 267 | self.update() 268 | 269 | 270 | class Controller(): 271 | 272 | def __init__(self, view=None): 273 | 274 | root = tk.Tk() 275 | root.title("Mesh Viewer") 276 | 277 | if view is None: 278 | view = View() 279 | 280 | f1 = ttk.Frame(root) 281 | f1.pack(side=tk.TOP, anchor=tk.W) 282 | 283 | toolbar = [ tk.Button(f1, text="Open"), 284 | tk.Button(f1, text="XY", command=view.xy), 285 | tk.Button(f1, text="XZ", command=view.xz), 286 | tk.Button(f1, text="YZ", command=view.yz), 287 | tk.Button(f1, text="Reset", command=view.reset) ] 288 | 289 | f2 = tk.Frame(f1, highlightthickness=1, highlightbackground="gray") 290 | options = ["solid","wireframe","solid + wireframe"] 291 | var = tk.StringVar() 292 | o1 = ttk.OptionMenu(f2, var, options[len(options)-1], *options, command=lambda val: self.view.plot(val)) 293 | o1["menu"].configure(bg="white") 294 | setMaxWidth(options, o1) 295 | o1.pack() 296 | toolbar.append(f2) 297 | 298 | toolbar[0].config(command=lambda: self.open(var)) 299 | 300 | [obj.pack(side=tk.LEFT, anchor=tk.W) for obj in toolbar] 301 | 302 | canvas = FigureCanvasTkAgg(view.figure, root) 303 | canvas.mpl_connect('button_press_event', view.axes._button_press) 304 | canvas.mpl_connect('button_release_event', view.axes._button_release) 305 | canvas.mpl_connect('motion_notify_event', view.axes._on_move) 306 | canvas.draw() 307 | canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) 308 | 309 | mpl_toolbar = NavigationToolbar2Tk(canvas, root) 310 | mpl_toolbar.update() 311 | canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) 312 | 313 | menubar = tk.Menu( root ) 314 | file_menu = tk.Menu(menubar, tearoff=0) 315 | file_menu.add_command(label="Open...", command=lambda: self.open(var)) 316 | file_menu.add_command(label="Exit", command=self.exit) 317 | menubar.add_cascade(label="File", menu=file_menu) 318 | root.config(menu=menubar) 319 | 320 | self.root = root 321 | view.canvas = canvas 322 | view.toolbar = mpl_toolbar 323 | self.view = view 324 | self.model = view.model 325 | 326 | def render(self): 327 | self.root.mainloop() 328 | 329 | def open(self, var): 330 | file_name = askopenfilename( title = "Select file to open", 331 | filetypes = (("CAD files","*.obj;*.stl"), 332 | ("all files","*.*")) ) 333 | self.model.clear() 334 | self.model.load_file(file_name) 335 | self.view.plot(var.get()) 336 | 337 | def exit(self): 338 | self.model.clear() 339 | self.view.clear() 340 | self.root.destroy() 341 | 342 | 343 | def setMaxWidth(stringList, element): 344 | try: 345 | f = tkfont.nametofont(element.cget("font")) 346 | zerowidth = f.measure("0") 347 | except: 348 | f = tkfont.nametofont(ttk.Style().lookup("TButton", "font")) 349 | zerowidth = f.measure("0") - 0.8 350 | 351 | w = max([f.measure(i) for i in stringList])/zerowidth 352 | element.config(width=int(w)) 353 | 354 | 355 | class App(): 356 | 357 | def __init__(self, model=None, view=None, controller=None): 358 | file_name = None 359 | if len(sys.argv) >= 2: 360 | file_name = sys.argv[1] 361 | 362 | if model is None: 363 | model = Model(file_name) 364 | 365 | if view is None: 366 | view = View(model) 367 | 368 | if controller is None: 369 | controller = Controller(view) 370 | 371 | self.model = model 372 | self.view = view 373 | self.controller = controller 374 | 375 | def start(self): 376 | self.controller.render() 377 | 378 | 379 | if __name__ == "__main__": 380 | 381 | app = App() 382 | app.start() 383 | -------------------------------------------------------------------------------- /meshviewer_plotly_cef_tk.py: -------------------------------------------------------------------------------- 1 | """STL/OBJ Python Mesh Viewer prototype with Plotly/CEF Webview/Tkinter 2 | using a Model View Controller (MVC) design. 3 | 4 | This is just a simple prototype/proof-of-concept and not intended to 5 | be a full fledged application. If you are interested in custom CAE and 6 | simulation tools such as this app and 7 | [FEATool Multiphysics](https://www.featool.com) please feel free to 8 | get in touch with [Precise Simulation](https://www.precisesimulation.com). 9 | 10 | :license: AGPL v3, see LICENSE for more details or contact 11 | Precise Simulation for alternative licensing options. 12 | :copyright: 2020 Precise Simulation Ltd. 13 | 14 | """ 15 | 16 | try: 17 | import tkinter as tk 18 | except ImportError: 19 | import Tkinter as tk 20 | import tkinter.ttk as ttk 21 | import tkinter.font as tkfont 22 | from tkinter.filedialog import askopenfilename 23 | 24 | from cefpython3 import cefpython as cef 25 | import ctypes 26 | import sys 27 | import os 28 | if os.name == "nt": 29 | from ctypes import windll, pointer, wintypes 30 | try: 31 | windll.shcore.SetProcessDpiAwareness(1) 32 | except Exception: 33 | pass # this will fail on Windows Server and maybe early Windows 34 | 35 | import platform 36 | 37 | import numpy as np 38 | 39 | g_multi_threaded = True 40 | if not platform.system() == "Windows": 41 | g_multi_threaded = False 42 | 43 | 44 | class Model(): 45 | 46 | def __init__(self, file_name=None): 47 | 48 | self.data = [] 49 | if file_name is None: 50 | # Define unit cube. 51 | vertices = [[0,0,0], [1,0,0], [1,1,0], [0,1,0], 52 | [0,0,1], [1,0,1], [1,1,1], [0,1,1]] 53 | faces = [[1,2,3], [1,3,4], [1,2,6], [1,6,5], [2,3,7], [2,7,6], 54 | [3,4,8], [3,8,7], [4,1,5], [4,5,8], [5,6,7], [5,7,8]] 55 | data = Mesh(vertices, faces) 56 | 57 | self.data = [data] 58 | else: 59 | self.load_file(file_name) 60 | 61 | def clear(self): 62 | self.data = [] 63 | 64 | def load_file(self, file_name): 65 | '''Load mesh from file 66 | ''' 67 | if file_name.lower().endswith(('.stl','.stla','.stlb')): 68 | self.load_stl(file_name) 69 | 70 | elif file_name.lower().endswith('.obj'): 71 | self.load_obj(file_name) 72 | 73 | def load_stl(self, file_name): 74 | '''Load STL CAD file 75 | ''' 76 | try: 77 | with open(file_name, 'r') as f: 78 | data = f.read() 79 | 80 | self.load_stl_ascii(data) 81 | 82 | except: 83 | self.load_stl_binary(file_name) 84 | 85 | def load_stl_ascii(self, data): 86 | '''Load ASCII STL CAD file 87 | ''' 88 | vertices = [] 89 | faces = [] 90 | v = [] 91 | for i, line in enumerate(data.splitlines()): 92 | if i == 0 and line.strip() != 'solid': 93 | raise ValueError('Not valid ASCII STL file.') 94 | 95 | line_data = line.split() 96 | 97 | if line_data[0]=='facet': 98 | v = [] 99 | 100 | elif line_data[0]=='vertex': 101 | v.append([float(line_data[1]), float(line_data[2]), float(line_data[3])]) 102 | 103 | elif line_data[0]=='endloop': 104 | if len(v)==3: 105 | vertices.extend(v) 106 | ind = 3*len(faces)+1 107 | faces.append([ind, ind+1, ind+2]) 108 | 109 | self.data.append(Mesh(vertices, faces)) 110 | 111 | def load_stl_binary(self, file_name): 112 | '''Load binary STL CAD file 113 | ''' 114 | from struct import unpack 115 | vertices = [] 116 | faces = [] 117 | with open(file_name, 'rb') as f: 118 | header = f.read(80) 119 | # name = header.strip() 120 | n_tri = unpack(' iv: 191 | edge = (iv, jv) 192 | else: 193 | edge = (jv, iv) 194 | 195 | line_segments.add(edge) 196 | 197 | return [[self.vertices[edge[0]-1], self.vertices[edge[1]-1]] for edge in line_segments] 198 | 199 | def get_bounding_box(self): 200 | v = [vti for face in self.get_vertices() for vti in face] 201 | bbox = [] 202 | for i in range(len(self.vertices[0])): 203 | x_i = [p[i] for p in v] 204 | bbox.append([min(x_i), max(x_i)]) 205 | 206 | return bbox 207 | 208 | 209 | class View(): 210 | 211 | def __init__(self, model=None): 212 | 213 | if model is None: 214 | model = Model() 215 | 216 | self.model = model 217 | self.browserframe = None 218 | self.browser = None 219 | 220 | def clear(self): 221 | s_cmd = 'Plotly.deleteTraces("canvas", [...data.keys()]);' 222 | self.browser.ExecuteJavascript(s_cmd) 223 | 224 | def update(self): 225 | s_cmd = self.get_plot_cmd() 226 | self.browser.ExecuteJavascript(s_cmd) 227 | 228 | def plot(self, types="solid + wireframe"): 229 | self.clear() 230 | if len(self.model.data) >= 1: 231 | s_cmd = self.get_model_data(types) 232 | self.browser.ExecuteJavascript(s_cmd) 233 | self.update() 234 | 235 | def get_plot_cmd(self): 236 | s_layout = '{"showlegend": false, "scene": {"aspectratio": {"x": 1, "y": 1, "z": 1}, "aspectmode": "manual"}}' 237 | s_config = '{"responsive": true}' 238 | s = 'Plotly.plot("canvas", data, ' + s_layout + ', ' + s_config +');' 239 | return s 240 | 241 | def get_model_data(self, types="solid + wireframe"): 242 | 243 | if isinstance(types, (str,)): 244 | types = [s.strip() for s in types.split('+')] 245 | 246 | s = 'var data = [' 247 | for mesh in self.model.data: 248 | for type in types: 249 | 250 | if type=="solid": 251 | s += self.get_plotly_mesh3d_data(mesh) + ', ' 252 | 253 | elif type=="wireframe": 254 | s += self.get_plotly_scatter3d_data(mesh) + ', ' 255 | 256 | else: 257 | # Unknown plot type 258 | return None 259 | 260 | s = s[:-2] + '];' 261 | return s 262 | 263 | def get_plotly_mesh3d_data(self, mesh): 264 | s_x = str([x[0] for x in mesh.vertices]) 265 | s_y = str([x[1] for x in mesh.vertices]) 266 | s_z = str([x[2] for x in mesh.vertices]) 267 | s_i = str([f[0]-1 for f in mesh.faces]) 268 | s_j = str([f[1]-1 for f in mesh.faces]) 269 | s_k = str([f[2]-1 for f in mesh.faces]) 270 | s = '{"type": "mesh3d", "name": "faces", "hoverinfo": "x+y+z", ' + \ 271 | '"x": ' + s_x + ', "y": ' + s_y + ', "z": ' + s_z + ', ' \ 272 | '"i": ' + s_i + ', "j": ' + s_j + ', "k": ' + s_k + ', ' \ 273 | '"showscale": false, "color": "rgb(204,204,255)"}' 274 | return s 275 | 276 | def get_plotly_scatter3d_data(self, mesh): 277 | s_x = '' 278 | s_y = '' 279 | s_z = '' 280 | for line in mesh.get_line_segments(): 281 | s_x += str(line[0][0]) + ', ' + str(line[1][0]) + ', null, ' 282 | s_y += str(line[0][1]) + ', ' + str(line[1][1]) + ', null, ' 283 | s_z += str(line[0][2]) + ', ' + str(line[1][2]) + ', null, ' 284 | 285 | s_x = s_x[:-8] 286 | s_y = s_y[:-8] 287 | s_z = s_z[:-8] 288 | 289 | s = '{"type": "scatter3d", "name": "", "mode": "lines", "hoverinfo": "x+y+z", ' + \ 290 | '"x": [' + s_x + '], "y": [' + s_y + '], "z": [' + s_z + '], "showlegend": false, ' + \ 291 | '"line": {"color": "rgb(0,0,0)", "width": 2, "dash": "solid", "showscale": false}}' 292 | return s 293 | 294 | def get_plotly_html_canvas(self): 295 | s_title = 'Mesh Viewer' 296 | 297 | s_body = '
Loading Plotly ...
' + \ 298 | '
' + \ 299 | '' + \ 300 | '' 305 | 306 | s_html = '' + s_title +'' + \ 307 | s_body + '' 308 | 309 | return s_html 310 | 311 | def set_html(self, s_html): 312 | 313 | s_cmd = 'document.open("text/html");' + \ 314 | 'document.write(\'' + s_html + '\');' + \ 315 | 'document.close();' 316 | 317 | self.browser.ExecuteJavascript(s_cmd) 318 | 319 | def xy(self): 320 | bbox = self.model.get_bounding_box() 321 | d = 2*(bbox[2][1] - bbox[2][0]) 322 | s_cmd = 'Plotly.relayout("canvas", {"scene":{"camera":{"eye":{"x":0, "y":0, "z":' + str(d) + '}}}});' 323 | self.browser.ExecuteJavascript(s_cmd) 324 | 325 | def xz(self): 326 | bbox = self.model.get_bounding_box() 327 | d = 2*(bbox[1][1] - bbox[1][0]) 328 | s_cmd = 'Plotly.relayout("canvas", {"scene":{"camera":{"eye":{"x":0, "y":' + str(d) + ', "z":0}}}});' 329 | self.browser.ExecuteJavascript(s_cmd) 330 | 331 | def yz(self): 332 | bbox = self.model.get_bounding_box() 333 | d = 2*(bbox[0][1] - bbox[0][0]) 334 | s_cmd = 'Plotly.relayout("canvas", {"scene":{"camera":{"eye":{"x":' + str(d) + ', "y":0, "z":0}}}});' 335 | self.browser.ExecuteJavascript(s_cmd) 336 | 337 | def reset(self): 338 | s_cmd = 'Plotly.relayout("canvas", {"scene": {"aspectratio": {"x": 1, "y": 1, "z": 1}, "aspectmode": "manual"}});' 339 | self.browser.ExecuteJavascript(s_cmd) 340 | 341 | 342 | class Controller(): 343 | 344 | def __init__(self, view=None): 345 | 346 | root = tk.Tk() 347 | root.geometry("600x550") 348 | root.title("Mesh Viewer") 349 | root.protocol("WM_DELETE_WINDOW", self.exit) 350 | 351 | if view is None: 352 | view = View() 353 | 354 | f1 = ttk.Frame(root) 355 | f1.pack(side=tk.TOP, anchor=tk.W) 356 | 357 | toolbar = [ tk.Button(f1, text="Open"), 358 | tk.Button(f1, text="XY", command=view.xy), 359 | tk.Button(f1, text="XZ", command=view.xz), 360 | tk.Button(f1, text="YZ", command=view.yz), 361 | tk.Button(f1, text="Reset", command=view.reset) ] 362 | 363 | f2 = tk.Frame(f1, highlightthickness=1, highlightbackground="gray") 364 | options = ["solid","wireframe","solid + wireframe"] 365 | var = tk.StringVar() 366 | o1 = ttk.OptionMenu(f2, var, options[len(options)-1], *options, command=lambda val: self.view.plot(val)) 367 | o1["menu"].configure(bg="white") 368 | setMaxWidth(options, o1) 369 | o1.pack() 370 | toolbar.append(f2) 371 | 372 | toolbar[0].config(command=lambda: self.open(var)) 373 | 374 | [obj.pack(side=tk.LEFT, anchor=tk.W) for obj in toolbar] 375 | 376 | f3 = tk.Frame(root) 377 | f3.bind("", self.on_configure) 378 | f3.pack(side=tk.TOP, fill=tk.BOTH, expand=True) 379 | view.browserframe = BrowserFrame(f3, view) 380 | view.browserframe.pack(fill=tk.BOTH, expand=True) 381 | 382 | menubar = tk.Menu( root ) 383 | file_menu = tk.Menu(menubar, tearoff=0) 384 | file_menu.add_command(label="Open...", command=lambda: self.open(var)) 385 | file_menu.add_command(label="Exit", command=self.exit) 386 | menubar.add_cascade(label="File", menu=file_menu) 387 | root.config(menu=menubar) 388 | 389 | self.root = root 390 | self.view = view 391 | self.model = view.model 392 | 393 | def render(self): 394 | if hasattr(sys, '_MEIPASS'): 395 | settings = {'multi_threaded_message_loop': g_multi_threaded, 396 | 'locales_dir_path': os.path.join(sys._MEIPASS, 'locales'), 397 | 'resources_dir_path': sys._MEIPASS, 398 | 'browser_subprocess_path': os.path.join(sys._MEIPASS, 'subprocess.exe'), 399 | 'log_file': os.path.join(sys._MEIPASS, 'debug.log')} 400 | else: 401 | settings = {'multi_threaded_message_loop': g_multi_threaded} 402 | 403 | cef.Initialize(settings=settings) 404 | self.root.mainloop() 405 | 406 | def open(self, var): 407 | file_name = askopenfilename( title = "Select file to open", 408 | filetypes = (("CAD files","*.obj;*.stl"), 409 | ("all files","*.*")) ) 410 | self.model.clear() 411 | self.model.load_file(file_name) 412 | self.view.plot(var.get()) 413 | 414 | def on_configure(self, event): 415 | if self.view.browserframe: 416 | self.view.browserframe.on_mainframe_configure(event.width, event.height) 417 | 418 | def exit(self): 419 | self.model.clear() 420 | self.view.set_html('Shutting down ...') 421 | if g_multi_threaded: 422 | cef.Shutdown() 423 | if self.view.browserframe: 424 | self.view.browserframe.on_root_close() 425 | 426 | self.root.destroy() 427 | if not g_multi_threaded: 428 | cef.Shutdown() 429 | 430 | 431 | def setMaxWidth(stringList, element): 432 | try: 433 | f = tkfont.nametofont(element.cget("font")) 434 | zerowidth = f.measure("0") 435 | except: 436 | f = tkfont.nametofont(ttk.Style().lookup("TButton", "font")) 437 | zerowidth = f.measure("0") - 0.8 438 | 439 | w = max([f.measure(i) for i in stringList])/zerowidth 440 | element.config(width=int(w)) 441 | 442 | 443 | class App(): 444 | 445 | def __init__(self, model=None, view=None, controller=None): 446 | file_name = None 447 | if len(sys.argv) >= 2: 448 | file_name = sys.argv[1] 449 | 450 | if model is None: 451 | model = Model(file_name) 452 | 453 | if view is None: 454 | view = View(model) 455 | 456 | if controller is None: 457 | controller = Controller(view) 458 | 459 | self.model = model 460 | self.view = view 461 | self.controller = controller 462 | 463 | def start(self): 464 | self.controller.render() 465 | 466 | 467 | class BrowserFrame(tk.Frame): 468 | 469 | def __init__(self, master, view=None): 470 | self.browser = None 471 | self.flag = 0 472 | self.view = view 473 | tk.Frame.__init__(self, master) 474 | self.bind("", self.on_focus_in) 475 | self.bind("", self.on_focus_out) 476 | self.bind("", self.on_configure) 477 | self.focus_set() 478 | 479 | def embed_browser(self): 480 | window_info = cef.WindowInfo() 481 | rect = [0, 0, self.winfo_width(), self.winfo_height()] 482 | window_info.SetAsChild(self.get_window_handle(), rect) 483 | if g_multi_threaded: 484 | cef.PostTask(cef.TID_UI, 485 | self.create_browser, 486 | window_info, 487 | {}, 488 | "about:blank") 489 | else: 490 | self.create_browser(window_info=window_info, 491 | settings={}, 492 | url="about:blank") 493 | 494 | self.browser_setup() 495 | 496 | def create_browser(self, window_info, settings, url): 497 | assert(cef.IsThread(cef.TID_UI)) 498 | self.browser = cef.CreateBrowserSync(window_info=window_info, 499 | settings=settings, 500 | url=url) 501 | 502 | def browser_setup(self): 503 | """Wait for browser object before calling setup. """ 504 | if self.browser is None: 505 | self.after(10, self.browser_setup) 506 | elif self.flag == 0: 507 | assert self.browser 508 | self.flag = -1; 509 | self.browser.SetClientHandler(LoadHandler(self)) 510 | self.browser.SetClientHandler(FocusHandler(self)) 511 | self.view.browser = self.browser 512 | self.view.set_html(self.view.get_plotly_html_canvas()) 513 | if not g_multi_threaded: 514 | self.message_loop_work() 515 | 516 | def get_window_handle(self): 517 | if self.winfo_id() > 0: 518 | return self.winfo_id() 519 | elif platform.system() == "Darwin": 520 | from AppKit import NSApp 521 | import objc 522 | return objc.pyobjc_id(NSApp.windows()[-1].contentView()) 523 | else: 524 | raise Exception("Couldn't obtain window handle") 525 | 526 | def message_loop_work(self): 527 | cef.MessageLoopWork() 528 | self.after(10, self.message_loop_work) 529 | 530 | def on_configure(self, _): 531 | if not self.browser: 532 | self.embed_browser() 533 | 534 | def on_root_configure(self): 535 | if self.browser: 536 | self.browser.NotifyMoveOrResizeStarted() 537 | 538 | def on_mainframe_configure(self, width, height): 539 | if self.browser: 540 | if platform.system() == "Windows": 541 | ctypes.windll.user32.SetWindowPos( 542 | self.browser.GetWindowHandle(), 0, 543 | 0, 0, width, height, 0x0002) 544 | elif platform.system() == "Linux": 545 | self.browser.SetBounds(0, 0, width, height) 546 | 547 | self.browser.NotifyMoveOrResizeStarted() 548 | 549 | def on_focus_in(self, _): 550 | if self.browser: 551 | self.browser.SetFocus(True) 552 | 553 | def on_focus_out(self, _): 554 | if self.browser: 555 | self.browser.SetFocus(False) 556 | 557 | def on_root_close(self): 558 | if self.browser: 559 | self.browser.CloseBrowser(True) 560 | self.browser = None 561 | 562 | self.destroy() 563 | 564 | class LoadHandler(object): 565 | 566 | def __init__(self, browser_frame): 567 | self.browser_frame = browser_frame 568 | 569 | def OnLoadStart(self, browser, **_): 570 | pass 571 | 572 | class FocusHandler(object): 573 | 574 | def __init__(self, browser_frame): 575 | self.browser_frame = browser_frame 576 | 577 | def OnTakeFocus(self, next_component, **_): 578 | pass 579 | 580 | def OnSetFocus(self, source, **_): 581 | return False 582 | 583 | def OnGotFocus(self, **_): 584 | self.browser_frame.focus_set() 585 | 586 | 587 | if __name__ == "__main__": 588 | 589 | assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this" 590 | sys.excepthook = cef.ExceptHook 591 | app = App() 592 | app.start() 593 | -------------------------------------------------------------------------------- /test/test.obj: -------------------------------------------------------------------------------- 1 | o solid_1 2 | 3 | g face_1 4 | v 0.000000e+00 0.000000e+00 1.000000e+00 5 | v 0.000000e+00 -1.664548e-01 9.860491e-01 6 | v 0.000000e+00 -3.201080e-01 9.473810e-01 7 | v 0.000000e+00 -4.563238e-01 8.898138e-01 8 | v 0.000000e+00 -5.854144e-01 8.107343e-01 9 | v 0.000000e+00 -7.024134e-01 7.117692e-01 10 | v 0.000000e+00 -8.029642e-01 5.960273e-01 11 | v 0.000000e+00 -8.838413e-01 4.677868e-01 12 | v 0.000000e+00 -9.432849e-01 3.319845e-01 13 | v 0.000000e+00 -9.810747e-01 1.936298e-01 14 | v 0.000000e+00 -9.954216e-01 9.558124e-02 15 | v 0.000000e+00 -1.000000e+00 0.000000e+00 16 | v 0.000000e+00 1.000000e+00 0.000000e+00 17 | v 0.000000e+00 9.860491e-01 1.664548e-01 18 | v 0.000000e+00 9.473810e-01 3.201080e-01 19 | v 0.000000e+00 8.898138e-01 4.563238e-01 20 | v 0.000000e+00 8.107343e-01 5.854144e-01 21 | v 0.000000e+00 7.117692e-01 7.024134e-01 22 | v 0.000000e+00 5.960273e-01 8.029642e-01 23 | v 0.000000e+00 4.677868e-01 8.838413e-01 24 | v 0.000000e+00 3.319845e-01 9.432849e-01 25 | v 0.000000e+00 1.936298e-01 9.810747e-01 26 | v 0.000000e+00 9.558124e-02 9.954216e-01 27 | v 0.000000e+00 0.000000e+00 -1.000000e+00 28 | v 0.000000e+00 1.664548e-01 -9.860491e-01 29 | v 0.000000e+00 3.201080e-01 -9.473810e-01 30 | v 0.000000e+00 4.563238e-01 -8.898138e-01 31 | v 0.000000e+00 5.854144e-01 -8.107343e-01 32 | v 0.000000e+00 7.024134e-01 -7.117692e-01 33 | v 0.000000e+00 8.029642e-01 -5.960273e-01 34 | v 0.000000e+00 8.838413e-01 -4.677868e-01 35 | v 0.000000e+00 9.432849e-01 -3.319845e-01 36 | v 0.000000e+00 9.810747e-01 -1.936298e-01 37 | v 0.000000e+00 9.954216e-01 -9.558124e-02 38 | v 0.000000e+00 -9.860491e-01 -1.664548e-01 39 | v 0.000000e+00 -9.473810e-01 -3.201080e-01 40 | v 0.000000e+00 -8.898138e-01 -4.563238e-01 41 | v 0.000000e+00 -8.107343e-01 -5.854144e-01 42 | v 0.000000e+00 -7.117692e-01 -7.024134e-01 43 | v 0.000000e+00 -5.960273e-01 -8.029642e-01 44 | v 0.000000e+00 -4.677868e-01 -8.838413e-01 45 | v 0.000000e+00 -3.319845e-01 -9.432849e-01 46 | v 0.000000e+00 -1.936298e-01 -9.810747e-01 47 | v 0.000000e+00 -9.558124e-02 -9.954216e-01 48 | 49 | f 41 40 39 50 | f 37 39 38 51 | f 42 41 39 52 | f 36 39 37 53 | f 44 43 42 54 | f 44 42 39 55 | f 11 35 12 56 | f 11 36 35 57 | f 11 39 36 58 | f 25 24 44 59 | f 26 25 44 60 | f 9 11 10 61 | f 29 27 26 62 | f 29 28 27 63 | f 29 44 39 64 | f 29 26 44 65 | f 6 8 7 66 | f 6 9 8 67 | f 6 39 11 68 | f 6 11 9 69 | f 31 30 29 70 | f 4 6 5 71 | f 32 31 29 72 | f 3 6 4 73 | f 34 32 29 74 | f 34 33 32 75 | f 23 2 1 76 | f 23 3 2 77 | f 23 6 3 78 | f 14 13 34 79 | f 15 14 34 80 | f 21 23 22 81 | f 18 34 29 82 | f 18 6 23 83 | f 18 16 15 84 | f 18 17 16 85 | f 18 15 34 86 | f 18 20 19 87 | f 18 21 20 88 | f 18 23 21 89 | f 18 29 39 90 | f 18 39 6 91 | 92 | g face_2 93 | v 0.000000e+00 -1.000000e+00 0.000000e+00 94 | v 0.000000e+00 -9.860491e-01 -1.664548e-01 95 | v 0.000000e+00 -9.473810e-01 -3.201080e-01 96 | v 0.000000e+00 -8.898138e-01 -4.563238e-01 97 | v 0.000000e+00 -8.107343e-01 -5.854144e-01 98 | v 0.000000e+00 -7.117692e-01 -7.024134e-01 99 | v 0.000000e+00 -5.960273e-01 -8.029642e-01 100 | v 0.000000e+00 -4.677868e-01 -8.838413e-01 101 | v 0.000000e+00 -3.319845e-01 -9.432849e-01 102 | v 0.000000e+00 -1.936298e-01 -9.810747e-01 103 | v 0.000000e+00 -9.558124e-02 -9.954216e-01 104 | v 0.000000e+00 0.000000e+00 -1.000000e+00 105 | v 1.000000e+00 0.000000e+00 -5.000000e-01 106 | v 1.000000e+00 -5.000000e-01 0.000000e+00 107 | v 1.000000e+00 -4.947217e-01 -7.245975e-02 108 | v 1.000000e+00 -4.779316e-01 -1.469060e-01 109 | v 1.000000e+00 -4.486878e-01 -2.206337e-01 110 | v 1.000000e+00 -4.069130e-01 -2.905543e-01 111 | v 1.000000e+00 -3.535534e-01 -3.535534e-01 112 | v 1.000000e+00 -2.905543e-01 -4.069130e-01 113 | v 1.000000e+00 -2.206337e-01 -4.486878e-01 114 | v 1.000000e+00 -1.469059e-01 -4.779316e-01 115 | v 1.000000e+00 -7.245973e-02 -4.947217e-01 116 | v 5.000000e-01 -7.480713e-01 -5.375200e-02 117 | v 2.500000e-01 -1.051589e-01 -8.686579e-01 118 | v 7.500000e-01 -7.511353e-02 -6.204699e-01 119 | v 1.250000e-01 -2.765893e-01 -8.957704e-01 120 | v 2.500000e-01 -3.267511e-01 -8.117011e-01 121 | v 4.166667e-01 -2.739235e-01 -7.427665e-01 122 | v 5.000000e-01 -1.827667e-01 -7.273901e-01 123 | v 5.000000e-01 -2.902412e-01 -6.915635e-01 124 | v 3.750000e-01 -2.059926e-01 -7.859538e-01 125 | v 3.750000e-01 -2.643952e-01 -7.682782e-01 126 | v 3.750000e-01 -4.835399e-02 -8.110599e-01 127 | v 6.250000e-01 -2.237190e-01 -6.500816e-01 128 | v 6.250000e-01 -1.743014e-01 -6.650378e-01 129 | v 7.500000e-01 -2.277261e-01 -5.820359e-01 130 | v 8.750000e-01 -1.582239e-01 -5.397883e-01 131 | v 1.250000e-01 -5.178929e-01 -7.814686e-01 132 | v 1.250000e-01 -4.572486e-01 -8.184314e-01 133 | v 2.500000e-01 -5.136179e-01 -7.083937e-01 134 | v 3.750000e-01 -4.216735e-01 -6.945126e-01 135 | v 5.000000e-01 -3.940458e-01 -6.381441e-01 136 | v 5.000000e-01 -4.899393e-01 -5.678552e-01 137 | v 6.250000e-01 -3.538506e-01 -5.894455e-01 138 | v 8.750000e-01 -3.068301e-01 -4.714462e-01 139 | v 8.333333e-02 -7.450847e-01 -6.027035e-01 140 | v 1.250000e-01 -6.635618e-01 -6.622628e-01 141 | v 1.250000e-01 -7.124344e-01 -6.093795e-01 142 | v 2.500000e-01 -6.945936e-01 -5.321323e-01 143 | v 3.750000e-01 -5.974480e-01 -5.506470e-01 144 | v 4.166667e-01 -5.901772e-01 -5.276618e-01 145 | v 5.000000e-01 -5.739693e-01 -4.827621e-01 146 | v 5.000000e-01 -6.407013e-01 -3.898741e-01 147 | v 5.625000e-01 -4.660624e-01 -5.471631e-01 148 | v 6.875000e-01 -4.346386e-01 -4.916842e-01 149 | v 9.375000e-01 -3.673895e-01 -3.837337e-01 150 | v 1.250000e-01 -8.281660e-01 -4.393715e-01 151 | v 2.500000e-01 -8.055777e-01 -3.415693e-01 152 | v 4.166667e-01 -7.218952e-01 -3.249668e-01 153 | v 5.000000e-01 -6.933970e-01 -2.858331e-01 154 | v 5.000000e-01 -7.298867e-01 -1.725266e-01 155 | v 3.750000e-01 -7.046105e-01 -4.045742e-01 156 | v 3.750000e-01 -7.354389e-01 -3.453778e-01 157 | v 5.937500e-01 -5.735772e-01 -4.066865e-01 158 | v 5.937500e-01 -5.394622e-01 -4.509604e-01 159 | v 7.291667e-01 -5.372872e-01 -3.392298e-01 160 | v 8.437500e-01 -4.599982e-01 -3.501859e-01 161 | v 7.187500e-01 -3.329756e-01 -5.472912e-01 162 | v 1.250000e-01 -9.198373e-01 -1.811233e-01 163 | v 2.500000e-01 -8.647836e-01 -1.333203e-01 164 | v 3.750000e-01 -7.906300e-01 -1.872444e-01 165 | v 6.145833e-01 -6.393834e-01 -2.665216e-01 166 | v 8.645833e-01 -5.333889e-01 -1.943940e-01 167 | v 8.645833e-01 -5.162369e-01 -2.362037e-01 168 | v 1.250000e-01 -8.842506e-01 -3.114596e-01 169 | v 6.822917e-01 -6.446870e-01 -1.358950e-01 170 | v 9.322917e-01 -5.261668e-01 -9.027045e-02 171 | v 7.057292e-01 -6.004318e-01 -2.413834e-01 172 | 173 | f 68 58 45 174 | f 69 55 56 175 | f 70 57 67 176 | f 71 53 54 177 | f 71 54 55 178 | f 71 55 69 179 | f 72 71 69 180 | f 73 74 75 181 | f 76 74 73 182 | f 76 72 69 183 | f 76 77 72 184 | f 76 73 77 185 | f 78 56 57 186 | f 78 74 76 187 | f 78 57 70 188 | f 78 69 56 189 | f 78 70 74 190 | f 78 76 69 191 | f 79 75 74 192 | f 80 79 74 193 | f 80 74 70 194 | f 81 79 80 195 | f 81 80 70 196 | f 82 66 65 197 | f 82 67 66 198 | f 82 70 67 199 | f 82 81 70 200 | f 83 51 52 201 | f 84 52 53 202 | f 84 53 71 203 | f 84 83 52 204 | f 84 71 72 205 | f 85 84 72 206 | f 85 83 84 207 | f 86 87 88 208 | f 86 75 87 209 | f 86 85 72 210 | f 86 73 75 211 | f 86 72 77 212 | f 86 77 73 213 | f 89 75 79 214 | f 89 87 75 215 | f 90 81 82 216 | f 90 65 64 217 | f 90 82 65 218 | f 91 49 50 219 | f 92 50 51 220 | f 92 93 91 221 | f 92 83 85 222 | f 92 91 50 223 | f 92 51 83 224 | f 94 92 85 225 | f 94 93 92 226 | f 95 86 88 227 | f 95 94 85 228 | f 95 85 86 229 | f 96 95 88 230 | f 96 88 97 231 | f 96 97 98 232 | f 99 87 89 233 | f 99 88 87 234 | f 99 97 88 235 | f 100 99 89 236 | f 101 63 62 237 | f 101 64 63 238 | f 101 90 64 239 | f 102 48 49 240 | f 102 91 93 241 | f 102 93 94 242 | f 102 49 91 243 | f 103 102 94 244 | f 104 105 106 245 | f 104 98 105 246 | f 107 95 96 247 | f 107 96 98 248 | f 107 108 103 249 | f 107 104 108 250 | f 107 103 94 251 | f 107 98 104 252 | f 107 94 95 253 | f 109 98 97 254 | f 110 99 100 255 | f 110 109 97 256 | f 110 97 99 257 | f 111 110 100 258 | f 111 109 110 259 | f 112 100 90 260 | f 112 90 101 261 | f 112 111 100 262 | f 112 101 62 263 | f 113 89 79 264 | f 113 79 81 265 | f 113 81 90 266 | f 113 90 100 267 | f 113 100 89 268 | f 114 45 46 269 | f 114 46 47 270 | f 115 68 45 271 | f 115 45 114 272 | f 116 106 68 273 | f 116 103 108 274 | f 116 108 104 275 | f 116 104 106 276 | f 116 68 115 277 | f 116 115 103 278 | f 117 106 105 279 | f 117 98 109 280 | f 117 105 98 281 | f 117 109 111 282 | f 118 61 60 283 | f 119 62 61 284 | f 119 61 118 285 | f 119 111 112 286 | f 119 112 62 287 | f 120 47 48 288 | f 120 102 103 289 | f 120 114 47 290 | f 120 115 114 291 | f 120 48 102 292 | f 120 103 115 293 | f 121 68 106 294 | f 121 58 68 295 | f 121 106 117 296 | f 122 121 118 297 | f 122 59 58 298 | f 122 60 59 299 | f 122 118 60 300 | f 122 58 121 301 | f 123 121 117 302 | f 123 118 121 303 | f 123 117 111 304 | f 123 119 118 305 | f 123 111 119 306 | 307 | g face_3 308 | v 0.000000e+00 0.000000e+00 -1.000000e+00 309 | v 0.000000e+00 1.664548e-01 -9.860491e-01 310 | v 0.000000e+00 3.201080e-01 -9.473810e-01 311 | v 0.000000e+00 4.563238e-01 -8.898138e-01 312 | v 0.000000e+00 5.854144e-01 -8.107343e-01 313 | v 0.000000e+00 7.024134e-01 -7.117692e-01 314 | v 0.000000e+00 8.029642e-01 -5.960273e-01 315 | v 0.000000e+00 8.838413e-01 -4.677868e-01 316 | v 0.000000e+00 9.432849e-01 -3.319845e-01 317 | v 0.000000e+00 9.810747e-01 -1.936298e-01 318 | v 0.000000e+00 9.954216e-01 -9.558124e-02 319 | v 0.000000e+00 1.000000e+00 0.000000e+00 320 | v 1.000000e+00 0.000000e+00 -5.000000e-01 321 | v 1.000000e+00 5.000000e-01 0.000000e+00 322 | v 1.000000e+00 4.947217e-01 -7.245975e-02 323 | v 1.000000e+00 4.779316e-01 -1.469060e-01 324 | v 1.000000e+00 4.486878e-01 -2.206337e-01 325 | v 1.000000e+00 4.069130e-01 -2.905543e-01 326 | v 1.000000e+00 3.535534e-01 -3.535534e-01 327 | v 1.000000e+00 2.905543e-01 -4.069130e-01 328 | v 1.000000e+00 2.206337e-01 -4.486878e-01 329 | v 1.000000e+00 1.469059e-01 -4.779316e-01 330 | v 1.000000e+00 7.245973e-02 -4.947217e-01 331 | v 5.000000e-01 7.491569e-01 -3.555232e-02 332 | v 2.500000e-01 8.686863e-01 -1.049243e-01 333 | v 2.500000e-01 9.928183e-02 -8.693493e-01 334 | v 7.500000e-01 7.091559e-02 -6.209638e-01 335 | v 1.250000e-01 8.958098e-01 -2.764617e-01 336 | v 2.500000e-01 8.117327e-01 -3.266726e-01 337 | v 3.750000e-01 7.859828e-01 -2.058819e-01 338 | v 5.000000e-01 7.273901e-01 -1.827667e-01 339 | v 3.750000e-01 7.683162e-01 -2.642849e-01 340 | v 4.166667e-01 7.427928e-01 -2.738521e-01 341 | v 5.000000e-01 6.915635e-01 -2.902412e-01 342 | v 1.250000e-01 2.678061e-01 -8.984354e-01 343 | v 2.500000e-01 3.196216e-01 -8.145349e-01 344 | v 4.166667e-01 2.690057e-01 -7.445616e-01 345 | v 5.000000e-01 1.725266e-01 -7.298867e-01 346 | v 5.000000e-01 2.858331e-01 -6.933970e-01 347 | v 3.750000e-01 2.007963e-01 -7.872973e-01 348 | v 3.750000e-01 2.592170e-01 -7.700408e-01 349 | v 3.750000e-01 4.566956e-02 -8.112155e-01 350 | v 6.250000e-01 2.193375e-01 -6.515730e-01 351 | v 6.250000e-01 1.699045e-01 -6.661747e-01 352 | v 7.500000e-01 2.250867e-01 -5.830617e-01 353 | v 8.750000e-01 1.563038e-01 -5.403475e-01 354 | v 1.250000e-01 8.184540e-01 -4.572081e-01 355 | v 1.250000e-01 7.814944e-01 -5.178539e-01 356 | v 2.500000e-01 7.084109e-01 -5.135942e-01 357 | v 3.750000e-01 6.945335e-01 -4.216390e-01 358 | v 5.000000e-01 6.381441e-01 -3.940459e-01 359 | v 5.000000e-01 5.678551e-01 -4.899393e-01 360 | v 1.250000e-01 5.092117e-01 -7.871529e-01 361 | v 1.250000e-01 4.482461e-01 -8.233965e-01 362 | v 2.500000e-01 5.053828e-01 -7.142921e-01 363 | v 3.750000e-01 4.142153e-01 -6.989864e-01 364 | v 5.000000e-01 3.898740e-01 -6.407014e-01 365 | v 5.000000e-01 4.827621e-01 -5.739693e-01 366 | v 6.250000e-01 3.488112e-01 -5.924416e-01 367 | v 8.750000e-01 3.057262e-01 -4.721628e-01 368 | v 8.333333e-02 6.736224e-01 -6.816418e-01 369 | v 1.250000e-01 6.592113e-01 -6.665934e-01 370 | v 1.666667e-01 6.792043e-01 -6.155967e-01 371 | v 1.875000e-01 6.234251e-01 -6.577463e-01 372 | v 2.500000e-01 6.151129e-01 -6.223031e-01 373 | v 2.083333e-01 5.845422e-01 -6.788429e-01 374 | v 5.625000e-01 4.602325e-01 -5.520758e-01 375 | v 6.875000e-01 4.309534e-01 -4.949174e-01 376 | v 9.375000e-01 3.669354e-01 -3.841679e-01 377 | v 5.937500e-01 5.707168e-01 -4.106911e-01 378 | v 5.937500e-01 5.362767e-01 -4.547439e-01 379 | v 7.291667e-01 5.357069e-01 -3.417199e-01 380 | v 8.437500e-01 4.586914e-01 -3.518959e-01 381 | v 7.187500e-01 3.296771e-01 -5.492845e-01 382 | v 6.145833e-01 6.368055e-01 -2.726234e-01 383 | v 8.645833e-01 5.329522e-01 -1.955882e-01 384 | v 8.645833e-01 5.156980e-01 -2.373779e-01 385 | v 5.572917e-01 7.037531e-01 -1.583774e-01 386 | v 6.822917e-01 6.462303e-01 -1.283560e-01 387 | v 9.322917e-01 5.260702e-01 -9.083178e-02 388 | 389 | f 147 135 137 390 | f 148 134 135 391 | f 148 135 147 392 | f 149 124 125 393 | f 150 146 136 394 | f 151 132 133 395 | f 151 133 134 396 | f 151 134 148 397 | f 152 151 148 398 | f 153 152 148 399 | f 153 147 154 400 | f 153 148 147 401 | f 155 152 153 402 | f 156 154 157 403 | f 156 153 154 404 | f 156 155 153 405 | f 158 125 126 406 | f 158 149 125 407 | f 159 149 158 408 | f 160 162 161 409 | f 163 164 160 410 | f 163 160 161 411 | f 163 159 164 412 | f 163 149 159 413 | f 165 149 163 414 | f 165 163 161 415 | f 165 136 124 416 | f 165 150 136 417 | f 165 124 149 418 | f 165 161 150 419 | f 166 161 162 420 | f 167 161 166 421 | f 167 150 161 422 | f 168 167 166 423 | f 168 150 167 424 | f 169 144 145 425 | f 169 145 146 426 | f 169 146 150 427 | f 169 150 168 428 | f 170 131 132 429 | f 170 132 151 430 | f 170 151 152 431 | f 171 130 131 432 | f 171 131 170 433 | f 172 170 152 434 | f 172 171 170 435 | f 173 172 152 436 | f 173 157 174 437 | f 173 174 175 438 | f 173 152 155 439 | f 173 156 157 440 | f 173 155 156 441 | f 176 127 128 442 | f 177 126 127 443 | f 177 127 176 444 | f 177 159 158 445 | f 177 158 126 446 | f 178 177 176 447 | f 178 159 177 448 | f 179 160 164 449 | f 179 159 178 450 | f 179 162 160 451 | f 179 181 180 452 | f 179 180 162 453 | f 179 164 159 454 | f 182 166 162 455 | f 182 162 180 456 | f 182 168 166 457 | f 183 144 169 458 | f 183 143 144 459 | f 183 169 168 460 | f 184 128 129 461 | f 184 129 130 462 | f 184 176 128 463 | f 184 130 171 464 | f 185 184 171 465 | f 185 176 184 466 | f 186 185 171 467 | f 186 171 172 468 | f 187 176 185 469 | f 187 185 186 470 | f 188 172 173 471 | f 188 173 175 472 | f 188 179 178 473 | f 188 181 179 474 | f 188 175 181 475 | f 188 186 172 476 | f 188 187 186 477 | f 189 188 178 478 | f 189 176 187 479 | f 189 187 188 480 | f 189 178 176 481 | f 190 181 175 482 | f 190 182 180 483 | f 190 180 181 484 | f 191 182 190 485 | f 192 143 183 486 | f 192 141 142 487 | f 192 142 143 488 | f 193 175 174 489 | f 194 190 175 490 | f 194 191 190 491 | f 194 175 193 492 | f 195 191 194 493 | f 195 194 193 494 | f 196 191 195 495 | f 196 192 183 496 | f 196 183 191 497 | f 196 141 192 498 | f 197 168 182 499 | f 197 182 191 500 | f 197 183 168 501 | f 197 191 183 502 | f 198 174 157 503 | f 198 193 174 504 | f 198 195 193 505 | f 199 139 140 506 | f 199 195 198 507 | f 200 195 199 508 | f 200 140 141 509 | f 200 199 140 510 | f 200 196 195 511 | f 200 141 196 512 | f 201 198 157 513 | f 201 154 147 514 | f 201 157 154 515 | f 202 201 147 516 | f 202 147 137 517 | f 202 198 201 518 | f 202 199 198 519 | f 203 202 137 520 | f 203 199 202 521 | f 203 137 138 522 | f 203 138 139 523 | f 203 139 199 524 | 525 | g face_4 526 | v 0.000000e+00 1.000000e+00 0.000000e+00 527 | v 0.000000e+00 9.860491e-01 1.664548e-01 528 | v 0.000000e+00 9.473810e-01 3.201080e-01 529 | v 0.000000e+00 8.898138e-01 4.563238e-01 530 | v 0.000000e+00 8.107343e-01 5.854144e-01 531 | v 0.000000e+00 7.117692e-01 7.024134e-01 532 | v 0.000000e+00 5.960273e-01 8.029642e-01 533 | v 0.000000e+00 4.677868e-01 8.838413e-01 534 | v 0.000000e+00 3.319845e-01 9.432849e-01 535 | v 0.000000e+00 1.936298e-01 9.810747e-01 536 | v 0.000000e+00 9.558124e-02 9.954216e-01 537 | v 0.000000e+00 0.000000e+00 1.000000e+00 538 | v 1.000000e+00 0.000000e+00 5.000000e-01 539 | v 1.000000e+00 5.000000e-01 0.000000e+00 540 | v 1.000000e+00 4.947217e-01 7.245975e-02 541 | v 1.000000e+00 4.779316e-01 1.469060e-01 542 | v 1.000000e+00 4.486878e-01 2.206337e-01 543 | v 1.000000e+00 4.069130e-01 2.905543e-01 544 | v 1.000000e+00 3.535534e-01 3.535534e-01 545 | v 1.000000e+00 2.905543e-01 4.069130e-01 546 | v 1.000000e+00 2.206337e-01 4.486878e-01 547 | v 1.000000e+00 1.469059e-01 4.779316e-01 548 | v 1.000000e+00 7.245973e-02 4.947217e-01 549 | v 5.000000e-01 7.480713e-01 5.375200e-02 550 | v 2.500000e-01 1.051589e-01 8.686579e-01 551 | v 7.500000e-01 7.511353e-02 6.204699e-01 552 | v 1.250000e-01 2.765893e-01 8.957704e-01 553 | v 2.500000e-01 3.267511e-01 8.117011e-01 554 | v 4.166667e-01 2.739235e-01 7.427665e-01 555 | v 5.000000e-01 1.827667e-01 7.273901e-01 556 | v 5.000000e-01 2.902412e-01 6.915635e-01 557 | v 3.750000e-01 2.059926e-01 7.859538e-01 558 | v 3.750000e-01 2.643952e-01 7.682782e-01 559 | v 3.750000e-01 4.835399e-02 8.110599e-01 560 | v 6.250000e-01 2.237190e-01 6.500816e-01 561 | v 6.250000e-01 1.743014e-01 6.650378e-01 562 | v 7.500000e-01 2.277261e-01 5.820359e-01 563 | v 8.750000e-01 1.582239e-01 5.397883e-01 564 | v 1.250000e-01 5.178929e-01 7.814686e-01 565 | v 1.250000e-01 4.572486e-01 8.184314e-01 566 | v 2.500000e-01 5.136179e-01 7.083937e-01 567 | v 3.750000e-01 4.216735e-01 6.945126e-01 568 | v 5.000000e-01 3.940458e-01 6.381441e-01 569 | v 5.000000e-01 4.899393e-01 5.678552e-01 570 | v 6.250000e-01 3.538506e-01 5.894455e-01 571 | v 8.750000e-01 3.068301e-01 4.714462e-01 572 | v 8.333333e-02 7.450847e-01 6.027035e-01 573 | v 1.250000e-01 6.635618e-01 6.622628e-01 574 | v 1.250000e-01 7.124344e-01 6.093795e-01 575 | v 2.500000e-01 6.945936e-01 5.321323e-01 576 | v 3.750000e-01 5.974480e-01 5.506470e-01 577 | v 4.166667e-01 5.901772e-01 5.276618e-01 578 | v 5.000000e-01 5.739693e-01 4.827621e-01 579 | v 5.000000e-01 6.407013e-01 3.898741e-01 580 | v 5.625000e-01 4.660624e-01 5.471631e-01 581 | v 6.875000e-01 4.346386e-01 4.916842e-01 582 | v 9.375000e-01 3.673895e-01 3.837337e-01 583 | v 1.250000e-01 8.281660e-01 4.393715e-01 584 | v 2.500000e-01 8.055777e-01 3.415693e-01 585 | v 4.166667e-01 7.218952e-01 3.249668e-01 586 | v 5.000000e-01 6.933970e-01 2.858331e-01 587 | v 5.000000e-01 7.298867e-01 1.725266e-01 588 | v 3.750000e-01 7.046105e-01 4.045742e-01 589 | v 3.750000e-01 7.354389e-01 3.453778e-01 590 | v 5.937500e-01 5.735772e-01 4.066865e-01 591 | v 5.937500e-01 5.394622e-01 4.509604e-01 592 | v 7.291667e-01 5.372872e-01 3.392298e-01 593 | v 8.437500e-01 4.599982e-01 3.501859e-01 594 | v 7.187500e-01 3.329756e-01 5.472912e-01 595 | v 1.250000e-01 9.198373e-01 1.811233e-01 596 | v 2.500000e-01 8.647836e-01 1.333203e-01 597 | v 3.750000e-01 7.906300e-01 1.872444e-01 598 | v 6.145833e-01 6.393834e-01 2.665216e-01 599 | v 8.645833e-01 5.333889e-01 1.943940e-01 600 | v 8.645833e-01 5.162369e-01 2.362037e-01 601 | v 1.250000e-01 8.842506e-01 3.114596e-01 602 | v 6.822917e-01 6.446870e-01 1.358950e-01 603 | v 9.322917e-01 5.261668e-01 9.027045e-02 604 | v 7.057292e-01 6.004318e-01 2.413834e-01 605 | 606 | f 227 217 204 607 | f 228 214 215 608 | f 229 216 226 609 | f 230 212 213 610 | f 230 213 214 611 | f 230 214 228 612 | f 231 230 228 613 | f 232 233 234 614 | f 235 233 232 615 | f 235 231 228 616 | f 235 236 231 617 | f 235 232 236 618 | f 237 215 216 619 | f 237 233 235 620 | f 237 216 229 621 | f 237 228 215 622 | f 237 229 233 623 | f 237 235 228 624 | f 238 234 233 625 | f 239 238 233 626 | f 239 233 229 627 | f 240 238 239 628 | f 240 239 229 629 | f 241 225 224 630 | f 241 226 225 631 | f 241 229 226 632 | f 241 240 229 633 | f 242 210 211 634 | f 243 211 212 635 | f 243 212 230 636 | f 243 242 211 637 | f 243 230 231 638 | f 244 243 231 639 | f 244 242 243 640 | f 245 246 247 641 | f 245 234 246 642 | f 245 244 231 643 | f 245 232 234 644 | f 245 231 236 645 | f 245 236 232 646 | f 248 234 238 647 | f 248 246 234 648 | f 249 240 241 649 | f 249 224 223 650 | f 249 241 224 651 | f 250 208 209 652 | f 251 209 210 653 | f 251 252 250 654 | f 251 242 244 655 | f 251 250 209 656 | f 251 210 242 657 | f 253 251 244 658 | f 253 252 251 659 | f 254 245 247 660 | f 254 253 244 661 | f 254 244 245 662 | f 255 254 247 663 | f 255 247 256 664 | f 255 256 257 665 | f 258 246 248 666 | f 258 247 246 667 | f 258 256 247 668 | f 259 258 248 669 | f 260 222 221 670 | f 260 223 222 671 | f 260 249 223 672 | f 261 207 208 673 | f 261 250 252 674 | f 261 252 253 675 | f 261 208 250 676 | f 262 261 253 677 | f 263 264 265 678 | f 263 257 264 679 | f 266 254 255 680 | f 266 255 257 681 | f 266 267 262 682 | f 266 263 267 683 | f 266 262 253 684 | f 266 257 263 685 | f 266 253 254 686 | f 268 257 256 687 | f 269 258 259 688 | f 269 268 256 689 | f 269 256 258 690 | f 270 269 259 691 | f 270 268 269 692 | f 271 259 249 693 | f 271 249 260 694 | f 271 270 259 695 | f 271 260 221 696 | f 272 248 238 697 | f 272 238 240 698 | f 272 240 249 699 | f 272 249 259 700 | f 272 259 248 701 | f 273 204 205 702 | f 273 205 206 703 | f 274 227 204 704 | f 274 204 273 705 | f 275 265 227 706 | f 275 262 267 707 | f 275 267 263 708 | f 275 263 265 709 | f 275 227 274 710 | f 275 274 262 711 | f 276 265 264 712 | f 276 257 268 713 | f 276 264 257 714 | f 276 268 270 715 | f 277 220 219 716 | f 278 221 220 717 | f 278 220 277 718 | f 278 270 271 719 | f 278 271 221 720 | f 279 206 207 721 | f 279 261 262 722 | f 279 273 206 723 | f 279 274 273 724 | f 279 207 261 725 | f 279 262 274 726 | f 280 227 265 727 | f 280 217 227 728 | f 280 265 276 729 | f 281 280 277 730 | f 281 218 217 731 | f 281 219 218 732 | f 281 277 219 733 | f 281 217 280 734 | f 282 280 276 735 | f 282 277 280 736 | f 282 276 270 737 | f 282 278 277 738 | f 282 270 278 739 | 740 | g face_5 741 | v 0.000000e+00 0.000000e+00 1.000000e+00 742 | v 0.000000e+00 -1.664548e-01 9.860491e-01 743 | v 0.000000e+00 -3.201080e-01 9.473810e-01 744 | v 0.000000e+00 -4.563238e-01 8.898138e-01 745 | v 0.000000e+00 -5.854144e-01 8.107343e-01 746 | v 0.000000e+00 -7.024134e-01 7.117692e-01 747 | v 0.000000e+00 -8.029642e-01 5.960273e-01 748 | v 0.000000e+00 -8.838413e-01 4.677868e-01 749 | v 0.000000e+00 -9.432849e-01 3.319845e-01 750 | v 0.000000e+00 -9.810747e-01 1.936298e-01 751 | v 0.000000e+00 -9.954216e-01 9.558124e-02 752 | v 0.000000e+00 -1.000000e+00 0.000000e+00 753 | v 1.000000e+00 0.000000e+00 5.000000e-01 754 | v 1.000000e+00 -5.000000e-01 0.000000e+00 755 | v 1.000000e+00 -4.947217e-01 7.245975e-02 756 | v 1.000000e+00 -4.779316e-01 1.469060e-01 757 | v 1.000000e+00 -4.486878e-01 2.206337e-01 758 | v 1.000000e+00 -4.069130e-01 2.905543e-01 759 | v 1.000000e+00 -3.535534e-01 3.535534e-01 760 | v 1.000000e+00 -2.905543e-01 4.069130e-01 761 | v 1.000000e+00 -2.206337e-01 4.486878e-01 762 | v 1.000000e+00 -1.469059e-01 4.779316e-01 763 | v 1.000000e+00 -7.245973e-02 4.947217e-01 764 | v 5.000000e-01 -7.491569e-01 3.555232e-02 765 | v 2.500000e-01 -8.686863e-01 1.049243e-01 766 | v 2.500000e-01 -9.928183e-02 8.693493e-01 767 | v 7.500000e-01 -7.091559e-02 6.209638e-01 768 | v 1.250000e-01 -8.958098e-01 2.764617e-01 769 | v 2.500000e-01 -8.117327e-01 3.266726e-01 770 | v 3.750000e-01 -7.859828e-01 2.058819e-01 771 | v 5.000000e-01 -7.273901e-01 1.827667e-01 772 | v 3.750000e-01 -7.683162e-01 2.642849e-01 773 | v 4.166667e-01 -7.427928e-01 2.738521e-01 774 | v 5.000000e-01 -6.915635e-01 2.902412e-01 775 | v 1.250000e-01 -2.678061e-01 8.984354e-01 776 | v 2.500000e-01 -3.196216e-01 8.145349e-01 777 | v 4.166667e-01 -2.690057e-01 7.445616e-01 778 | v 5.000000e-01 -1.725266e-01 7.298867e-01 779 | v 5.000000e-01 -2.858331e-01 6.933970e-01 780 | v 3.750000e-01 -2.007963e-01 7.872973e-01 781 | v 3.750000e-01 -2.592170e-01 7.700408e-01 782 | v 3.750000e-01 -4.566956e-02 8.112155e-01 783 | v 6.250000e-01 -2.193375e-01 6.515730e-01 784 | v 6.250000e-01 -1.699045e-01 6.661747e-01 785 | v 7.500000e-01 -2.250867e-01 5.830617e-01 786 | v 8.750000e-01 -1.563038e-01 5.403475e-01 787 | v 1.250000e-01 -8.184540e-01 4.572081e-01 788 | v 1.250000e-01 -7.814944e-01 5.178539e-01 789 | v 2.500000e-01 -7.084109e-01 5.135942e-01 790 | v 3.750000e-01 -6.945335e-01 4.216390e-01 791 | v 5.000000e-01 -6.381441e-01 3.940459e-01 792 | v 5.000000e-01 -5.678551e-01 4.899393e-01 793 | v 1.250000e-01 -5.092117e-01 7.871529e-01 794 | v 1.250000e-01 -4.482461e-01 8.233965e-01 795 | v 2.500000e-01 -5.053828e-01 7.142921e-01 796 | v 3.750000e-01 -4.142153e-01 6.989864e-01 797 | v 5.000000e-01 -3.898740e-01 6.407014e-01 798 | v 5.000000e-01 -4.827621e-01 5.739693e-01 799 | v 6.250000e-01 -3.488112e-01 5.924416e-01 800 | v 8.750000e-01 -3.057262e-01 4.721628e-01 801 | v 8.333333e-02 -6.736224e-01 6.816418e-01 802 | v 1.250000e-01 -6.592113e-01 6.665934e-01 803 | v 1.666667e-01 -6.792043e-01 6.155967e-01 804 | v 1.875000e-01 -6.234251e-01 6.577463e-01 805 | v 2.500000e-01 -6.151129e-01 6.223031e-01 806 | v 2.083333e-01 -5.845422e-01 6.788429e-01 807 | v 5.625000e-01 -4.602325e-01 5.520758e-01 808 | v 6.875000e-01 -4.309534e-01 4.949174e-01 809 | v 9.375000e-01 -3.669354e-01 3.841679e-01 810 | v 5.937500e-01 -5.707168e-01 4.106911e-01 811 | v 5.937500e-01 -5.362767e-01 4.547439e-01 812 | v 7.291667e-01 -5.357069e-01 3.417199e-01 813 | v 8.437500e-01 -4.586914e-01 3.518959e-01 814 | v 7.187500e-01 -3.296771e-01 5.492845e-01 815 | v 6.145833e-01 -6.368055e-01 2.726234e-01 816 | v 8.645833e-01 -5.329522e-01 1.955882e-01 817 | v 8.645833e-01 -5.156980e-01 2.373779e-01 818 | v 5.572917e-01 -7.037531e-01 1.583774e-01 819 | v 6.822917e-01 -6.462303e-01 1.283560e-01 820 | v 9.322917e-01 -5.260702e-01 9.083178e-02 821 | 822 | f 306 294 296 823 | f 307 293 294 824 | f 307 294 306 825 | f 308 283 284 826 | f 309 305 295 827 | f 310 291 292 828 | f 310 292 293 829 | f 310 293 307 830 | f 311 310 307 831 | f 312 311 307 832 | f 312 306 313 833 | f 312 307 306 834 | f 314 311 312 835 | f 315 313 316 836 | f 315 312 313 837 | f 315 314 312 838 | f 317 284 285 839 | f 317 308 284 840 | f 318 308 317 841 | f 319 321 320 842 | f 322 323 319 843 | f 322 319 320 844 | f 322 318 323 845 | f 322 308 318 846 | f 324 308 322 847 | f 324 322 320 848 | f 324 295 283 849 | f 324 309 295 850 | f 324 283 308 851 | f 324 320 309 852 | f 325 320 321 853 | f 326 320 325 854 | f 326 309 320 855 | f 327 326 325 856 | f 327 309 326 857 | f 328 303 304 858 | f 328 304 305 859 | f 328 305 309 860 | f 328 309 327 861 | f 329 290 291 862 | f 329 291 310 863 | f 329 310 311 864 | f 330 289 290 865 | f 330 290 329 866 | f 331 329 311 867 | f 331 330 329 868 | f 332 331 311 869 | f 332 316 333 870 | f 332 333 334 871 | f 332 311 314 872 | f 332 315 316 873 | f 332 314 315 874 | f 335 286 287 875 | f 336 285 286 876 | f 336 286 335 877 | f 336 318 317 878 | f 336 317 285 879 | f 337 336 335 880 | f 337 318 336 881 | f 338 319 323 882 | f 338 318 337 883 | f 338 321 319 884 | f 338 340 339 885 | f 338 339 321 886 | f 338 323 318 887 | f 341 325 321 888 | f 341 321 339 889 | f 341 327 325 890 | f 342 303 328 891 | f 342 302 303 892 | f 342 328 327 893 | f 343 287 288 894 | f 343 288 289 895 | f 343 335 287 896 | f 343 289 330 897 | f 344 343 330 898 | f 344 335 343 899 | f 345 344 330 900 | f 345 330 331 901 | f 346 335 344 902 | f 346 344 345 903 | f 347 331 332 904 | f 347 332 334 905 | f 347 338 337 906 | f 347 340 338 907 | f 347 334 340 908 | f 347 345 331 909 | f 347 346 345 910 | f 348 347 337 911 | f 348 335 346 912 | f 348 346 347 913 | f 348 337 335 914 | f 349 340 334 915 | f 349 341 339 916 | f 349 339 340 917 | f 350 341 349 918 | f 351 302 342 919 | f 351 300 301 920 | f 351 301 302 921 | f 352 334 333 922 | f 353 349 334 923 | f 353 350 349 924 | f 353 334 352 925 | f 354 350 353 926 | f 354 353 352 927 | f 355 350 354 928 | f 355 351 342 929 | f 355 342 350 930 | f 355 300 351 931 | f 356 327 341 932 | f 356 341 350 933 | f 356 342 327 934 | f 356 350 342 935 | f 357 333 316 936 | f 357 352 333 937 | f 357 354 352 938 | f 358 298 299 939 | f 358 354 357 940 | f 359 354 358 941 | f 359 299 300 942 | f 359 358 299 943 | f 359 355 354 944 | f 359 300 355 945 | f 360 357 316 946 | f 360 313 306 947 | f 360 316 313 948 | f 361 360 306 949 | f 361 306 296 950 | f 361 357 360 951 | f 361 358 357 952 | f 362 361 296 953 | f 362 358 361 954 | f 362 296 297 955 | f 362 297 298 956 | f 362 298 358 957 | 958 | g face_6 959 | v 1.000000e+00 -5.000000e-01 0.000000e+00 960 | v 1.000000e+00 -4.947217e-01 -7.245975e-02 961 | v 1.000000e+00 -4.779316e-01 -1.469060e-01 962 | v 1.000000e+00 -4.486878e-01 -2.206337e-01 963 | v 1.000000e+00 -4.069130e-01 -2.905543e-01 964 | v 1.000000e+00 -3.535534e-01 -3.535534e-01 965 | v 1.000000e+00 -2.905543e-01 -4.069130e-01 966 | v 1.000000e+00 -2.206337e-01 -4.486878e-01 967 | v 1.000000e+00 -1.469059e-01 -4.779316e-01 968 | v 1.000000e+00 -7.245973e-02 -4.947217e-01 969 | v 1.000000e+00 0.000000e+00 -5.000000e-01 970 | v 1.000000e+00 5.000000e-01 0.000000e+00 971 | v 1.000000e+00 4.947217e-01 -7.245975e-02 972 | v 1.000000e+00 4.779316e-01 -1.469060e-01 973 | v 1.000000e+00 4.486878e-01 -2.206337e-01 974 | v 1.000000e+00 4.069130e-01 -2.905543e-01 975 | v 1.000000e+00 3.535534e-01 -3.535534e-01 976 | v 1.000000e+00 2.905543e-01 -4.069130e-01 977 | v 1.000000e+00 2.206337e-01 -4.486878e-01 978 | v 1.000000e+00 1.469059e-01 -4.779316e-01 979 | v 1.000000e+00 7.245973e-02 -4.947217e-01 980 | v 1.000000e+00 4.947217e-01 7.245975e-02 981 | v 1.000000e+00 4.779316e-01 1.469060e-01 982 | v 1.000000e+00 4.486878e-01 2.206337e-01 983 | v 1.000000e+00 4.069130e-01 2.905543e-01 984 | v 1.000000e+00 3.535534e-01 3.535534e-01 985 | v 1.000000e+00 2.905543e-01 4.069130e-01 986 | v 1.000000e+00 2.206337e-01 4.486878e-01 987 | v 1.000000e+00 1.469059e-01 4.779316e-01 988 | v 1.000000e+00 7.245973e-02 4.947217e-01 989 | v 1.000000e+00 0.000000e+00 5.000000e-01 990 | v 1.000000e+00 -4.947217e-01 7.245975e-02 991 | v 1.000000e+00 -4.779316e-01 1.469060e-01 992 | v 1.000000e+00 -4.486878e-01 2.206337e-01 993 | v 1.000000e+00 -4.069130e-01 2.905543e-01 994 | v 1.000000e+00 -3.535534e-01 3.535534e-01 995 | v 1.000000e+00 -2.905543e-01 4.069130e-01 996 | v 1.000000e+00 -2.206337e-01 4.486878e-01 997 | v 1.000000e+00 -1.469059e-01 4.779316e-01 998 | v 1.000000e+00 -7.245973e-02 4.947217e-01 999 | 1000 | f 396 398 397 1001 | f 400 399 398 1002 | f 394 396 395 1003 | f 394 398 396 1004 | f 402 401 400 1005 | f 402 400 398 1006 | f 392 393 402 1007 | f 364 394 363 1008 | f 390 391 392 1009 | f 366 364 365 1010 | f 388 389 390 1011 | f 388 392 402 1012 | f 388 402 398 1013 | f 388 390 392 1014 | f 368 366 367 1015 | f 368 394 364 1016 | f 368 398 394 1017 | f 368 364 366 1018 | f 386 387 388 1019 | f 370 368 369 1020 | f 384 385 386 1021 | f 384 386 388 1022 | f 372 370 371 1023 | f 372 368 370 1024 | f 383 372 373 1025 | f 375 374 384 1026 | f 375 384 388 1027 | f 381 383 382 1028 | f 377 376 375 1029 | f 379 368 372 1030 | f 379 372 383 1031 | f 379 377 375 1032 | f 379 375 388 1033 | f 379 383 381 1034 | f 379 378 377 1035 | f 379 381 380 1036 | f 379 388 398 1037 | f 379 398 368 1038 | 1039 | g edge_1 1040 | v 0.000000e+00 -1.000000e+00 0.000000e+00 1041 | v 0.000000e+00 -9.860491e-01 -1.664548e-01 1042 | v 0.000000e+00 -9.473810e-01 -3.201080e-01 1043 | v 0.000000e+00 -8.898138e-01 -4.563238e-01 1044 | v 0.000000e+00 -8.107343e-01 -5.854144e-01 1045 | v 0.000000e+00 -7.117692e-01 -7.024134e-01 1046 | v 0.000000e+00 -5.960273e-01 -8.029642e-01 1047 | v 0.000000e+00 -4.677868e-01 -8.838413e-01 1048 | v 0.000000e+00 -3.319845e-01 -9.432849e-01 1049 | v 0.000000e+00 -1.936298e-01 -9.810747e-01 1050 | v 0.000000e+00 -9.558124e-02 -9.954216e-01 1051 | v 0.000000e+00 0.000000e+00 -1.000000e+00 1052 | 1053 | l 403 404 405 406 407 408 409 410 411 412 413 414 1054 | 1055 | g edge_2 1056 | v 0.000000e+00 0.000000e+00 -1.000000e+00 1057 | v 0.000000e+00 1.664548e-01 -9.860491e-01 1058 | v 0.000000e+00 3.201080e-01 -9.473810e-01 1059 | v 0.000000e+00 4.563238e-01 -8.898138e-01 1060 | v 0.000000e+00 5.854144e-01 -8.107343e-01 1061 | v 0.000000e+00 7.024134e-01 -7.117692e-01 1062 | v 0.000000e+00 8.029642e-01 -5.960273e-01 1063 | v 0.000000e+00 8.838413e-01 -4.677868e-01 1064 | v 0.000000e+00 9.432849e-01 -3.319845e-01 1065 | v 0.000000e+00 9.810747e-01 -1.936298e-01 1066 | v 0.000000e+00 9.954216e-01 -9.558124e-02 1067 | v 0.000000e+00 1.000000e+00 0.000000e+00 1068 | 1069 | l 415 416 417 418 419 420 421 422 423 424 425 426 1070 | 1071 | g edge_3 1072 | v 0.000000e+00 1.000000e+00 0.000000e+00 1073 | v 0.000000e+00 9.860491e-01 1.664548e-01 1074 | v 0.000000e+00 9.473810e-01 3.201080e-01 1075 | v 0.000000e+00 8.898138e-01 4.563238e-01 1076 | v 0.000000e+00 8.107343e-01 5.854144e-01 1077 | v 0.000000e+00 7.117692e-01 7.024134e-01 1078 | v 0.000000e+00 5.960273e-01 8.029642e-01 1079 | v 0.000000e+00 4.677868e-01 8.838413e-01 1080 | v 0.000000e+00 3.319845e-01 9.432849e-01 1081 | v 0.000000e+00 1.936298e-01 9.810747e-01 1082 | v 0.000000e+00 9.558124e-02 9.954216e-01 1083 | v 0.000000e+00 0.000000e+00 1.000000e+00 1084 | 1085 | l 427 428 429 430 431 432 433 434 435 436 437 438 1086 | 1087 | g edge_4 1088 | v 0.000000e+00 0.000000e+00 1.000000e+00 1089 | v 0.000000e+00 -1.664548e-01 9.860491e-01 1090 | v 0.000000e+00 -3.201080e-01 9.473810e-01 1091 | v 0.000000e+00 -4.563238e-01 8.898138e-01 1092 | v 0.000000e+00 -5.854144e-01 8.107343e-01 1093 | v 0.000000e+00 -7.024134e-01 7.117692e-01 1094 | v 0.000000e+00 -8.029642e-01 5.960273e-01 1095 | v 0.000000e+00 -8.838413e-01 4.677868e-01 1096 | v 0.000000e+00 -9.432849e-01 3.319845e-01 1097 | v 0.000000e+00 -9.810747e-01 1.936298e-01 1098 | v 0.000000e+00 -9.954216e-01 9.558124e-02 1099 | v 0.000000e+00 -1.000000e+00 0.000000e+00 1100 | 1101 | l 439 440 441 442 443 444 445 446 447 448 449 450 1102 | 1103 | g edge_5 1104 | v 1.000000e+00 -5.000000e-01 0.000000e+00 1105 | v 1.000000e+00 -4.947217e-01 -7.245975e-02 1106 | v 1.000000e+00 -4.779316e-01 -1.469060e-01 1107 | v 1.000000e+00 -4.486878e-01 -2.206337e-01 1108 | v 1.000000e+00 -4.069130e-01 -2.905543e-01 1109 | v 1.000000e+00 -3.535534e-01 -3.535534e-01 1110 | v 1.000000e+00 -2.905543e-01 -4.069130e-01 1111 | v 1.000000e+00 -2.206337e-01 -4.486878e-01 1112 | v 1.000000e+00 -1.469059e-01 -4.779316e-01 1113 | v 1.000000e+00 -7.245973e-02 -4.947217e-01 1114 | v 1.000000e+00 0.000000e+00 -5.000000e-01 1115 | 1116 | l 451 452 453 454 455 456 457 458 459 460 461 1117 | 1118 | g edge_6 1119 | v 0.000000e+00 -1.000000e+00 0.000000e+00 1120 | v 1.000000e+00 -5.000000e-01 0.000000e+00 1121 | 1122 | l 462 463 1123 | 1124 | g edge_7 1125 | v 0.000000e+00 0.000000e+00 -1.000000e+00 1126 | v 1.000000e+00 0.000000e+00 -5.000000e-01 1127 | 1128 | l 464 465 1129 | 1130 | g edge_8 1131 | v 1.000000e+00 5.000000e-01 0.000000e+00 1132 | v 1.000000e+00 4.947217e-01 -7.245975e-02 1133 | v 1.000000e+00 4.779316e-01 -1.469060e-01 1134 | v 1.000000e+00 4.486878e-01 -2.206337e-01 1135 | v 1.000000e+00 4.069130e-01 -2.905543e-01 1136 | v 1.000000e+00 3.535534e-01 -3.535534e-01 1137 | v 1.000000e+00 2.905543e-01 -4.069130e-01 1138 | v 1.000000e+00 2.206337e-01 -4.486878e-01 1139 | v 1.000000e+00 1.469059e-01 -4.779316e-01 1140 | v 1.000000e+00 7.245973e-02 -4.947217e-01 1141 | v 1.000000e+00 0.000000e+00 -5.000000e-01 1142 | 1143 | l 466 467 468 469 470 471 472 473 474 475 476 1144 | 1145 | g edge_9 1146 | v 0.000000e+00 1.000000e+00 0.000000e+00 1147 | v 1.000000e+00 5.000000e-01 0.000000e+00 1148 | 1149 | l 477 478 1150 | 1151 | g edge_10 1152 | v 1.000000e+00 5.000000e-01 0.000000e+00 1153 | v 1.000000e+00 4.947217e-01 7.245975e-02 1154 | v 1.000000e+00 4.779316e-01 1.469060e-01 1155 | v 1.000000e+00 4.486878e-01 2.206337e-01 1156 | v 1.000000e+00 4.069130e-01 2.905543e-01 1157 | v 1.000000e+00 3.535534e-01 3.535534e-01 1158 | v 1.000000e+00 2.905543e-01 4.069130e-01 1159 | v 1.000000e+00 2.206337e-01 4.486878e-01 1160 | v 1.000000e+00 1.469059e-01 4.779316e-01 1161 | v 1.000000e+00 7.245973e-02 4.947217e-01 1162 | v 1.000000e+00 0.000000e+00 5.000000e-01 1163 | 1164 | l 479 480 481 482 483 484 485 486 487 488 489 1165 | 1166 | g edge_11 1167 | v 0.000000e+00 0.000000e+00 1.000000e+00 1168 | v 1.000000e+00 0.000000e+00 5.000000e-01 1169 | 1170 | l 490 491 1171 | 1172 | g edge_12 1173 | v 1.000000e+00 -5.000000e-01 0.000000e+00 1174 | v 1.000000e+00 -4.947217e-01 7.245975e-02 1175 | v 1.000000e+00 -4.779316e-01 1.469060e-01 1176 | v 1.000000e+00 -4.486878e-01 2.206337e-01 1177 | v 1.000000e+00 -4.069130e-01 2.905543e-01 1178 | v 1.000000e+00 -3.535534e-01 3.535534e-01 1179 | v 1.000000e+00 -2.905543e-01 4.069130e-01 1180 | v 1.000000e+00 -2.206337e-01 4.486878e-01 1181 | v 1.000000e+00 -1.469059e-01 4.779316e-01 1182 | v 1.000000e+00 -7.245973e-02 4.947217e-01 1183 | v 1.000000e+00 0.000000e+00 5.000000e-01 1184 | 1185 | l 492 493 494 495 496 497 498 499 500 501 502 1186 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | --------------------------------------------------------------------------------