├── .DS_Store ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── archgeolab ├── __init__.py ├── archgeometry │ ├── __init__.py │ ├── conicSection.py │ ├── curves.py │ ├── gridshell_new.py │ ├── gui_basic.py │ ├── orient.py │ ├── orthogonalVectors.py │ └── quadrings.py ├── constraints │ ├── __init__.py │ ├── constraints_basic.py │ ├── constraints_equilibrium.py │ ├── constraints_fairness.py │ ├── constraints_glide.py │ └── constraints_net.py ├── guidedprojection_orthonet.py ├── opt_gui_orthonet.py └── readfile_orthonet.py ├── assets ├── AG.png ├── _graph.TXT ├── anet.png ├── cmc.png ├── files.png ├── frame.png ├── funicular.png ├── layout.png ├── mayavi.png ├── pq.png ├── teaser.png ├── tree.png ├── tree_emoji.py └── tree_print.py ├── conda ├── macos │ └── environment.yml └── windows │ └── environment.yml └── objs ├── obj_anet ├── enneper2.obj └── knet1.obj ├── obj_equilibrium └── quad_dome.obj ├── obj_pq ├── conical1.obj └── heart.obj └── obj_snet └── cmc1.obj /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.bak 3 | .spyproject/config/backups/encoding.ini.bak 4 | *.ini 5 | *.ini 6 | archgeolab/constraints/__pycache__/constraints_glide.cpython-39.pyc 7 | *.pyc 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "geometrylab"] 2 | path = geometrylab 3 | url = https://github.com/WWmore/geometrylab 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 WWmore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArchGeo Library 2 | 3 | | Basic Library | Related Projects | **License** | **Documentation** | 4 | |:-:|:-:|:-:|:-:| 5 | | Numpy,SciPy,Mayavi,[geometrylab](https://github.com/WWmore/geometrylab) | [Discrete Orthogonal Structures ](https://github.com/WWmore/DOS#discrete-orthogonal-structures) | [![GitHub license](https://img.shields.io/github/license/alshedivat/al-folio?color=blue)](https://tlo.mit.edu/researchers-mit-community/protect/software-open-source-protection)| [![doc](https://img.shields.io/badge/doc-readthedocs-blueviolet)](https://www.huiwang.me/mkdocs-archgeo/) | 6 | 7 | # Discrete Orthogonal Structures 8 | 9 | 10 | 11 | Felix Dellinger, Xinye Li, and Hui Wang* (corresponding author)
12 | | [Project Page](https://www.huiwang.me/projects/10_project/) | [Full Paper](https://www.huiwang.me/assets/pdf/2023SMI.pdf) | [Publication Page](https://doi.org/10.1016/j.cag.2023.05.024) | [Documentation](https://www.huiwang.me/mkdocs-archgeo/) |
13 | ![Teaser image](assets/teaser.png) 14 | 15 |
16 | Abstract 17 | 18 | *To represent smooth geometric shapes by coarse polygonal meshes, visible edges often follow special families of curves on a surface to achieve visually pleasing results. Important examples of such families are principal curvature lines, asymptotic lines or geodesics. In a surprisingly big amount of use-cases, these curves form an orthogonal net. While the condition of orthogonality between smooth curves on a surface is straightforward, the discrete counterpart, namely orthogonal quad meshes, is not. In this paper, we study the definition of discrete orthogonality based on equal diagonal lengths in every quadrilateral. We embed this definition in the theory of discrete differential geometry and highlight its benefits for practical applications. We demonstrate the versatility of this approach by combining discrete orthogonality with other classical constraints known from discrete differential geometry. Orthogonal multi-nets, i.e. meshes where discrete orthogonality holds on any parameter rectangle, receive an in-depth analysis.* 19 | 20 |
21 |
22 | 23 | This repository contains the implementation associated with the paper ["Discrete Orthogonal Structures"](https://doi.org/10.1016/j.cag.2023.05.024). 24 | Please cite the paper if you use this code in your project. 25 | 26 |
27 |
28 |

BibTeX

29 |
@Article{DOS2023,
 30 |       author       = {Dellinger, Felix and Li, Xinye and Wang, Hui},
 31 |       title        = {Discrete Orthogonal Structures},
 32 |       journal      = {Computers & Graphics},
 33 |       volume       = {114},
 34 |       pages        = {126--137},
 35 |       month        = {June},
 36 |       year         = {2023},
 37 |       doi          = {10.1016/j.cag.2023.05.024},
 38 |       url          = {https://www.huiwang.me/projects/10_project/}
 39 | }
40 |
41 |
42 | 43 | 44 | ## Set up a working environment in Windows / MacOS 45 | 46 | Using Anaconda to install every package. 47 | 48 | 1. Download Anaconda 49 | 50 | 2. Open Anaconda Prompt 51 | ``` 52 | $ conda create -n geo 53 | $ conda activate geo 54 | $ conda install mayavi traits traitsui qt pyqt vtk scipy spyder 55 | $ conda install -c haasad pypardiso 56 | ``` 57 | 3. Open Anaconda, under "geo" environment open Spyder 58 | 59 | Once above installation failed because of versions conflict, then try below installations: 60 |
61 | step-by-step installation. 62 | 63 | ``` 64 | $ conda create -n geo python=3.6 65 | $ conda activate geo 66 | $ pip install numpy scipy 67 | $ pip install python-vtk 68 | $ pip install mayavi --no-cache 69 | $ conda install -c haasad pypardiso 70 | $ conda install pyface 71 | ``` 72 | 73 | Or use the exported files within ```./conda/``` to set your environment 74 | 75 | ``` 76 | $ conda env create -f environment.yml 77 | ``` 78 | 79 |
80 |
81 | 82 | 83 | ## File Relations 84 | 85 |
86 | File tree. 87 | 88 | ![File](assets/tree.png) 89 | 90 |
91 |
92 | 93 | ![File](assets/files.png) 94 | 95 | ![File](assets/frame.png) 96 | 97 |
98 | File notice. 99 | 100 | - files in geometrylab folder are basic, nothing need to be changed. 101 | 102 | - archgeolab/archgeometry: meshpy.py --> quadrings.py --> gridshell_new.py --> gui_basic.py --> guidedprojection_orthonet.py --> opt_gui_orthonet.py --> readfile_orthonet.py 103 | 104 | - run readfile_orthonet.py to test how it works; a GUI window will be opened 105 | 106 | - The GUI settings are in opt_gui_orthonet.py 107 | 108 | - The constraints settings are in guidedprojection_orthonet.py 109 | 110 | - if you want to add a new optimization project, please refer to archgeolab; You can create a new folder similar to the folder 'archgeolab'. Then the mesh geometry, optimization and GUI will be based on the files in geometrylab folder. 111 | 112 |
113 |
114 | 115 | 116 | ## Mesh Optimization 117 | The optimizer uses Guided Projection Algorithm, a Gauss-Newton algorithm, as dissused in the paper [Form-finding with polyhedral meshes made simple](https://doi.org/10.1145/2601097.2601213), in a Python environment to produce quadmesh models. 118 | 119 |
120 | Abstract of the paper 'Form-finding with Polyhedral Meshes Made Simple' 121 | 122 | *We solve the form-finding problem for polyhedral meshes in a way which combines form, function and fabrication; taking care of user-specified constraints like boundary interpolation, planarity of faces, statics, panel size and shape, enclosed volume, and last, but not least, cost. Our main application is the interactive modeling of meshes for architectural and industrial design. Our approach can be described as guided exploration of the constraint space whose algebraic structure is simplified by introducing auxiliary variables and ensuring that constraints are at most quadratic. Computationally, we perform a projection onto the constraint space which is biased towards low values of an energy which expresses desirable "soft" properties like fairness. We have created a tool which elegantly handles difficult tasks, such as taking boundary-alignment of polyhedral meshes into account, planarization, fairing under planarity side conditions, handling hybrid meshes, and extending the treatment of static equilibrium to shapes which possess overhanging parts.* 123 | 124 |
125 |
126 | 127 | ## ArchGeo Visualization 128 | 129 | 130 | Python programming visualization for optimization problems in the Architectural Geometry / Geometry Processing area. 131 | This implementation major works on quad meshes. 132 | 133 | 134 | ![File](assets/mayavi.png) 135 | 136 | 137 | ### Implementation layout 138 | [![layout](assets/layout.png)](https://www.youtube.com/embed/1l6DCW9BmYM) 139 | 140 | 141 | ### Implementation of a principal net optimized from an orthogonal PQ mesh 142 | [![PQ](assets/pq.png)](https://www.youtube.com/embed/m-CFC0XZ488) 143 | 144 | 145 | ### Implementation of a minimal net optimized from an orthogonal A-net 146 | [![Anet](assets/anet.png)](https://www.youtube.com/embed/KQbJ2e_Ow7M) 147 | 148 | 149 | ### Implementation of a CMC net optimized from an orthogonal S-net with const. radius 150 | [![CMC](assets/cmc.png)](https://www.youtube.com/embed/vgb9A6uAidw) 151 | 152 | 153 | ### Implementation of a principal stress net from an orthogonal equilibrium mesh 154 | [![Funicular](assets/funicular.png)](https://www.youtube.com/embed/sOzjRHIrR-s) 155 | 156 | 157 | ------ 158 | ## Contributions 159 | If you find this codebase and paper helpful in your research, welcome to cite the paper and give a :star: . 160 | This project was initially developed by [Davide Pellis](https://scholar.google.com/citations?user=JnocFM4AAAAJ&hl=en). 161 | It is still under development. 162 | Please feel free to push issues or submit requests to contribute to our codebase. 163 | Welcome to work together to make a Grasshopper plugin if you are interested. For any commercial uses, please contact us. 164 | Hoping this codebase is helpful for your research work. 165 | 166 | Welcome to the research collaborations! 167 | -------------------------------------------------------------------------------- /archgeolab/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from archgeolab import archgeometry 4 | 5 | from archgeolab import constraints 6 | -------------------------------------------------------------------------------- /archgeolab/archgeometry/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ## Note: add this file (path) 4 | 5 | 6 | ### functions related with the mesh geometry: 7 | from archgeolab.archgeometry import quadrings 8 | 9 | from archgeolab.archgeometry import orient 10 | 11 | from archgeolab.archgeometry import conicSection 12 | 13 | from archgeolab.archgeometry import orthogonalVectors 14 | 15 | from archgeolab.archgeometry import curves 16 | 17 | ### meshpy.py --> quadrings.py --> gridshell_new.py --> gui_basic.py --> project folder 18 | 19 | from archgeolab.archgeometry import gridshell_new 20 | 21 | from archgeolab.archgeometry import gui_basic -------------------------------------------------------------------------------- /archgeolab/archgeometry/conicSection.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Dec 18 22:16:21 2022 4 | 5 | @author: WANGH0M 6 | """ 7 | __author__ = 'Hui Wang' 8 | # ----------------------------------------------------------------------------- 9 | import numpy as np 10 | 11 | import scipy 12 | #------------------------------------------------------------------------------ 13 | from geometrylab.geometry.meshprimitives import mesh_sphere 14 | # ----------------------------------------------------------------------------- 15 | """ 16 | vs_sphere_equation 17 | sphere_equation 18 | get_vs_interpolated_sphere 19 | interpolate_sphere 20 | get_sphere_packing 21 | """ 22 | 23 | #------------------------------------------------------------------------------ 24 | # GENERATION 25 | #------------------------------------------------------------------------------ 26 | def vs_sphere_equation(V,vneib): 27 | "V=vertices_coordinate, index: vneib=[v,neib]" 28 | "P = [x^2+y^2+z^2,x,y,z,1]" 29 | Pc0 = np.einsum('ij,ij->i',V[vneib],V[vneib]) 30 | P = np.c_[Pc0, V[vneib], np.ones(len(vneib))] 31 | H = np.einsum('ij,jk',P.T,P) 32 | Q = np.array([[0,0,0,0,-2],[ 0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[-2,0,0,0,0]]) 33 | vals, vecs = scipy.linalg.eig(H,Q) 34 | vals = np.abs(vals) 35 | smallest = list(vals).index(min(list(vals[vals>=0]))) 36 | ####smallest = np.argmin(vals) 37 | vector = vecs[:,smallest] 38 | A, B, C, D, E = vector[0],vector[1],vector[2],vector[3],vector[4] 39 | delt = np.sqrt(np.abs(B*B+C*C+D*D-4*A*E)) 40 | A,B,C,D,E = A/delt,B/delt,C/delt,D/delt,E/delt 41 | eps = np.finfo(float).eps 42 | A = A+eps 43 | cM = -1/(2*A) * np.array([B, C, D]) 44 | r = np.abs((B*B+C*C+D*D-4*A*E)/(4*A*A)) 45 | if A < 0: 46 | coo = [-A,-B,-C,-D,-E] 47 | else: 48 | coo = [A,B,C,D,E] 49 | # test: coo * V[vneib] * coo--->0 50 | # print 'test', vals[smallest], np.dot(np.dot(np.array(coo), H),np.array(coo).reshape(-1,1)) 51 | return coo, cM, np.sqrt(r) 52 | 53 | def sphere_equation(V,order,somelist): 54 | "somelist = ringlist / vringlist" 55 | V4 = V[order] 56 | coolist,clist,rlist = [],[],[] 57 | for v in order: 58 | ring = somelist[v] 59 | coo,c,r = vs_sphere_equation(V,ring) 60 | coolist.append(coo) 61 | clist.append(c) 62 | rlist.append(r) 63 | coo = np.array(coolist) 64 | sphere_coeff = (coo.T).flatten() 65 | M = np.array(clist).reshape(-1,3) 66 | nx = 2*coo[:,0]*V4[:,0]+coo[:,1] 67 | ny = 2*coo[:,0]*V4[:,1]+coo[:,2] 68 | nz = 2*coo[:,0]*V4[:,2]+coo[:,3] 69 | sphere_n = np.c_[nx,ny,nz].flatten() 70 | return M,np.array(rlist),sphere_coeff,sphere_n 71 | 72 | def get_vs_interpolated_sphere(V,v,ringlist): 73 | C,r,_,_ = sphere_equation(V,v,ringlist) 74 | all_vi = np.array([],dtype=int) 75 | for i in v: 76 | all_vi = np.r_[all_vi,np.array(ringlist[i])] 77 | Vneib = V[all_vi] 78 | return C,r,Vneib 79 | 80 | def interpolate_sphere(V0,V1,V2,V3,V4): 81 | """interpolate 5 vertices 82 | a(x^2+y^2+z^2)+(bx+cy+dz)+e=0 ; normalize: F^2 = b^2+c^2+d^2-4ae=1 83 | sphere center C:= (m1,m2,m3) = -(b, c, d) /a/2 84 | sphere radius:= F^2/a/2 = 1/(2a) 85 | shere normal N:// V-C // (Vx+B/A/2, Vy+C/A/2, Vz+D/A/2); 86 | unit_sphere_normal==-(2*A*Vx+B, 2*A*Vy+C, 2*A*Vz+D), (note direction: from vertex to center) 87 | since P(Vx,Vy,Vz) satisfy the sphere eq. and the normalizated eq., so that 88 | N ^2=1 89 | """ 90 | num = len(V0) 91 | allV = np.vstack((V0,V1,V2,V3,V4)) 92 | arr = num*np.arange(5) 93 | def _vs(partV): 94 | "P = [x^2+y^2+z^2,x,y,z,1]" 95 | Pc0 = np.einsum('ij,ij->i',partV,partV) 96 | P = np.c_[Pc0, partV, np.ones(5)] 97 | H = np.einsum('ij,jk',P.T,P) 98 | Q = np.array([[0,0,0,0,-2],[ 0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[-2,0,0,0,0]]) 99 | vals, vecs = scipy.linalg.eig(H,Q) 100 | vals = np.abs(vals) 101 | smallest = list(vals).index(min(list(vals[vals>=0]))) 102 | vector = vecs[:,smallest] 103 | A, B, C, D, E = vector[0],vector[1],vector[2],vector[3],vector[4] 104 | delt = np.sqrt(np.abs(B*B+C*C+D*D-4*A*E)) 105 | A,B,C,D,E = A/delt,B/delt,C/delt,D/delt,E/delt 106 | cM = -1/(2*A) * np.array([B, C, D]) 107 | r = np.abs((B*B+C*C+D*D-4*A*E)/(4*A*A)) 108 | if A < 0: 109 | coo = [-A,-B,-C,-D,-E] 110 | else: 111 | coo = [A,B,C,D,E] 112 | return coo, cM, np.sqrt(r) 113 | 114 | coolist,clist,rlist = [],[],[] 115 | for i in range(num): 116 | partV = allV[i+arr] 117 | coo,c,r = _vs(partV) 118 | coolist.append(coo) 119 | clist.append(c) 120 | rlist.append(r) 121 | coo = np.array(coolist) 122 | sphere_coeff = (coo.T).flatten() 123 | M = np.array(clist).reshape(-1,3) 124 | nx = 2*coo[:,0]*V0[:,0]+coo[:,1] #==2*A*Vx+B 125 | ny = 2*coo[:,0]*V0[:,1]+coo[:,2] #==2*A*Vx+C 126 | nz = 2*coo[:,0]*V0[:,2]+coo[:,3] #==2*A*Vx+D 127 | sphere_n = -np.c_[nx,ny,nz]#.flatten() ##note the sign 128 | return M,np.array(rlist),sphere_coeff,sphere_n 129 | 130 | def get_sphere_packing(C,r,Fa=20,Fv=20): 131 | num = C.shape[0] 132 | M0 = mesh_sphere(C[0],r[0],Fa,Fv) 133 | for i in range(num-1): 134 | Si = mesh_sphere(C[i+1], r[i+1],Fa,Fv) 135 | half = Si.halfedges 136 | V,E,F = Si.V, Si.E, Si.F 137 | M0.vertices = np.vstack((M0.vertices, Si.vertices)) 138 | half[:,0] += (i+1)*V 139 | half[:,1] += (i+1)*F 140 | half[:,2] += (i+1)*2*E 141 | half[:,3] += (i+1)*2*E 142 | half[:,4] += (i+1)*2*E 143 | half[:,5] += (i+1)*2*E 144 | M0.halfedges = np.vstack((M0.halfedges, half)) 145 | M0.topology_update() 146 | return M0 147 | 148 | -------------------------------------------------------------------------------- /archgeolab/archgeometry/curves.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Nov 2 12:55:43 2022 4 | 5 | @author: WANGH0M 6 | """ 7 | __author__ = 'Hui Wang' 8 | #--------------------------------------------------------------------------- 9 | import numpy as np 10 | 11 | from geometrylab.geometry import Polyline 12 | 13 | #----------------------------------------------------------------------------- 14 | 15 | """from huilab.huimesh.curves import 16 | mesh_polylines, 17 | make_polyline_from_endpoints, 18 | make_multiple_polylines_from_endpoints, 19 | get_isoline_between_2bdry, 20 | get_diagonal_polyline_from_2points 21 | """ 22 | ####------------------------------------------------------------- 23 | 24 | 25 | def mesh_polylines(V, plys): 26 | "copy from meshpy.py/mesh_polylines; plys are seglists" #not work 27 | polylines = [] 28 | for family in plys: 29 | poly_family = [] 30 | for curve in family: 31 | poly_family.append(Polyline(V[curve,:])) 32 | polylines.append(poly_family) 33 | return polylines 34 | 35 | def diagonal_cell_array(v1): 36 | """represent polyline data 37 | suppose num=6 38 | a0 = [2,2,2,2,2,2] 39 | a1 = [0,1,2,3,4,5] 40 | a2 = [6,7,8,9,10,11] 41 | cells = [2,0,6, 2,1,7,..., 2,5,11] 42 | """ 43 | num = len(v1) 44 | c = np.repeat(2,num) 45 | "i = np.arange(num), j = num + i" 46 | i,j = np.arange(2*num).reshape(2,-1) 47 | cells = np.vstack((c,i,j)).T 48 | cells = np.ravel(cells) 49 | return cells 50 | 51 | def make_polyline_from_endpoints(Vl,Vr): 52 | "fork from quadring.py" 53 | VV = np.vstack((Vl,Vr)) 54 | v = np.arange(len(Vl)) 55 | data = diagonal_cell_array(v) 56 | poly = Polyline(VV) 57 | poly.cell_array=data 58 | #poly.refine(steps=3) 59 | return poly 60 | 61 | 62 | def get_diagonal_polyline_from_2points(mesh,vi,is_poly=True): 63 | if len(vi)==1: 64 | print('You should select at least two diagonal vertices!') 65 | else: 66 | H,V = mesh.halfedges, mesh.vertices 67 | vl = vr = np.array([],dtype=int) 68 | es1 = np.where([H[:,0]==vi[0]][0])[0] 69 | es2 = np.where([H[:,0]==vi[1]][0])[0] 70 | f1 = H[es1,1] 71 | f2 = H[es2,1] 72 | f = np.intersect1d(f1,f2) 73 | il = es1[np.where(f1==f)[0]] 74 | ir = es2[np.where(f2==f)[0]] 75 | 76 | vl = np.r_[vl,H[il,0]] 77 | num = len(np.where(H[:,0]==H[il,0])[0]) 78 | while num==4 and H[H[H[H[il,4],2],4],1]!=-1 and H[H[il,4],1]!=-1: 79 | il = H[H[H[H[il,4],2],4],3] 80 | if H[il,0] in vl: 81 | break 82 | vl = np.r_[vl, H[il,0]] 83 | num = len(np.where(H[:,0]==H[il,0])[0]) 84 | 85 | vr = np.r_[vr,H[ir,0]] 86 | num = len(np.where(H[:,0]==H[ir,0])[0]) 87 | while num==4 and H[H[H[H[ir,4],2],4],1]!=-1 and H[H[ir,4],1]!=-1: 88 | ir =H[H[H[H[ir,4],2],4],3] 89 | if H[ir,0] in vr: 90 | break 91 | vr = np.r_[vr, H[ir,0]] 92 | num = len(np.where(H[:,0]==H[ir,0])[0]) 93 | "Vl = self.vertices[vl[::-1]]; Vr = self.vertices[vr]" 94 | iv = np.r_[vl[::-1],vr] 95 | VV = V[iv] 96 | if is_poly: 97 | poly = make_polyline_from_endpoints(VV[:-1,:],VV[1:,:]) 98 | return iv,VV,poly 99 | return iv,VV 100 | 101 | 102 | def make_multiple_polylines_from_endpoints(VV,ns): 103 | def _multiple_segments_cell_array(ns): 104 | "ns is an array of nums of each segment" 105 | ci = np.array([],dtype=int) 106 | a = 0 107 | for n in ns: 108 | i = a + np.arange(n) 109 | ci = np.r_[ci,i] 110 | a += n + 1 111 | c = np.ones(len(ci))*2 112 | cj = ci + 1 113 | cells = np.vstack((c,ci,cj)).T 114 | cells = np.ravel(cells) 115 | return cells 116 | data = _multiple_segments_cell_array(ns) 117 | poly = Polyline(VV) 118 | poly.cell_array=data 119 | return poly 120 | 121 | def get_isoline_between_2bdry(mesh,vb): 122 | "starting from 1 boundary-vertex, get isoline untile to opposit bdry" 123 | "work for rectangular-patch + cylinder-annulus; vb in continious order" 124 | H = mesh.halfedges 125 | if True: 126 | "reverse the boundary list" 127 | vi,vj = vb[0],vb[1] 128 | ei = np.intersect1d(np.where(H[:,0]==vi)[0], np.where(H[H[:,4],0]==vj)[0])[0] 129 | if H[ei,1]!=-1: 130 | vb = vb[::-1] 131 | allv = [] 132 | for i in range(len(vb)-1): 133 | vi,vj = vb[i],vb[i+1] 134 | ei = np.intersect1d(np.where(H[:,0]==vi)[0], np.where(H[H[:,4],0]==vj)[0])[0] 135 | plv = [vi] 136 | e = ei 137 | while H[H[e,4],1]!=-1: 138 | e = H[H[H[e,4],2],2] 139 | plv.append(H[e,0]) 140 | allv.append(plv) 141 | "last boundary" 142 | plvj = [vj] 143 | e = H[ei,4] 144 | while H[e,1]!=-1: 145 | e = H[H[H[e,2],2],4] 146 | plvj.append(H[e,0]) 147 | allv.append(plvj) 148 | return allv -------------------------------------------------------------------------------- /archgeolab/archgeometry/gui_basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # -*- coding: utf-8 -*- 4 | 5 | __author__ = 'Davide Pellis + Hui Wang' 6 | #------------------------------------------------------------------------------ 7 | import os 8 | 9 | import sys 10 | 11 | path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 12 | 13 | sys.path.append(path) 14 | #print(path) 15 | 16 | from traits.api import Instance,String,on_trait_change, Bool, Int,List 17 | 18 | from traitsui.api import View, Item, HSplit,ListEditor, \ 19 | Action, ToolBar, Separator, Controller 20 | 21 | from tvtk.pyface.scene_editor import SceneEditor 22 | 23 | from mayavi.tools.mlab_scene_model import MlabSceneModel 24 | 25 | from pyface.image_resource import ImageResource 26 | 27 | #------------------------------------------------------------------------------ 28 | from geometrylab.vtkplot.meshplotmanager import MeshPlotManager 29 | 30 | from geometrylab.gui.scenemanager import SceneManager 31 | 32 | from geometrylab.gui.multiscenemanager import MultiSceneManager 33 | 34 | from geometrylab.gui.geolabscene import GeolabScene 35 | 36 | from geometrylab.gui.geolabcomponent import GeolabComponent 37 | 38 | from geometrylab.gui.handler import Handler 39 | 40 | from geometrylab.gui.tools import IncrementalRemesh,CornerTolerance,Loads,SaveMesh 41 | 42 | #from geometrylab.optimization.gridshell import Gridshell ##Hui comment 43 | ##Hui: super on geometrylab/optimization/Gridshell() 44 | from archgeolab.archgeometry.gridshell_new import GridshellNew 45 | 46 | # ----------------------------------------------------------------------------- 47 | """forked from geometrylab/gui/geolabgui.py 48 | 49 | meshpy.py --> quadrings.py --> gridshell_new.py --> gui_basic.py --> project folder 50 | """ 51 | # ----------------------------------------------------------------------------- 52 | # ----------------------------------------------------------------------------- 53 | # Handler 54 | # ----------------------------------------------------------------------------- 55 | # ----------------------------------------------------------------------------- 56 | 57 | 58 | class GlHandler(Controller): 59 | 60 | def close(self, info, is_ok): 61 | info.object._closed = True 62 | Controller.close(self ,info, is_ok) 63 | return True 64 | 65 | #-------------------------------------------------------------------------- 66 | # Tools 67 | #-------------------------------------------------------------------------- 68 | 69 | def open_plot_manager(self): 70 | self.info.object.open_plot_manager() 71 | 72 | def open_corner_tolerance(self): 73 | self.info.object.open_corner_tolerance() 74 | 75 | def open_save_mesh(self): 76 | self.info.object.open_save_mesh() 77 | 78 | def open_remesh(self): 79 | self.info.object.open_remesh() 80 | 81 | def open_loads(self): 82 | self.info.object.open_loads() 83 | 84 | 85 | #-------------------------------------------------------------------------- 86 | # Selection 87 | #-------------------------------------------------------------------------- 88 | 89 | def background_switch(self): 90 | self.info.object.background_switch() 91 | 92 | def select_object(self): 93 | self.info.object.select_object() 94 | 95 | def select_vertices(self): 96 | self.info.object.select_vertices() 97 | 98 | def select_edges(self): 99 | self.info.object.select_edges() 100 | 101 | def select_faces(self): 102 | self.info.object.select_faces() 103 | 104 | def select_boundary_vertices(self): 105 | self.info.object.select_boundary_vertices() 106 | 107 | def move_vertices(self): 108 | self.info.object.move_vertices() 109 | 110 | #-------------------------------------------------------------------------- 111 | # Mesh state 112 | #-------------------------------------------------------------------------- 113 | 114 | def reset_mesh(self): 115 | self.info.object.reset_mesh() 116 | 117 | def set_reference(self): 118 | self.info.object.set_reference() 119 | 120 | def start_mesh(self): # Hui 121 | self.info.object.start_mesh() 122 | 123 | def hide_mesh(self): # Hui 124 | self.info.object.hide_mesh() 125 | 126 | def clear(self): # Hui 127 | self.info.object.clear() 128 | #-------------------------------------------------------------------------- 129 | # Mesh Edit 130 | #-------------------------------------------------------------------------- 131 | 132 | def flip_edges(self): 133 | self.info.object.flip_edges() 134 | 135 | def collapse_edges(self): 136 | self.info.object.collapse_edges() 137 | 138 | def split_edges(self): 139 | self.info.object.split_edges() 140 | 141 | def catmull_clark(self): 142 | self.info.object.catmull_clark() 143 | 144 | def loop(self): 145 | self.info.object.loop() 146 | 147 | #-------------------------------------------------------------------------- 148 | # Set conditions 149 | #-------------------------------------------------------------------------- 150 | 151 | def fix_vertices(self): 152 | self.info.object.fix_vertices() 153 | 154 | def unfix_vertices(self): 155 | self.info.object.unfix_vertices() 156 | 157 | def constrain_vertices(self): 158 | self.info.object.constrain_vertices() 159 | 160 | 161 | # ----------------------------------------------------------------------------- 162 | # ----------------------------------------------------------------------------- 163 | # The Base Graphic User Interface 164 | # ----------------------------------------------------------------------------- 165 | # ----------------------------------------------------------------------------- 166 | 167 | class GeolabGUI(MultiSceneManager): 168 | 169 | _handler = GlHandler() 170 | 171 | _closed = Bool(True) 172 | 173 | _current_object = String('none') 174 | 175 | _components = [] 176 | 177 | scene_model_0 = Instance(MlabSceneModel, ()) 178 | 179 | scene_model_1 = Instance(MlabSceneModel, ()) 180 | 181 | scene_model_2 = Instance(MlabSceneModel, ()) 182 | 183 | scene_model_3 = Instance(MlabSceneModel, ()) 184 | 185 | components = List(GeolabComponent) 186 | 187 | remesh_tool = IncrementalRemesh() 188 | 189 | corner_tolerance_tool = CornerTolerance() 190 | 191 | loads_tool = Loads() 192 | 193 | save_mesh_tool = SaveMesh() 194 | 195 | _background_switch_counter = Int(1) 196 | 197 | path = path + '/geometrylab/gui/img/window' ##Hui add 198 | 199 | background_switch_button = Action(action = 'background_switch', 200 | image = ImageResource(path+'/background.png'), 201 | style = 'push', 202 | tooltip = 'Switch background color', 203 | show_label = False) 204 | 205 | save_mesh_button = Action(action = 'open_save_mesh', 206 | image = ImageResource(path+'/savemesh.png'), 207 | style = 'push', 208 | tooltip = 'Save mesh', 209 | show_label = False) 210 | 211 | plot_manager_button = Action(action = 'open_plot_manager', 212 | image=ImageResource(path+'/plotmanager.png'), 213 | style = 'push', 214 | tooltip = 'Object plot settings', 215 | enabled_when = ('_current_object == \ 216 | "Mesh_plot_manager" \ 217 | or _current_object == \ 218 | "Points_plot_manager"'), 219 | show_label=False) 220 | 221 | corner_tolerance_button = Action(action = 'open_corner_tolerance', 222 | image = ImageResource(path+'/corners.png'), 223 | style = 'push', 224 | tooltip = 'Set corner tolerance', 225 | enabled_when = ('_current_object == \ 226 | "Mesh_plot_manager"'), 227 | show_label=False) 228 | 229 | select_object_button = Action(action = 'select_object', 230 | image = ImageResource(path+'/selectobject.png'), 231 | style = 'toggle', 232 | tooltip = 'Select object', 233 | show_label = False) 234 | 235 | flip_edges_button = Action(action = 'flip_edges', 236 | image = ImageResource(path+'/flip.png'), 237 | style = 'toggle', 238 | tooltip = 'Flip mesh edges', 239 | enabled_when = ('_current_object == \ 240 | "Mesh_plot_manager"'), 241 | show_label=False) 242 | 243 | split_edges_button = Action(action='split_edges', 244 | image = ImageResource(path+'/split.png'), 245 | style = 'toggle', 246 | enabled_when = ('_current_object == \ 247 | "Mesh_plot_manager"'), 248 | tooltip = 'Split mesh edges', 249 | show_label = False) 250 | 251 | collapse_edges_button = Action(action='collapse_edges', 252 | image=ImageResource(path+'/collapse.png'), 253 | style='toggle', 254 | enabled_when =('_current_object == \ 255 | "Mesh_plot_manager"'), 256 | tooltip = 'Collapse mesh edges', 257 | show_label=False) 258 | 259 | catmull_clark_button = Action(action = 'catmull_clark', 260 | image = ImageResource(path+'/catmullclark.png'), 261 | style = 'push', 262 | enabled_when = ('_current_object == \ 263 | "Mesh_plot_manager"'), 264 | tooltip = 'Catmull-Clark subdivision', 265 | show_label = False) 266 | 267 | loop_button = Action(action = 'loop', 268 | image = ImageResource(path+'/loop.png'), 269 | style = 'push', 270 | enabled_when = ('_current_object == "Mesh_plot_manager"'), 271 | tooltip = 'Loop subdivision', 272 | show_label = False) 273 | 274 | remesh_button = Action(action = 'open_remesh', 275 | image = ImageResource(path+'/remesh.png'), 276 | style = 'push', 277 | enabled_when = ('_current_object == "Mesh_plot_manager"'), 278 | tooltip = 'Incremental remesh', 279 | show_label = False) 280 | 281 | move_vertices_button = Action(action = 'move_vertices', 282 | image = ImageResource(path+'/movevertex.png'), 283 | style = 'toggle', 284 | tooltip = 'Move vertices', 285 | enabled_when = ('_current_object == \ 286 | "Mesh_plot_manager" \ 287 | or _current_object == \ 288 | "Points_plot_manager"'), 289 | show_label=False) 290 | 291 | select_vertices_button = Action(action='select_vertices', 292 | image=ImageResource(path+'/selectvertices.png'), 293 | style='toggle', 294 | tooltip = 'Select vertices', 295 | enabled_when = ('_current_object == \ 296 | "Mesh_plot_manager" \ 297 | or _current_object == \ 298 | "Points_plot_manager"'), 299 | show_label=False) 300 | 301 | select_edges_button = Action(action='select_edges', 302 | image=ImageResource(path+'/selectedges.png'), 303 | style='toggle', 304 | enabled_when =('_current_object=="Mesh_plot_manager"'), 305 | tooltip = 'Select edges', 306 | show_label=False) 307 | 308 | select_faces_button = Action(action='select_faces', 309 | image=ImageResource(path+'/selectfaces.png'), 310 | style='toggle', 311 | enabled_when =('_current_object == \ 312 | "Mesh_plot_manager"'), 313 | tooltip = 'Select faces', 314 | show_label=False) 315 | 316 | select_boundary_vertices_button = Action(action='select_boundary_vertices', 317 | image=ImageResource(path+'/boundary.png'), 318 | style='toggle', 319 | enabled_when =('_current_object == \ 320 | "Mesh_plot_manager"'), 321 | tooltip = 'Select boundary vertices', 322 | show_label=False) 323 | 324 | fix_vertices_button = Action(action='fix_vertices', 325 | image=ImageResource(path+'/fixvertices.png'), 326 | style='push', 327 | tooltip = 'Fix selected vertices', 328 | show_label=False) 329 | 330 | unfix_vertices_button = Action(action='unfix_vertices', 331 | image=ImageResource(path+'/unfixvertices.png'), 332 | style='push', 333 | tooltip = 'Unfix selected vertices', 334 | show_label=False) 335 | 336 | constrain_vertices_button = Action(action='constrain_vertices', 337 | image=ImageResource(path+'/constrain.png'), 338 | style='push', 339 | tooltip = 'Constrain selected vertices', 340 | show_label=False) 341 | 342 | unconstrain_vertices_button = Action(action='constrain_vertices', 343 | image=ImageResource(path+'/unconstrain.png'), 344 | style='push', 345 | tooltip = 'Release selected vertices', 346 | show_label=False) 347 | 348 | loads_button = Action(action='open_loads', 349 | image=ImageResource(path+'/applyforce.png'), 350 | style='push', 351 | tooltip = 'loads_tool', 352 | show_label=False) 353 | 354 | reset_mesh_button = Action(action='reset_mesh', 355 | image=ImageResource(path+'/resetmesh.png'), 356 | style='push', 357 | tooltip = 'Reset mesh', 358 | show_label=False) 359 | 360 | set_reference_button = Action(action='set_reference', 361 | image=ImageResource(path+'/setreference.png'), 362 | style='push', 363 | tooltip = 'Set as reference mesh', 364 | show_label=False) 365 | 366 | start_mesh_button = Action(action='start_mesh', # Hui 367 | image=ImageResource(path+'/startmesh.png'), 368 | style='push', 369 | tooltip = 'Start mesh', 370 | show_label=False) 371 | 372 | hide_mesh_button = Action(action='hide_mesh', # Hui 373 | image=ImageResource(path+'/hide.png'), 374 | style='push', 375 | tooltip = 'Hide mesh', 376 | show_label=False) 377 | 378 | clear_button = Action(action='clear', # Hui 379 | image=ImageResource(path+'/clear.png'), 380 | style='push', 381 | tooltip = 'Clear ploting', 382 | show_label=False) 383 | 384 | __toolbar = [Separator(), 385 | plot_manager_button, 386 | 387 | Separator(), 388 | select_object_button, 389 | select_vertices_button, 390 | select_edges_button, 391 | select_faces_button, 392 | move_vertices_button, 393 | select_boundary_vertices_button, 394 | corner_tolerance_button, 395 | 396 | Separator(), 397 | fix_vertices_button, 398 | unfix_vertices_button, 399 | constrain_vertices_button, 400 | unconstrain_vertices_button, 401 | loads_button, 402 | 403 | Separator(), 404 | collapse_edges_button, 405 | flip_edges_button, 406 | split_edges_button, 407 | catmull_clark_button, 408 | loop_button, 409 | remesh_button, 410 | 411 | Separator(), 412 | save_mesh_button, 413 | reset_mesh_button, 414 | set_reference_button, 415 | 416 | Separator(), 417 | clear_button, # Hui 418 | hide_mesh_button, # Hui 419 | start_mesh_button, # Hui 420 | 421 | Separator(), 422 | background_switch_button, 423 | ] 424 | 425 | toolbar = { 'handler': _handler, 426 | 'resizable' : True, 427 | 'title' : 'ArchGeo', #Hui change 428 | 'icon' : ImageResource(path+'/logo3.png'), 429 | 'toolbar' : ToolBar(*__toolbar, 430 | show_labels=False, 431 | image_size=(16,16)), 432 | } 433 | 434 | 435 | 436 | tabs = [Item('components', 437 | editor=ListEditor(use_notebook=True, page_name='.name'), 438 | style ='custom', 439 | width = 1, 440 | resizable = False, 441 | show_label=False) 442 | ] 443 | 444 | __view3D = [] 445 | 446 | __windows = [] 447 | 448 | height = Int(600) 449 | 450 | width = Int(800) 451 | 452 | side_width = Int(400) 453 | 454 | #-------------------------------------------------------------------------- 455 | # 456 | #-------------------------------------------------------------------------- 457 | 458 | def __init__(self): 459 | MultiSceneManager.__init__(self) 460 | 461 | self.handler = Handler() 462 | 463 | self.__scenes = ['scene_0'] 464 | 465 | self.__geometries = [] 466 | 467 | self.__object_open_callbacks = [] 468 | 469 | self.__initialize_plot = True 470 | 471 | self._scene_model = self.scene_model_0 472 | 473 | self.handler.add_state_callback(self.set_state) 474 | 475 | @property 476 | def geometries(self): 477 | return self.__geometries 478 | 479 | #-------------------------------------------------------------------------- 480 | # Building up 481 | #-------------------------------------------------------------------------- 482 | 483 | def start(self): 484 | self.make_scenes() 485 | if len(self._components) > 0 and len(self.__windows) > 0: 486 | self.components = self._components 487 | view = View(HSplit(self.tabs, 488 | self.__view3D, 489 | self.__windows), 490 | **self.toolbar) 491 | elif len(self._components) > 0: 492 | self.components = self._components 493 | view = View(HSplit(self.tabs, 494 | self.__view3D), 495 | **self.toolbar) 496 | else: 497 | view = View(self.__view3D, **self.toolbar) 498 | self._closed = False 499 | for component in self._components: 500 | component.initialize_plot() 501 | if self.__initialize_plot: 502 | for geometry in self.__geometries: 503 | self.add(geometry) 504 | for key in self._objects: 505 | self._objects[key].update_plot() 506 | for args in self.__object_open_callbacks: 507 | self.object_open(*args) 508 | self.object_changed() 509 | self.update_plot() 510 | self.configure_traits(view=view) 511 | 512 | def add_component(self, component): 513 | component.geolab = self 514 | self._components.append(component) 515 | component.geolab_settings() 516 | self.__initialize_plot = False 517 | 518 | def add_scene(self, name): 519 | if name not in self.__scenes: 520 | self.__scenes.append(name) 521 | 522 | def make_scenes(self): 523 | index = 0 524 | for key in self.__scenes: 525 | if index == 0: 526 | scene = self.scene_model_0 527 | self.__view3D = [Item('scene_model_0', 528 | editor = SceneEditor(scene_class=GeolabScene), 529 | show_label = False, 530 | resizable = True, 531 | height = self.height, 532 | width = self.width)] 533 | else: 534 | if index == 1: 535 | scene = self.scene_model_1 536 | elif index == 2: 537 | scene = self.scene_model_2 538 | elif index == 3: 539 | scene = self.scene_model_3 540 | else: 541 | return 542 | name = ('scene_model_{}').format(index) 543 | self.__windows.append(Item(name, 544 | editor = SceneEditor(scene_class=GeolabScene), 545 | show_label = False, 546 | resizable = True, 547 | height = self.height, 548 | width = self.side_width)) 549 | self.add_scene_model(scene, key) 550 | index += 1 551 | 552 | #-------------------------------------------------------------------------- 553 | # Standard Methods 554 | #-------------------------------------------------------------------------- 555 | 556 | def set_state(self, name): 557 | self.select_off() 558 | if name != 'select_object': 559 | self.select_object_button.checked = False 560 | if name != 'flip_edges': 561 | self.flip_edges_button.checked = False 562 | if name != 'split_edges': 563 | self.split_edges_button.checked = False 564 | if name != 'collapse_edges': 565 | self.collapse_edges_button.checked = False 566 | if name != 'move_vertices': 567 | self.move_vertices_button.checked = False 568 | if name != 'select_vertices': 569 | self.select_vertices_button.checked = False 570 | if name != 'select_faces': 571 | self.select_faces_button.checked = False 572 | if name != 'select_edges': 573 | self.select_edges_button.checked = False 574 | if name != 'select_boundary_vertices': 575 | self.select_boundary_vertices_button.checked = False 576 | 577 | def object_changed(self): 578 | SceneManager.object_changed(self) 579 | self.close_tools() 580 | self._current_object = self.current_object_type 581 | 582 | #-------------------------------------------------------------------------- 583 | # Background 584 | #-------------------------------------------------------------------------- 585 | 586 | def background_switch(self): 587 | if self._background_switch_counter == 1: 588 | self.set_background((1, 1, 1)) 589 | self._background_switch_counter = 0 590 | else: 591 | self.set_background((0.5, 0.5, 0.5)) 592 | self._background_switch_counter = 1 593 | 594 | #-------------------------------------------------------------------------- 595 | # Open 596 | #-------------------------------------------------------------------------- 597 | 598 | def open_obj_file(self, file_name): 599 | mesh = GridshellNew() 600 | mesh.read_obj_file(file_name) 601 | self.__geometries.append(mesh) 602 | if not self._closed: 603 | self.object_open(file_name, mesh) 604 | else: 605 | self.__object_open_callbacks.append((file_name, mesh)) 606 | 607 | def open_geometry(self, geometry): 608 | self.__object_open_callbacks.append(('M', geometry)) 609 | 610 | def reset_mesh(self): 611 | self.handler.set_state(None) 612 | self.current_object.geometry.reset() 613 | self.current_object.update_plot() 614 | self.object_changed() 615 | 616 | def set_reference(self): 617 | self.current_object.geometry.set_reference() 618 | 619 | def hide_mesh(self): # Hui 620 | self.hide(name='startmesh') 621 | #self.current_object.update_plot() 622 | 623 | def clear(self): # Hui ## can't clear current obj 624 | self.remove(names='startmesh') 625 | #self.clear_scene() 626 | #self.current_object.update_plot() 627 | 628 | 629 | def start_mesh(self,move=False): # Hui 630 | v0 = self.current_object.geometry.vertices_0 631 | f0 = self.current_object.geometry.faces_list() 632 | import numpy as np # Hui 633 | from geometrylab.geometry.meshpy import Mesh 634 | obj = Mesh() 635 | obj.make_mesh(v0, f0) # start mesh 636 | if move: 637 | #obj.move([-1.2*(np.max(v0[:,0])-np.min(v0[:,0])),0,0]) 638 | # mesh = GridshellNew() 639 | # mesh.import_mesh(obj) 640 | obj.move([0,0,-0.1*np.mean(obj.edge_lengths())]) 641 | name = 'startmesh'#obj.name + '_start' #== 'mesh_start' 642 | # self.add_object(mesh, name = name) 643 | self.add_object(obj, name = name) 644 | r = self.current_object.r 645 | #MeshPlotManager.plot_faces(self.get_object(name), color = 'w') 646 | MeshPlotManager.plot_edges(self.get_object(name),tube_radius=0.5*r,color = 'black') 647 | MeshPlotManager.update_plot(self.current_object) 648 | #-------------------------------------------------------------------------- 649 | # Tools 650 | #-------------------------------------------------------------------------- 651 | 652 | def open_plot_manager(self): 653 | self.selection_off() 654 | self.current_object.start() 655 | 656 | def open_corner_tolerance(self): 657 | self.handler.set_state(None) 658 | self.corner_tolerance_tool.scenemanager = self 659 | self.corner_tolerance_tool.start() 660 | 661 | def open_save_mesh(self): 662 | self.save_mesh_tool.scenemanager = self 663 | self.save_mesh_tool.start() 664 | 665 | def open_remesh(self): 666 | self.handler.set_state(None) 667 | self.remesh_tool.scenemanager = self 668 | self.remesh_tool.start() 669 | 670 | def open_loads(self): 671 | self.loads_tool.scenemanager = self 672 | self.loads_tool.start() 673 | 674 | @on_trait_change('_closed') 675 | def close_tools(self): 676 | try: 677 | self.current_object.close() 678 | except: 679 | pass 680 | self.corner_tolerance_tool.close() 681 | self.remesh_tool.close() 682 | self.loads_tool.close() 683 | self.save_mesh_tool.close() 684 | 685 | #-------------------------------------------------------------------------- 686 | # Selection 687 | #-------------------------------------------------------------------------- 688 | 689 | def selection_off(self): 690 | MultiSceneManager.select_off(self) 691 | self.select_boundary_vertices_button.checked = False 692 | self.select_edges_button.checked = False 693 | self.select_object_button.checked = False 694 | self.select_vertices_button.checked = False 695 | self.move_vertices_button.checked = False 696 | 697 | def select_object(self): 698 | if self.select_object_button.checked: 699 | self.handler.set_state('select_object') 700 | super(GeolabGUI, self).select_object() 701 | else: 702 | self.select_off() 703 | 704 | def select_vertices(self): 705 | if self.select_vertices_button.checked: 706 | self.handler.set_state('select_vertices') 707 | self.current_object.select_vertices() 708 | else: 709 | self.current_object.select_vertices_off() 710 | 711 | def select_edges(self): 712 | if self.select_edges_button.checked: 713 | self.handler.set_state('select_edges') 714 | self.current_object.select_edges() 715 | else: 716 | self.current_object.select_edges_off() 717 | 718 | def select_faces(self): 719 | if self.select_faces_button.checked: 720 | self.handler.set_state('select_faces') 721 | self.current_object.select_faces() 722 | else: 723 | self.current_object.select_faces_off() 724 | 725 | def select_boundary_vertices(self): 726 | if self.select_boundary_vertices_button.checked: 727 | self.handler.set_state('select_boundary_vertices') 728 | self.current_object.select_boundary_vertices() 729 | else: 730 | self.current_object.select_boundary_vertices_off() 731 | 732 | def move_vertices(self): 733 | if self.move_vertices_button.checked: 734 | self.handler.set_state('move_vertices') 735 | def callback(): 736 | self.current_object.update_plot() 737 | self.current_object.move_vertices(callback) 738 | else: 739 | self.current_object.move_vertices_off() 740 | 741 | #-------------------------------------------------------------------------- 742 | # Mesh Edit 743 | #-------------------------------------------------------------------------- 744 | 745 | def flip(self, edge_index): 746 | self.current_object.mesh.flip_edge(edge_index) 747 | self.object_changed() 748 | self.current_object.update_plot() 749 | 750 | def collapse(self, edge_index): 751 | self.current_object.mesh.collapse_edge(edge_index) 752 | self.object_changed() 753 | self.current_object.update_plot() 754 | 755 | def split(self, edge_index): 756 | self.current_object.mesh.split_edge(edge_index) 757 | self.object_changed() 758 | self.current_object.update_plot() 759 | 760 | def flip_edges(self): 761 | if self.flip_edges_button.checked: 762 | self.handler.set_state('flip_edges') 763 | self.current_object.on_edge_selection(self.flip) 764 | 765 | else: 766 | self.current_object.select_edges_off() 767 | 768 | def collapse_edges(self): 769 | if self.collapse_edges_button.checked: 770 | self.handler.set_state('collapse_edges') 771 | self.current_object.on_edge_selection(self.collapse) 772 | self.object_changed() 773 | else: 774 | self.current_object.select_edges_off() 775 | 776 | def split_edges(self): 777 | if self.split_edges_button.checked: 778 | self.handler.set_state('split_edges') 779 | self.current_object.on_edge_selection(self.split) 780 | else: 781 | self.current_object.select_edges_off() 782 | 783 | def catmull_clark(self): 784 | self.handler.set_state(None) 785 | self.fix_edges_bug() 786 | self.current_object.mesh.catmull_clark() 787 | self.object_changed() 788 | self.current_object.update_plot() 789 | 790 | def loop(self): 791 | self.handler.set_state(None) 792 | self.fix_edges_bug() 793 | self.current_object.mesh.loop() 794 | self.object_changed() 795 | self.current_object.update_plot() 796 | 797 | def fix_edges_bug(self): 798 | obj = self.current_object 799 | if True:#obj.mesh.E > 2000: 800 | if obj.edge_plot != 'none': 801 | if obj.edge_plot != 'wireframe': 802 | obj.remove_edges() 803 | 804 | #-------------------------------------------------------------------------- 805 | # Set conditions 806 | #-------------------------------------------------------------------------- 807 | 808 | def fix_vertices(self): 809 | selected = self.current_object.selected_vertices 810 | self.current_object.mesh.fix(selected) 811 | self.current_object.update_plot() 812 | 813 | def unfix_vertices(self): 814 | selected = self.current_object.selected_vertices 815 | self.current_object.mesh.unfix(selected) 816 | self.current_object.update_plot() 817 | 818 | def constrain_vertices(self): 819 | selected = self.current_object.selected_vertices 820 | self.current_object.mesh.constrain(selected) 821 | self.current_object.update_plot() 822 | 823 | 824 | # ----------------------------------------------------------------------------- 825 | 826 | def view(objects, position=None): 827 | viewer = GeolabGUI() 828 | #viewer.position = position 829 | viewer.add(objects) 830 | viewer.start() 831 | -------------------------------------------------------------------------------- /archgeolab/archgeometry/orient.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Jan 8 12:26:01 2020 4 | 5 | """ 6 | __author__ = 'Davide' 7 | #------------------------------------------------------------------------------ 8 | import numpy as np 9 | #------------------------------------------------------------------------------ 10 | 11 | def orient_rings(mesh): 12 | h_boundary = mesh.boundary_halfedges() 13 | v_visited = np.full(mesh.V, False) 14 | _, _, l = mesh.vertex_ring_vertices_iterators(return_lengths=True, sort=True) 15 | v_visited[np.where(l != 4)] = True 16 | R = [] 17 | for h in range(2*mesh.E): 18 | h_ring = mesh.halfedge_ring(h) 19 | if len(h_ring) == 4: 20 | v = mesh.origin(h) 21 | v_ring = mesh.origin(mesh.twin(h_ring)) 22 | R.append([v, v_ring[0], v_ring[1], v_ring[2], v_ring[3]]) 23 | v_visited[v] = True 24 | H1 = [h_ring[2]] 25 | H2 = [h_ring[1]] 26 | H3 = [h_ring[0]] 27 | H4 = [h_ring[3]] 28 | break 29 | while not np.all(v_visited): 30 | #for i in range(80): 31 | H1_new = [] 32 | H2_new = [] 33 | H3_new = [] 34 | H4_new = [] 35 | for h in H1: 36 | ht = mesh.twin(h) 37 | h_ring = mesh.halfedge_ring(ht) 38 | if len(h_ring) == 4: 39 | v = mesh.origin(ht) 40 | v_ring = mesh.origin(mesh.twin(h_ring)) 41 | if not v_visited[v]: 42 | pass 43 | R.append([v, v_ring[0], v_ring[1], v_ring[2], v_ring[3]]) 44 | v_visited[v] = True 45 | H1_new.append(h_ring[2]) 46 | H2_new.append(h_ring[1]) 47 | H4_new.append(h_ring[3]) 48 | else: 49 | v_visited[mesh.origin(ht)] = True 50 | for h in H2: 51 | ht = mesh.twin(h) 52 | h_ring = mesh.halfedge_ring(ht) 53 | if len(h_ring) == 4: 54 | v = mesh.origin(ht) 55 | v_ring = mesh.origin(mesh.twin(h_ring)) 56 | if not v_visited[v]: 57 | pass 58 | R.append([v, v_ring[1], v_ring[2], v_ring[3], v_ring[0]]) 59 | v_visited[v] = True 60 | H2_new.append(h_ring[2]) 61 | H1_new.append(h_ring[3]) 62 | H3_new.append(h_ring[1]) 63 | else: 64 | v_visited[mesh.origin(ht)] = True 65 | for h in H3: 66 | ht = mesh.twin(h) 67 | h_ring = mesh.halfedge_ring(ht) 68 | if len(h_ring) == 4: 69 | v = mesh.origin(ht) 70 | v_ring = mesh.origin(mesh.twin(h_ring)) 71 | if not v_visited[v]: 72 | pass 73 | R.append([v, v_ring[2], v_ring[3], v_ring[0], v_ring[1]]) 74 | v_visited[v] = True 75 | H3_new.append(h_ring[2]) 76 | H4_new.append(h_ring[1]) 77 | H2_new.append(h_ring[3]) 78 | else: 79 | v_visited[mesh.origin(ht)] = True 80 | for h in H4: 81 | ht = mesh.twin(h) 82 | h_ring = mesh.halfedge_ring(ht) 83 | if len(h_ring) == 4: 84 | v = mesh.origin(ht) 85 | v_ring = mesh.origin(mesh.twin(h_ring)) 86 | if not v_visited[v]: 87 | pass 88 | R.append([v, v_ring[3], v_ring[0], v_ring[1], v_ring[2]]) 89 | v_visited[v] = True 90 | H3_new.append(h_ring[3]) 91 | H4_new.append(h_ring[2]) 92 | H1_new.append(h_ring[1]) 93 | else: 94 | v_visited[mesh.origin(ht)] = True 95 | H1 = np.unique(np.array(H1_new)) 96 | H1 = H1[np.invert(np.in1d(H1, h_boundary))] 97 | H1 = H1[np.invert(np.in1d(H1, mesh.twin(h_boundary)))] 98 | H2 = np.unique(np.array(H2_new)) 99 | H2 = H2[np.invert(np.in1d(H2, h_boundary))] 100 | H2 = H2[np.invert(np.in1d(H2, mesh.twin(h_boundary)))] 101 | H3 = np.unique(np.array(H3_new)) 102 | H3 = H3[np.invert(np.in1d(H3, h_boundary))] 103 | H3 = H3[np.invert(np.in1d(H3, mesh.twin(h_boundary)))] 104 | H4 = np.unique(np.array(H4_new)) 105 | H4 = H4[np.invert(np.in1d(H4, h_boundary))] 106 | H4 = H4[np.invert(np.in1d(H4, mesh.twin(h_boundary)))] 107 | return(R) 108 | 109 | # 110 | ###------------------------------------------------------------------------------ 111 | # 112 | #import sys 113 | # 114 | #import os 115 | # 116 | #sys.path.append('/Users\Davide\OneDrive\MeshPy\geometrylab04') 117 | # 118 | #import geometrylab as geo 119 | # 120 | #path = os.path.dirname(os.path.abspath(__file__)) 121 | # 122 | #file_name = path + '/W_4.obj' 123 | # 124 | #M = geo.geometry.mesh_plane() 125 | # 126 | #M = geo.geometry.Mesh(file_name) 127 | # 128 | # 129 | #R = np.array(orient_rings(M)) 130 | # 131 | #P = M.vertices[R[:,0]] 132 | # 133 | #V1 = M.vertices[R[:,3]] - M.vertices[R[:,1]] 134 | # 135 | #V2 = M.vertices[R[:,2]] - M.vertices[R[:,4]] 136 | # 137 | #plot = [geo.vtkplot.Edges(M, color='r')] 138 | # 139 | #plot.append(geo.vtkplot.Vectors(V1, anchor=P, color='r', position='center', scale_factor=0.2)) 140 | # 141 | #plot.append(geo.vtkplot.Vectors(V2, anchor=P, color='b', position='center', scale_factor=0.2)) 142 | # 143 | #geo.vtkplot.view(plot) 144 | # 145 | # 146 | # 147 | -------------------------------------------------------------------------------- /archgeolab/archgeometry/orthogonalVectors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Mar 22 19:01:26 2019 4 | 5 | @author: hwang 6 | """ 7 | __author__ = 'Hui Wang' 8 | #------------------------------------------------------------------------------ 9 | import numpy as np 10 | #------------------------------------------------------------------------------ 11 | 12 | 13 | class Basis(object): 14 | 15 | def __init__(self, vectors, **kwargs): 16 | 17 | self.N = vectors 18 | 19 | self.V0 = kwargs.get('anchors', None) # circles center 20 | 21 | self.ri = kwargs.get('r', 1) 22 | 23 | 24 | def orthogonalPlane3Vectors(self): 25 | "get three unit vectors E1,E2,E3 on planes that are orthogonal to vectors N" 26 | if self.V0 is not None: 27 | P1, P2, P3 = [], [], [] 28 | V0 = self.V0 29 | else: 30 | E1, E2 ,E3 = [], [], [] 31 | N = self.N 32 | num = len(N) 33 | 34 | arrR = self.ri * np.ones(num) 35 | 36 | for i in range(num): 37 | #x,y,z = round(N[i,0],6),round(N[i,1],6),round(N[i,2],6) 38 | x,y,z = N[i,0],N[i,1],N[i,2] 39 | if x==0 or y==0 or z==0: 40 | e1, e2, e3 = [0,0,0],[0,0,0],[0,0,0] 41 | j = 0 if x==0 else 1 if y==0 else 2 42 | e1[j],e2[j],e3[j]=1,2,3 43 | e1[j-1],e1[j-2]=-N[i,j-2],N[i,j-1] 44 | e2[j-1],e2[j-2]=-N[i,j-2],N[i,j-1] 45 | e3[j-1],e3[j-2]=-N[i,j-2],N[i,j-1] 46 | if (y==0 and z==0) or (x==0 and z==0) or (x==0 and y==0): 47 | e1, e2, e3 = [0,0,0],[0,0,0],[0,0,0] 48 | j = 0 if (y==0 and z==0) else 1 if (x==0 and z==0) else 2 49 | e1[j-1]=1 50 | e2[j-2]=1 51 | e3[j-1],e3[j-2]=-1,-1 52 | else: 53 | e1 = [0,-z,y] 54 | e2 = [-z,0,x] 55 | e3 = [-y,x,0] 56 | e1,e2,e3 = np.array(e1),np.array(e2),np.array(e3) 57 | eps = np.finfo(float).eps 58 | e1=e1/(np.linalg.norm(e1)+eps) 59 | e2=e2/(np.linalg.norm(e2)+eps) 60 | e3=e3/(np.linalg.norm(e3)+eps) 61 | if self.V0 is not None: 62 | P1.append(V0[i]+e1*arrR[i]) 63 | P2.append(V0[i]+e2*arrR[i]) 64 | P3.append(V0[i]+e3*arrR[i]) 65 | else: 66 | E1.append(e1) 67 | E2.append(e2) 68 | E3.append(e3) 69 | 70 | if self.V0 is not None: 71 | return P1,P2,P3 72 | else: 73 | return np.array(E1),np.array(E2),np.array(E3) 74 | 75 | def orthogonalBasis(self): 76 | "get another two unit vectors together with it to form a Frame" 77 | E1,_,_ = self.orthogonalPlane3Vectors() 78 | eps = np.finfo(float).eps 79 | E0 = self.N / (np.linalg.norm(self.N, axis=1, keepdims=True)+eps) 80 | E2 = np.cross(E0, E1) 81 | E2 = E2 / (np.linalg.norm(E2, axis=1, keepdims=True)+eps) 82 | return E0, E1, E2 83 | 84 | 85 | -------------------------------------------------------------------------------- /archgeolab/constraints/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ## Note: add this file (path) 4 | 5 | 6 | from archgeolab.constraints import constraints_basic 7 | 8 | from archgeolab.constraints import constraints_fairness 9 | 10 | from archgeolab.constraints import constraints_net 11 | 12 | from archgeolab.constraints import constraints_glide -------------------------------------------------------------------------------- /archgeolab/constraints/constraints_basic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Aug 23 14:35:11 2021 4 | 5 | @author: wangh0m 6 | """ 7 | __author__ = 'Hui' 8 | #------------------------------------------------------------------------------ 9 | import numpy as np 10 | 11 | from scipy import sparse 12 | #------------------------------------------------------------------------------ 13 | """ 14 | from constraints_basic import 15 | column3D,con_edge,con_unit,con_constl,con_equal_length,\ 16 | con_planarity,con_planarity_constraints,con_unit_normal,con_orient 17 | """ 18 | # ------------------------------------------------------------------------- 19 | # general / basic 20 | # ------------------------------------------------------------------------- 21 | 22 | def column3D(arr, num1, num2): 23 | """ 24 | Parameters 25 | ---------- 26 | array : array([1,4,7]). 27 | num1 : starting num.=100 28 | num2 : interval num.= 10 29 | 30 | Returns 31 | ------- 32 | a : array(100+[1,4,7, 10,14,17, 20,24,27]). 33 | """ 34 | a = num1 + np.r_[arr, num2+arr, 2*num2+arr] 35 | return a 36 | 37 | def con_edge(X,c_v1,c_v3,c_ld1,c_ud1): 38 | "(v1-v3) = ld1*ud1" 39 | num = len(c_ld1) 40 | ld1 = X[c_ld1] 41 | ud1 = X[c_ud1] 42 | a3 = np.ones(3*num) 43 | row = np.tile(np.arange(3*num),4) 44 | col = np.r_[c_v1,c_v3,np.tile(c_ld1,3),c_ud1] 45 | data = np.r_[a3,-a3,-ud1,-np.tile(ld1,3)] 46 | r = -np.tile(ld1,3)*ud1 47 | H = sparse.coo_matrix((data,(row,col)), shape=(3*num, len(X))) 48 | return H,r 49 | 50 | def con_unit_normal(X,c_e1,c_e2,c_e3,c_e4,c_n): 51 | "n^2=1; n*(e1-e3)=0; n*(e2-e4);" 52 | "Hui: better than (l*n=(e1-e3)x(e2-e4), but no orientation" 53 | H1,r1 = con_unit(X,c_n) 54 | H2,r2 = con_planarity(X,c_e1,c_e3,c_n) 55 | H3,r3 = con_planarity(X,c_e2,c_e4,c_n) 56 | H = sparse.vstack((H1,H2,H3)) 57 | r = np.r_[r1,r2,r3] 58 | return H,r 59 | 60 | def con_unit(X,c_ud1,w=100): 61 | "ud1**2=1" 62 | num = int(len(c_ud1)/3) 63 | arr = np.arange(num) 64 | row = np.tile(arr,3) 65 | col = c_ud1 66 | data = 2*X[col] 67 | r = np.linalg.norm(X[col].reshape(-1,3,order='F'),axis=1)**2 + np.ones(num) 68 | H = sparse.coo_matrix((data,(row,col)), shape=(num, len(X))) 69 | return H*w,r*w 70 | 71 | def con_constl(c_ld1,init_l1,N): 72 | "ld1 == const." 73 | num = len(c_ld1) 74 | row = np.arange(num,dtype=int) 75 | col = c_ld1 76 | data = np.ones(num,dtype=int) 77 | r = init_l1 78 | H = sparse.coo_matrix((data,(row,col)), shape=(num, N)) 79 | return H,r 80 | 81 | def con_planarity(X,c_v1,c_v2,c_n): 82 | "n*(v1-v2)=0" 83 | num = int(len(c_n)/3) 84 | col = np.r_[c_n,c_v1,c_v2] 85 | row = np.tile(np.arange(num),9) 86 | data = np.r_[X[c_v1]-X[c_v2],X[c_n],-X[c_n]] 87 | r = np.einsum('ij,ij->i',X[c_n].reshape(-1,3, order='F'),(X[c_v1]-X[c_v2]).reshape(-1,3, order='F')) 88 | H = sparse.coo_matrix((data,(row,col)), shape=(num, len(X))) 89 | return H,r 90 | 91 | def con_equal_length(X,c1,c2,c3,c4): 92 | "(v1-v3)^2=(v2-v4)^2" 93 | num = int(len(c1)/3) 94 | row = np.tile(np.arange(num),12) 95 | col = np.r_[c1,c2,c3,c4] 96 | data = 2*np.r_[X[c1]-X[c3],X[c4]-X[c2],X[c3]-X[c1],X[c2]-X[c4]] 97 | r = np.linalg.norm((X[c1]-X[c3]).reshape(-1,3, order='F'),axis=1)**2 98 | r = r-np.linalg.norm((X[c2]-X[c4]).reshape(-1,3, order='F'),axis=1)**2 99 | H = sparse.coo_matrix((data,(row,col)), shape=(num,len(X))) 100 | return H,r 101 | 102 | def con_orient(X,Nv,c_vN,c_a,neg=False): 103 | "vN*Nv = a^2; if neg: vN*Nv = -a^2; variables: vN, a; Nv is given" 104 | if neg: 105 | sign = -1 106 | else: 107 | sign = 1 108 | num = int(len(c_a)) 109 | row = np.tile(np.arange(num),4) 110 | col = np.r_[c_vN,c_a] 111 | data = np.r_[Nv.flatten('F'),-sign*2*X[c_a]] 112 | r = -sign*X[c_a]**2 113 | H = sparse.coo_matrix((data,(row,col)), shape=(num,len(X))) 114 | return H,r 115 | 116 | 117 | # ------------------------------------------------------------------------- 118 | # Geometric Constraints (from Davide) 119 | # ------------------------------------------------------------------------- 120 | 121 | def con_normal_constraints(**kwargs): 122 | "represent unit normal: n^2=1" 123 | #w = kwargs.get('normal') * kwargs.get('geometric') 124 | mesh = kwargs.get('mesh') 125 | X = kwargs.get('X') 126 | V = mesh.V 127 | F = mesh.F 128 | f = 3*V + np.arange(F) 129 | i = np.arange(F) 130 | i = np.hstack((i, i, i)) #row ==np.tile(i,3) == np.r_[i,i,i] 131 | j = np.hstack((f, F+f, 2*F+f)) #col ==np.r_[f,F+f,2*F+f] 132 | data = 2 * np.hstack((X[f], X[F+f], X[2*F+f])) #* w 133 | H = sparse.coo_matrix((data,(i,j)), shape=(F,len(X))) 134 | r = ((X[f]**2 + X[F+f]**2 + X[2*F+f]**2) + 1) #* w 135 | return H,r 136 | 137 | 138 | def con_planarity_constraints(is_unit_edge=False,**kwargs): 139 | "n*(vi-vj) = 0; Note: making sure normals is always next to V in X[V,N]" 140 | w = kwargs.get('planarity') 141 | mesh = kwargs.get('mesh') 142 | X = kwargs.get('X') 143 | V = mesh.V 144 | F = mesh.F 145 | f, v1, v2 = mesh.face_edge_vertices_iterators(order=True) 146 | if is_unit_edge: 147 | "f*(v1-v2)/length = 0, to avoid shrinkage of edges" 148 | num = len(v1) 149 | col_v1 = column3D(v1,0,V) 150 | col_v2 = column3D(v2,0,V) 151 | col_f = column3D(f,3*V,F) 152 | Ver = mesh.vertices 153 | edge_length = np.linalg.norm(Ver[v1]-Ver[v2],axis=1) 154 | row = np.tile(np.arange(num), 9) 155 | col = np.r_[col_f,col_v1,col_v2] 156 | l = np.tile(edge_length,3) 157 | data = np.r_[(X[col_v1]-X[col_v2])/l, X[col_f]/l, -X[col_f]/l] 158 | H = sparse.coo_matrix((data,(row, col)), shape=(num, len(X))) 159 | r = np.einsum('ij,ij->i',X[col_f].reshape(-1,3,order='F'),(X[col_v1]-X[col_v2]).reshape(-1,3,order='F')) 160 | r /= edge_length 161 | Hn,rn = con_unit(X,col_f,10*w) 162 | H = sparse.vstack((H*w,Hn)) 163 | r = np.r_[r*w,rn] 164 | else: 165 | K = f.shape[0] 166 | f = 3*V + f 167 | r = ((X[v2] - X[v1]) * X[f] + (X[V+v2] - X[V+v1]) * X[F+f] 168 | + (X[2*V+v2] - X[2*V+v1]) * X[2*F+f] ) * w 169 | v1 = np.hstack((v1, V+v1, 2*V+v1)) 170 | v2 = np.hstack((v2, V+v2, 2*V+v2)) 171 | f = np.hstack((f, F+f, 2*F+f)) 172 | i = np.arange(K) 173 | i = np.hstack((i, i, i, i, i, i, i, i, i)) 174 | j = np.hstack((f, v2, v1)) 175 | data = 2 * np.hstack((X[v2] - X[v1], X[f], -X[f])) * w 176 | H = sparse.coo_matrix((data,(i,j)), shape=(K, len(X))) 177 | Hn,rn = con_normal_constraints(**kwargs) 178 | H = sparse.vstack((H*w,Hn*w*10)) 179 | r = np.r_[r*w,rn*w*10] 180 | return H,r 181 | -------------------------------------------------------------------------------- /archgeolab/constraints/constraints_equilibrium.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jan 24 09:40:14 2023 4 | 5 | @author: WANGH0M 6 | """ 7 | #------------------------------------------------------------------------------ 8 | import numpy as np 9 | 10 | from scipy import sparse 11 | 12 | from geometrylab import utilities 13 | #------------------------------------------------------------------------------ 14 | 15 | """ 16 | below constraints are copied from geometrylab/optimization/tuidedprojection.py 17 | normal_constraints 18 | planarity_constraints 19 | 20 | edge_length_constraints 21 | equilibrium_constraints, 22 | compression_constraints, 23 | area_constraints, 24 | vector_area_constraints 25 | 26 | boundary_densities_constraints 27 | fixed_boundary_normals_constraints 28 | """ 29 | 30 | # ------------------------------------------------------------------------- 31 | # Principal Meshes 32 | # ------------------------------------------------------------------------- 33 | 34 | def normal_constraints(**kwargs): ## replaced by Hui's constraint 35 | "note: based on self.planarity=True: face_normal^2==1 " 36 | w = kwargs.get('normal') * kwargs.get('geometric') 37 | mesh = kwargs.get('mesh') 38 | V = mesh.V 39 | F = mesh.F 40 | N = kwargs.get('N') 41 | f = 3*V + np.arange(F) 42 | i = np.arange(F) 43 | i = np.hstack((i, i, i)) 44 | j = np.hstack((f, F+f, 2*F+f)) 45 | X = kwargs.get('X') 46 | data = 2 * np.hstack((X[f], X[F+f], X[2*F+f])) * w 47 | H = sparse.coo_matrix((data,(i,j)), shape=(F, N)) 48 | r = ((X[f]**2 + X[F+f]**2 + X[2*F+f]**2) + 1) * w 49 | #self.add_iterative_constraint(H, r, 'face_normal_length') 50 | print('n:', np.sum(np.square((H*X)-r))) 51 | return H,r 52 | 53 | def planarity_constraints(**kwargs): ## replaced by Hui's constraint 54 | "note: based on self.planarity=True: face_normal _|_ (vi-vj)" 55 | w = kwargs.get('planarity') 56 | mesh = kwargs.get('mesh') 57 | V = mesh.V 58 | F = mesh.F 59 | N = kwargs.get('N') 60 | X = kwargs.get('X') 61 | f, v1, v2 = mesh.face_edge_vertices_iterators(order=True) 62 | K = f.shape[0] 63 | f = 3*V + f 64 | r = ((X[v2] - X[v1]) * X[f] + (X[V+v2] - X[V+v1]) * X[F+f] 65 | + (X[2*V+v2] - X[2*V+v1]) * X[2*F+f] ) * w 66 | v1 = np.hstack((v1, V+v1, 2*V+v1)) 67 | v2 = np.hstack((v2, V+v2, 2*V+v2)) 68 | f = np.hstack((f, F+f, 2*F+f)) 69 | i = np.arange(K) 70 | i = np.hstack((i, i, i, i, i, i, i, i, i)) 71 | j = np.hstack((f, v2, v1)) 72 | data = 2 * np.hstack((X[v2] - X[v1], X[f], -X[f])) * w 73 | H = sparse.coo_matrix((data,(i,j)), shape=(K, N)) 74 | #self.add_iterative_constraint(H, r, 'face_normal (planarity)') 75 | print('pq:', np.sum(np.square((H*X)-r))) 76 | return H,r 77 | 78 | # ------------------------------------------------------------------------- 79 | # Equilibrium 80 | # default these three run 81 | # equilibrium_constraints; edge_length_constraints; boundary_densities_constraints 82 | # ------------------------------------------------------------------------- 83 | 84 | def equilibrium_constraints(**kwargs): 85 | """based on self.equilibrium=True (N2); X[N1: N1+3E] 86 | edge_length:= X[N1: N1+E]; 87 | density wij:= X[N1+E: N1+2E] 88 | sqrt_density sqrt(wij):= X[N1+2E: N1+3E] 89 | constraints: wij * (vi-vj) = [0; 0; 0.5*edge_length*Fe-P[:,2]] 90 | where edge_length is defined(constrained) in edge_length_constraints() 91 | density is defined(constrained) here equilibrium_constraints() 92 | sqrt_density is defined(constrained) in compression_constraints() (may not be used) 93 | """ 94 | w = kwargs.get('equilibrium') 95 | mesh = kwargs.get('mesh') 96 | P = mesh.applied_forces 97 | Fe, Fa = mesh.self_weigth_loads ##note: known/computed values 98 | #print(P,Fe,Fa) 99 | norm = max(np.max(np.linalg.norm(P, axis=1)), np.max(Fe), np.max(Fa)) 100 | w = 0.1 * w / (norm + 1e-6) 101 | V = mesh.V 102 | E = mesh.E 103 | F = mesh.F 104 | N = kwargs.get('N') 105 | N1 = kwargs.get('N1') 106 | X = kwargs.get('X') 107 | constrained = mesh.constrained_vertices 108 | inner = np.invert(np.in1d(np.arange(V), constrained)) 109 | v0, vj = mesh.vertex_ring_vertices_iterators(sort=True) 110 | __, ej = mesh.vertex_ring_edges_iterators(sort=True) 111 | v_mask = np.invert(np.in1d(v0, constrained)) 112 | v0 = v0[v_mask] 113 | vj = vj[v_mask] 114 | ej = ej[v_mask] 115 | ix = np.hstack((v0, v0, v0)) 116 | jx = np.hstack((v0, vj, N1+E+ej)) 117 | datax = np.hstack((X[N1+E+ej], -X[N1+E+ej], X[v0]-X[vj])) 118 | ri = X[N1+E+ej]*(X[v0]-X[vj]) 119 | ri = utilities.sum_repeated(ri,v0) 120 | rx = -P[:,0] 121 | rx[inner] += ri 122 | iy = ix + V 123 | jy = np.hstack((V+v0, V+vj, N1+E+ej)) 124 | datay = np.hstack((X[N1+E+ej], -X[N1+E+ej], X[V+v0]-X[V+vj])) 125 | ri = X[N1+E+ej]*(X[V+v0]-X[V+vj]) 126 | ri = utilities.sum_repeated(ri,v0) 127 | ry = -P[:,1] 128 | ry[inner] += ri 129 | iz = np.hstack((iy+V, 2*V+v0)) 130 | jz = np.hstack((2*V+v0, 2*V+vj, N1+E+ej, N1+ej)) ##desity,edge_length 131 | dataz = np.hstack((X[N1+E+ej], -X[N1+E+ej], 132 | X[2*V+v0]-X[2*V+vj], -0.5*Fe[ej])) 133 | ri = X[N1+E+ej]*(X[2*V+v0]-X[2*V+vj]) 134 | ri = utilities.sum_repeated(ri,v0) 135 | rz = -P[:,2] 136 | rz[inner] += ri 137 | i = np.hstack((ix, iy, iz)) 138 | j = np.hstack((jx, jy, jz)) 139 | data = np.hstack((datax, datay, dataz)) * w 140 | if kwargs.get('area') != 0: 141 | "note: based on self.area=True (3)" 142 | N2 = kwargs.get('N2') 143 | vf, fj = mesh.vertex_ring_faces_iterators(sort=True) 144 | f_mask = np.invert(np.in1d(vf, constrained)) 145 | vf = vf[f_mask] 146 | fj = fj[f_mask] 147 | Lf = mesh.face_lengths() 148 | iz = 2*V + vf 149 | jz = N2 + 3*F + fj 150 | dataz = - Fa[fj] / Lf[fj] * w 151 | i = np.hstack((i,iz)) 152 | j = np.hstack((j,jz)) 153 | data = np.hstack((data, dataz)) 154 | r = np.hstack((rx, ry, rz)) * w 155 | H = sparse.coo_matrix((data,(i,j)), shape=(3*V, N)) 156 | #self.add_iterative_constraint(H, r,'equilibrium') 157 | #print('eq:', np.sum(np.square((H*X)-r))) 158 | return H,r 159 | 160 | def edge_length_constraints(**kwargs): 161 | "if self.equilibrium=True (N2); then it's used!" 162 | "variables edge_length E; constraints: E^2:= (Vi-Vj)^2;" 163 | w = kwargs.get('edge_length') * kwargs.get('geometric') 164 | mesh = kwargs.get('mesh') 165 | V = mesh.V 166 | E = mesh.E 167 | N = kwargs.get('N') 168 | N1 = kwargs.get('N1') 169 | X = kwargs.get('X') 170 | i = np.arange(E) 171 | e = N1 + i 172 | v1, v2 = mesh.edge_vertices() 173 | r = ( X[v1]**2 + X[v2]**2 - 2*X[v1]*X[v2] 174 | + X[V+v1]**2 + X[V+v2]**2 - 2*X[V+v1]*X[V+v2] 175 | + X[2*V+v1]**2 + X[2*V+v2]**2 - 2*X[2*V+v1]*X[2*V+v2] 176 | - X[e]**2 ) * w 177 | v1 = np.hstack((v1,V+v1,2*V+v1)) 178 | v2 = np.hstack((v2,V+v2,2*V+v2)) 179 | i = np.hstack((i,i,i,i,i,i,i)) 180 | j = np.hstack((v1,v2,e)) 181 | data = 2 * np.hstack((X[v1] - X[v2], X[v2] - X[v1], -X[e])) * w 182 | H = sparse.coo_matrix((data,(i,j)), shape=(E, N)) 183 | #self.add_iterative_constraint(H, r, 'edge_length') 184 | #print('el:', np.sum(np.square((H*X)-r))) 185 | return H,r 186 | 187 | def boundary_densities_constraints(**kwargs): 188 | """if self.equilibrium=True (N2); then it's used! 189 | density wij:= X[N1+E: N1+2E]; 190 | where boundary density=0; constraint: bdry_desity^2=0 191 | """ 192 | w = kwargs.get('equilibrium') 193 | mesh = kwargs.get('mesh') 194 | E = mesh.E 195 | N = kwargs.get('N') 196 | N1 = kwargs.get('N1') 197 | X = kwargs.get('X') 198 | O = N1 + E 199 | constrained = mesh.constrained_vertices 200 | v1, v2 = mesh.edge_vertices() 201 | mask1 = np.in1d(v1, constrained) 202 | mask2 = np.in1d(v2, constrained) 203 | mask = np.logical_and(mask1, mask2) 204 | #mask = mesh.are_boundary_edges() 205 | j = O + np.arange(E)[mask] 206 | W = len(j) 207 | i = np.arange(len(j)) 208 | data = 2*X[j] * w 209 | r = X[j]**2 * w 210 | H = sparse.coo_matrix((data,(i,j)), shape=(W,N)) 211 | #self.add_constant_constraint(H, r, 'boundary_equilibrium') 212 | #print('bdry:', np.sum(np.square((H*X)-r))) 213 | return H,r 214 | 215 | def compression_constraints(w, **kwargs): 216 | """if self.equilibrium=True (N2); it may use or not 217 | density wij:= X[N1+E: N1+2E] 218 | sqrt_density sqrt(wij):= X[N1+2E: N1+3E] 219 | constraint: density = sqrt_density ^2 220 | """ 221 | mesh = kwargs.get('mesh') 222 | sign = np.sign(w) 223 | E = mesh.E 224 | N = kwargs.get('N') 225 | N1 = kwargs.get('N1') 226 | X = kwargs.get('X') 227 | e = np.arange(E) 228 | i = np.hstack((e,e)) 229 | j = np.hstack((N1+2*E+e, N1+E+e)) 230 | data = np.hstack((2.0 * X[N1+2*E+e], -sign*np.ones(E))) * abs(w) 231 | H = sparse.coo_matrix((data,(i,j)), shape=(E,N)) 232 | r = X[N1+2*E+e]**2 * abs(w) 233 | #self.add_iterative_constraint(H, r, 'compression') 234 | print('sqrt:', np.sum(np.square((H*X)-r))) 235 | return H, r 236 | 237 | 238 | ##below area from X[N3: N3+4F] are not used as mentioned in Davide's AAG-paper 239 | def area_constraints(**kwargs): 240 | "note: based on self.area=True (N3)" 241 | "Ax,Ay,Az := v1 x v2" 242 | w = kwargs.get('area') * kwargs.get('geometric') 243 | mesh = kwargs.get('mesh') 244 | V = mesh.V 245 | F = mesh.F 246 | N = kwargs.get('N') 247 | N2 = kwargs.get('N2') 248 | X = kwargs.get('X') 249 | fi, v1, v2 = mesh.face_edge_vertices_iterators(order=True) 250 | v1a = np.hstack((V+v1,2*V+v1,v1)) 251 | v1b = np.hstack((2*V+v1,v1,V+v1)) 252 | v2a = np.hstack((V+v2,2*V+v2,v2)) 253 | v2b = np.hstack((2*V+v2,v2,V+v2)) 254 | r = 0.5 * (X[v1a] * X[v2b] - X[v1b] * X[v2a]) * w 255 | k = np.hstack((fi,F+fi,2*F+fi)) 256 | r = utilities.sum_repeated(r,k) 257 | f = N2 + np.arange(F) 258 | i = np.hstack((k,k,k,k,np.arange(3*F))) 259 | j = np.hstack((v1a, v2b, v1b, v2a, f, F+f, 2*F+f)) 260 | data1 = 0.5 * np.hstack((X[v2b], X[v1a], -X[v2a], -X[v1b])) 261 | data2 = - np.ones(3*F) 262 | data = np.hstack((data1, data2)) * w 263 | H = sparse.coo_matrix((data,(i,j)), shape=(3*F, N)) 264 | #self.add_iterative_constraint(H, r, 'face_vector_area') 265 | print('a1:', np.sum(np.square((H*X)-r))) 266 | return H,r 267 | 268 | def vector_area_constraints(**kwargs): 269 | "note: based on self.equilibrium=True (N2)" 270 | "area^2:= Ax^2 + Ay^2 + Az^2" 271 | w = kwargs.get('area') * kwargs.get('geometric') 272 | mesh = kwargs.get('mesh') 273 | F = mesh.F 274 | N = kwargs.get('N') 275 | N2 = kwargs.get('N2') 276 | f = N2 + np.arange(F) 277 | i = np.arange(F) 278 | i = np.hstack((i,i,i,i)) 279 | j = np.hstack((f,F+f,2*F+f,3*F+f)) 280 | X = kwargs.get('X') 281 | data = 2 * np.hstack((X[f], X[F+f], X[2*F+f], - X[3*F+f])) * w 282 | H = sparse.coo_matrix((data,(i,j)), shape=(F, N)) 283 | r = (X[f]**2 + X[F+f]**2 + X[2*F+f]**2 - X[3*F+f]**2) * w 284 | #self.add_iterative_constraint(H, r, 'face_area') 285 | print('a2:', np.sum(np.square((H*X)-r))) 286 | return H,r 287 | 288 | # ------------------------------------------------------------------------- 289 | # Boundary 290 | # ------------------------------------------------------------------------- 291 | 292 | def fixed_boundary_normals_constraints(**kwargs): #not necessary, may not be used 293 | "based on self.planarity=True (N1)" 294 | "face_normal [Nx,Ny,Nz] from X[3V:3V+3F]; constraint: [Nx,Ny,Nz] are fixed" 295 | w = kwargs.get('fixed_boundary_normals') 296 | mesh = kwargs.get('mesh') 297 | N = kwargs.get('N') 298 | F = mesh.F 299 | V = mesh.V 300 | f = mesh.boundary_faces() 301 | X = kwargs.get('X') 302 | W = 3*len(f) 303 | nx = 3*V + f 304 | ny = 3*V + F + f 305 | nz = 3*V + 2*F + f 306 | data = np.ones(W) * w 307 | i = np.arange(W) 308 | j = np.hstack((nx, ny, nz)) 309 | H = sparse.coo_matrix((data,(i,j)), shape=(W,N)) 310 | r = np.hstack((X[nx],X[ny],X[nz])) * w 311 | #self.add_constant_constraint(H, r, 'fixed_boundary_normals') 312 | print('fix:', np.sum(np.square((H*X)-r))) 313 | return H, r 314 | -------------------------------------------------------------------------------- /archgeolab/constraints/constraints_fairness.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu May 26 10:20:13 2022 4 | 5 | @author: WANGH0M 6 | """ 7 | __author__ = 'Hui' 8 | #------------------------------------------------------------------------------ 9 | import numpy as np 10 | 11 | from scipy import sparse 12 | #------------------------------------------------------------------------------ 13 | from archgeolab.constraints.constraints_basic import column3D 14 | # ------------------------------------------------------------------------- 15 | 16 | """ 17 | from constraints.constraints_fairness import 18 | con_fair_midpoint 19 | con_laplacian_fairness 20 | con_fairness_4th_different_polylines 21 | """ 22 | 23 | # ------------------------------------------------------------------------- 24 | # fairness 25 | # ------------------------------------------------------------------------- 26 | def con_fair_midpoint(v,vl,vr,move,Vnum,N): 27 | "vl+vr-2v = 0" 28 | num = len(v) 29 | arr = np.arange(3*num) 30 | one = np.ones(3*num) 31 | row = np.tile(arr,3) 32 | cc = column3D(v, move,Vnum) 33 | c1 = column3D(vl,move,Vnum) 34 | c2 = column3D(vr,move,Vnum) 35 | col = np.r_[cc,c1,c2] 36 | data = np.r_[2*one,-one,-one] 37 | K = sparse.coo_matrix((data,(row,col)), shape=(3*num, N)) 38 | return K 39 | 40 | def con_laplacian_fairness(v,neib,move,Vnum,N): 41 | "v1+v2+..+vn = n*v" 42 | valence = neib.shape[1] # column num 43 | num = len(v) 44 | one = np.ones(3*num) 45 | row = np.tile(np.arange(3*num),valence+1) 46 | col = column3D(v, move,Vnum) 47 | data = valence*one 48 | for i in range(valence): 49 | ci = column3D(neib[:,i], move,Vnum) 50 | col = np.r_[col, ci] 51 | data = np.r_[data,-one] 52 | K = sparse.coo_matrix((data,(row,col)), shape=(3*num, N)) 53 | return K 54 | 55 | def con_fairness_4th_different_polylines(pylist,diag=False,**kwargs): 56 | "generate con_fairness_4th_different to any given polyline-list" 57 | "(v0-4*v1+6*v2-4*v3+v4)^2=0" 58 | if diag: 59 | w = kwargs.get('fairness_diag_4diff') 60 | else: 61 | w = kwargs.get('fairness_4diff') 62 | mesh = kwargs.get('mesh') 63 | X = kwargs.get('X') 64 | v0=v1=v2=v3=v4 = np.array([],dtype=int) 65 | for pl in pylist: 66 | if len(pl)>4: 67 | v0 = np.r_[v0,pl[:-4]] 68 | v1 = np.r_[v1,pl[1:-3]] 69 | v2 = np.r_[v2,pl[2:-2]] 70 | v3 = np.r_[v3,pl[3:-1]] 71 | v4 = np.r_[v4,pl[4:]] 72 | num = len(v0) 73 | arr = np.arange(num) 74 | row = np.tile(arr,15) 75 | c0 = column3D(v0,0,mesh.V) 76 | c1 = column3D(v1,0,mesh.V) 77 | c2 = column3D(v2,0,mesh.V) 78 | c3 = column3D(v3,0,mesh.V) 79 | c4 = column3D(v4,0,mesh.V) 80 | col = np.r_[c0,c1,c2,c3,c4] 81 | d = np.r_[X[c0]-4*X[c1]+6*X[c2]-4*X[c3]+X[c4]] 82 | data = 2*np.r_[d,-4*d,6*d,-4*d,d] 83 | r = np.linalg.norm(d.reshape(-1,3,order='F'),axis=1)**2 84 | H = sparse.coo_matrix((data,(row,col)), shape=(num, len(X))) 85 | return H*w,r*w 86 | -------------------------------------------------------------------------------- /archgeolab/constraints/constraints_glide.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Nov 8 11:29:34 2021 4 | 5 | @author: WANGH0M 6 | """ 7 | __author__ = 'Hui' 8 | #------------------------------------------------------------------------------ 9 | import numpy as np 10 | 11 | from scipy import sparse 12 | #------------------------------------------------------------------------------ 13 | from geometrylab import utilities 14 | 15 | from archgeolab.constraints.constraints_basic import column3D 16 | #------------------------------------------------------------------------------ 17 | """ 18 | from constraints_glide import 19 | con_alignment,con_alignments,con_glide_in_plane, 20 | con_sharp_corner,con_fix_vertices 21 | con_selected_vertices_glide_in_one_plane 22 | """ 23 | #------------------------------------------------------------------------------ 24 | 25 | # ------------------------------------------------------------------------- 26 | # Glide / Alignment 27 | # ------------------------------------------------------------------------- 28 | def con_alignments(w,refPoly, glideInd, overlap=False,**kwargs): 29 | #w = kwargs.get('i_boundary_glide') 30 | N = kwargs.get('N') 31 | null = np.zeros([0]) 32 | H = sparse.coo_matrix((null,(null,null)), shape=(0,N)) 33 | r = np.array([]) 34 | for i in range(len(glideInd)): 35 | v, crv = glideInd[i], refPoly[i] 36 | Hi,ri = con_alignment(w,crv,v,**kwargs) 37 | H = sparse.vstack((H,Hi)) 38 | r = np.r_[r,ri] 39 | return H,r 40 | 41 | def con_alignment(w, refPoly, glideInd, overlap=False,**kwargs): 42 | """glide on a given polylineCurve (may be not closed) 43 | refPoly: reference polylineCurve 44 | glideInd: indices of constraint vertices from the mesh 45 | constraints: from tangents e1 to get orthogonal e2,e3, 46 | then(P-Q)*e2=0; (P-Q)*e3=0 47 | such that P-Q align nealy on direction e1 48 | where P (varaibles), and Q,e2,e3 are computed_concrete_values 49 | linear equations: P*e2=Q*e2; P*e3=Q*e3 50 | ~ [P;P] * [e2;e3] = [Q;Q] * [e2;e3] 51 | another way: P-Q // e1 <==> (P-Q) x e1 = 0 52 | """ 53 | #w = kwargs.get('boundary_glide') 54 | mesh = kwargs.get('mesh') 55 | X = kwargs.get('X') 56 | ind = glideInd 57 | Vr = refPoly.vertices 58 | Tr = refPoly.vertex_tangents() 59 | c_p = column3D(ind,0,mesh.V) 60 | P = X[c_p].reshape(-1,3,order='F') 61 | closeP = refPoly.closest_vertices(P) 62 | Q = Vr[closeP] 63 | e1 = Tr[closeP] 64 | e2 = utilities.orthogonal_vectors(e1) 65 | e3 = np.cross(e1,e2) 66 | r = np.r_[np.einsum('ij,ij->i',Q,e2),np.einsum('ij,ij->i',Q,e3)] 67 | 68 | num = len(ind) 69 | row = np.tile(np.arange(2*num),3) 70 | col = column3D(np.tile(ind,2),0,mesh.V) 71 | ee = np.vstack((e2,e3)) 72 | data = ee.flatten('F') 73 | H = sparse.coo_matrix((data,(row,col)), shape=(2*num,len(X))) 74 | if overlap: 75 | "P=Q" 76 | row = np.arange(3*num) 77 | col = c_p 78 | data = np.ones(3*num) 79 | r0 = Q.flatten('F') 80 | H0 = sparse.coo_matrix((data,(row,col)), shape=(3*num,len(X))) 81 | H = sparse.vstack((H,H0*1)) 82 | r = np.r_[r,r0*1] 83 | return H*w,r*w 84 | 85 | def con_glide_in_plane(coo,**kwargs): 86 | "glide on xy plane: coo=0,1,2 ~ yz, xz, xy " 87 | w = kwargs.get('z0') 88 | mesh = kwargs.get('mesh') 89 | N = kwargs.get('N') 90 | numv = mesh.V 91 | row = np.arange(numv) 92 | crr = np.arange(numv) 93 | col = coo*numv+crr 94 | data = np.ones(numv) 95 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 96 | r = np.zeros(numv) 97 | return H*w, r*w 98 | 99 | def con_selected_vertices_glide_in_one_plane(v,coo,value,**kwargs): 100 | "glide on x/y/z plane: coo=0,1,2 ~ yz, xz, xy, e.g. z=1 <==>coo=2,value=1" 101 | mesh = kwargs.get('mesh') 102 | N = kwargs.get('N') 103 | numv = len(v) 104 | row = np.arange(numv) 105 | col = coo*mesh.V+v 106 | data = np.ones(numv) 107 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 108 | r = np.ones(numv) * value 109 | return H, r 110 | 111 | def con_sharp_corner(move=0,angle=90,**kwargs): 112 | "if given angle, need change (vl-v)*(vr-v) = 0" 113 | w = kwargs.get('sharp_corner') 114 | mesh = kwargs.get('mesh') 115 | X = kwargs.get('X') 116 | v = mesh.corner 117 | neib = [] 118 | for i in v: 119 | neib.append(mesh.ringlist[i]) 120 | neib = np.array(neib) 121 | vl,vr = neib[:,0],neib[:,1] 122 | c_v = column3D(v,move,mesh.V) 123 | c_vl = column3D(vl,move,mesh.V) 124 | c_vr = column3D(vr,move,mesh.V) 125 | col = np.r_[c_v,c_vl,c_vr] 126 | row = np.tile(np.arange(len(v)),9) 127 | data = np.r_[2*X[c_v]-X[c_vl]-X[c_vr],X[c_vr]-X[c_v],X[c_vl]-X[c_v]] 128 | r = np.einsum('ij,ij->i',(X[c_vl]-X[c_v]).reshape(-1,3, order='F'),(X[c_vr]-X[c_v]).reshape(-1,3, order='F')) 129 | H = sparse.coo_matrix((data,(row,col)), shape=(len(v), len(X))) 130 | return H*w,r*w 131 | 132 | def con_fix_vertices( index, Vf,**kwargs): 133 | "X[column(index)]==Vf" 134 | w = kwargs.get('fix_point') 135 | mesh = kwargs.get('mesh') 136 | N = kwargs.get('N') 137 | try: 138 | row = np.arange(3*len(index)) 139 | num = 3*len(index) 140 | except: 141 | row = np.arange(3*1) 142 | num = 3 143 | col = column3D(index,0,mesh.V) 144 | data = np.ones(3*1) 145 | r = Vf 146 | H = sparse.coo_matrix((data,(row,col)), shape=(num,N)) 147 | return H*w,r*w 148 | -------------------------------------------------------------------------------- /archgeolab/constraints/constraints_net.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Dec 18 22:16:21 2022 4 | 5 | @author: WANGH0M 6 | """ 7 | __author__ = 'Hui' 8 | #------------------------------------------------------------------------------ 9 | import numpy as np 10 | 11 | from scipy import sparse 12 | #------------------------------------------------------------------------------ 13 | from archgeolab.constraints.constraints_basic import column3D,con_edge,\ 14 | con_unit,con_constl,con_equal_length,\ 15 | con_planarity,con_unit_normal,con_orient 16 | # ------------------------------------------------------------------------- 17 | """ 18 | from archgeolab.constraints.constraints_net import 19 | con_unit_edge,con_orthogonal_midline,\ 20 | con_anet,con_anet_diagnet,con_snet,con_snet_diagnet 21 | """ 22 | #-------------------------------------------------------------------------- 23 | # isogonals: 24 | #-------------------------------------------------------------------------- 25 | def con_unit_edge(rregular=False,**kwargs): 26 | """ unit_edge / unit_diag_edge_vec 27 | X += [l1,l2,l3,l4,ue1,ue2,ue3,ue4]; exists multiples between ue1,ue2,ue3,ue4 28 | (vi-v) = li*ui, ui**2=1, (i=1,2,3,4) 29 | """ 30 | if kwargs.get('unit_diag_edge_vec'): 31 | w = kwargs.get('unit_diag_edge_vec') 32 | diag=True 33 | elif kwargs.get('unit_edge_vec'): 34 | w = kwargs.get('unit_edge_vec') 35 | diag=False 36 | mesh = kwargs.get('mesh') 37 | X = kwargs.get('X') 38 | N5 = kwargs.get('N5') 39 | V = mesh.V 40 | if diag: 41 | v,v1,v2,v3,v4 = mesh.rr_star_corner 42 | elif rregular: 43 | v,v1,v2,v3,v4 = mesh.rrv4f4 44 | else: 45 | #v,v1,v2,v3,v4 = mesh.ver_regular_star.T # default angle=90, non-orient 46 | v,v1,v2,v3,v4 = mesh.ver_star_matrix.T # oriented 47 | num = len(v) 48 | c_v = column3D(v,0,V) 49 | c_v1 = column3D(v1,0,V) 50 | c_v2 = column3D(v2,0,V) 51 | c_v3 = column3D(v3,0,V) 52 | c_v4 = column3D(v4,0,V) 53 | 54 | arr = np.arange(num) 55 | c_l1 = N5-16*num + arr 56 | c_l2 = c_l1 + num 57 | c_l3 = c_l2 + num 58 | c_l4 = c_l3 + num 59 | c_ue1 = column3D(arr,N5-12*num,num) 60 | c_ue2 = column3D(arr,N5-9*num,num) 61 | c_ue3 = column3D(arr,N5-6*num,num) 62 | c_ue4 = column3D(arr,N5-3*num,num) 63 | 64 | H1,r1 = con_edge(X,c_v1,c_v,c_l1,c_ue1) 65 | H2,r2 = con_edge(X,c_v2,c_v,c_l2,c_ue2) 66 | H3,r3 = con_edge(X,c_v3,c_v,c_l3,c_ue3) 67 | H4,r4 = con_edge(X,c_v4,c_v,c_l4,c_ue4) 68 | Hu1,ru1 = con_unit(X,c_ue1) 69 | Hu2,ru2 = con_unit(X,c_ue2) 70 | Hu3,ru3 = con_unit(X,c_ue3) 71 | Hu4,ru4 = con_unit(X,c_ue4) 72 | 73 | H = sparse.vstack((H1,H2,H3,H4,Hu1,Hu2,Hu3,Hu4)) 74 | r = np.r_[r1,r2,r3,r4,ru1,ru2,ru3,ru4] 75 | return H*w,r*w 76 | 77 | def con_orient_rr_vn(**kwargs): 78 | """ X +=[vN, a], given computed Nv,which is defined at rr_vs 79 | vN *(e1-e3) = vN *(e2-e4) = 0; vN^2=1 80 | vN*Nv=a^2 81 | ==> vN is unit vertex-normal defined by t1xt2, **orient same with Nv** 82 | """ 83 | mesh = kwargs.get('mesh') 84 | X = kwargs.get('X') 85 | N5 = kwargs.get('N5') 86 | Norient = kwargs.get('Norient') 87 | v = mesh.ver_rrv4f4 88 | Nv = mesh.vertex_normals()[v] 89 | num = mesh.num_rrv4f4 90 | arr,arr3 = np.arange(num),np.arange(3*num) 91 | c_n = arr3 + Norient-4*num 92 | c_a = arr + Norient-num 93 | c_ue1 = column3D(arr,N5-12*num,num) 94 | c_ue2 = column3D(arr,N5-9*num,num) 95 | c_ue3 = column3D(arr,N5-6*num,num) 96 | c_ue4 = column3D(arr,N5-3*num,num) 97 | "vN should be oriented with oriented-vertex-normal" 98 | Hvn,rvn = con_unit_normal(X,c_ue1,c_ue2,c_ue3,c_ue4,c_n) 99 | 100 | "make sure the variable vN has same orientation with Nv:" 101 | Ho,ro = con_orient(X,Nv,c_n,c_a,neg=False) 102 | H = sparse.vstack((Hvn,Ho)) 103 | r = np.r_[rvn,ro] 104 | return H,r 105 | 106 | def con_orthogonal_midline(is_rr=True,**kwargs): 107 | """ 108 | control quadfaces: two middle line are orthogonal to each other 109 | quadface: v1,v2,v3,v4 110 | middle lins: e1 = (v1+v2)/2-(v3+v4)/2; e2 = (v2+v3)/2-(v4+v1)/2 111 | <===> e1 * e2 = 0 <==> (v1-v3)^2=(v2-v4)^2 112 | """ 113 | w = kwargs.get('orthogonal') 114 | mesh = kwargs.get('mesh') 115 | X = kwargs.get('X') 116 | v1,v2,v3,v4 = mesh.rr_quadface.T # in odrder 117 | if is_rr: 118 | ind = mesh.ind_rr_quadface_with_rrv 119 | v1,v2,v3,v4 = v1[ind],v2[ind],v3[ind],v4[ind] 120 | c_v1 = column3D(v1,0,mesh.V) 121 | c_v2 = column3D(v2,0,mesh.V) 122 | c_v3 = column3D(v3,0,mesh.V) 123 | c_v4 = column3D(v4,0,mesh.V) 124 | H,r = con_equal_length(X,c_v1,c_v2,c_v3,c_v4) 125 | return H*w,r*w 126 | 127 | 128 | #-------------------------------------------------------------------------- 129 | # A-net: 130 | #-------------------------------------------------------------------------- 131 | def _con_anet(X,w,c_n,c_v,c_v1,c_v2,c_v3,c_v4): 132 | "vn*(vi-v)=0; vn**2=1" 133 | H1,r1 = con_planarity(X,c_v,c_v1,c_n) 134 | H2,r2 = con_planarity(X,c_v,c_v2,c_n) 135 | H3,r3 = con_planarity(X,c_v,c_v3,c_n) 136 | H4,r4 = con_planarity(X,c_v,c_v4,c_n) 137 | Hn,rn = con_unit(X,c_n) 138 | H = sparse.vstack((H1,H2,H3,H4,Hn)) 139 | r = np.r_[r1,r2,r3,r4,rn] 140 | return H*w, r*w 141 | 142 | def con_anet(rregular=False,**kwargs): 143 | """ based on con_unit_edge() 144 | X += [ni] 145 | ni * (vij - vi) = 0 146 | """ 147 | w = kwargs.get('Anet') 148 | mesh = kwargs.get('mesh') 149 | X = kwargs.get('X') 150 | 151 | Nanet = kwargs.get('Nanet') 152 | 153 | if rregular: 154 | v,v1,v2,v3,v4 = mesh.rrv4f4 155 | num=mesh.num_rrv4f4 156 | else: 157 | num = mesh.num_regular 158 | v,v1,v2,v3,v4 = mesh.ver_regular_star.T 159 | 160 | c_n = Nanet-3*num+np.arange(3*num) 161 | c_v = column3D(v ,0,mesh.V) 162 | c_v1 = column3D(v1,0,mesh.V) 163 | c_v2 = column3D(v2,0,mesh.V) 164 | c_v3 = column3D(v3,0,mesh.V) 165 | c_v4 = column3D(v4,0,mesh.V) 166 | 167 | H,r = _con_anet(X,w,c_n,c_v,c_v1,c_v2,c_v3,c_v4) 168 | return H,r 169 | 170 | def con_anet_diagnet(**kwargs): 171 | "based on con_unit_edge(diag=True); X += [ni]; ni * (vij - vi) = 0" 172 | w = kwargs.get('Anet_diagnet') 173 | mesh = kwargs.get('mesh') 174 | X = kwargs.get('X') 175 | Nanet = kwargs.get('Nanet') 176 | 177 | #c_v,c_v1,c_v2,c_v3,c_v4 = mesh.get_vs_diagonal_v(index=False) 178 | v,v1,v2,v3,v4 = mesh.rr_star_corner 179 | c_v = column3D(v ,0,mesh.V) 180 | c_v1 = column3D(v1,0,mesh.V) 181 | c_v2 = column3D(v2,0,mesh.V) 182 | c_v3 = column3D(v3,0,mesh.V) 183 | c_v4 = column3D(v4,0,mesh.V) 184 | 185 | num = int(len(c_v)/3) 186 | c_n = Nanet-3*num+np.arange(3*num) 187 | 188 | H,r = _con_anet(X,w,c_n,c_v,c_v1,c_v2,c_v3,c_v4) 189 | return H,r 190 | 191 | 192 | #-------------------------------------------------------------------------- 193 | # S-net: 194 | #-------------------------------------------------------------------------- 195 | def con_snet(orientrn,is_rrvstar=True,is_diagmesh=False, 196 | is_uniqR=False,assigned_r=None,**kwargs): 197 | """a(x^2+y^2+z^2)+(bx+cy+dz)+e=0 ; normalize: F^2 = b^2+c^2+d^2-4ae=1 198 | sphere center C:= (m1,m2,m3) = -(b, c, d) /a/2 199 | sphere radius:= F /a/2 200 | unit_sphere_normal N==-(2*A*Vx+B, 2*A*Vy+C, 2*A*Vz+D), (pointing from v to center) 201 | since P(Vx,Vy,Vz) satisfy the sphere eq. and the normalizated eq., so that 202 | N ^2=1 203 | """ 204 | w = kwargs.get('Snet') 205 | Nsnet = kwargs.get('Nsnet') 206 | mesh = kwargs.get('mesh') 207 | X = kwargs.get('X') 208 | N = kwargs.get('N') 209 | V = mesh.V 210 | 211 | if is_rrvstar: 212 | "new for SSGweb-project" 213 | if is_diagmesh: 214 | w = kwargs.get('Snet_diagnet') 215 | v0,v1,v2,v3,v4 = mesh.rr_star_corner 216 | else: 217 | v0,v1,v2,v3,v4 = mesh.rrv4f4 218 | #orientrn = orientrn[mesh.ind_rr_star_v4f4] ##below should be the same 219 | ##print(len(mesh.ind_rr_star_v4f4),len(v0)) 220 | else: 221 | "used in CRPC" 222 | v0,v1,v2,v3,v4 = mesh.rr_star.T 223 | numv = len(v0) ##print(numv,mesh.num_rrv4f4) 224 | c_v0 = column3D(v0,0,V) 225 | c_v1 = column3D(v1,0,V) 226 | c_v2 = column3D(v2,0,V) 227 | c_v3 = column3D(v3,0,V) 228 | c_v4 = column3D(v4,0,V) 229 | arr1 = np.arange(numv) 230 | arr3 = np.arange(3*numv) 231 | _n1 = Nsnet-11*numv 232 | c_squ, c_a = _n1+np.arange(5*numv),_n1+5*numv+arr1 233 | c_b,c_c,c_d,c_e = c_a+numv,c_a+2*numv,c_a+3*numv,c_a+4*numv 234 | c_a_sqr = c_a+5*numv 235 | 236 | def _con_v_square(c_squ): 237 | "[v;v1,v2,v3,v4]=[x,y,z], X[c_squ]=x^2+y^2+z^2" 238 | row_v = np.tile(arr1,3) 239 | row_1 = row_v+numv 240 | row_2 = row_v+2*numv 241 | row_3 = row_v+3*numv 242 | row_4 = row_v+4*numv 243 | row = np.r_[row_v,row_1,row_2,row_3,row_4,np.arange(5*numv)] 244 | col = np.r_[c_v0,c_v1,c_v2,c_v3,c_v4,c_squ] 245 | dv = 2*np.r_[X[c_v0]] 246 | d1 = 2*np.r_[X[c_v1]] 247 | d2 = 2*np.r_[X[c_v2]] 248 | d3 = 2*np.r_[X[c_v3]] 249 | d4 = 2*np.r_[X[c_v4]] 250 | data = np.r_[dv,d1,d2,d3,d4,-np.ones(5*numv)] 251 | H = sparse.coo_matrix((data,(row,col)), shape=(5*numv, N)) 252 | def xyz(c_i): 253 | c_x = c_i[:numv] 254 | c_y = c_i[numv:2*numv] 255 | c_z = c_i[2*numv:] 256 | return np.r_[X[c_x]**2+X[c_y]**2+X[c_z]**2] 257 | r = np.r_[xyz(c_v0),xyz(c_v1),xyz(c_v2),xyz(c_v3),xyz(c_v4)] 258 | return H,r 259 | def _con_pos_a(c_a,c_a_sqr): 260 | "a>=0 <---> a_sqr^2 - a = 0" 261 | row = np.tile(arr1,2) 262 | col = np.r_[c_a_sqr, c_a] 263 | data = np.r_[2*X[c_a_sqr], -np.ones(numv)] 264 | r = X[c_a_sqr]**2 265 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 266 | return H,r 267 | def _con_sphere_normalization(c_a,c_b,c_c,c_d,c_e): 268 | """normalize the sphere equation, 269 | convinent for computing/represent distance\normals 270 | ||df|| = b^2+c^2+d^2-4ae=1 271 | """ 272 | row = np.tile(arr1,5) 273 | col = np.r_[c_a,c_b,c_c,c_d,c_e] 274 | data = 2*np.r_[-2*X[c_e],X[c_b],X[c_c],X[c_d],-2*X[c_a]] 275 | r = X[c_b]**2+X[c_c]**2+X[c_d]**2-4*X[c_a]*X[c_e]+np.ones(numv) 276 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 277 | return H,r 278 | def _con_sphere(c_squ,c_a,c_b,c_c,c_d,c_e): 279 | "a(x^2+y^2+z^2)+(bx+cy+dz)+e=0" 280 | row = np.tile(arr1,9) 281 | def __sphere(c_vi,c_sq): 282 | c_x = c_vi[:numv] 283 | c_y = c_vi[numv:2*numv] 284 | c_z = c_vi[2*numv:] 285 | col = np.r_[c_x,c_y,c_z,c_sq,c_a,c_b,c_c,c_d,c_e] 286 | data = np.r_[X[c_b],X[c_c],X[c_d],X[c_a],X[c_sq],X[c_x],X[c_y],X[c_z],np.ones(numv)] 287 | r = X[c_b]*X[c_x]+X[c_c]*X[c_y]+X[c_d]*X[c_z]+X[c_a]*X[c_sq] 288 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 289 | return H,r 290 | H0,r0 = __sphere(c_v0,c_squ[:numv]) 291 | H1,r1 = __sphere(c_v1,c_squ[numv:2*numv]) 292 | H2,r2 = __sphere(c_v2,c_squ[2*numv:3*numv]) 293 | H3,r3 = __sphere(c_v3,c_squ[3*numv:4*numv]) 294 | H4,r4 = __sphere(c_v4,c_squ[4*numv:]) 295 | H = sparse.vstack((H0,H1,H2,H3,H4)) 296 | r = np.r_[r0,r1,r2,r3,r4] 297 | return H,r 298 | def _con_const_radius(c_a,c_r): 299 | "2*ai * r = 1 == df" 300 | c_rr = np.tile(c_r, numv) 301 | row = np.tile(arr1,2) 302 | col = np.r_[c_a, c_rr] 303 | data = np.r_[X[c_rr], X[c_a]] 304 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 305 | r = X[c_rr] * X[c_a] + 0.5*np.ones(numv) 306 | return H,r 307 | def _con_anet(c_a): 308 | row = arr1 309 | col = c_a 310 | data = np.ones(numv) 311 | r = np.zeros(numv) 312 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 313 | return H,r 314 | 315 | "this fun. is new added." 316 | def _con_unit_sphere_normal(c_v0,c_a,c_b,c_c,c_d,c_n): ##need definition of unitnormal 317 | "N==-(2*A*Vx+B, 2*A*Vy+C, 2*A*Vz+D)" 318 | c_nx,c_ny,c_nz = c_n[arr1], c_n[arr1+numv], c_n[arr1+2*numv] 319 | c_vx,c_vy,c_vz = c_v0[arr1], c_v0[arr1+numv], c_v0[arr1+2*numv] 320 | def _con_coordinate(c_nx,c_vx,c_a,c_b): 321 | "2*a*vx+b+nx = 0" 322 | col = np.r_[c_nx,c_vx,c_a,c_b] 323 | row = np.tile(arr1, 4) 324 | one = np.ones(numv) 325 | data = np.r_[one,2*X[c_a],2*X[c_vx],one] 326 | r = 2*X[c_a]*X[c_vx] 327 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 328 | return H,r 329 | Hx,rx = _con_coordinate(c_nx,c_vx,c_a,c_b) 330 | Hy,ry = _con_coordinate(c_ny,c_vy,c_a,c_c) 331 | Hz,rz = _con_coordinate(c_nz,c_vz,c_a,c_d) 332 | H = sparse.vstack((Hx,Hy,Hz)) 333 | r = np.r_[rx,ry,rz] 334 | return H,r 335 | 336 | def _con_orient(c_n,c_o): 337 | "N*orientn = const^2 <==> n0x*nx+n0y*ny+n0z*nz-x_orient^2 = 0" 338 | row = np.tile(arr1,4) 339 | col = np.r_[c_n, c_o] 340 | data = np.r_[orientrn.flatten('F'), -2*X[c_o]] 341 | r = -X[c_o]**2 342 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 343 | "add limitation for spherical normal" 344 | return H,r 345 | 346 | H0,r0 = _con_v_square(c_squ) 347 | H1,r1 = _con_pos_a(c_a,c_a_sqr) 348 | Hn,rn = _con_sphere_normalization(c_a,c_b,c_c,c_d,c_e) 349 | Hs,rs = _con_sphere(c_squ,c_a,c_b,c_c,c_d,c_e) 350 | H = sparse.vstack((H0,H1,Hn,Hs)) 351 | r = np.r_[r0,r1,rn,rs] 352 | # print('s0:', np.sum(np.square((H0*X)-r0))) 353 | # print('s1:', np.sum(np.square((H1*X)-r1))) 354 | # print('s2:', np.sum(np.square((Hn*X)-rn))) 355 | # print('s3:', np.sum(np.square((Hs*X)-rs))) 356 | # print('snet:', np.sum(np.square((H*X)-r))) 357 | if kwargs.get('Snet_orient'): 358 | w1 = kwargs.get('Snet_orient') 359 | Ns_n = kwargs.get('Ns_n') 360 | c_n = Ns_n-4*numv+arr3 361 | c_n_sqr = Ns_n-numv+arr1 362 | Ho,ro = _con_orient(c_n,c_n_sqr) 363 | Hn,rn = _con_unit_sphere_normal(c_v0,c_a,c_b,c_c,c_d,c_n) 364 | H = sparse.vstack((H, Ho * w1, Hn*w1*10)) #need check the weight 365 | r = np.r_[r, ro * w1, rn*w1*10] 366 | # print('o:', np.sum(np.square((Ho*X)-ro))) 367 | # print('n:', np.sum(np.square((Hn*X)-rn))) 368 | 369 | if kwargs.get('Snet_constR'): 370 | w2 = kwargs.get('Snet_constR') 371 | Ns_r = kwargs.get('Ns_r') 372 | c_r = np.array([Ns_r-1],dtype=int) 373 | Hr,rr = _con_const_radius(c_a,c_r) 374 | H = sparse.vstack((H, Hr * w2)) 375 | r = np.r_[r, rr * w2] 376 | if is_uniqR: 377 | H0,r0 = con_constl(c_r,assigned_r,N) 378 | H = sparse.vstack((H, H0)) 379 | r = np.r_[r,r0] 380 | #print('r:', np.sum(np.square((Hr*X)-rr))) 381 | if kwargs.get('Snet_anet'): 382 | w3 = kwargs.get('Snet_anet') 383 | Ha,ra = _con_anet(c_a) 384 | H = sparse.vstack((H, Ha * w3)) 385 | r = np.r_[r, ra * w3] 386 | 387 | return H*w,r*w 388 | 389 | def con_snet_diagnet(orientrn,**kwargs): 390 | w = kwargs.get('Snet_diagnet') 391 | mesh = kwargs.get('mesh') 392 | X = kwargs.get('X') 393 | N = kwargs.get('N') 394 | Nsnet = kwargs.get('Nsnet') 395 | 396 | V = mesh.V 397 | numv = mesh.num_rrv4f4 398 | arr1 = np.arange(numv) 399 | arr3 = np.arange(3*numv) 400 | 401 | #c_v,c_cen1,c_cen2,c_cen3,c_cen4 = mesh.get_vs_diagonal_v(ck1=ck1,ck2=ck2,index=False) 402 | v,v1,v2,v3,v4 = mesh.rr_star_corner 403 | c_v = column3D(v,0,V) 404 | c_cen1 = column3D(v1,0,V) 405 | c_cen2 = column3D(v2,0,V) 406 | c_cen3 = column3D(v3,0,V) 407 | c_cen4 = column3D(v4,0,V) 408 | c_cen = [c_cen1,c_cen2,c_cen3,c_cen4] 409 | _n1 = Nsnet-11*numv 410 | c_squ, c_a = _n1+np.arange(5*numv),_n1+5*numv+arr1 411 | c_b,c_c,c_d,c_e = c_a+numv,c_a+2*numv,c_a+3*numv,c_a+4*numv 412 | c_a_sqr = c_a+5*numv 413 | 414 | def _con_v_square(c_v,c_cen,c_squ): 415 | "[v;c1,c2,c3,c4]=[x,y,z], X[c_squ]=x^2+y^2+z^2" 416 | c_cen1,c_cen2,c_cen3,c_cen4 = c_cen 417 | row_v = np.tile(arr1,3) 418 | row_1 = row_v+numv 419 | row_2 = row_v+2*numv 420 | row_3 = row_v+3*numv 421 | row_4 = row_v+4*numv 422 | row = np.r_[row_v,row_1,row_2,row_3,row_4,np.arange(5*numv)] 423 | col = np.r_[c_v,c_cen1,c_cen2,c_cen3,c_cen4,c_squ] 424 | dv = 2*np.r_[X[c_v]] 425 | d1 = 2*np.r_[X[c_cen1]] 426 | d2 = 2*np.r_[X[c_cen2]] 427 | d3 = 2*np.r_[X[c_cen3]] 428 | d4 = 2*np.r_[X[c_cen4]] 429 | data = np.r_[dv,d1,d2,d3,d4,-np.ones(5*numv)] 430 | H = sparse.coo_matrix((data,(row,col)), shape=(5*numv, N)) 431 | def xyz(c_i): 432 | c_x = c_i[:numv] 433 | c_y = c_i[numv:2*numv] 434 | c_z = c_i[2*numv:] 435 | return np.r_[X[c_x]**2+X[c_y]**2+X[c_z]**2] 436 | r = np.r_[xyz(c_v),xyz(c_cen1),xyz(c_cen2),xyz(c_cen3),xyz(c_cen4)] 437 | return H,r 438 | 439 | def _con_pos_a(c_a,c_a_sqr): 440 | "a>=0 <---> a_sqr^2 - a = 0" 441 | row = np.tile(arr1,2) 442 | col = np.r_[c_a_sqr, c_a] 443 | data = np.r_[2*X[c_a_sqr], -np.ones(numv)] 444 | r = X[c_a_sqr]**2 445 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 446 | return H,r 447 | 448 | def _con_sphere_normalization(c_a,c_b,c_c,c_d,c_e): 449 | """normalize the sphere equation, 450 | convinent for computing/represent distance\normals 451 | ||df|| = b^2+c^2+d^2-4ae=1 452 | """ 453 | row = np.tile(arr1,5) 454 | col = np.r_[c_a,c_b,c_c,c_d,c_e] 455 | data = 2*np.r_[-2*X[c_e],X[c_b],X[c_c],X[c_d],-2*X[c_a]] 456 | r = X[c_b]**2+X[c_c]**2+X[c_d]**2-4*X[c_a]*X[c_e]+np.ones(numv) 457 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 458 | return H,r 459 | 460 | def _con_sphere(c_v,c_cen,c_squ,c_a,c_b,c_c,c_d,c_e): 461 | "a(x^2+y^2+z^2)+(bx+cy+dz)+e=0" 462 | c_cen1,c_cen2,c_cen3,c_cen4 = c_cen 463 | row = np.tile(arr1,9) 464 | def __sphere(c_vi,c_sq): 465 | c_x = c_vi[:numv] 466 | c_y = c_vi[numv:2*numv] 467 | c_z = c_vi[2*numv:] 468 | col = np.r_[c_x,c_y,c_z,c_sq,c_a,c_b,c_c,c_d,c_e] 469 | data = np.r_[X[c_b],X[c_c],X[c_d],X[c_a],X[c_sq],X[c_x],X[c_y],X[c_z],np.ones(numv)] 470 | r = X[c_b]*X[c_x]+X[c_c]*X[c_y]+X[c_d]*X[c_z]+X[c_a]*X[c_sq] 471 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 472 | return H,r 473 | H0,r0 = __sphere(c_v,c_squ[:numv]) 474 | H1,r1 = __sphere(c_cen1,c_squ[numv:2*numv]) 475 | H2,r2 = __sphere(c_cen2,c_squ[2*numv:3*numv]) 476 | H3,r3 = __sphere(c_cen3,c_squ[3*numv:4*numv]) 477 | H4,r4 = __sphere(c_cen4,c_squ[4*numv:]) 478 | H = sparse.vstack((H0,H1,H2,H3,H4)) 479 | r = np.r_[r0,r1,r2,r3,r4] 480 | return H,r 481 | 482 | def _con_const_radius(c_a,c_r): 483 | "2*ai * r = 1 == df" 484 | c_rr = np.tile(c_r, numv) 485 | row = np.tile(arr1,2) 486 | col = np.r_[c_a, c_rr] 487 | data = np.r_[X[c_rr], X[c_a]] 488 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 489 | r = X[c_rr] * X[c_a] + 0.5*np.ones(numv) 490 | return H,r 491 | 492 | def _con_orient(c_n,c_o): 493 | "n0x*nx+n0y*ny+n0z*nz-x_orient^2 = 0" 494 | row = np.tile(arr1,4) 495 | col = np.r_[c_n, c_o] 496 | data = np.r_[orientrn.flatten('F'), -2*X[c_o]] 497 | r = -X[c_o]**2 498 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 499 | return H,r 500 | 501 | def _con_unit_normal(c_n): 502 | cen = -np.c_[X[c_b]/X[c_a],X[c_c]/X[c_a],X[c_d]/X[c_a]]/2 503 | rad1 = np.linalg.norm(cen-X[c_v].reshape(-1,3,order='F'),axis=1) 504 | rad2 = np.linalg.norm(cen-X[c_cen1].reshape(-1,3,order='F'),axis=1) 505 | rad3 = np.linalg.norm(cen-X[c_cen2].reshape(-1,3,order='F'),axis=1) 506 | rad4 = np.linalg.norm(cen-X[c_cen3].reshape(-1,3,order='F'),axis=1) 507 | rad5 = np.linalg.norm(cen-X[c_cen4].reshape(-1,3,order='F'),axis=1) 508 | radii = (rad1+rad2+rad3+rad4+rad5)/5 509 | 510 | def _normal(c_a,c_b,c_anx,c_nx): 511 | row = np.tile(np.arange(numv),4) 512 | col = np.r_[c_a,c_b,c_anx,c_nx] 513 | one = np.ones(numv) 514 | data = np.r_[2*(radii*X[c_nx]+X[c_anx]),one,2*X[c_a],2*radii*X[c_a]] 515 | r = 2*X[c_a]*(radii*X[c_nx]+X[c_anx]) 516 | H = sparse.coo_matrix((data,(row,col)), shape=(numv, N)) 517 | return H,r 518 | Hb,rb = _normal(c_a,c_b,c_v[:numv],c_n[:numv]) 519 | Hc,rc = _normal(c_a,c_c,c_v[numv:2*numv],c_n[numv:2*numv]) 520 | Hd,rd = _normal(c_a,c_d,c_v[2*numv:],c_n[2*numv:]) 521 | Hn,rn = con_unit(X,c_n) 522 | H = sparse.vstack((Hb, Hc, Hd, Hn)) 523 | r = np.r_[rb, rc, rd, rn] 524 | return H,r 525 | 526 | H0,r0 = _con_v_square(c_v,c_cen,c_squ) 527 | H1,r1 = _con_pos_a(c_a,c_a_sqr) 528 | Hn,rn = _con_sphere_normalization(c_a,c_b,c_c,c_d,c_e) 529 | Hs,rs = _con_sphere(c_v,c_cen,c_squ,c_a,c_b,c_c,c_d,c_e) 530 | H = sparse.vstack((H0,H1,Hn,Hs)) 531 | r = np.r_[r0,r1,rn,rs] 532 | 533 | if kwargs.get('Snet_orient'): 534 | w1 = kwargs.get('Snet_orient') 535 | Ns_n = kwargs.get('Ns_n') 536 | c_n = Ns_n-4*numv+arr3 537 | c_n_sqr = Ns_n-numv+arr1 538 | Ho,ro = _con_orient(c_n,c_n_sqr) 539 | H = sparse.vstack((H, Ho * w1)) 540 | r = np.r_[r, ro * w1] 541 | ##c 542 | if kwargs.get('Snet_constR'): 543 | w2 = kwargs.get('Snet_constR') 544 | Ns_r = kwargs.get('Ns_r') 545 | c_r = np.array([Ns_r-1],dtype=int) 546 | Hr,rr = _con_const_radius(c_a,c_r) 547 | H = sparse.vstack((H, Hr * w2)) 548 | r = np.r_[r, rr * w2] 549 | 550 | return H*w,r*w 551 | 552 | #-------------------------------------------------------------------------- 553 | # Multi-nets: 554 | # 555 | #-------------------------------------------------------------------------- 556 | def con_multinets_orthogonal(**kwargs): 557 | "(v1-v3)^2=(v2-v4)^2" 558 | # info_from_GetDiagonals_MMesh = MMesh() 559 | # Halfedge_1_NextNext,Halfedge_1_Prev,Halfedge_2_NextNext,Halfedge_2_Prev=info_from_GetDiagonals_MMesh.Get_Diagonals_of_Multinets() 560 | mesh = kwargs.get('mesh') 561 | # _,_,Halfedge_1_NextNext,Halfedge_1_Prev,Halfedge_2_NextNext,Halfedge_2_Prev=mesh.Get_Diagonals_of_Multinets() 562 | H=mesh.halfedges 563 | number_of_halfedges = len(H[:,0]) 564 | Bool_List = mesh.Bool_SequenceNumber 565 | Halfedge_1_NextNext = np.array([0]) 566 | Halfedge_1_Prev = np.array([0]) 567 | Halfedge_2_NextNext = np.array([0]) 568 | Halfedge_2_Prev = np.array([0]) 569 | # a=V[[H[H[H[1,2],2],0]]] 570 | # print(a) 571 | for i in range(number_of_halfedges) : 572 | if Bool_List[i] == 1: 573 | Halfedge_1_NextNext = np.r_[Halfedge_1_NextNext,[H[H[H[i,2],2],0]]] 574 | Halfedge_1_Prev = np.r_[Halfedge_1_Prev,[H[H[i,3],0]]] 575 | Halfedge_2_NextNext = np.r_[Halfedge_2_NextNext,[H[H[H[H[i,4],2],2],0]]] 576 | Halfedge_2_Prev = np.r_[Halfedge_2_Prev,[H[H[H[i,4],3],0]]] 577 | Halfedge_1_NextNext = np.delete(Halfedge_1_NextNext,0,axis=0) 578 | Halfedge_1_Prev = np.delete(Halfedge_1_Prev,0,axis=0) 579 | Halfedge_2_NextNext = np.delete(Halfedge_2_NextNext,0,axis=0) 580 | Halfedge_2_Prev = np.delete(Halfedge_2_Prev,0,axis=0) 581 | # number_of_points = len(H[:,0]) 582 | c1 = column3D(Halfedge_1_NextNext,0,mesh.V) 583 | c2 = column3D(Halfedge_1_Prev,0,mesh.V) 584 | c3 = column3D(Halfedge_2_NextNext,0,mesh.V) 585 | c4 = column3D(Halfedge_2_Prev,0,mesh.V) 586 | X = kwargs.get('X') 587 | w=kwargs.get('multinets_orthogonal') 588 | H,r = con_equal_length(X, c1, c2, c3, c4,) 589 | return H*w,r*w -------------------------------------------------------------------------------- /archgeolab/guidedprojection_orthonet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Dec 18 22:16:21 2022 4 | 5 | @author: WANGH0M 6 | """ 7 | __author__ = 'Hui' 8 | #------------------------------------------------------------------------------ 9 | import numpy as np 10 | 11 | # ----------------------------------------------------------------------------- 12 | from geometrylab.optimization.guidedprojectionbase import GuidedProjectionBase 13 | 14 | from archgeolab.constraints.constraints_basic import con_planarity_constraints 15 | 16 | from archgeolab.constraints.constraints_fairness import con_fairness_4th_different_polylines 17 | 18 | from archgeolab.constraints.constraints_net import con_unit_edge,\ 19 | con_orthogonal_midline,con_anet,con_anet_diagnet,con_snet,\ 20 | con_snet_diagnet,con_multinets_orthogonal 21 | 22 | from archgeolab.constraints.constraints_glide import con_glide_in_plane,\ 23 | con_alignment,con_alignments,con_selected_vertices_glide_in_one_plane,\ 24 | con_fix_vertices,con_sharp_corner 25 | 26 | from archgeolab.constraints.constraints_equilibrium import edge_length_constraints,\ 27 | equilibrium_constraints,compression_constraints,area_constraints,\ 28 | vector_area_constraints,\ 29 | boundary_densities_constraints,fixed_boundary_normals_constraints 30 | 31 | from archgeolab.archgeometry.conicSection import interpolate_sphere 32 | 33 | # ----------------------------------------------------------------------------- 34 | 35 | # ----------------------------------------------------------------------------- 36 | 37 | class GP_OrthoNet(GuidedProjectionBase): 38 | _N1 = 0 39 | 40 | _N2 = 0 41 | 42 | _N3 = 0 43 | 44 | _N4 = 0 45 | 46 | _N5 = 0 47 | 48 | _compression = 0 49 | 50 | _mesh = None 51 | 52 | _Nanet = 0 53 | _Nsnet,_Ns_n,_Ns_r = 0,0,0 54 | _Nsdnet = 0 55 | 56 | def __init__(self): 57 | GuidedProjectionBase.__init__(self) 58 | 59 | weights = { 60 | 61 | 'fairness_4diff' :0, 62 | 'fairness_diag_4diff' :0, 63 | 64 | 'boundary_glide' :0, #Hui in gpbase.py doesn't work, replace here. 65 | 'i_boundary_glide' :0, 66 | 'boundary_z0' :0, 67 | 'sharp_corner' : 0, 68 | 'z0' : 0, 69 | 70 | 'unit_edge_vec' : 0, ## [ei, li] 71 | 'unit_diag_edge_vec' : 0, 72 | 73 | 'planarity' : 0, 74 | 75 | 'orthogonal' :0, 76 | 77 | 'Anet' : 0, 78 | 'Anet_diagnet' : 0, 79 | 80 | 'Snet' : 0, 81 | 'Snet_diagnet' : 0, 82 | 'Snet_orient' : 1, 83 | 'Snet_constR' : 0, 84 | 85 | 86 | ##Note: below from geometrylab/optimization/Guidedprojection.py: 87 | 'normal' : 0, #no use, replaced Davide's planarity way 88 | 89 | 'edge_length' : 0, 90 | 91 | 'area' : 0, 92 | 93 | 'geometric' : 1, #default is True, used in constraints_equilibrium.py 94 | 95 | 'fixed_vertices' : 1, 96 | 97 | 'fixed_corners' : 0, 98 | 99 | 'gliding' : 0, # Huinote: glide on boundary, used for itself boundary 100 | 101 | 'equilibrium' : 0, 102 | 103 | 'multinets_orthogonal' : 0, 104 | 105 | 'fixed_boundary_normals': 0, 106 | 107 | } 108 | 109 | self.add_weights(weights) 110 | 111 | self.switch_diagmeth = False 112 | 113 | self.is_initial = True 114 | 115 | self._glide_reference_polyline = None 116 | self.i_glide_bdry_crv, self.i_glide_bdry_ver = [],[] 117 | self.assign_coordinates = None 118 | 119 | self.if_uniqradius = False 120 | self.assigned_snet_radius = 0 121 | 122 | #-------------------------------------------------------------------------- 123 | # 124 | #-------------------------------------------------------------------------- 125 | 126 | @property 127 | def mesh(self): 128 | return self._mesh 129 | 130 | @mesh.setter 131 | def mesh(self, mesh): 132 | self._mesh = mesh 133 | self.initialization() 134 | 135 | @property 136 | def compression(self): 137 | return self._compression 138 | 139 | @compression.setter 140 | def compression(self, bool): 141 | if bool: 142 | self._compression = 2*self.get_weight('equilibrium') 143 | self.reinitialize = True 144 | elif self._compression > 0: 145 | self._compression = 0 146 | 147 | @property 148 | def tension(self): 149 | return -self._compression 150 | 151 | @tension.setter 152 | def tension(self, bool): 153 | if bool: 154 | self._compression = -2*self.get_weight('equilibrium') 155 | self.reinitialize = True 156 | elif self._compression < 0: 157 | self._compression = 0 158 | 159 | @property 160 | def max_weight(self): 161 | return max(self.get_weight('geometric'), 162 | self.get_weight('equilibrium'), 163 | self.get_weight('boundary_glide'), 164 | self.get_weight('planarity'), 165 | 166 | self.get_weight('multinets_orthogonal'), 167 | 168 | self.get_weight('unit_edge_vec'), 169 | self.get_weight('unit_diag_edge_vec'), 170 | 171 | self.get_weight('orthogonal'), 172 | 173 | self.get_weight('Anet'), 174 | self.get_weight('Anet_diagnet'), 175 | 176 | self.get_weight('Snet'), 177 | self.get_weight('Snet_diagnet'), 178 | 179 | 1) 180 | @property 181 | def angle(self): 182 | return self._angle 183 | 184 | @angle.setter 185 | def angle(self,angle): 186 | if angle != self._angle: 187 | self.mesh.angle=angle 188 | self._angle = angle 189 | 190 | @property 191 | def glide_reference_polyline(self): 192 | if self._glide_reference_polyline is None: 193 | #polylines = self.mesh.boundary_polylines() #Hui note: problem for boundary_polylines() 194 | polylines = self.mesh.boundary_curves(corner_split=False)[0] 195 | ##print(polylines) 196 | 197 | N = 5 198 | try: 199 | for polyline in polylines: 200 | polyline.refine(N) 201 | except: 202 | ###Add below for closed 1 boundary of reference mesh 203 | from geometrylab.geometry import Polyline 204 | polyline = Polyline(self.mesh.vertices[polylines],closed=True) 205 | polyline.refine(N) 206 | 207 | self._glide_reference_polyline = polyline 208 | return self._glide_reference_polyline 209 | 210 | @glide_reference_polyline.setter 211 | def glide_reference_polyline(self,polyline): 212 | self._glide_reference_polyline = polyline 213 | 214 | #-------------------------------------------------------------------------- 215 | # Initialization 216 | #-------------------------------------------------------------------------- 217 | 218 | def set_weights(self): 219 | if self.get_weight('equilibrium') != 0: 220 | if self.mesh.area_load != 0: 221 | if self.get_weight('area') == 0: 222 | self.set_weight('area', 1 * self.get_weight('equilibrium')) 223 | else: 224 | self.set_weight('area', 0) 225 | if self.reinitialize: 226 | if self.get_weight('equilibrium') != 0: 227 | self.set_weight('edge_length', 1 * self.get_weight('equilibrium')) 228 | if self.mesh.area_load != 0: 229 | self.set_weight('area', 1*self.get_weight('equilibrium')) 230 | if self.get_weight('planarity') != 0: 231 | self.set_weight('normal', 1*self.get_weight('planarity')) 232 | self.set_weight('fixed_vertices', 10 * self.max_weight) 233 | self.set_weight('gliding', 10 * self.max_weight) 234 | if self.get_weight('fixed_corners') != 0: 235 | self.set_weight('fixed_corners', 10 * self.max_weight) 236 | if self.get_weight('fixed_boundary_normals') != 0: 237 | self.set_weight('fixed_boundary_normals', 10 * self.max_weight) 238 | 239 | 240 | def set_dimensions(self): # Huinote: be used in guidedprojectionbase 241 | "X:= [Vx,Vy,Vz]" 242 | V = self.mesh.V 243 | F = self.mesh.F 244 | E = self.mesh.E 245 | N = 3*V 246 | N1 = N2 = N3 = N4 = N5 = N 247 | num_regular = self.mesh.num_regular 248 | 249 | Nanet = N 250 | Nsnet = Ns_n = Ns_r = N 251 | 252 | #--------------------------------------------- 253 | if self.get_weight('planarity') != 0: 254 | "X += [Nx,Ny,Nz]" 255 | N += 3*F 256 | N1 = N2 = N3 = N4 = N 257 | if self.get_weight('equilibrium') != 0: 258 | "X += [edge_length, force_density, sqrt_force_density]" 259 | N += 3*E 260 | N2 = N3 = N4 = N 261 | if self.get_weight('area') != 0: 262 | "X += [Ax,Ay,Az, area]" 263 | N += 4*F 264 | N3 = N4 = N 265 | 266 | if self.get_weight('unit_edge_vec'): #Gnet, AGnet 267 | "X+=[le1,le2,le3,le4,ue1,ue2,ue3,ue4]" 268 | if self.get_weight('isogonal'): 269 | N += 16*num_regular 270 | else: 271 | "for Anet, AGnet, DGPC" 272 | N += 16*self.mesh.num_rrv4f4 273 | N5 = N 274 | elif self.get_weight('unit_diag_edge_vec'): #Gnet_diagnet 275 | "le1,le2,le3,le4,ue1,ue2,ue3,ue4 " 276 | N += 16*self.mesh.num_rrv4f4 277 | N5 = N 278 | 279 | if self.get_weight('Anet') or self.get_weight('Anet_diagnet'): 280 | N += 3*self.mesh.num_rrv4f4#3*num_regular 281 | Nanet = N 282 | 283 | 284 | ### Snet(_diag) project: 285 | if self.get_weight('Snet') or self.get_weight('Snet_diagnet'): 286 | num_snet = self.mesh.num_rrv4f4 287 | N += 11*num_snet 288 | Nsnet = N 289 | if self.get_weight('Snet_orient'): 290 | N +=4*num_snet 291 | Ns_n = N 292 | if self.get_weight('Snet_constR'): 293 | N += 1 294 | Ns_r = N 295 | 296 | #--------------------------------------------- 297 | if N1 != self._N1 or N2 != self._N2: 298 | self.reinitialize = True 299 | if N3 != self._N3 or N4 != self._N4: 300 | self.reinitialize = True 301 | if self._N2 - self._N1 == 0 and N2 - N1 > 0: 302 | self.mesh.reinitialize_densities() 303 | 304 | if N5 != self._N5: 305 | self.reinitialize = True 306 | if Nanet != self._Nanet: 307 | self.reinitialize = True 308 | if Nsnet != self._Nsnet: 309 | self.reinitialize = True 310 | if Ns_n != self._Ns_n: 311 | self.reinitialize = True 312 | if Ns_r != self._Ns_r: 313 | self.reinitialize = True 314 | 315 | #---------------------------------------------- 316 | self._N = N 317 | self._N1 = N1 318 | self._N2 = N2 319 | self._N3 = N3 320 | self._N4 = N4 321 | self._N5 = N5 322 | self._Nanet = Nanet 323 | self._Nsnet,self._Ns_n,self._Ns_r = Nsnet,Ns_n,Ns_r 324 | 325 | self.build_added_weight() # Hui add 326 | 327 | 328 | def initialize_unknowns_vector(self): 329 | "X:= [Vx,Vy,Vz]" 330 | X = self.mesh.vertices.flatten('F') 331 | if self.get_weight('planarity') != 0: 332 | "X += [Nx,Ny,Nz]; len=3F" 333 | normals = self.mesh.face_normals() 334 | X = np.hstack((X, normals.flatten('F'))) 335 | if self.get_weight('equilibrium') != 0: 336 | "X += [edge_length, force_density, sqrt_force_density]; len=3E" 337 | lengths = self.mesh.edge_lengths() 338 | W = self.mesh.force_densities 339 | X = np.hstack((X, lengths, W, np.abs(W)**0.5)) 340 | if self.get_weight('area') != 0: 341 | "X += [Ax,Ay,Az, area]; len=4F" 342 | vector_area = self.mesh.face_vector_areas() 343 | face_area = np.linalg.norm(vector_area, axis=1) 344 | vector_area = vector_area.flatten('F') 345 | X = np.hstack((X, vector_area, face_area)) 346 | 347 | if self.get_weight('unit_edge_vec'): 348 | _,l1,l2,l3,l4,E1,E2,E3,E4 = self.mesh.get_v4_unit_edge(rregular=True) 349 | X = np.r_[X,l1,l2,l3,l4] 350 | X = np.r_[X,E1.flatten('F'),E2.flatten('F'),E3.flatten('F'),E4.flatten('F')] 351 | 352 | elif self.get_weight('unit_diag_edge_vec'): 353 | _,l1,l2,l3,l4,E1,E2,E3,E4 = self.mesh.get_v4_diag_unit_edge() 354 | X = np.r_[X,l1,l2,l3,l4] 355 | X = np.r_[X,E1.flatten('F'),E2.flatten('F'),E3.flatten('F'),E4.flatten('F')] 356 | 357 | if self.get_weight('Anet') or self.get_weight('Anet_diagnet'): 358 | if self.get_weight('Anet'): 359 | if True: 360 | "only r-regular vertex" 361 | v = self.mesh.ver_rrv4f4 362 | else: 363 | v = self.mesh.ver_regular 364 | elif self.get_weight('Anet_diagnet'): 365 | v = self.mesh.rr_star_corner[0] 366 | V4N = self.mesh.vertex_normals()[v] 367 | X = np.r_[X,V4N.flatten('F')] 368 | 369 | ### Snet-project: 370 | if self.get_weight('Snet') or self.get_weight('Snet_diagnet'): 371 | r = self.get_weight('Snet_constR') 372 | is_diag = False if self.get_weight('Snet') else True 373 | x_snet,Nv4 = self.get_snet(r,is_diag) 374 | X = np.r_[X,x_snet] 375 | #----------------------- 376 | 377 | self._X = X 378 | self._X0 = np.copy(X) 379 | 380 | self.build_added_weight() # Hui add 381 | 382 | #-------------------------------------------------------------------------- 383 | # Getting (initilization + Plotting): 384 | #-------------------------------------------------------------------------- 385 | 386 | def get_snet(self,is_r,is_diag=False,is_orient=True): 387 | """ 388 | each vertex has one [a,b,c,d,e] for sphere equation: 389 | f=a(x^2+y^2+z^2)+(bx+cy+dz)+e=0 390 | when a=0; plane equation 391 | (x-x0)^2+(y-y0)^2+(z-z0)^2=R^2 392 | M = (x0,y0,z0)=-(b,c,d)/2a 393 | R^2 = (b^2+c^2+d^2-4ae)/4a^2 394 | unit_sphere_normal==-(2*A*Vx+B, 2*A*Vy+C, 2*A*Vz+D), 395 | (note direction: from vertex to center) 396 | 397 | X += [V^2,A,B,C,D,E,a_sqrt] 398 | if orient: 399 | X += [n4,n4_sqrt], n4=-[2ax+b,2ay+c,2az+d] 400 | if r: 401 | X += [r] 402 | if angle 403 | X += [l1,l2,l3,l4,ue1,ue2,ue3,ue4] 404 | """ 405 | V = self.mesh.vertices 406 | if is_diag: 407 | s0,s1,s2,s3,s4 = self.mesh.rr_star_corner 408 | else: 409 | s0,s1,s2,s3,s4 = self.mesh.rrv4f4 410 | S0,S1,S2,S3,S4 = V[s0],V[s1],V[s2],V[s3],V[s4] 411 | centers,radius,coeff,Nv4 = interpolate_sphere(S0,S1,S2,S3,S4) 412 | VV = np.linalg.norm(np.vstack((S0,S1,S2,S3,S4)),axis=1)**2 413 | A,B,C,D,E = coeff.reshape(5,-1) 414 | A_sqrt = np.sqrt(A) 415 | XA = np.r_[VV,A,B,C,D,E,A_sqrt] 416 | if is_orient: ##always True 417 | B,C,D,Nv4,n4_sqrt = self.mesh.orient(S0,A,B,C,D,Nv4) 418 | XA = np.r_[VV,A,B,C,D,E,A_sqrt] 419 | XA = np.r_[XA, Nv4.flatten('F'),n4_sqrt] 420 | if is_r: 421 | r = np.mean(radius) 422 | XA = np.r_[XA,r] 423 | return XA, Nv4 424 | 425 | def get_snet_data(self,is_diag=False, ##note: combine together suitable for diagonal 426 | center=False,normal=False,tangent=False,ss=False, 427 | is_diag_binormal=False): 428 | "at star = self.rr_star" 429 | V = self.mesh.vertices 430 | if is_diag: 431 | s0,s1,s2,s3,s4 = self.mesh.rr_star_corner 432 | else: 433 | s0,s1,s2,s3,s4 = self.mesh.rrv4f4 434 | 435 | S0,S1,S2,S3,S4 = V[s0],V[s1],V[s2],V[s3],V[s4] 436 | centers,r,coeff,Nv4 = interpolate_sphere(S0,S1,S2,S3,S4) 437 | if self.get_weight('Snet_orient'): 438 | A,B,C,D,E = coeff.reshape(5,-1) 439 | _,_,_,Nv4,_ = self.mesh.orient(S0,A,B,C,D,Nv4) 440 | #Nv4 = self.mesh.get_v4_orient_unit_normal()[1][self.mesh.ind_rr_star_v4f4] 441 | centers = S0+r[:,None]*Nv4 442 | if center: 443 | er0 = np.abs(np.linalg.norm(S0-centers,axis=1)-r) 444 | er1 = np.abs(np.linalg.norm(S1-centers,axis=1)-r) 445 | er2 = np.abs(np.linalg.norm(S2-centers,axis=1)-r) 446 | er3 = np.abs(np.linalg.norm(S3-centers,axis=1)-r) 447 | er4 = np.abs(np.linalg.norm(S4-centers,axis=1)-r) 448 | #err = (er0+er1+er2+er3+er4) / 5 449 | err = np.sqrt(er0**2+er1**2+er2**2+er3**2+er4**2)/r 450 | print('radii:[min,mean,max]=','%.3f'%np.min(r),'%.3f'%np.mean(r),'%.3f'%np.max(r)) 451 | print('Err:[min,mean,max]=','%.3g'%np.min(err),'%.3g'%np.mean(err),'%.3g'%np.max(err)) 452 | return centers,err 453 | elif normal: 454 | # n = np.cross(C3-C1,C4-C2) 455 | #n = S0-centers 456 | n = Nv4 457 | un = n / np.linalg.norm(n,axis=1)[:,None] 458 | return S0,un 459 | elif is_diag_binormal: 460 | "only work for SSG/GSS/SSGG/GGSS-project, not for general Snet" 461 | n = Nv4 462 | un = n / np.linalg.norm(n,axis=1)[:,None] 463 | if is_diag: 464 | _,sa,sb,sc,sd = self.mesh.rrv4f4 465 | else: 466 | _,sa,sb,sc,sd = self.mesh.rr_star_corner 467 | t1 = (V[sa]-V[sc])/np.linalg.norm(V[sa]-V[sc], axis=1)[:,None] 468 | t2 = (V[sb]-V[sd])/np.linalg.norm(V[sb]-V[sd], axis=1)[:,None] 469 | "note works for SSG..case, since un,sa-v,sc are coplanar" 470 | bin1 = np.cross(un, t1) 471 | bin2 = np.cross(un, t2) 472 | bin1 = bin1 / np.linalg.norm(bin1, axis=1)[:,None] 473 | bin2 = bin2 / np.linalg.norm(bin2, axis=1)[:,None] 474 | return S0, bin1, bin2 475 | elif tangent: 476 | inn,_ = self.mesh.get_rr_vs_bounary() 477 | V0,V1,V2,V3,V4 = S0[inn],S1[inn],S2[inn],S3[inn],S4[inn] 478 | l1 = np.linalg.norm(V1-V0,axis=1) 479 | l2 = np.linalg.norm(V2-V0,axis=1) 480 | l3 = np.linalg.norm(V3-V0,axis=1) 481 | l4 = np.linalg.norm(V4-V0,axis=1) 482 | t1 = (V1-V0)*(l3**2)[:,None] - (V3-V0)*(l1**2)[:,None] 483 | t1 = t1 / np.linalg.norm(t1,axis=1)[:,None] 484 | t2 = (V2-V0)*(l4**2)[:,None] - (V4-V0)*(l2**2)[:,None] 485 | t2 = t2 / np.linalg.norm(t2,axis=1)[:,None] 486 | return V0,t1,t2 487 | elif ss: 488 | n = Nv4 489 | un = n / np.linalg.norm(n,axis=1)[:,None] 490 | return s0,un 491 | return S0,S1,S2,S3,S4,centers,r,coeff,Nv4 492 | 493 | # ------------------------------------------------------------------------- 494 | # Build 495 | # ------------------------------------------------------------------------- 496 | 497 | def build_iterative_constraints(self): 498 | self.build_added_weight() # Hui change 499 | 500 | H, r = self.mesh.iterative_constraints(**self.weights) ##NOTE: in gridshell.py 501 | self.add_iterative_constraint(H, r, 'mesh_iterative') 502 | 503 | H, r = self.mesh.fairness_energy(**self.weights) ##NOTE: in gridshell.py 504 | self.add_iterative_constraint(H, r, 'fairness') 505 | 506 | if self.get_weight('fairness_4diff'): 507 | pl1,pl2 = self.mesh.all_rr_continuous_polylist 508 | pl1.extend(pl2) 509 | H,r = con_fairness_4th_different_polylines(pl1,**self.weights) 510 | self.add_iterative_constraint(H, r, 'fairness_4diff') 511 | if self.get_weight('fairness_diag_4diff'): 512 | pl1 = self.mesh.all_rr_diag_polylist[0][0] 513 | pl2 = self.mesh.all_rr_diag_polylist[1][0] 514 | pl1.extend(pl2) 515 | H,r = con_fairness_4th_different_polylines(pl1,diag=True,**self.weights) 516 | self.add_iterative_constraint(H, r, 'fairness_diag_4diff') 517 | 518 | if self.get_weight('planarity'): 519 | #"use Hui's way not Davide's" 520 | H,r = con_planarity_constraints(**self.weights) 521 | self.add_iterative_constraint(H, r, 'planarity') 522 | 523 | if self.get_weight('equilibrium') != 0: 524 | H,r = edge_length_constraints(**self.weights) 525 | self.add_iterative_constraint(H, r, 'edge_length') 526 | H,r = equilibrium_constraints(**self.weights) 527 | self.add_iterative_constraint(H, r,'equilibrium') 528 | 529 | if self.compression != 0 and self.get_weight('equilibrium') != 0: 530 | H,r = compression_constraints(self.compression,**self.weights) 531 | self.add_iterative_constraint(H, r, 'compression') 532 | 533 | if self.get_weight('area') != 0: 534 | H,r = area_constraints(**self.weights) 535 | self.add_iterative_constraint(H, r, 'face_vector_area') 536 | H,r = vector_area_constraints(**self.weights) 537 | self.add_iterative_constraint(H, r, 'face_area') 538 | 539 | if self.get_weight('multinets_orthogonal') !=0: 540 | H,r = con_multinets_orthogonal(**self.weights) 541 | self.add_iterative_constraint(H, r,'multinets_orthogonal') 542 | 543 | ###-------partially shared-used codes:--------------------------------- 544 | if self.get_weight('unit_edge_vec'): 545 | H,r = con_unit_edge(rregular=True,**self.weights) 546 | self.add_iterative_constraint(H, r, 'unit_edge') 547 | elif self.get_weight('unit_diag_edge_vec'): 548 | H,r = con_unit_edge(rregular=True,**self.weights) 549 | self.add_iterative_constraint(H, r, 'unit_diag_edge_vec') 550 | 551 | if self.get_weight('boundary_z0') !=0: 552 | z = 0 553 | v = np.array([816,792,768,744,720,696,672,648,624,600,576,552,528,504,480,456,432,408,384,360,336,312,288,264,240,216,192,168,144,120,96,72,48,24,0],dtype=int) 554 | H,r = con_selected_vertices_glide_in_one_plane(v,2,z,**self.weights) 555 | self.add_iterative_constraint(H, r, 'boundary_z0') 556 | 557 | if self.assign_coordinates is not None: 558 | index,Vf = self.assign_coordinates 559 | H,r = con_fix_vertices(index, Vf.flatten('F'),**self.weights) 560 | self.add_iterative_constraint(H, r, 'fix_pts') 561 | 562 | if self.get_weight('boundary_glide'): 563 | "the whole boundary" 564 | refPoly = self.glide_reference_polyline 565 | glideInd = self.mesh.boundary_curves(corner_split=False)[0] 566 | w = self.get_weight('boundary_glide') 567 | H,r = con_alignment(w, refPoly, glideInd,**self.weights) 568 | self.add_iterative_constraint(H, r, 'boundary_glide') 569 | elif self.get_weight('i_boundary_glide'): 570 | "the i-th boundary" 571 | refPoly = self.i_glide_bdry_crv 572 | glideInd = self.i_glide_bdry_ver 573 | if len(glideInd)!=0: 574 | w = self.get_weight('i_boundary_glide') 575 | H,r = con_alignments(w, refPoly, glideInd,**self.weights) 576 | self.add_iterative_constraint(H, r, 'iboundary_glide') 577 | 578 | if self.get_weight('sharp_corner'): 579 | H,r = con_sharp_corner(move=0,**self.weights) 580 | self.add_iterative_constraint(H,r, 'sharp_corner') 581 | 582 | if self.get_weight('orthogonal'): 583 | H,r = con_orthogonal_midline(**self.weights) 584 | self.add_iterative_constraint(H, r, 'orthogonal') 585 | 586 | if self.get_weight('z0') !=0: 587 | H,r = con_glide_in_plane(2,**self.weights) 588 | self.add_iterative_constraint(H,r, 'z0') 589 | 590 | if self.get_weight('Anet'): 591 | H,r = con_anet(rregular=True,**self.weights) 592 | self.add_iterative_constraint(H, r, 'Anet') 593 | elif self.get_weight('Anet_diagnet'): 594 | H,r = con_anet_diagnet(**self.weights) 595 | self.add_iterative_constraint(H, r, 'Anet_diagnet') 596 | 597 | if self.get_weight('Snet'): 598 | orientrn = self.mesh.new_vertex_normals() 599 | H,r = con_snet(orientrn, 600 | is_uniqR=self.if_uniqradius, 601 | assigned_r=self.assigned_snet_radius, 602 | **self.weights) 603 | self.add_iterative_constraint(H, r, 'Snet') 604 | elif self.get_weight('Snet_diagnet'): 605 | if 1: 606 | "SSG-PROJECT" 607 | orientrn = self.mesh.new_vertex_normals() 608 | H,r = con_snet(orientrn,is_diagmesh=True, 609 | is_uniqR=self.if_uniqradius, 610 | assigned_r=self.assigned_snet_radius, 611 | **self.weights) 612 | else: 613 | "CRPC-project" 614 | H,r = con_snet_diagnet(**self.weights) 615 | self.add_iterative_constraint(H, r, 'Snet_diag') 616 | 617 | ###-------------------------------------------------------------------- 618 | 619 | self.is_initial = False 620 | 621 | #print('-'*10) 622 | print(' Err_total: = ','%.3e' % np.sum(np.square(self._H*self.X-self._r))) 623 | #print('-'*10) 624 | 625 | def build_added_weight(self): # Hui add 626 | self.add_weight('mesh', self.mesh) 627 | self.add_weight('N', self.N) 628 | self.add_weight('X', self.X) 629 | self.add_weight('N1', self._N1) 630 | self.add_weight('N2', self._N2) 631 | self.add_weight('N3', self._N3) 632 | self.add_weight('N4', self._N4) 633 | self.add_weight('N5', self._N5) 634 | self.add_weight('Nanet', self._Nanet) 635 | self.add_weight('Nsnet', self._Nsnet) 636 | self.add_weight('Ns_n', self._Ns_n) 637 | self.add_weight('Ns_r', self._Ns_r) 638 | 639 | def values_from_each_iteration(self,**kwargs): 640 | if kwargs.get('unit_edge_vec'): 641 | if True: 642 | rr=True 643 | _,l1,l2,l3,l4,_,_,_,_ = self.mesh.get_v4_unit_edge(rregular=rr) 644 | Xi = np.r_[l1,l2,l3,l4] 645 | return Xi 646 | 647 | if kwargs.get('unit_diag_edge_vec'): 648 | _,l1,l2,l3,l4,_,_,_,_ = self.mesh.get_v4_diag_unit_edge() 649 | Xi = np.r_[l1,l2,l3,l4] 650 | return Xi 651 | 652 | def build_constant_constraints(self): #copy from guidedprojection,need to check if it works 653 | self.add_weight('N', self.N) 654 | H, r = self.mesh.constant_constraints(**self.weights) 655 | self.add_constant_constraint(H, r, 'mesh_constant') 656 | if self.get_weight('equilibrium') > 0: 657 | boundary_densities_constraints(**self.weights) 658 | if self.get_weight('fixed_boundary_normals') > 0: 659 | fixed_boundary_normals_constraints(**self.weights) 660 | 661 | def build_constant_fairness(self): #copy from guidedprojection,need to check if it works 662 | self.add_weight('N', self.N) 663 | K, s = self.mesh.fairness_energy(**self.weights) 664 | self.add_constant_fairness(K, s) 665 | 666 | def post_iteration_update(self): #copy from guidedprojection,need to check if it works 667 | V = self.mesh.V 668 | E = self.mesh.E 669 | N1 = self._N1 670 | self.mesh.vertices[:,0] = self.X[0:V] 671 | self.mesh.vertices[:,1] = self.X[V:2*V] 672 | self.mesh.vertices[:,2] = self.X[2*V:3*V] 673 | if self.get_weight('equilibrium')!= 0: 674 | self.mesh.force_densities = self.X[N1+E:N1+2*E] 675 | else: 676 | self.mesh.force_densities = np.zeros(self.mesh.E) 677 | 678 | def on_reinitilize(self): #copy from guidedprojection,need to check if it works 679 | self.mesh.reinitialize_force_densities() 680 | #-------------------------------------------------------------------------- 681 | # Results 682 | #-------------------------------------------------------------------------- 683 | 684 | def vertices(self): 685 | V = self.mesh.V 686 | vertices = self.X[0:3*V] 687 | vertices = np.reshape(vertices, (V,3), order='F') 688 | return vertices 689 | 690 | def edge_lengths(self, initialized=False): 691 | if self.get_weight('equilibrium') == 0: 692 | return None 693 | if initialized: 694 | X = self._X0 695 | else: 696 | X = self.X 697 | E = self.mesh.E 698 | N1 = self._N1 699 | return X[N1:N1+E] 700 | 701 | def face_normals(self, initialized=False): 702 | if self.get_weight('planarity') == 0: 703 | return None 704 | if initialized: 705 | X = self._X0 706 | else: 707 | X = self.X 708 | V = self.mesh.V 709 | F = self.mesh.F 710 | normals = X[3*V:3*V+3*F] 711 | normals = np.reshape(normals, (F,3), order='F') 712 | return normals 713 | 714 | def face_vector_areas(self, initialized=False): 715 | if self.get_weight('area') == 0: 716 | return None 717 | if initialized: 718 | X = self._X0 719 | else: 720 | X = self.X 721 | F = self.mesh.F 722 | N2 = self._N2 723 | areas = X[N2:N2+3*F] 724 | areas = np.reshape(areas, (F,3), order='F') 725 | return areas 726 | 727 | def face_areas(self, initialized=False): 728 | if self.get_weight('area') == 0: 729 | return None 730 | if initialized: 731 | X = self._X0 732 | else: 733 | X = self.X 734 | F = self.mesh.F 735 | N2 = self._N2 736 | areas = X[N2+3*F:N2+4*F] 737 | return areas 738 | 739 | def force_densities(self): 740 | if self.get_weight('equilibrium') == 0: 741 | return None 742 | E = self.mesh.E 743 | N1 = self._N1 744 | return self.X[N1+E:N1+2*E] 745 | 746 | #-------------------------------------------------------------------------- 747 | # Errors strings 748 | #-------------------------------------------------------------------------- 749 | def make_errors(self): 750 | self.edge_length_error() 751 | self.equilibrium_error() 752 | self.face_areas_error() 753 | self.face_vector_areas_error() 754 | self.planarity_error() #self.face_normals_error() 755 | self.orthogonal_error() 756 | self.anet_error() 757 | #self.geometric_error() 758 | 759 | def planarity_error(self): 760 | if self.get_weight('planarity') == 0: 761 | return None 762 | P = self.mesh.face_planarity() 763 | emean = np.mean(P) 764 | emax = np.max(P) 765 | self.add_error('planarity', emean, emax, self.get_weight('planarity')) 766 | print('planarity:[mean,max]=','%.3g'%emean,'%.3g'%emax) 767 | 768 | def orthogonal_error(self): 769 | if self.get_weight('orthogonal') == 0: 770 | return None 771 | _,_,t1,t2,_ = self.mesh.get_quad_midpoint_cross_vectors() 772 | cos = np.einsum('ij,ij->i',t1,t2) 773 | cos0 = np.mean(cos) 774 | err = np.abs(cos-cos0) 775 | emean = np.mean(err) 776 | emax = np.max(err) 777 | self.add_error('orthogonal', emean, emax, self.get_weight('orthogonal')) 778 | print('orthogonal:[mean,max]=','%.3g'%emean,'%.3g'%emax) 779 | 780 | def anet_error(self): 781 | if self.get_weight('Anet') == 0 and self.get_weight('Anet_diagnet')==0: 782 | return None 783 | if self.get_weight('Anet'): 784 | name = 'Anet' 785 | v,v1,v2,v3,v4 = self.mesh.rrv4f4 786 | elif self.get_weight('Anet_diagnet'): 787 | name = 'Anet_diagnet' 788 | v,v1,v2,v3,v4 = self.mesh.rr_star_corner 789 | 790 | if self.is_initial: 791 | Nv = self.mesh.vertex_normals()[v] 792 | else: 793 | num = len(v) 794 | c_n = self._Nanet-3*num+np.arange(3*num) 795 | Nv = self.X[c_n].reshape(-1,3,order='F') 796 | V = self.mesh.vertices 797 | err1 = np.abs(np.einsum('ij,ij->i',Nv,V[v1]-V[v])) 798 | err2 = np.abs(np.einsum('ij,ij->i',Nv,V[v2]-V[v])) 799 | err3 = np.abs(np.einsum('ij,ij->i',Nv,V[v3]-V[v])) 800 | err4 = np.abs(np.einsum('ij,ij->i',Nv,V[v4]-V[v])) 801 | Err = err1+err2+err3+err4 802 | emean = np.mean(Err) 803 | emax = np.max(Err) 804 | self.add_error(name, emean, emax, self.get_weight(name)) 805 | print('anet:[mean,max]=','%.3g'%emean,'%.3g'%emax) 806 | 807 | def face_normals_error(self): 808 | if self.get_weight('planarity') == 0: 809 | return None 810 | N = self.face_normals() 811 | N0 = self.face_normals(initialized=True) 812 | norm = np.mean(np.linalg.norm(N, axis=1)) 813 | Err = (np.linalg.norm(N-N0, axis=1)) / norm 814 | emean = np.mean(Err) 815 | emax = np.max(Err) 816 | self.add_error('face_normal', emean, emax, self.get_weight('normal')) 817 | print('planarity:[mean,max]=','%.3g'%emean,'%.3g'%emax) 818 | 819 | def edge_length_error(self): 820 | if self.get_weight('equilibrium') == 0: 821 | return None 822 | L = self.edge_lengths() 823 | L0 = self.edge_lengths(initialized=True) 824 | norm = np.mean(L) 825 | Err = np.abs(L-L0) / norm 826 | emean = np.mean(Err) 827 | emax = np.max(Err) 828 | self.add_error('edge_length', emean, emax, self.get_weight('edge_length')) 829 | print('edge_length:[mean,max]=','%.3g'%emean,'%.3g'%emax) 830 | 831 | def face_vector_areas_error(self): 832 | if self.get_weight('area') == 0: 833 | return None 834 | A = self.face_vector_areas() 835 | A0 = self.face_vector_areas(initialized=True) 836 | norm = np.mean(np.linalg.norm(A, axis=1)) 837 | Err = (np.linalg.norm(A-A0, axis=1)) / norm 838 | emean = np.mean(Err) 839 | emax = np.max(Err) 840 | self.add_error('face_vector_area', emean, emax, self.get_weight('area')) 841 | print('area_vector:[mean,max]=','%.3g'%emean,'%.3g'%emax) 842 | 843 | def face_areas_error(self): 844 | if self.get_weight('area') == 0: 845 | return None 846 | A = self.face_areas() 847 | A0 = self.face_areas(initialized=True) 848 | norm = np.mean(A) 849 | Err = (np.abs(A-A0)) / norm 850 | emean = np.mean(Err) 851 | emax = np.max(Err) 852 | self.add_error('face_area', emean, emax, self.get_weight('area')) 853 | print('area:[mean,max]=','%.3g'%emean,'%.3g'%emax) 854 | 855 | def equilibrium_error(self): 856 | if self.get_weight('equilibrium') == 0: 857 | return None 858 | Err = self.mesh.equilibrium_error() 859 | emean = np.mean(Err) 860 | emax = np.max(Err) 861 | self.add_error('equilibrium', emean, emax, self.get_weight('equilibrium')) 862 | print('equilibrium:[mean,max]=','%.3g'%emean,'%.3g'%emax) 863 | 864 | def geometric_error(self): 865 | if len(self._errors) == 0: 866 | return None 867 | n = 0 868 | geo_mean = 0 869 | geo_max = 0 870 | if self.get_weight('planarity') != 0: 871 | err = self.get_error('face_normal') 872 | geo_mean += err[0] 873 | geo_max = max([geo_max, err[1]]) 874 | n += 1 875 | if self.get_weight('equilibrium') != 0: 876 | err = self.get_error('edge_length') 877 | geo_mean += err[0] 878 | geo_max = max([geo_max, err[1]]) 879 | n += 1 880 | if self.get_weight('area') != 0: 881 | err = self.get_error('face_vector_area') 882 | geo_mean += err[0] 883 | geo_max = max([geo_max, err[1]]) 884 | err = self.get_error('face_area') 885 | geo_mean += err[0] 886 | geo_max = max([geo_max, err[1]]) 887 | n += 2 888 | if n > 0: 889 | geo_mean = geo_mean / n 890 | self.add_error('geometric', geo_mean, geo_mean, 891 | self.get_weight('geometric')) 892 | 893 | def geometric_error_string(self): 894 | return self.error_string('geometric') 895 | 896 | def equilibrium_error_string(self): 897 | return self.error_string('equilibrium') 898 | 899 | def planarity_error_string(self): 900 | return self.error_string('planarity') 901 | 902 | def orthogonal_error_string(self): 903 | return self.error_string('orthogonal') 904 | 905 | def anet_error_string(self): 906 | return self.error_string('Anet') 907 | 908 | #-------------------------------------------------------------------------- 909 | # Utilities 910 | #-------------------------------------------------------------------------- 911 | 912 | def axial_forces(self): 913 | if self.equilibrium != 0: 914 | return self.mesh.axial_forces() 915 | else: 916 | return np.zeros(self.mesh.E) 917 | 918 | def force_resultants(self): 919 | return self.mesh.force_resultants() 920 | 921 | def applied_loads(self): 922 | return self.mesh.applied_loads() 923 | -------------------------------------------------------------------------------- /archgeolab/readfile_orthonet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Dec 18 22:16:21 2022 4 | 5 | @author: WANGH0M 6 | """ 7 | 8 | # All rights reserved. 9 | # 10 | # This software is free for non-commercial, research and evaluation use 11 | # under the terms of the LICENSE.md file. 12 | # 13 | # For inquiries contact hui.wang.1@kaust.edu.sa 14 | 15 | #------------------------------------------------------------------------------ 16 | import os 17 | os.environ['KMP_DUPLICATE_LIB_OK']='True' 18 | 19 | import sys 20 | 21 | path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 22 | 23 | sys.path.append(path) 24 | 25 | #print(path) ##/Users/X/Github/DOS 26 | #------------------------------------------------------------------------------ 27 | 28 | 29 | 30 | # ------------------------------------------------------------------------- 31 | # Run 32 | # ------------------------------------------------------------------------- 33 | if __name__ == '__main__': 34 | 35 | a = path + r'\objs' 36 | 37 | pq = a + r'\obj_pq' 38 | anet = a + r'\obj_anet' 39 | snet = a + r'\obj_snet' 40 | equ = a +r'\obj_equilibrium' 41 | 42 | file = pq + r'\heart.obj' #conical1.obj 43 | #file = anet + r'\knet1.obj' 44 | #file = snet + r'\cmc1.obj' 45 | #file = equ + r'\quad_dome.obj' 46 | 47 | ## if MacBook: 48 | file = path + '/objs/obj_equilibrium' + '/quad_dome.obj' 49 | 50 | #---------------------------------------- 51 | 52 | '''Instantiate the sample component''' 53 | from opt_gui_orthonet import OrthoNet 54 | component = OrthoNet() 55 | 56 | '''Instantiate the main geolab application''' 57 | from archgeolab.archgeometry.gui_basic import GeolabGUI 58 | GUI = GeolabGUI() 59 | 60 | '''Add the component to geolab''' 61 | GUI.add_component(component) 62 | 63 | '''Open an obj file''' 64 | GUI.open_obj_file(file) 65 | 66 | '''Open another obj file''' 67 | #GUI.open_obj_file(reffile) 68 | 69 | '''Start geolab main loop''' 70 | GUI.start() 71 | 72 | -------------------------------------------------------------------------------- /assets/AG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/AG.png -------------------------------------------------------------------------------- /assets/_graph.TXT: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | graph LR 5 | A[meshpy.py] --> B([geometry]) 6 | B --> C([geometrylab]) 7 | A --> D[quadring.py] 8 | D --> E([archgeogeometry]) 9 | E --> F([archgeolab]) 10 | F --> G[guidedprojection_orthonet.py] 11 | G --> H[opt_gui_orthonet.py] 12 | H --> I[readfile_orthonet.py] 13 | J([objs]) --> I 14 | C --> E 15 | K([constraints]) --> F -------------------------------------------------------------------------------- /assets/anet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/anet.png -------------------------------------------------------------------------------- /assets/cmc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/cmc.png -------------------------------------------------------------------------------- /assets/files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/files.png -------------------------------------------------------------------------------- /assets/frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/frame.png -------------------------------------------------------------------------------- /assets/funicular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/funicular.png -------------------------------------------------------------------------------- /assets/layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/layout.png -------------------------------------------------------------------------------- /assets/mayavi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/mayavi.png -------------------------------------------------------------------------------- /assets/pq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/pq.png -------------------------------------------------------------------------------- /assets/teaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/teaser.png -------------------------------------------------------------------------------- /assets/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WWmore/DOS/3bf8c6853916fa21b1803e994d5cdd011f27c62e/assets/tree.png -------------------------------------------------------------------------------- /assets/tree_emoji.py: -------------------------------------------------------------------------------- 1 | 2 | """https://github.com/earnestt1234/seedir 3 | pip install seedir 4 | pip install emoji 5 | """ 6 | 7 | import seedir as sd 8 | 9 | 10 | #import os 11 | 12 | # def foo(x): # omits folders with more than 2 items 13 | # if os.path.isdir(x) and len(os.listdir(x)) > 2: 14 | # return False 15 | # return True 16 | 17 | folder = ['.git', '_pycache_', '__pycache__', '.spyproject', '.gitignore'] 18 | file = '.gitignore.txt' 19 | path = r'C:\Users\WANGH0M\Documents\GitHub\DOS' 20 | sd.seedir(path, depthlimit=2, exclude_folders=folder, exclude_files=file, style='emoji') -------------------------------------------------------------------------------- /assets/tree_print.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | from pathlib import Path 4 | 5 | class DisplayablePath(object): 6 | display_filename_prefix_middle = '├──' 7 | display_filename_prefix_last = '└──' 8 | display_parent_prefix_middle = ' ' 9 | display_parent_prefix_last = '│ ' 10 | 11 | def __init__(self, path, parent_path, is_last): 12 | self.path = Path(str(path)) 13 | self.parent = parent_path 14 | self.is_last = is_last 15 | if self.parent: 16 | self.depth = self.parent.depth + 1 17 | else: 18 | self.depth = 0 19 | 20 | @property 21 | def displayname(self): 22 | if self.path.is_dir(): 23 | return self.path.name + '/' 24 | return self.path.name 25 | 26 | @classmethod 27 | def make_tree(cls, root, parent=None, is_last=False, criteria=None): 28 | root = Path(str(root)) 29 | criteria = criteria or cls._default_criteria 30 | 31 | displayable_root = cls(root, parent, is_last) 32 | yield displayable_root 33 | 34 | children = sorted(list(path 35 | for path in root.iterdir() 36 | if criteria(path)), 37 | key=lambda s: str(s).lower()) 38 | count = 1 39 | for path in children: 40 | is_last = count == len(children) 41 | if path.is_dir(): 42 | yield from cls.make_tree(path, 43 | parent=displayable_root, 44 | is_last=is_last, 45 | criteria=criteria) 46 | else: 47 | yield cls(path, displayable_root, is_last) 48 | count += 1 49 | 50 | @classmethod 51 | def _default_criteria(cls, path): 52 | return True 53 | 54 | @property 55 | def displayname(self): 56 | if self.path.is_dir(): 57 | return self.path.name + '/' 58 | return self.path.name 59 | 60 | def displayable(self): 61 | if self.parent is None: 62 | return self.displayname 63 | 64 | _filename_prefix = (self.display_filename_prefix_last 65 | if self.is_last 66 | else self.display_filename_prefix_middle) 67 | 68 | parts = ['{!s} {!s}'.format(_filename_prefix, 69 | self.displayname)] 70 | 71 | parent = self.parent 72 | while parent and parent.parent is not None: 73 | parts.append(self.display_parent_prefix_middle 74 | if parent.is_last 75 | else self.display_parent_prefix_last) 76 | parent = parent.parent 77 | 78 | return ''.join(reversed(parts)) 79 | 80 | 81 | 82 | # With a criteria (skip hidden files) 83 | def is_not_hidden(path): 84 | return not path.name.startswith(".") 85 | 86 | project_folder = r'C:\Users\WANGH0M\Documents\GitHub\DOS' 87 | paths = DisplayablePath.make_tree(Path(project_folder), criteria=is_not_hidden) 88 | for path in paths: 89 | print(path.displayable()) 90 | 91 | -------------------------------------------------------------------------------- /conda/macos/environment.yml: -------------------------------------------------------------------------------- 1 | name: geometrylab 2 | channels: 3 | - haasad 4 | - defaults 5 | dependencies: 6 | - blas=1.0=mkl 7 | - ca-certificates=2023.05.30=hecd8cb5_0 8 | - certifi=2021.5.30=py36hecd8cb5_0 9 | - intel-openmp=2023.1.0=ha357a0b_43547 10 | - libcxx=14.0.6=h9765a3e_0 11 | - libffi=3.3=hb1e8313_2 12 | - libgfortran=3.0.1=h93005f0_2 13 | - mkl=2019.4=233 14 | - mkl-service=2.3.0=py36h9ed2024_0 15 | - mkl_fft=1.3.0=py36ha059aab_0 16 | - mkl_random=1.1.1=py36h959d312_0 17 | - ncurses=6.4=hcec6c5f_0 18 | - numpy=1.19.2=py36h456fd55_0 19 | - numpy-base=1.19.2=py36hcfb5961_0 20 | - openssl=1.1.1v=hca72f7f_0 21 | - pip=21.2.2=py36hecd8cb5_0 22 | - pypardiso=0.4.2=py_0 23 | - python=3.6.13=h88f2d9e_0 24 | - readline=8.2=hca72f7f_0 25 | - scipy=1.5.2=py36h912ce22_0 26 | - setuptools=58.0.4=py36hecd8cb5_0 27 | - six=1.16.0=pyhd3eb1b0_1 28 | - sqlite=3.41.2=h6c40b1e_0 29 | - tk=8.6.12=h5d9f67b_0 30 | - traits=6.2.0=py36h9ed2024_0 31 | - wheel=0.37.1=pyhd3eb1b0_0 32 | - xz=5.4.2=h6c40b1e_0 33 | - zlib=1.2.13=h4dc903c_0 34 | - pip: 35 | - apptools==5.2.1 36 | - attrs==19.3.0 37 | - configobj==5.0.8 38 | - cycler==0.11.0 39 | - envisage==6.1.1 40 | - importlib-metadata==4.8.3 41 | - importlib-resources==5.4.0 42 | - kiwisolver==1.3.1 43 | - matplotlib==3.3.4 44 | - mayavi==4.8.0 45 | - nose==1.3.7 46 | - pillow==8.4.0 47 | - pyface==7.4.4 48 | - pygments==2.14.0 49 | - pyparsing==3.1.1 50 | - pyqt5==5.15.6 51 | - pyqt5-qt5==5.15.2 52 | - pyqt5-sip==12.9.1 53 | - python-dateutil==2.8.2 54 | - python-vtk==0.1.0 55 | - traitsui==7.4.3 56 | - typing-extensions==4.1.1 57 | - vtk==8.1.2 58 | - zipp==3.6.0 59 | prefix: /Users/memo2/opt/anaconda3/envs/geometrylab 60 | -------------------------------------------------------------------------------- /conda/windows/environment.yml: -------------------------------------------------------------------------------- 1 | name: geometrylab 2 | channels: 3 | - haasad 4 | - defaults 5 | dependencies: 6 | - blas=1.0=mkl 7 | - ca-certificates=2021.4.13=haa95532_1 8 | - certifi=2020.12.5=py36haa95532_0 9 | - icc_rt=2019.0.0=h0cc432a_1 10 | - icu=58.2=ha925a31_3 11 | - intel-openmp=2021.2.0=haa95532_616 12 | - jpeg=9b=hb83a4c4_2 13 | - libpng=1.6.37=h2a8f88b_0 14 | - mkl=2020.2=256 15 | - mkl-service=2.3.0=py36h196d8e1_0 16 | - mkl_fft=1.3.0=py36h46781fe_0 17 | - mkl_random=1.1.1=py36h47e9c7a_0 18 | - numpy-base=1.19.2=py36ha3acd2a_0 19 | - openssl=1.1.1k=h2bbff1b_0 20 | - pip=21.0.1=py36haa95532_0 21 | - pyface=7.3.0=py36haa95532_1 22 | - pypardiso=0.2.2=py_0 23 | - pyqt=5.9.2=py36h6538335_2 24 | - python=3.6.13=h3758d61_0 25 | - qt=5.9.7=vc14h73c81de_0 26 | - setuptools=52.0.0=py36haa95532_0 27 | - sip=4.19.8=py36h6538335_0 28 | - sqlite=3.35.4=h2bbff1b_0 29 | - traits=6.2.0=py36h2bbff1b_0 30 | - vc=14.2=h21ff451_1 31 | - vs2015_runtime=14.27.29016=h5e58377_2 32 | - wheel=0.36.2=pyhd3eb1b0_0 33 | - wincertstore=0.2=py36h7fe50ca_0 34 | - zlib=1.2.11=h62dcd97_4 35 | - pip: 36 | - apptools==5.1.0 37 | - attrs==19.3.0 38 | - configobj==5.0.6 39 | - envisage==5.0.0 40 | - importlib-metadata==4.0.1 41 | - importlib-resources==5.1.2 42 | - mayavi==4.7.3 43 | - numpy==1.19.5 44 | - pygments==2.9.0 45 | - python-vtk==0.1.0 46 | - scipy==1.5.4 47 | - six==1.16.0 48 | - traitsui==7.1.1 49 | - typing-extensions==3.10.0.0 50 | - vtk==8.1.2 51 | - zipp==3.4.1 52 | prefix: C:\Users\CEBALLV\.conda\envs\geometrylab 53 | -------------------------------------------------------------------------------- /objs/obj_equilibrium/quad_dome.obj: -------------------------------------------------------------------------------- 1 | # Rhino 2 | 3 | g object_1 4 | v 3.368055582046509 3.368055582046509 3.819444417953491 5 | v 6.63194465637207 3.368055582046509 3.819444417953491 6 | v 6.63194465637207 6.63194465637207 3.819444417953491 7 | v 3.368055582046509 6.63194465637207 3.819444417953491 8 | v 6.63194465637207 1.180555582046509 1.631944417953491 9 | v 3.368055582046509 1.180555582046509 1.631944417953491 10 | v 8.81944465637207 6.63194465637207 1.631944417953491 11 | v 8.81944465637207 3.368055582046509 1.631944417953491 12 | v 3.368055582046509 8.81944465637207 1.631944417953491 13 | v 6.63194465637207 8.81944465637207 1.631944417953491 14 | v 1.180555582046509 3.368055582046509 1.631944417953491 15 | v 1.180555582046509 6.63194465637207 1.631944417953491 16 | v 3.489583253860474 2.005208253860474 2.994791746139526 17 | v 5 3.246527671813965 4.097222328186035 18 | v 3.246527671813965 5 4.097222328186035 19 | v 2.005208253860474 3.489583253860474 2.994791746139526 20 | v 6.510416984558106 2.005208253860474 2.994791746139526 21 | v 7.994791984558106 3.489583253860474 2.994791746139526 22 | v 6.753472328186035 5 4.097222328186035 23 | v 7.994791984558106 6.510416984558106 2.994791746139526 24 | v 6.510416984558106 7.994791984558106 2.994791746139526 25 | v 5 6.753472328186035 4.097222328186035 26 | v 3.489583253860474 7.994791984558106 2.994791746139526 27 | v 2.005208253860474 6.510416984558106 2.994791746139526 28 | v 3.246527671813965 0.9027777910232544 0 29 | v 6.753472328186035 0.9027777910232544 0 30 | v 7.994791984558106 2.005208253860474 1.510416746139526 31 | v 5 0.9027777910232544 1.753472328186035 32 | v 2.005208253860474 2.005208253860474 1.510416746139526 33 | v 9.097222328186035 3.246527671813965 0 34 | v 9.097222328186035 6.753472328186035 0 35 | v 7.994791984558106 7.994791984558106 1.510416746139526 36 | v 9.097222328186035 5 1.753472328186035 37 | v 6.753472328186035 9.097222328186035 0 38 | v 3.246527671813965 9.097222328186035 0 39 | v 2.005208253860474 7.994791984558106 1.510416746139526 40 | v 5 9.097222328186035 1.753472328186035 41 | v 0.9027777910232544 6.753472328186035 0 42 | v 0.9027777910232544 3.246527671813965 0 43 | v 0.9027777910232544 5 1.753472328186035 44 | v 5 5 4.392361164093018 45 | v 5 0.6076388955116272 0 46 | v 9.392360687255859 5 0 47 | v 5 9.392360687255859 0 48 | v 0.6076388955116272 5 0 49 | v 5 1.783854007720947 3.216145992279053 50 | v 8.216145515441895 5 3.216145992279053 51 | v 5 8.216145515441895 3.216145992279053 52 | v 1.783854007720947 5 3.216145992279053 53 | v 8.216145515441895 1.783854007720947 0 54 | v 1.783854007720947 1.783854007720947 0 55 | v 8.216145515441895 8.216145515441895 0 56 | v 1.783854007720947 8.216145515441895 0 57 | v 2.45370364189148 2.45370364189148 2.546296358108521 58 | v 7.546297073364258 2.45370364189148 2.546296358108521 59 | v 2.45370364189148 7.546297073364258 2.546296358108521 60 | v 7.546297073364258 7.546297073364258 2.546296358108521 61 | vn -0.3522928953170776 -0.3522928953170776 0.8670521378517151 62 | vn 0.3522928953170776 -0.3522928655147553 0.8670521378517151 63 | vn 0.3522928655147553 0.3522928655147553 0.8670521974563599 64 | vn -0.3522928655147553 0.3522928953170776 0.8670521378517151 65 | vn 0.3522928953170776 -0.8670521974563599 0.3522928357124329 66 | vn -0.3522928953170776 -0.8670521378517151 0.3522928953170776 67 | vn 0.8670522570610046 0.3522928059101105 0.3522927761077881 68 | vn 0.8670521974563599 -0.3522928059101105 0.3522928059101105 69 | vn -0.3522928059101105 0.8670521974563599 0.3522928059101105 70 | vn 0.3522928059101105 0.8670522570610046 0.3522927761077881 71 | vn -0.8670521378517151 -0.3522928953170776 0.3522928953170776 72 | vn -0.8670521974563599 0.3522928953170776 0.3522928357124329 73 | vn -0.3526979982852936 -0.6616661548614502 0.6616660952568054 74 | vn -9.901650166455056e-09 -0.3535585105419159 0.9354124069213867 75 | vn -0.3535585105419159 -9.901650166455056e-09 0.9354124069213867 76 | vn -0.6616661548614502 -0.3526979982852936 0.6616660952568054 77 | vn 0.3526979386806488 -0.6616661548614502 0.6616661548614502 78 | vn 0.6616661548614502 -0.3526978492736816 0.6616661548614502 79 | vn 0.3535585403442383 -9.901644837384538e-09 0.9354124069213867 80 | vn 0.6616661548614502 0.3526978194713593 0.6616661548614502 81 | vn 0.3526978194713593 0.6616661548614502 0.6616661548614502 82 | vn -9.901644837384538e-09 0.3535585403442383 0.9354124069213867 83 | vn -0.3526978492736816 0.6616661548614502 0.6616661548614502 84 | vn -0.6616661548614502 0.3526979386806488 0.6616661548614502 85 | vn -0.3476200699806213 -0.9197010397911072 0.182511106133461 86 | vn 0.3476200997829437 -0.9197010397911072 0.1825110167264938 87 | vn 0.6616661548614502 -0.6616661548614502 0.3526978492736816 88 | vn -9.901649278276636e-09 -0.9354124069213867 0.3535584807395935 89 | vn -0.6616661548614502 -0.6616661548614502 0.3526979684829712 90 | vn 0.919701099395752 -0.347620040178299 0.1825109124183655 91 | vn 0.919701099395752 0.3476200699806213 0.1825108230113983 92 | vn 0.661666214466095 0.661666214466095 0.3526977300643921 93 | vn 0.9354124069213867 -9.90163773195718e-09 0.3535584807395935 94 | vn 0.3476200699806213 0.919701099395752 0.1825108230113983 95 | vn -0.347620040178299 0.919701099395752 0.1825109124183655 96 | vn -0.6616661548614502 0.6616661548614502 0.3526978492736816 97 | vn -9.90163773195718e-09 0.9354124069213867 0.3535584807395935 98 | vn -0.9197010397911072 0.3476200997829437 0.1825110167264938 99 | vn -0.9197010397911072 -0.3476200699806213 0.182511106133461 100 | vn -0.9354124069213867 -9.901650166455056e-09 0.3535584807395935 101 | vn -5.533367097854125e-09 -5.533367097854125e-09 1 102 | vn -5.4503015434193e-09 -0.9849879741668701 0.1726230084896088 103 | vn 0.9849879741668701 -5.450292217545893e-09 0.1726228147745132 104 | vn -5.450292217545893e-09 0.9849879741668701 0.1726228147745132 105 | vn -0.9849879741668701 -5.4503015434193e-09 0.1726230084896088 106 | vn -1.441590669060133e-08 -0.7071067690849304 0.7071067690849304 107 | vn 0.7071067690849304 -1.441589336792504e-08 0.7071067690849304 108 | vn -1.441589336792504e-08 0.7071067690849304 0.7071067690849304 109 | vn -0.7071067690849304 -1.441590669060133e-08 0.7071067690849304 110 | vn 0.6936981678009033 -0.6936982274055481 0.1938186436891556 111 | vn -0.6936981678009033 -0.6936981678009033 0.1938188374042511 112 | vn 0.6936982274055481 0.6936982274055481 0.1938184648752213 113 | vn -0.6936982274055481 0.6936981678009033 0.1938186436891556 114 | vn -0.5773502588272095 -0.5773502588272095 0.5773502588272095 115 | vn 0.5773502588272095 -0.5773502588272095 0.5773502588272095 116 | vn -0.5773502588272095 0.5773502588272095 0.5773502588272095 117 | vn 0.5773502588272095 0.5773502588272095 0.5773502588272095 118 | f 38//38 45//45 40//40 12//12 119 | f 53//53 38//38 12//12 36//36 120 | f 39//39 51//51 29//29 11//11 121 | f 45//45 39//39 11//11 40//40 122 | f 34//34 44//44 37//37 10//10 123 | f 52//52 34//34 10//10 32//32 124 | f 35//35 53//53 36//36 9//9 125 | f 44//44 35//35 9//9 37//37 126 | f 30//30 43//43 33//33 8//8 127 | f 50//50 30//30 8//8 27//27 128 | f 31//31 52//52 32//32 7//7 129 | f 43//43 31//31 7//7 33//33 130 | f 25//25 42//42 28//28 6//6 131 | f 51//51 25//25 6//6 29//29 132 | f 26//26 50//50 27//27 5//5 133 | f 42//42 26//26 5//5 28//28 134 | f 36//36 12//12 24//24 56//56 135 | f 12//12 40//40 49//49 24//24 136 | f 40//40 11//11 16//16 49//49 137 | f 11//11 29//29 54//54 16//16 138 | f 32//32 10//10 21//21 57//57 139 | f 10//10 37//37 48//48 21//21 140 | f 37//37 9//9 23//23 48//48 141 | f 9//9 36//36 56//56 23//23 142 | f 27//27 8//8 18//18 55//55 143 | f 8//8 33//33 47//47 18//18 144 | f 33//33 7//7 20//20 47//47 145 | f 7//7 32//32 57//57 20//20 146 | f 29//29 6//6 13//13 54//54 147 | f 6//6 28//28 46//46 13//13 148 | f 28//28 5//5 17//17 46//46 149 | f 5//5 27//27 55//55 17//17 150 | f 24//24 4//4 23//23 56//56 151 | f 4//4 22//22 48//48 23//23 152 | f 15//15 41//41 22//22 4//4 153 | f 49//49 15//15 4//4 24//24 154 | f 22//22 3//3 21//21 48//48 155 | f 3//3 20//20 57//57 21//21 156 | f 19//19 47//47 20//20 3//3 157 | f 41//41 19//19 3//3 22//22 158 | f 14//14 2//2 19//19 41//41 159 | f 2//2 18//18 47//47 19//19 160 | f 17//17 55//55 18//18 2//2 161 | f 46//46 17//17 2//2 14//14 162 | f 16//16 1//1 15//15 49//49 163 | f 1//1 14//14 41//41 15//15 164 | f 13//13 46//46 14//14 1//1 165 | f 54//54 13//13 1//1 16//16 166 | -------------------------------------------------------------------------------- /objs/obj_pq/heart.obj: -------------------------------------------------------------------------------- 1 | o C:\Users\WANGH0M\Desktop\geometrylab7\obj_all\chebyshev_sphere_chebyshev_sphere_crown1 2 | v -3.0831429285171907e-06 -3.5085256513411878e-06 1.204803228378296 3 | v 0.09636549651622772 -0.020076394081115723 1.225475788116455 4 | v 0.07638391852378845 0.07772330194711685 1.2769325971603394 5 | v -0.020795254036784172 0.09699711948633194 1.2255253791809082 6 | v 0.1988220363855362 -0.030706152319908142 1.2752540111541748 7 | v 0.18204058706760406 0.06933873146772385 1.3572359085083008 8 | v 0.31223785877227783 -0.02385556884109974 1.3291475772857666 9 | v 0.30297866463661194 0.0820721909403801 1.4354536533355713 10 | v 0.4373895823955536 0.003997476305812597 1.3528454303741455 11 | v 0.4409366548061371 0.12077631801366806 1.4744093418121338 12 | v 0.5670412182807922 0.04753514379262924 1.3193250894546509 13 | v 0.5860887765884399 0.17784319818019867 1.4416817426681519 14 | v 0.686961829662323 0.09303579479455948 1.2184141874313354 15 | v 0.7194406390190125 0.2350129783153534 1.3261631727218628 16 | v 0.7808725237846375 0.12305436283349991 1.0610742568969727 17 | v 0.8199188709259033 0.2701913118362427 1.1410597562789917 18 | v 0.8403089046478271 0.12649042904376984 0.8710850477218628 19 | v 0.875156581401825 0.2685936987400055 0.9176113605499268 20 | v 0.8694565296173096 0.10395835340023041 0.6746208071708679 21 | v 0.8905158042907715 0.23233544826507568 0.6846221089363098 22 | v 0.8862032890319824 0.06973923742771149 0.49291759729385376 23 | v 0.889784038066864 0.1818331927061081 0.4658361077308655 24 | v 0.06741323322057724 0.18385259807109833 1.3573790788650513 25 | v -0.03203073889017105 0.19994059205055237 1.2754443883895874 26 | v 0.17836366593837738 0.18071725964546204 1.4633709192276 27 | v 0.31029021739959717 0.20367681980133057 1.5625998973846436 28 | v 0.4628859758377075 0.2558608651161194 1.6120731830596924 29 | v 0.6259019374847412 0.32949769496917725 1.574982762336731 30 | v 0.7726373076438904 0.39875319600105286 1.4390082359313965 31 | v 0.8769964575767517 0.4367161989212036 1.2211365699768066 32 | v 0.9233185648918152 0.42550531029701233 0.9573203921318054 33 | v 0.9173823595046997 0.3680623769760132 0.6836909651756287 34 | v 0.8894813656806946 0.2915599048137665 0.41903620958328247 35 | v 0.07981617748737335 0.3049766421318054 1.4358108043670654 36 | v -0.025574689731001854 0.3135997951030731 1.3295451402664185 37 | v 0.20107144117355347 0.3127538859844208 1.5628199577331543 38 | v 0.3458726406097412 0.34851253032684326 1.6771942377090454 39 | v 0.5178928375244141 0.41953974962234497 1.7316346168518066 40 | v 0.6969762444496155 0.5085577964782715 1.688511848449707 41 | v 0.8555659055709839 0.5889278054237366 1.5293257236480713 42 | v 0.9587036371231079 0.6250339150428772 1.27823007106781 43 | v 0.989173948764801 0.5977663397789001 0.9763646125793457 44 | v 0.9525331854820251 0.5102731585502625 0.6623691320419312 45 | v 0.884618878364563 0.3956286609172821 0.352150559425354 46 | v 0.1185196116566658 0.44279226660728455 1.4750090837478638 47 | v 0.00217261235229671 0.4387091398239136 1.353473424911499 48 | v 0.2533522844314575 0.4651110768318176 1.612549901008606 49 | v 0.41710662841796875 0.5201827883720398 1.7319023609161377 50 | v 0.6050276756286621 0.6070520877838135 1.7886425256729126 51 | v 0.8010565638542175 0.7125803232192993 1.7326194047927856 52 | v 0.9650575518608093 0.7981656193733215 1.5584752559661865 53 | v 1.0608394145965576 0.8268392086029053 1.2795517444610596 54 | v 1.0683143138885498 0.7770742177963257 0.9496480822563171 55 | v 0.9942644834518433 0.6537484526634216 0.6088824272155762 56 | v 0.8743478655815125 0.4903867840766907 0.26530030369758606 57 | v 0.17588527500629425 0.5875511765480042 1.4424947500228882 58 | v 0.045879658311605453 0.5680984258651733 1.3201501369476318 59 | v 0.32741257548332214 0.6276058554649353 1.5756951570510864 60 | v 0.5066227316856384 0.6986640691757202 1.6890360116958618 61 | v 0.7110970616340637 0.8024303317070007 1.7328919172286987 62 | v 0.9151580929756165 0.9160054326057434 1.6733542680740356 63 | v 1.0785473585128784 1.000770092010498 1.4818919897079468 64 | v 1.1626478433609009 1.0182620286941528 1.1963577270507812 65 | v 1.142932653427124 0.9424154758453369 0.8559974431991577 66 | v 1.0313118696212769 0.7841094136238098 0.5091074705123901 67 | v 0.8575870394706726 0.5717929005622864 0.1592341661453247 68 | v 0.2335357815027237 0.7204106450080872 1.32709801197052 69 | v 0.09173396229743958 0.6876617074012756 1.2193444967269897 70 | v 0.3972514569759369 0.7737352252006531 1.4398692846298218 71 | v 0.5876336693763733 0.8565759658813477 1.5300319194793701 72 | v 0.7973129153251648 0.9657494425773621 1.5589569807052612 73 | v 1.0004854202270508 1.0787725448608398 1.4821209907531738 74 | v 1.158951997756958 1.1587024927139282 1.2964510917663574 75 | v 1.224165916442871 1.1575227975845337 1.0136605501174927 76 | v 1.185555338859558 1.0643706321716309 0.6886347532272339 77 | v 1.0449469089508057 0.8802127838134766 0.3598542809486389 78 | v 0.8328509330749512 0.6354466080665588 0.03503036126494408 79 | v 0.2692211866378784 0.8204532861709595 1.1419763565063477 80 | v 0.12215947359800339 0.7812525629997253 1.0619741678237915 81 | v 0.4357874095439911 0.877574622631073 1.2220066785812378 82 | v 0.6243231296539307 0.9591617584228516 1.2789827585220337 83 | v 0.8265154361724854 1.0610105991363525 1.2801241874694824 84 | v 1.018409252166748 1.162430763244629 1.196712851524353 85 | v 1.1580734252929688 1.2235963344573975 1.0138100385665894 86 | v 1.216163158416748 1.215388536453247 0.7560680508613586 87 | v 1.1617789268493652 1.107354998588562 0.4642568826675415 88 | v 1.016955852508545 0.9220300316810608 0.1705041229724884 89 | v 0.7975785136222839 0.6763474345207214 -0.10849044471979141 90 | v 0.2680411636829376 0.8754013180732727 0.9183506965637207 91 | v 0.12595956027507782 0.8404750227928162 0.8718038201332092 92 | v 0.4250142574310303 0.9235626459121704 0.9580355286598206 93 | v 0.5974572896957397 0.9893050789833069 0.9770025610923767 94 | v 0.7770596146583557 1.0682220458984375 0.9501568078994751 95 | v 0.9427403211593628 1.142559289932251 0.8563454151153564 96 | v 1.0649800300598145 1.1849323511123657 0.6888225078582764 97 | v 1.108089804649353 1.1610438823699951 0.4643213450908661 98 | v 1.06083345413208 1.0601773262023926 0.21296319365501404 99 | v 0.9351754784584045 0.8956213593482971 -0.03505381941795349 100 | v 0.7477040886878967 0.6869244575500488 -0.26773861050605774 101 | v 0.23208478093147278 0.8906100392341614 0.6850411891937256 102 | v 0.10371411591768265 0.869515597820282 0.6750247478485107 103 | v 0.3678496181964874 0.9174695611000061 0.684101939201355 104 | v 0.5101646780967712 0.9525529742240906 0.6627419590950012 105 | v 0.6538082361221313 0.9941542148590088 0.6091862320899963 106 | v 0.7843614816665649 1.031040072441101 0.5093204975128174 107 | v 0.8806200623512268 1.0445376634597778 0.35997459292411804 108 | v 0.9225013852119446 1.0164872407913208 0.17055177688598633 109 | v 0.8960415124893188 0.9347569346427917 -0.03504502400755882 110 | v 0.7823569178581238 0.7821676135063171 -0.22809937596321106 111 | v 0.6792202591896057 0.6594640612602234 -0.4310939908027649 112 | v 0.1818331927061081 0.889784038066864 0.4658361077308655 113 | v 0.06973923742771149 0.8862032890319824 0.49291759729385376 114 | v 0.2915599048137665 0.8894813656806946 0.41903620958328247 115 | v 0.3956286609172821 0.884618878364563 0.352150559425354 116 | v 0.4903867840766907 0.8743478655815125 0.26530030369758606 117 | v 0.5717929005622864 0.8575870394706726 0.1592341661453247 118 | v 0.6354466080665588 0.8328509330749512 0.03503036126494408 119 | v 0.6763474345207214 0.7975785136222839 -0.10849044471979141 120 | v 0.6869244575500488 0.7477040886878967 -0.26773861050605774 121 | v 0.6594640612602234 0.6792202591896057 -0.4310939908027649 122 | v 0.5867047905921936 0.5867047905921936 -0.564778745174408 123 | v -0.11664751917123795 0.11655168235301971 1.2124645709991455 124 | v -0.0963716134428978 0.020069558173418045 1.2254759073257446 125 | v -0.12835673987865448 0.21708597242832184 1.23103928565979 126 | v -0.1251879185438156 0.3249836564064026 1.2566583156585693 127 | v -0.10496749728918076 0.4400055408477783 1.2609286308288574 128 | v -0.07162612676620483 0.5567134022712708 1.22081458568573 129 | v -0.03585454449057579 0.6643498539924622 1.1275869607925415 130 | v -0.010379520244896412 0.7517156600952148 0.9892910718917847 131 | v -0.004488905426114798 0.8124884963035583 0.8250994086265564 132 | v -0.01802986115217209 0.8506486415863037 0.6561915874481201 133 | v -0.041933540254831314 0.8791988492012024 0.5011640787124634 134 | v -0.2166811227798462 0.12763433158397675 1.2309002876281738 135 | v -0.19882802665233612 0.030699726194143295 1.2752536535263062 136 | v -0.22700515389442444 0.2267788052558899 1.2163804769515991 137 | v -0.2248152792453766 0.33048927783966064 1.2119144201278687 138 | v -0.2089027464389801 0.43802568316459656 1.193349838256836 139 | v -0.1826872080564499 0.5448839664459229 1.1415066719055176 140 | v -0.15400418639183044 0.6433948278427124 1.0494329929351807 141 | v -0.13261614739894867 0.7254488468170166 0.9229060411453247 142 | v -0.1254989504814148 0.7871082425117493 0.7768104672431946 143 | v -0.13342192769050598 0.8316504955291748 0.628197431564331 144 | v -0.15084145963191986 0.8690167665481567 0.49177050590515137 145 | v -0.3242965042591095 0.12402504682540894 1.2563164234161377 146 | v -0.3122432827949524 0.023850036785006523 1.329145908355713 147 | v -0.3304064869880676 0.22411629557609558 1.2117130756378174 148 | v -0.32642602920532227 0.32603663206100464 1.1785615682601929 149 | v -0.311771035194397 0.428890198469162 1.1368019580841064 150 | v -0.2893146574497223 0.5291374325752258 1.0715458393096924 151 | v -0.26499849557876587 0.6212497353553772 0.9768062233924866 152 | v -0.24604134261608124 0.6997266411781311 0.8570356965065002 153 | v -0.2378932237625122 0.7621937394142151 0.7234986424446106 154 | v -0.24186670780181885 0.8115718960762024 0.5895023345947266 155 | v -0.2549058794975281 0.855847954750061 0.46605706214904785 156 | v -0.4392718970775604 0.10360823571681976 1.2603622674942017 157 | v -0.43739384412765503 -0.004001675173640251 1.3528423309326172 158 | v -0.43782997131347656 0.20794130861759186 1.1929258108139038 159 | v -0.42912647128105164 0.3110876679420471 1.1365774869918823 160 | v -0.412837952375412 0.41231557726860046 1.0758545398712158 161 | v -0.3912653625011444 0.509025514125824 0.9987947344779968 162 | v -0.3688128888607025 0.5974009037017822 0.9010869264602661 163 | v -0.350771963596344 0.6738864183425903 0.7859466671943665 164 | v -0.34138023853302 0.737270176410675 0.6618850827217102 165 | v -0.342235803604126 0.79038006067276 0.539003849029541 166 | v -0.35224607586860657 0.8398698568344116 0.42544323205947876 167 | v -0.5561188459396362 0.07031742483377457 1.2200576066970825 168 | v -0.5670438408851624 -0.0475376695394516 1.3193210363388062 169 | v -0.5447240471839905 0.18168042600154877 1.14089035987854 170 | v -0.5293346047401428 0.28852584958076477 1.071122169494629 171 | v -0.5094677209854126 0.39061617851257324 0.9985889196395874 172 | v -0.4867802560329437 0.4862207770347595 0.914694607257843 173 | v -0.46442314982414246 0.5729169845581055 0.8163414001464844 174 | v -0.44613152742385864 0.6485327482223511 0.7060514688491821 175 | v -0.4351654052734375 0.7127771377563477 0.5902964472770691 176 | v -0.4332979917526245 0.7684395909309387 0.47667816281318665 177 | v -0.44093912839889526 0.8214532732963562 0.37140655517578125 178 | v -0.6639748811721802 0.03477378934621811 1.1267285346984863 179 | v -0.6869626641273499 -0.09303665161132812 1.2184103727340698 180 | v -0.6433377265930176 0.1531224250793457 1.0487070083618164 181 | v -0.6214588284492493 0.26426294445991516 0.9762570261955261 182 | v -0.5977956056594849 0.36817750334739685 0.9007382392883301 183 | v -0.5734018087387085 0.46386438608169556 0.816186785697937 184 | v -0.5503317713737488 0.549849271774292 0.720758318901062 185 | v -0.5312120914459229 0.6250467300415039 0.6167749762535095 186 | v -0.51844322681427 0.6896064281463623 0.5090739727020264 187 | v -0.5138843059539795 0.7463864088058472 0.4036141335964203 188 | v -0.5191673636436462 0.801099419593811 0.3055539131164551 189 | v -0.7515420913696289 0.009605293162167072 0.9884602427482605 190 | v -0.780872106552124 -0.12305406481027603 1.0610716342926025 191 | v -0.7254838943481445 0.1319516897201538 0.9221899509429932 192 | v -0.6999408602714539 0.24545852839946747 0.8564693331718445 193 | v -0.6742265224456787 0.35024842619895935 0.7855502963066101 194 | v -0.6489319205284119 0.44566115736961365 0.7058224678039551 195 | v -0.6254380941390991 0.5308038592338562 0.6166849136352539 196 | v -0.6054710149765015 0.6051412224769592 0.5201964974403381 197 | v -0.5906240344047546 0.6689403057098389 0.42034032940864563 198 | v -0.5832583904266357 0.7249782681465149 0.3219125270843506 199 | v -0.5856527090072632 0.7790971994400024 0.2296770066022873 200 | v -0.812438428401947 0.004012156743556261 0.8244372606277466 201 | v -0.8403080701828003 -0.12648972868919373 0.8710840344429016 202 | v -0.7871820330619812 0.12507329881191254 0.7762346863746643 203 | v -0.76237553358078 0.23750416934490204 0.7230335474014282 204 | v -0.7375277280807495 0.3410187363624573 0.6615456938743591 205 | v -0.7130681872367859 0.4348338842391968 0.5900824069976807 206 | v -0.6898871660232544 0.5181530117988586 0.5089664459228516 207 | v -0.6691747903823853 0.5903897285461426 0.4203057885169983 208 | v -0.652631402015686 0.6524664163589478 0.3277355134487152 209 | v -0.6410203576087952 0.7049099802970886 0.2341025173664093 210 | v -0.6396147012710571 0.7555297613143921 0.14566540718078613 211 | v -0.8506446480751038 0.01780826598405838 0.6558206677436829 212 | v -0.8694559931755066 -0.10395790636539459 0.6746208667755127 213 | v -0.8317059874534607 0.13321951031684875 0.6278736591339111 214 | v -0.8116796016693115 0.24167561531066895 0.589238703250885 215 | v -0.790524423122406 0.3420529365539551 0.5388092398643494 216 | v -0.7685988545417786 0.43312692642211914 0.47655317187309265 217 | v -0.7465378642082214 0.5137332081794739 0.403548926115036 218 | v -0.7251030802726746 0.5831363201141357 0.3218887746334076 219 | v -0.7049967646598816 0.6409347653388977 0.2340986132621765 220 | v -0.6890026926994324 0.6889607906341553 0.14496833086013794 221 | v -0.6811439990997314 0.7300369739532471 0.05558300018310547 222 | v -0.8791988492012024 0.041933562606573105 0.5011641383171082 223 | v -0.8862032890319824 -0.0697392150759697 0.49291759729385376 224 | v -0.8690167665481567 0.15084145963191986 0.49177050590515137 225 | v -0.855847954750061 0.2549058794975281 0.46605706214904785 226 | v -0.8398697972297668 0.3522462248802185 0.42544326186180115 227 | v -0.8214534521102905 0.4409390091896057 0.37140652537345886 228 | v -0.801099419593811 0.5191673636436462 0.3055539131164551 229 | v -0.7790971994400024 0.5856527090072632 0.2296770066022873 230 | v -0.7555297613143921 0.6396147012710571 0.14566540718078613 231 | v -0.7300369739532471 0.6811439990997314 0.05558300018310547 232 | v -0.7065899968147278 0.7065899968147278 -0.03824000060558319 233 | v -0.07639100402593613 -0.07773097604513168 1.2769322395324707 234 | v 0.02078915573656559 -0.0970039814710617 1.2255254983901978 235 | v -0.18204821646213531 -0.0693466067314148 1.3572338819503784 236 | v -0.30298611521720886 -0.08207955956459045 1.4354487657546997 237 | v -0.4409427344799042 -0.12078216671943665 1.4744014739990234 238 | v -0.5860925912857056 -0.1778467744588852 1.4416719675064087 239 | v -0.7194418907165527 -0.2350141406059265 1.3261538743972778 240 | v -0.8199182152748108 -0.2701907157897949 1.1410526037216187 241 | v -0.8751553297042847 -0.2685925364494324 0.9176072478294373 242 | v -0.8905150294303894 -0.23233471810817719 0.6846206784248352 243 | v -0.8897841572761536 -0.1818332076072693 0.4658360481262207 244 | v -0.0674208402633667 -0.18386052548885345 1.3573769330978394 245 | v 0.03202478960156441 -0.19994710385799408 1.2754440307617188 246 | v -0.17837248742580414 -0.1807260662317276 1.4633653163909912 247 | v -0.31029894948005676 -0.2036852240562439 1.562589168548584 248 | v -0.46289294958114624 -0.2558674216270447 1.6120574474334717 249 | v -0.6259057521820068 -0.3295011520385742 1.5749642848968506 250 | v -0.7726376056671143 -0.3987533450126648 1.4389902353286743 251 | v -0.876994252204895 -0.4367139935493469 1.2211222648620605 252 | v -0.9233157634735107 -0.42550256848335266 0.9573112726211548 253 | v -0.917380690574646 -0.36806076765060425 0.6836868524551392 254 | v -0.8894813656806946 -0.2915598154067993 0.419036328792572 255 | v -0.0798235759139061 -0.30498412251472473 1.4358059167861938 256 | v 0.025569338351488113 -0.3136054575443268 1.3295435905456543 257 | v -0.20108012855052948 -0.3127623498439789 1.5628092288970947 258 | v -0.34588107466697693 -0.3485204875469208 1.6771758794784546 259 | v -0.5178986191749573 -0.41954505443573 1.7316091060638428 260 | v -0.6969779133796692 -0.508558988571167 1.6884822845458984 261 | v -0.8555629849433899 -0.5889247059822083 1.5292972326278687 262 | v -0.9586977362632751 -0.6250280737876892 1.2782069444656372 263 | v -0.9891678690910339 -0.5977603793144226 0.9763490557670593 264 | v -0.9525296688079834 -0.5102697014808655 0.6623615622520447 265 | v -0.884618878364563 -0.3956286609172821 0.3521505296230316 266 | v -0.1185256764292717 -0.4427981972694397 1.4750012159347534 267 | v -0.002176841488108039 -0.4387134611606598 1.3534703254699707 268 | v -0.25335928797721863 -0.4651176929473877 1.6125341653823853 269 | v -0.41711246967315674 -0.5201880931854248 1.7318768501281738 270 | v -0.6050299406051636 -0.607053816318512 1.7886078357696533 271 | v -0.8010532259941101 -0.7125766277313232 1.7325800657272339 272 | v -0.9650487899780273 -0.79815673828125 1.5584371089935303 273 | v -1.0608274936676025 -0.8268274664878845 1.2795206308364868 274 | v -1.0683032274246216 -0.7770633101463318 0.9496267437934875 275 | v -0.994257926940918 -0.6537420153617859 0.6088715195655823 276 | v -0.8743478655815125 -0.49038687348365784 0.26530006527900696 277 | v -0.17588910460472107 -0.5875548124313354 1.442484974861145 278 | v -0.045882295817136765 -0.5681009888648987 1.320146083831787 279 | v -0.32741641998291016 -0.6276093125343323 1.575676441192627 280 | v -0.5066244006156921 -0.6986652612686157 1.6890064477920532 281 | v -0.7110937237739563 -0.8024266362190247 1.732852578163147 282 | v -0.9151480793952942 -0.915995180606842 1.673309326171875 283 | v -1.078531265258789 -1.0007541179656982 1.4818490743637085 284 | v -1.1626288890838623 -1.0182433128356934 1.1963223218917847 285 | v -1.1429158449172974 -0.9423989653587341 0.8559731245040894 286 | v -1.0313018560409546 -0.7840995192527771 0.5090948939323425 287 | v -0.8575870394706726 -0.5717930197715759 0.1592339128255844 288 | v -0.23353713750839233 -0.7204117774963379 1.3270885944366455 289 | v -0.09173492342233658 -0.6876625418663025 1.2193406820297241 290 | v -0.3972518742084503 -0.7737353444099426 1.4398512840270996 291 | v -0.5876308083534241 -0.8565728068351746 1.5300034284591675 292 | v -0.7973041534423828 -0.9657405018806458 1.5589187145233154 293 | v -1.0004693269729614 -1.07875657081604 1.4820780754089355 294 | v -1.1589295864105225 -1.1586803197860718 1.2964094877243042 295 | v -1.2241414785385132 -1.1574985980987549 1.0136266946792603 296 | v -1.1855340003967285 -1.0643495321273804 0.688611626625061 297 | v -1.0449341535568237 -0.880200207233429 0.3598422408103943 298 | v -0.8328510522842407 -0.6354465484619141 0.03503073379397392 299 | v -0.2692206799983978 -0.8204526305198669 1.1419692039489746 300 | v -0.1221592128276825 -0.7812521457672119 1.0619715452194214 301 | v -0.43578535318374634 -0.8775723576545715 1.2219923734664917 302 | v -0.6243173480033875 -0.959155797958374 1.2789595127105713 303 | v -0.8265036344528198 -1.060998797416687 1.2800930738449097 304 | v -1.018390417098999 -1.1624120473861694 1.1966774463653564 305 | v -1.1580489873886108 -1.2235721349716187 1.013776183128357 306 | v -1.2161368131637573 -1.215362548828125 0.756040632724762 307 | v -1.1617565155029297 -1.1073330640792847 0.4642382264137268 308 | v -1.0169422626495361 -0.9220167398452759 0.1704949289560318 309 | v -0.7975784540176392 -0.6763474345207214 -0.10849080979824066 310 | v -0.2680400311946869 -0.8754000663757324 0.9183465838432312 311 | v -0.1259588748216629 -0.8404741883277893 0.871802806854248 312 | v -0.4250115752220154 -0.9235597848892212 0.9580264091491699 313 | v -0.5974513292312622 -0.9892989993095398 0.9769869446754456 314 | v -0.7770485877990723 -1.0682110786437988 0.9501354098320007 315 | v -0.9427235722541809 -1.1425426006317139 0.8563210964202881 316 | v -1.0649585723876953 -1.1849112510681152 0.6887993216514587 317 | v -1.1080673933029175 -1.1610218286514282 0.4643026888370514 318 | v -1.060814619064331 -1.0601587295532227 0.21295097470283508 319 | v -0.9351639747619629 -0.8956100940704346 -0.03505978360772133 320 | v -0.7477044463157654 -0.6869247555732727 -0.26773831248283386 321 | v -0.23208406567573547 -0.8906093239784241 0.685039758682251 322 | v -0.10371366143226624 -0.8695151209831238 0.6750248074531555 323 | v -0.3678480386734009 -0.9174679517745972 0.6840977668762207 324 | v -0.5101612210273743 -0.9525494575500488 0.66273432970047 325 | v -0.6538017392158508 -0.9941477179527283 0.6091752648353577 326 | v -0.7843514680862427 -1.0310301780700684 0.5093079209327698 327 | v -0.8806072473526001 -1.044525146484375 0.359962522983551 328 | v -0.9224878549575806 -1.0164738893508911 0.17054258286952972 329 | v -0.8960300087928772 -0.9347456097602844 -0.03505098819732666 330 | v -0.7823517918586731 -0.782162606716156 -0.22810246050357819 331 | v -0.6792201995849609 -0.6594639420509338 -0.4310939908027649 332 | v -0.1818332076072693 -0.8897841572761536 0.4658360481262207 333 | v -0.0697392150759697 -0.8862032890319824 0.49291759729385376 334 | v -0.2915598154067993 -0.8894813656806946 0.419036328792572 335 | v -0.3956286609172821 -0.884618878364563 0.3521505296230316 336 | v -0.49038687348365784 -0.8743478655815125 0.26530006527900696 337 | v -0.5717930197715759 -0.8575870394706726 0.1592339128255844 338 | v -0.6354465484619141 -0.8328510522842407 0.03503073379397392 339 | v -0.6763474345207214 -0.7975784540176392 -0.10849080979824066 340 | v -0.6869247555732727 -0.7477044463157654 -0.26773831248283386 341 | v -0.6594639420509338 -0.6792201995849609 -0.4310939908027649 342 | v -0.5867056250572205 -0.5867056250572205 -0.5647801756858826 343 | v 0.11664233356714249 -0.11655759066343307 1.2124645709991455 344 | v 0.12835246324539185 -0.21709083020687103 1.2310394048690796 345 | v 0.1251845359802246 -0.32498741149902344 1.2566580772399902 346 | v 0.10496512800455093 -0.4400080740451813 1.2609277963638306 347 | v 0.07162489742040634 -0.556714653968811 1.220813274383545 348 | v 0.03585435450077057 -0.6643499732017517 1.1275858879089355 349 | v 0.010380030609667301 -0.7517150640487671 0.989290714263916 350 | v 0.004489600192755461 -0.8124877214431763 0.825099766254425 351 | v 0.018030306324362755 -0.8506481647491455 0.6561921834945679 352 | v 0.041933562606573105 -0.8791988492012024 0.5011641383171082 353 | v 0.21667681634426117 -0.12763912975788116 1.2309001684188843 354 | v 0.22700221836566925 -0.2267821580171585 1.2163804769515991 355 | v 0.22481341660022736 -0.33049142360687256 1.2119144201278687 356 | v 0.2089017927646637 -0.4380267560482025 1.1933497190475464 357 | v 0.18268702924251556 -0.544884204864502 1.1415064334869385 358 | v 0.15400460362434387 -0.6433943510055542 1.0494329929351807 359 | v 0.13261690735816956 -0.7254480123519897 0.9229063987731934 360 | v 0.1254996806383133 -0.7871074676513672 0.7768111228942871 361 | v 0.1334223747253418 -0.8316500186920166 0.628197968006134 362 | v 0.15084145963191986 -0.8690167665481567 0.49177050590515137 363 | v 0.3242930769920349 -0.12402870506048203 1.2563166618347168 364 | v 0.3304046094417572 -0.2241183966398239 1.2117130756378174 365 | v 0.3264252543449402 -0.32603755593299866 1.1785615682601929 366 | v 0.3117709755897522 -0.42889031767845154 1.1368019580841064 367 | v 0.2893151044845581 -0.5291370153427124 1.0715458393096924 368 | v 0.2649992108345032 -0.6212489604949951 0.9768064022064209 369 | v 0.2460421323776245 -0.6997258067131042 0.8570361137390137 370 | v 0.23789390921592712 -0.7621930241584778 0.7234991788864136 371 | v 0.24186712503433228 -0.811571478843689 0.58950275182724 372 | v 0.2549058794975281 -0.855847954750061 0.46605706214904785 373 | v 0.439269483089447 -0.10361068695783615 1.2603631019592285 374 | v 0.43782901763916016 -0.20794233679771423 1.1929259300231934 375 | v 0.42912641167640686 -0.3110877573490143 1.1365774869918823 376 | v 0.4128383994102478 -0.41231513023376465 1.0758545398712158 377 | v 0.3912660479545593 -0.5090247988700867 0.9987947940826416 378 | v 0.3688136637210846 -0.5974000692367554 0.9010871052742004 379 | v 0.3507726788520813 -0.673885703086853 0.7859469056129456 380 | v 0.3413808047771454 -0.7372696399688721 0.6618853807449341 381 | v 0.34223610162734985 -0.7903797626495361 0.5390040874481201 382 | v 0.3522462248802185 -0.8398697972297668 0.42544326186180115 383 | v 0.5561176538467407 -0.07031863927841187 1.2200589179992676 384 | v 0.5447238683700562 -0.1816806197166443 1.1408904790878296 385 | v 0.529335081577301 -0.28852543234825134 1.071122169494629 386 | v 0.5094684362411499 -0.39061546325683594 0.9985888600349426 387 | v 0.48678097128868103 -0.48622000217437744 0.914694607257843 388 | v 0.464423805475235 -0.5729162693023682 0.8163415193557739 389 | v 0.4461320638656616 -0.6485322117805481 0.7060515880584717 390 | v 0.43516576290130615 -0.7127767205238342 0.5902966260910034 391 | v 0.4332982003688812 -0.7684394121170044 0.4766782820224762 392 | v 0.4409390091896057 -0.8214534521102905 0.37140652537345886 393 | v 0.6639747619628906 -0.03477395325899124 1.1267296075820923 394 | v 0.6433382630348206 -0.15312199294567108 1.0487070083618164 395 | v 0.6214596033096313 -0.26426222920417786 0.9762568473815918 396 | v 0.5977963805198669 -0.36817672848701477 0.9007381200790405 397 | v 0.573402464389801 -0.46386370062828064 0.816186785697937 398 | v 0.550332248210907 -0.549848735332489 0.720758318901062 399 | v 0.5312125086784363 -0.6250463724136353 0.6167750358581543 400 | v 0.5184434056282043 -0.6896061897277832 0.5090740323066711 401 | v 0.513884425163269 -0.7463863492012024 0.4036141633987427 402 | v 0.5191673636436462 -0.801099419593811 0.3055539131164551 403 | v 0.7515426874160767 -0.00960478838533163 0.9884606599807739 404 | v 0.7254847288131714 -0.1319509595632553 0.9221896529197693 405 | v 0.6999416947364807 -0.2454577535390854 0.8564689755439758 406 | v 0.6742272973060608 -0.35024771094322205 0.785550057888031 407 | v 0.6489324569702148 -0.44566062092781067 0.7058223485946655 408 | v 0.6254384517669678 -0.5308034420013428 0.6166848540306091 409 | v 0.6054711937904358 -0.6051409840583801 0.5201965570449829 410 | v 0.5906241536140442 -0.6689401865005493 0.42034032940864563 411 | v 0.5832584500312805 -0.7249782085418701 0.3219125270843506 412 | v 0.5856527090072632 -0.7790971994400024 0.2296770066022873 413 | v 0.8124392032623291 -0.0040114871226251125 0.8244369626045227 414 | v 0.7871828675270081 -0.12507259845733643 0.7762340903282166 415 | v 0.7623762488365173 -0.2375035136938095 0.72303307056427 416 | v 0.7375283241271973 -0.3410181999206543 0.66154545545578 417 | v 0.7130685448646545 -0.4348335266113281 0.5900822877883911 418 | v 0.6898874044418335 -0.5181528329849243 0.5089664459228516 419 | v 0.6691749691963196 -0.590389609336853 0.4203057885169983 420 | v 0.6526314616203308 -0.652466356754303 0.3277355134487152 421 | v 0.6410203576087952 -0.7049099206924438 0.2341025173664093 422 | v 0.6396147012710571 -0.7555297613143921 0.14566540718078613 423 | v 0.850645124912262 -0.017807845026254654 0.6558200716972351 424 | v 0.8317064642906189 -0.13321907818317413 0.6278730630874634 425 | v 0.811680018901825 -0.2416752278804779 0.5892383456230164 426 | v 0.7905247211456299 -0.3420526683330536 0.538809061050415 427 | v 0.7685990333557129 -0.4331267178058624 0.4765530824661255 428 | v 0.7465379238128662 -0.5137330889701843 0.403548926115036 429 | v 0.7251031398773193 -0.5831363201141357 0.3218887746334076 430 | v 0.7049967646598816 -0.6409347057342529 0.2340986132621765 431 | v 0.6890027523040771 -0.6889607906341553 0.14496833086013794 432 | v 0.6811439990997314 -0.7300369739532471 0.05558300018310547 433 | v 0.8791988492012024 -0.041933540254831314 0.5011640787124634 434 | v 0.8690167665481567 -0.15084145963191986 0.49177050590515137 435 | v 0.855847954750061 -0.2549058794975281 0.46605706214904785 436 | v 0.8398698568344116 -0.35224607586860657 0.42544323205947876 437 | v 0.8214532732963562 -0.44093912839889526 0.37140655517578125 438 | v 0.801099419593811 -0.5191673636436462 0.3055539131164551 439 | v 0.7790971994400024 -0.5856527090072632 0.2296770066022873 440 | v 0.7555297613143921 -0.6396147012710571 0.14566540718078613 441 | v 0.7300369739532471 -0.6811439990997314 0.05558300018310547 442 | v 0.7065899968147278 -0.7065899968147278 -0.03824000060558319 443 | f 1 2 3 4 444 | f 2 5 6 3 445 | f 7 8 6 5 446 | f 7 9 10 8 447 | f 9 11 12 10 448 | f 14 12 11 13 449 | f 13 15 16 14 450 | f 17 18 16 15 451 | f 19 20 18 17 452 | f 19 21 22 20 453 | f 23 24 4 3 454 | f 6 25 23 3 455 | f 6 8 26 25 456 | f 8 10 27 26 457 | f 27 10 12 28 458 | f 28 12 14 29 459 | f 14 16 30 29 460 | f 18 31 30 16 461 | f 18 20 32 31 462 | f 33 32 20 22 463 | f 24 23 34 35 464 | f 25 36 34 23 465 | f 25 26 37 36 466 | f 26 27 38 37 467 | f 27 28 39 38 468 | f 40 39 28 29 469 | f 29 30 41 40 470 | f 41 30 31 42 471 | f 31 32 43 42 472 | f 44 43 32 33 473 | f 35 34 45 46 474 | f 34 36 47 45 475 | f 47 36 37 48 476 | f 37 38 49 48 477 | f 50 49 38 39 478 | f 39 40 51 50 479 | f 40 41 52 51 480 | f 53 52 41 42 481 | f 42 43 54 53 482 | f 54 43 44 55 483 | f 46 45 56 57 484 | f 58 56 45 47 485 | f 48 59 58 47 486 | f 49 60 59 48 487 | f 49 50 61 60 488 | f 50 51 62 61 489 | f 51 52 63 62 490 | f 53 64 63 52 491 | f 53 54 65 64 492 | f 54 55 66 65 493 | f 57 56 67 68 494 | f 67 56 58 69 495 | f 58 59 70 69 496 | f 59 60 71 70 497 | f 60 61 72 71 498 | f 72 61 62 73 499 | f 62 63 74 73 500 | f 63 64 75 74 501 | f 64 65 76 75 502 | f 76 65 66 77 503 | f 78 79 68 67 504 | f 67 69 80 78 505 | f 80 69 70 81 506 | f 70 71 82 81 507 | f 82 71 72 83 508 | f 83 72 73 84 509 | f 73 74 85 84 510 | f 85 74 75 86 511 | f 75 76 87 86 512 | f 77 88 87 76 513 | f 79 78 89 90 514 | f 78 80 91 89 515 | f 92 91 80 81 516 | f 81 82 93 92 517 | f 82 83 94 93 518 | f 83 84 95 94 519 | f 84 85 96 95 520 | f 85 86 97 96 521 | f 86 87 98 97 522 | f 87 88 99 98 523 | f 100 101 90 89 524 | f 89 91 102 100 525 | f 91 92 103 102 526 | f 93 104 103 92 527 | f 93 94 105 104 528 | f 95 106 105 94 529 | f 95 96 107 106 530 | f 96 97 108 107 531 | f 108 97 98 109 532 | f 109 98 99 110 533 | f 112 101 100 111 534 | f 102 113 111 100 535 | f 102 103 114 113 536 | f 103 104 115 114 537 | f 116 115 104 105 538 | f 116 105 106 117 539 | f 117 106 107 118 540 | f 118 107 108 119 541 | f 119 108 109 120 542 | f 120 109 110 121 543 | f 1 4 122 123 544 | f 122 4 24 124 545 | f 124 24 35 125 546 | f 35 46 126 125 547 | f 126 46 57 127 548 | f 127 57 68 128 549 | f 129 128 68 79 550 | f 90 130 129 79 551 | f 90 101 131 130 552 | f 101 112 132 131 553 | f 134 123 122 133 554 | f 122 124 135 133 555 | f 136 135 124 125 556 | f 125 126 137 136 557 | f 126 127 138 137 558 | f 127 128 139 138 559 | f 139 128 129 140 560 | f 129 130 141 140 561 | f 131 142 141 130 562 | f 131 132 143 142 563 | f 134 133 144 145 564 | f 133 135 146 144 565 | f 135 136 147 146 566 | f 137 148 147 136 567 | f 149 148 137 138 568 | f 138 139 150 149 569 | f 151 150 139 140 570 | f 140 141 152 151 571 | f 142 153 152 141 572 | f 153 142 143 154 573 | f 145 144 155 156 574 | f 144 146 157 155 575 | f 157 146 147 158 576 | f 159 158 147 148 577 | f 159 148 149 160 578 | f 149 150 161 160 579 | f 150 151 162 161 580 | f 162 151 152 163 581 | f 152 153 164 163 582 | f 165 164 153 154 583 | f 156 155 166 167 584 | f 155 157 168 166 585 | f 168 157 158 169 586 | f 170 169 158 159 587 | f 159 160 171 170 588 | f 161 172 171 160 589 | f 161 162 173 172 590 | f 162 163 174 173 591 | f 163 164 175 174 592 | f 176 175 164 165 593 | f 167 166 177 178 594 | f 177 166 168 179 595 | f 168 169 180 179 596 | f 181 180 169 170 597 | f 170 171 182 181 598 | f 171 172 183 182 599 | f 183 172 173 184 600 | f 173 174 185 184 601 | f 186 185 174 175 602 | f 175 176 187 186 603 | f 178 177 188 189 604 | f 190 188 177 179 605 | f 179 180 191 190 606 | f 191 180 181 192 607 | f 181 182 193 192 608 | f 182 183 194 193 609 | f 184 195 194 183 610 | f 185 196 195 184 611 | f 185 186 197 196 612 | f 186 187 198 197 613 | f 200 189 188 199 614 | f 199 188 190 201 615 | f 190 191 202 201 616 | f 192 203 202 191 617 | f 192 193 204 203 618 | f 193 194 205 204 619 | f 195 206 205 194 620 | f 195 196 207 206 621 | f 196 197 208 207 622 | f 208 197 198 209 623 | f 211 200 199 210 624 | f 199 201 212 210 625 | f 202 213 212 201 626 | f 202 203 214 213 627 | f 214 203 204 215 628 | f 215 204 205 216 629 | f 217 216 205 206 630 | f 206 207 218 217 631 | f 219 218 207 208 632 | f 219 208 209 220 633 | f 221 222 211 210 634 | f 221 210 212 223 635 | f 212 213 224 223 636 | f 224 213 214 225 637 | f 214 215 226 225 638 | f 227 226 215 216 639 | f 217 228 227 216 640 | f 217 218 229 228 641 | f 218 219 230 229 642 | f 219 220 231 230 643 | f 123 232 233 1 644 | f 234 232 123 134 645 | f 134 145 235 234 646 | f 235 145 156 236 647 | f 156 167 237 236 648 | f 167 178 238 237 649 | f 239 238 178 189 650 | f 239 189 200 240 651 | f 200 211 241 240 652 | f 241 211 222 242 653 | f 233 232 243 244 654 | f 245 243 232 234 655 | f 234 235 246 245 656 | f 236 247 246 235 657 | f 247 236 237 248 658 | f 237 238 249 248 659 | f 238 239 250 249 660 | f 250 239 240 251 661 | f 252 251 240 241 662 | f 252 241 242 253 663 | f 255 244 243 254 664 | f 243 245 256 254 665 | f 245 246 257 256 666 | f 246 247 258 257 667 | f 258 247 248 259 668 | f 248 249 260 259 669 | f 249 250 261 260 670 | f 250 251 262 261 671 | f 263 262 251 252 672 | f 252 253 264 263 673 | f 254 265 266 255 674 | f 254 256 267 265 675 | f 256 257 268 267 676 | f 257 258 269 268 677 | f 270 269 258 259 678 | f 259 260 271 270 679 | f 271 260 261 272 680 | f 261 262 273 272 681 | f 274 273 262 263 682 | f 263 264 275 274 683 | f 266 265 276 277 684 | f 276 265 267 278 685 | f 267 268 279 278 686 | f 280 279 268 269 687 | f 269 270 281 280 688 | f 270 271 282 281 689 | f 283 282 271 272 690 | f 272 273 284 283 691 | f 284 273 274 285 692 | f 274 275 286 285 693 | f 277 276 287 288 694 | f 278 289 287 276 695 | f 279 290 289 278 696 | f 279 280 291 290 697 | f 280 281 292 291 698 | f 281 282 293 292 699 | f 283 294 293 282 700 | f 283 284 295 294 701 | f 284 285 296 295 702 | f 285 286 297 296 703 | f 299 288 287 298 704 | f 287 289 300 298 705 | f 289 290 301 300 706 | f 290 291 302 301 707 | f 302 291 292 303 708 | f 292 293 304 303 709 | f 293 294 305 304 710 | f 294 295 306 305 711 | f 306 295 296 307 712 | f 297 308 307 296 713 | f 299 298 309 310 714 | f 298 300 311 309 715 | f 312 311 300 301 716 | f 301 302 313 312 717 | f 313 302 303 314 718 | f 303 304 315 314 719 | f 315 304 305 316 720 | f 305 306 317 316 721 | f 306 307 318 317 722 | f 319 318 307 308 723 | f 310 309 320 321 724 | f 309 311 322 320 725 | f 311 312 323 322 726 | f 312 313 324 323 727 | f 313 314 325 324 728 | f 326 325 314 315 729 | f 326 315 316 327 730 | f 316 317 328 327 731 | f 317 318 329 328 732 | f 318 319 330 329 733 | f 321 320 331 332 734 | f 320 322 333 331 735 | f 334 333 322 323 736 | f 324 335 334 323 737 | f 324 325 336 335 738 | f 336 325 326 337 739 | f 338 337 326 327 740 | f 327 328 339 338 741 | f 340 339 328 329 742 | f 340 329 330 341 743 | f 2 1 233 342 744 | f 343 342 233 244 745 | f 343 244 255 344 746 | f 255 266 345 344 747 | f 266 277 346 345 748 | f 346 277 288 347 749 | f 348 347 288 299 750 | f 299 310 349 348 751 | f 310 321 350 349 752 | f 332 351 350 321 753 | f 2 342 352 5 754 | f 342 343 353 352 755 | f 343 344 354 353 756 | f 354 344 345 355 757 | f 345 346 356 355 758 | f 346 347 357 356 759 | f 358 357 347 348 760 | f 348 349 359 358 761 | f 349 350 360 359 762 | f 350 351 361 360 763 | f 352 362 7 5 764 | f 352 353 363 362 765 | f 363 353 354 364 766 | f 365 364 354 355 767 | f 366 365 355 356 768 | f 356 357 367 366 769 | f 368 367 357 358 770 | f 358 359 369 368 771 | f 360 370 369 359 772 | f 370 360 361 371 773 | f 7 362 372 9 774 | f 362 363 373 372 775 | f 373 363 364 374 776 | f 375 374 364 365 777 | f 375 365 366 376 778 | f 366 367 377 376 779 | f 367 368 378 377 780 | f 378 368 369 379 781 | f 369 370 380 379 782 | f 381 380 370 371 783 | f 9 372 382 11 784 | f 372 373 383 382 785 | f 383 373 374 384 786 | f 385 384 374 375 787 | f 375 376 386 385 788 | f 376 377 387 386 789 | f 377 378 388 387 790 | f 378 379 389 388 791 | f 389 379 380 390 792 | f 390 380 381 391 793 | f 11 382 392 13 794 | f 392 382 383 393 795 | f 394 393 383 384 796 | f 384 385 395 394 797 | f 385 386 396 395 798 | f 386 387 397 396 799 | f 387 388 398 397 800 | f 399 398 388 389 801 | f 389 390 400 399 802 | f 400 390 391 401 803 | f 13 392 402 15 804 | f 402 392 393 403 805 | f 403 393 394 404 806 | f 404 394 395 405 807 | f 406 405 395 396 808 | f 397 407 406 396 809 | f 397 398 408 407 810 | f 398 399 409 408 811 | f 409 399 400 410 812 | f 401 411 410 400 813 | f 15 402 412 17 814 | f 402 403 413 412 815 | f 403 404 414 413 816 | f 414 404 405 415 817 | f 405 406 416 415 818 | f 407 417 416 406 819 | f 407 408 418 417 820 | f 418 408 409 419 821 | f 409 410 420 419 822 | f 421 420 410 411 823 | f 17 412 422 19 824 | f 412 413 423 422 825 | f 413 414 424 423 826 | f 414 415 425 424 827 | f 415 416 426 425 828 | f 417 427 426 416 829 | f 428 427 417 418 830 | f 418 419 429 428 831 | f 429 419 420 430 832 | f 431 430 420 421 833 | f 21 19 422 432 834 | f 432 422 423 433 835 | f 423 424 434 433 836 | f 424 425 435 434 837 | f 435 425 426 436 838 | f 426 427 437 436 839 | f 437 427 428 438 840 | f 428 429 439 438 841 | f 429 430 440 439 842 | f 440 430 431 441 843 | -------------------------------------------------------------------------------- /objs/obj_snet/cmc1.obj: -------------------------------------------------------------------------------- 1 | o cmc1 2 | v -2.41135311127 2.29546260834 -4.07387876511 3 | v -1.49506103992 3.15898823738 -3.6872947216 4 | v -2.40302062035 3.67343139648 -2.87840151787 5 | v -3.24580287933 2.87534427643 -3.34024453163 6 | v -2.40039849281 4.48955583572 -1.24975168705 7 | v -1.49197340012 4.82872486115 -0.351256787777 8 | v -2.40663361549 4.62120580673 0.571494996548 9 | v -3.24707269669 4.38011074066 -0.333878666162 10 | v -2.41649055481 -1.25259757042 -4.53753185272 11 | v -1.50625538826 -0.375676751137 -4.87154769897 12 | v -2.41357827187 0.570385813713 -4.65568447113 13 | v -3.26228523254 -0.316749572754 -4.41608524323 14 | v -2.41221046448 4.04643535614 2.30732059479 15 | v -1.50813508034 3.64810276031 3.19270038605 16 | v -2.42791199684 2.85006356239 3.68973135948 17 | v -3.26615333557 3.32112574577 2.86865448952 18 | v -2.43384575844 1.21340250969 4.51340484619 19 | v -1.53189456463 0.30433088541 4.86346721649 20 | v -2.45025801659 -0.615498900414 4.64437532425 21 | v -3.28747963905 0.299916088581 4.39194107056 22 | v -2.45514011383 -2.35807847977 4.06573820114 23 | v -1.54955196381 -3.24386501312 3.67850017548 24 | v -2.4651966095 -3.74378418922 2.86142063141 25 | v -3.30579137802 -2.92306685448 3.3219602108 26 | v -2.4575343132 -4.5648765564 1.21732461452 27 | v -1.55108380318 -4.91359233856 0.317626684904 28 | v -2.45492386818 -4.68963766098 -0.607962906361 29 | v -3.29642128944 -4.43892049789 0.297215998173 30 | v -0.578842878342 -4.3623418808 -2.47250199318 31 | v -1.52595829964 -4.67371034622 -1.55971741676 32 | v -0.584372639656 -4.97895050049 -0.639513015747 33 | v 0.379854440689 -4.74262571335 -1.57557976246 34 | v 3.01952695847 -1.17255246639 -4.12793064117 35 | v 2.218978405 -2.09742188454 -4.09605360031 36 | v 3.03217172623 -2.66924548149 -3.37926602364 37 | v 3.74753332138 -1.80029702187 -3.51572537422 38 | v 2.22846627235 1.39570128918 -4.33873605728 39 | v 1.34936583042 2.33230257034 -4.17260408401 40 | v 0.406313180923 1.51589035988 -4.68763875961 41 | v 1.34037899971 0.553339540958 -4.76835250854 42 | v 1.36016023159 4.58543300629 -1.26513969898 43 | v 2.24218392372 4.51008224487 -0.31916347146 44 | v 1.3579723835 4.71795082092 0.607334733009 45 | v 0.424318164587 4.88242197037 -0.347367972136 46 | v 2.2400560379 4.28551578522 1.45459532738 47 | v 1.35183238983 4.12135839462 2.39169120789 48 | v 0.416705936193 4.6402759552 1.56912207603 49 | v 1.33064031601 1.2089548111 4.64595651627 50 | v 2.2074368 0.258309811354 4.57634019852 51 | v 1.3174084425 -0.663097858429 4.77781963348 52 | v 0.384932070971 0.29342392087 4.93550872803 53 | v 1.3125743866 -2.44546484947 4.18168544769 54 | v 2.19344043732 -3.06791329384 3.46428513527 55 | v 1.30681097507 -3.86246418953 2.95193767548 56 | v 0.36956179142 -3.29827642441 3.73501968384 57 | v 2.19179844856 -4.16226482391 2.05294561386 58 | v 1.31175148487 -4.70177602768 1.26842439175 59 | v 0.36754027009 -4.48250341415 2.20632982254 60 | v 2.21920824051 -3.51587915421 -2.9998588562 61 | v 3.01623415947 -3.77792978287 -2.11666464806 62 | v 3.74337720871 -3.01873707771 -2.58053898811 63 | v 4.92247056961 -2.455108881 -2.109582901 64 | v 5.39323472977 -2.52204632759 -1.42796778679 65 | v 5.80297088623 -1.95854866505 -1.67217850685 66 | v 5.38984584808 -1.79235339165 -2.26304554939 67 | v 4.37184858322 -0.987594604492 -3.43800711632 68 | v 4.91947078705 -0.27759835124 -3.18983387947 69 | v 4.36713218689 0.40136796236 -3.53664541245 70 | v 3.73696184158 -0.320543527603 -3.92269086838 71 | v 4.37651777267 1.70991969109 -3.09268760681 72 | v 4.92514944077 2.03661489487 -2.41409778595 73 | v 4.38156747818 2.7567024231 -2.18079280853 74 | v 3.75194716454 2.51766705513 -2.96551203728 75 | v 4.38599872589 3.37419748306 -0.941035091877 76 | v 4.93210315704 3.12524175644 -0.231379896402 77 | v 4.38683366776 3.47325015068 0.44121748209 78 | v 3.76186299324 3.85783004761 -0.278130739927 79 | v 4.38388872147 3.0358774662 1.76209676266 80 | v 4.92857885361 2.35743570328 2.0886900425 81 | v 4.37771177292 2.1279168129 2.81490850449 82 | v 3.75106906891 2.91190218925 2.57652950287 83 | v 4.3672990799 0.883418738842 3.44376993179 84 | v 4.91239213943 0.168701812625 3.19626927376 85 | v 4.36013793945 -0.506509840488 3.54602169991 86 | v 3.73166441917 0.218267798424 3.93109416962 87 | v 4.35383939743 -1.83242416382 3.10695695877 88 | v 4.90509939194 -2.16648221016 2.41973209381 89 | v 4.35385656357 -2.88528060913 2.19202327728 90 | v 3.7180378437 -2.64486980438 2.98085689545 91 | v 4.90485143661 -3.25883150101 0.220348373055 92 | v 5.37765836716 -2.81958627701 0.750413835049 93 | v 5.80244159698 -2.58475780487 0.158364996314 94 | v 5.3912820816 -2.88305830956 -0.379716396332 95 | v 6.48619556427 -1.37273931503 1.50440621376 96 | v 6.78506422043 -0.946230232716 1.54270780087 97 | v 7.06359577179 -1.1187735796 1.198569417 98 | v 6.78966903687 -1.47301912308 1.07824623585 99 | v 6.1682100296 -2.22722601891 0.572259545326 100 | v 6.49790906906 -2.04349303246 0.11929705739 101 | v 6.17111873627 -2.27818775177 -0.304001450539 102 | v 6.16719007492 -1.99569356441 -1.13340950012 103 | v 6.49260854721 -1.54778182507 -1.3283623457 104 | v 6.16709280014 -1.42038083076 -1.78731274605 105 | v 6.16396045685 -0.63896715641 -2.17671728134 106 | v 6.48881816864 -0.187867686152 -2.00242877007 107 | v 6.16415500641 0.230529427528 -2.23591136932 108 | v 5.79848527908 -0.227441564202 -2.53360652924 109 | v 6.16822814941 1.05126309395 -1.9583940506 110 | v 6.49701929092 1.2404563427 -1.51864528656 111 | v 6.16863489151 1.71250450611 -1.38542807102 112 | v 5.80307435989 1.60255289078 -1.9168407917 113 | v 6.17413043976 2.0988740921 -0.607142031193 114 | v 6.50150918961 1.92162632942 -0.159721627831 115 | v 6.17567682266 2.16284251213 0.263926059008 116 | v 5.81194591522 2.46005058289 -0.1936750561 117 | v 6.17425394058 1.89148712158 1.09385693073 118 | v 6.49993276596 1.44841790199 1.28747427464 119 | v 6.17289495468 1.32194364071 1.75865530968 120 | v 5.81056308746 1.85719275475 1.6432300806 121 | v 6.4957242012 0.0819154456258 1.98099386692 122 | v 6.79504823685 0.411239236593 1.70250535011 123 | v 7.07058858871 0.0509234666824 1.58173298836 124 | v 6.79060792923 -0.286431252956 1.75754523277 125 | v 5.7995018959 0.126065999269 2.52573275566 126 | v 6.16767692566 0.538857877254 2.15889763832 127 | v 6.16455745697 -0.338981240988 2.2260184288 128 | v 5.80682754517 1.07877469063 2.25591850281 129 | v 6.49739456177 0.838017106056 1.7692091465 130 | v 6.79531764984 1.03340995312 1.38707816601 131 | v 7.07266426086 0.653600275517 1.41238963604 132 | v 6.50038290024 1.82957172394 0.609103798866 133 | v 5.81383228302 2.33865618706 0.785661458969 134 | v 6.79643154144 1.69988226891 0.200218841434 135 | v 7.0702252388 1.45376372337 0.482465147972 136 | v 6.79613113403 1.48481571674 0.859380722046 137 | v 7.07152223587 1.14852559566 1.02433872223 138 | v 6.49530935287 1.71951568127 -0.905986189842 139 | v 5.81137084961 2.19831490517 -1.13997817039 140 | v 6.7936205864 1.33718538284 -1.10878169537 141 | v 7.07044315338 1.35988748074 -0.737974405289 142 | v 6.79423046112 1.64956974983 -0.487408190966 143 | v 7.07070398331 1.52726185322 -0.134456261992 144 | v 6.48977947235 0.57555347681 -1.90350604057 145 | v 5.80559968948 0.743176281452 -2.40461826324 146 | v 6.78396129608 0.169794008136 -1.7820302248 147 | v 7.05952596664 0.446291655302 -1.53783500195 148 | v 6.7880282402 0.819675862789 -1.56142604351 149 | v 7.06548404694 0.981170892715 -1.22787392139 150 | v 6.49169969559 -0.935591459274 -1.79830574989 151 | v 5.80069065094 -1.17578959465 -2.27579855919 152 | v 6.78930425644 -1.12845945358 -1.42746520042 153 | v 7.06036520004 -0.747756898403 -1.45736181736 154 | v 6.78607082367 -0.512846887112 -1.73399651051 155 | v 7.05518531799 -0.16111086309 -1.61902701855 156 | v 6.49616241455 -1.93930232525 -0.650610864162 157 | v 5.80539274216 -2.44816255569 -0.826610028744 158 | v 6.79543924332 -1.81475222111 -0.239083766937 159 | v 7.07383918762 -1.56038844585 -0.520553469658 160 | v 6.79554510117 -1.58729243279 -0.899975955486 161 | v 7.07258081436 -1.24257957935 -1.06830298901 162 | v 6.15838336945 -1.83964157104 1.37602245808 163 | v 6.49376344681 -1.84705603123 0.877577424049 164 | v 5.79285764694 -2.33357620239 1.12767517567 165 | v 7.06605911255 -1.49335467815 0.705271661282 166 | v 6.79479646683 -1.77315092087 0.455398499966 167 | v 7.07228565216 -1.64652776718 0.105422399938 168 | v 5.79174661636 -1.72487664223 1.91683650017 169 | v 6.16009283066 -1.17716050148 1.9505739212 170 | v 5.79756832123 -0.863872766495 2.40333414078 171 | v 6.48902606964 -0.691962361336 1.89001607895 172 | v 7.06429815292 -0.574092924595 1.50928556919 173 | v 3.72111201286 -3.99094367027 0.283799469471 174 | v 4.35524320602 -3.50759482384 0.94127112627 175 | v 4.35744476318 -3.60296154022 -0.445094555616 176 | v 3.72707891464 -3.58577537537 1.75705695152 177 | v 4.89849758148 -2.93350982666 1.43490421772 178 | v 5.37769412994 -2.32346391678 1.74884808064 179 | v 4.90277290344 -1.07345986366 3.04623174667 180 | v 3.72733187675 -1.3092751503 3.7384326458 181 | v 5.38201141357 -0.415497213602 2.83559703827 182 | v 5.37943792343 -1.4769231081 2.48363280296 183 | v 4.91759967804 1.37728750706 2.86074399948 184 | v 3.74584293365 1.69590604305 3.52110624313 185 | v 5.39487934113 1.69392740726 2.24531769753 186 | v 5.389585495 0.69982534647 2.74934220314 187 | v 4.92928218842 2.97416830063 1.0010933876 188 | v 3.76218748093 3.66588926315 1.24293732643 189 | v 5.40142393112 2.76536512375 0.345939546824 190 | v 5.40088415146 2.41764307022 1.39955449104 191 | v 4.92743682861 2.79789209366 -1.43230378628 192 | v 3.75991559029 3.45448350906 -1.75235295296 193 | v 5.39664697647 2.19031763077 -1.7513409853 194 | v 5.39946699142 2.68563818932 -0.760085165501 195 | v 4.91294240952 0.963974952698 -3.03620672226 196 | v 3.74913096428 1.19077348709 -3.72314095497 197 | v 5.38988637924 0.304008215666 -2.83124423027 198 | v 5.38974332809 1.36069202423 -2.47785115242 199 | v 4.37045145035 -2.22794675827 -2.82425522804 200 | v 4.91108894348 -1.4775094986 -2.86985349655 201 | v 5.38611412048 -0.799368679523 -2.75765347481 202 | v 4.37739133835 -3.14046168327 -1.7773348093 203 | v 3.73420763016 -3.78987908363 -1.24538016319 204 | v 4.91639471054 -3.08721733093 -1.02601575851 205 | v 0.395765334368 -3.78148508072 -3.25037050247 206 | v 1.32663190365 -4.23204517365 -2.39082503319 207 | v 1.33634233475 -2.9989964962 -3.80298066139 208 | v 1.317263484 -4.83227491379 -0.603269457817 209 | v 2.20227193832 -4.4071598053 -1.44914054871 210 | v 3.00965762138 -4.30811548233 -0.53835862875 211 | v 3.00407290459 -4.19331455231 1.1325160265 212 | v 3.00111746788 -3.44813656807 2.62848901749 213 | v 2.2016351223 -4.63218927383 0.316356569529 214 | v 0.375057041645 -4.98871612549 0.351322084665 215 | v 2.19728589058 -1.51383686066 4.3520450592 216 | v 0.374041795731 -1.62342381477 4.69179534912 217 | v 3.00979423523 -0.600183963776 4.25322437286 218 | v 3.0027589798 -2.18433332443 3.72558283806 219 | v 1.3397988081 2.89102435112 3.80774712563 220 | v 2.21871042252 1.98752343655 4.10393810272 221 | v 0.39530941844 2.15296769142 4.42920398712 222 | v 3.03049063683 2.56089067459 3.38640260696 223 | v 3.01901197433 1.06760644913 4.13418054581 224 | v 3.0386698246 3.65691184998 2.12160539627 225 | v 3.04512500763 4.18288612366 0.540201425552 226 | v 2.22911262512 3.39849448204 3.01010274887 227 | v 0.408829033375 3.68261408806 3.24509096146 228 | v 1.3554058075 3.74753856659 -2.94358420372 229 | v 2.24183392525 4.03782606125 -2.04397034645 230 | v 0.421674519777 4.37357378006 -2.20723247528 231 | v 3.04047489166 3.32156825066 -2.61622548103 232 | v 3.04453372955 4.06560182571 -1.12426614761 233 | v 3.03164958954 2.06592035294 -3.71010994911 234 | v 3.02943301201 0.485484391451 -4.23868846893 235 | v 2.23297214508 2.94787073135 -3.45219874382 236 | v 0.418635398149 3.18867278099 -3.73327088356 237 | v 2.22085952759 -0.376439392567 -4.56455564499 238 | v 0.40383630991 -0.397718191147 -4.92997550964 239 | v 1.33842253685 -1.32116234303 -4.63667392731 240 | v 0.400782883167 -2.25742554665 -4.42432403564 241 | v -0.565411865711 -3.08233857155 -3.93807268143 242 | v -1.53346812725 -3.72281455994 -3.21222877502 243 | v -2.43239021301 -2.8961930275 -3.72722601891 244 | v -3.27435088158 -3.35014033318 -2.93374156952 245 | v -2.43992447853 -4.10161781311 -2.35438346863 246 | v -3.29200363159 -4.21382713318 -1.43626236916 247 | v -1.5484367609 -4.41108131409 2.17340159416 248 | v -3.30331730843 -3.98877215385 1.94825518131 249 | v -0.593432843685 -3.9784245491 3.04054808617 250 | v -0.598198354244 -4.84441614151 1.30370950699 251 | v -1.54257166386 -1.58477091789 4.62489938736 252 | v -3.29488801956 -1.42019307613 4.1795425415 253 | v -0.58152616024 -0.671280443668 4.92844009399 254 | v -0.594928264618 -2.51063466072 4.31431818008 255 | v -1.52164375782 2.14563751221 4.35878372192 256 | v -3.27055096626 1.96043336391 3.93470144272 257 | v -0.560000181198 2.99868416786 3.92606854439 258 | v -0.574221670628 1.26382219791 4.79181718826 259 | v -1.50013208389 4.59125471115 1.53700435162 260 | v -3.24824261665 4.17181301117 1.37189364433 261 | v -0.541806161404 4.88460016251 0.621883332729 262 | v -0.551989912987 4.27167272568 2.45935440063 263 | v -1.50750815868 -2.20460796356 -4.38105630875 264 | v -3.26161336899 -1.99704515934 -3.97122049332 265 | v -0.556391954422 -1.34567201138 -4.7961640358 266 | v -0.559124171734 0.5791259408 -4.92790317535 267 | v -1.49351894855 4.32353115082 -2.18788838387 268 | v -3.23913764954 3.92726612091 -1.98612189293 269 | v -0.542747020721 3.88006353378 -3.04492139816 270 | v -0.540403962135 4.74701309204 -1.31165671349 271 | v -1.50717258453 1.50550067425 -4.6292848587 272 | v -3.25063490868 1.39212799072 -4.19187355042 273 | v -0.549559354782 2.41618275642 -4.31438732147 274 | f 1 2 3 4 275 | f 5 6 7 8 276 | f 10 11 12 9 277 | f 13 14 15 16 278 | f 19 20 17 18 279 | f 21 22 23 24 280 | f 25 26 27 28 281 | f 29 30 31 32 282 | f 35 36 33 34 283 | f 38 39 40 37 284 | f 41 42 43 44 285 | f 43 45 46 47 286 | f 48 49 50 51 287 | f 52 53 54 55 288 | f 56 57 58 54 289 | f 61 35 59 60 290 | f 62 63 64 65 291 | f 67 68 69 66 292 | f 70 71 72 73 293 | f 74 75 76 77 294 | f 80 81 78 79 295 | f 82 83 84 85 296 | f 86 87 88 89 297 | f 92 93 90 91 298 | f 94 95 96 97 299 | f 98 99 100 92 300 | f 64 101 102 103 301 | f 107 104 105 106 302 | f 108 109 110 111 303 | f 114 115 112 113 304 | f 116 117 118 119 305 | f 123 120 121 122 306 | f 124 125 120 126 307 | f 118 128 125 127 308 | f 128 129 130 121 309 | f 114 131 116 132 310 | f 131 133 134 135 311 | f 135 136 129 117 312 | f 110 137 112 138 313 | f 141 137 139 140 314 | f 141 142 133 113 315 | f 106 143 108 144 316 | f 145 146 147 143 317 | f 139 109 147 148 318 | f 103 149 104 150 319 | f 152 153 149 151 320 | f 154 145 105 153 321 | f 100 155 101 156 322 | f 159 155 157 158 323 | f 160 151 102 159 324 | f 161 162 98 163 325 | f 97 164 165 162 326 | f 99 165 166 157 327 | f 167 168 94 161 328 | f 169 126 170 168 329 | f 170 123 171 95 330 | f 173 90 174 172 331 | f 175 88 176 173 332 | f 176 177 163 91 333 | f 179 84 178 86 334 | f 180 169 181 178 335 | f 181 167 177 87 336 | f 80 182 82 183 337 | f 185 182 184 127 338 | f 185 124 180 83 339 | f 76 186 78 187 340 | f 186 188 132 189 341 | f 189 119 184 79 342 | f 72 190 74 191 343 | f 192 138 193 190 344 | f 193 115 188 75 345 | f 195 68 194 70 346 | f 196 144 197 194 347 | f 71 197 111 192 348 | f 198 199 66 36 349 | f 199 65 150 200 350 | f 200 107 196 67 351 | f 61 201 62 198 352 | f 201 202 174 203 353 | f 156 63 203 93 354 | f 204 205 59 206 355 | f 32 207 208 205 356 | f 209 202 60 208 357 | f 211 175 210 56 358 | f 172 209 212 210 359 | f 57 212 207 213 360 | f 52 215 50 214 361 | f 214 216 179 217 362 | f 217 89 211 53 363 | f 218 219 48 220 364 | f 219 221 183 222 365 | f 49 222 85 216 366 | f 187 223 45 224 367 | f 223 81 221 225 368 | f 226 46 225 218 369 | f 227 228 41 229 370 | f 230 191 231 228 371 | f 231 77 224 42 372 | f 37 233 195 232 373 | f 73 230 234 232 374 | f 234 227 235 38 375 | f 69 233 236 33 376 | f 236 40 237 238 377 | f 238 239 206 34 378 | f 240 241 29 204 379 | f 244 241 242 243 380 | f 30 244 245 27 381 | f 23 246 25 247 382 | f 249 246 248 58 383 | f 213 31 26 249 384 | f 19 250 21 251 385 | f 253 250 252 215 386 | f 253 55 248 22 387 | f 15 254 17 255 388 | f 256 220 257 254 389 | f 18 257 51 252 390 | f 7 258 13 259 391 | f 260 47 261 258 392 | f 261 226 256 14 393 | f 242 262 9 263 394 | f 240 239 264 262 395 | f 264 237 265 10 396 | f 3 266 5 267 397 | f 266 268 229 269 398 | f 269 44 260 6 399 | f 11 270 1 271 400 | f 265 39 272 270 401 | f 2 272 235 268 402 | f 44 43 47 260 403 | f 226 218 220 256 404 | f 50 215 252 51 405 | f 248 55 54 58 406 | f 213 207 32 31 407 | f 239 240 204 206 408 | f 40 39 265 237 409 | f 268 235 227 229 410 | f 224 77 76 187 411 | f 81 80 183 221 412 | f 85 84 179 216 413 | f 211 89 88 175 414 | f 172 174 202 209 415 | f 198 36 35 61 416 | f 195 233 69 68 417 | f 73 72 191 230 418 | f 114 132 188 115 419 | f 119 118 127 184 420 | f 124 126 169 180 421 | f 163 177 167 161 422 | f 93 92 100 156 423 | f 65 64 103 150 424 | f 144 196 107 106 425 | f 111 110 138 192 426 | f 272 39 38 235 427 | f 2 268 266 3 428 | f 265 270 11 10 429 | f 269 229 41 44 430 | f 7 6 260 258 431 | f 264 239 238 237 432 | f 240 262 242 241 433 | f 261 47 46 226 434 | f 256 254 15 14 435 | f 257 220 48 51 436 | f 252 250 19 18 437 | f 253 215 52 55 438 | f 23 22 248 246 439 | f 249 58 57 213 440 | f 31 30 27 26 441 | f 29 32 205 204 442 | f 40 236 233 37 443 | f 69 33 36 66 444 | f 206 59 35 34 445 | f 228 227 234 230 446 | f 232 195 70 73 447 | f 224 45 43 42 448 | f 231 191 74 77 449 | f 219 218 225 221 450 | f 223 187 78 81 451 | f 49 216 214 50 452 | f 85 222 183 82 453 | f 53 211 56 54 454 | f 89 217 179 86 455 | f 209 208 207 212 456 | f 172 210 175 173 457 | f 201 61 60 202 458 | f 203 174 90 93 459 | f 198 62 65 199 460 | f 156 101 64 63 461 | f 196 194 68 67 462 | f 200 150 104 107 463 | f 72 71 192 190 464 | f 144 108 111 197 465 | f 186 76 75 188 466 | f 193 138 112 115 467 | f 182 80 79 184 468 | f 189 132 116 119 469 | f 178 84 83 180 470 | f 185 127 125 124 471 | f 177 176 88 87 472 | f 181 169 168 167 473 | f 92 91 163 98 474 | f 170 126 120 123 475 | f 94 97 162 161 476 | f 155 100 99 157 477 | f 102 151 149 103 478 | f 145 143 106 105 479 | f 109 139 137 110 480 | f 114 113 133 131 481 | f 117 129 128 118 482 | f 121 120 125 128 483 | f 117 116 131 135 484 | f 141 113 112 137 485 | f 147 109 108 143 486 | f 105 104 149 153 487 | f 159 102 101 155 488 | f 162 165 99 98 489 | f 95 94 168 170 490 | f 91 90 173 176 491 | f 87 86 178 181 492 | f 182 185 83 82 493 | f 189 79 78 186 494 | f 75 74 190 193 495 | f 197 71 70 194 496 | f 199 200 67 66 497 | f 63 62 201 203 498 | f 208 60 59 205 499 | f 57 56 210 212 500 | f 53 52 214 217 501 | f 49 48 219 222 502 | f 46 45 223 225 503 | f 42 41 228 231 504 | f 232 234 38 37 505 | f 236 238 34 33 506 | f 30 29 241 244 507 | f 26 25 246 249 508 | f 22 21 250 253 509 | f 17 254 257 18 510 | f 14 13 258 261 511 | f 10 9 262 264 512 | f 269 6 5 266 513 | f 2 1 270 272 514 | --------------------------------------------------------------------------------