├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── add_license.sh ├── data ├── alipay.png ├── linedrawings.png ├── teddy.off ├── teddy.png ├── teddy_line_drawings.gif ├── teddy_line_drawings.png ├── view │ ├── 0.xf │ ├── 1.xf │ ├── 10.xf │ ├── 100.xf │ ├── 101.xf │ ├── 11.xf │ ├── 12.xf │ ├── 13.xf │ ├── 14.xf │ ├── 15.xf │ ├── 16.xf │ ├── 17.xf │ ├── 18.xf │ ├── 19.xf │ ├── 2.xf │ ├── 20.xf │ ├── 21.xf │ ├── 22.xf │ ├── 23.xf │ ├── 24.xf │ ├── 25.xf │ ├── 26.xf │ ├── 27.xf │ ├── 28.xf │ ├── 29.xf │ ├── 3.xf │ ├── 30.xf │ ├── 31.xf │ ├── 32.xf │ ├── 33.xf │ ├── 34.xf │ ├── 35.xf │ ├── 36.xf │ ├── 37.xf │ ├── 38.xf │ ├── 39.xf │ ├── 4.xf │ ├── 40.xf │ ├── 41.xf │ ├── 42.xf │ ├── 43.xf │ ├── 44.xf │ ├── 45.xf │ ├── 46.xf │ ├── 47.xf │ ├── 48.xf │ ├── 49.xf │ ├── 5.xf │ ├── 50.xf │ ├── 51.xf │ ├── 52.xf │ ├── 53.xf │ ├── 54.xf │ ├── 55.xf │ ├── 56.xf │ ├── 57.xf │ ├── 58.xf │ ├── 59.xf │ ├── 6.xf │ ├── 60.xf │ ├── 61.xf │ ├── 62.xf │ ├── 63.xf │ ├── 64.xf │ ├── 65.xf │ ├── 66.xf │ ├── 67.xf │ ├── 68.xf │ ├── 69.xf │ ├── 7.xf │ ├── 70.xf │ ├── 71.xf │ ├── 72.xf │ ├── 73.xf │ ├── 74.xf │ ├── 75.xf │ ├── 76.xf │ ├── 77.xf │ ├── 78.xf │ ├── 79.xf │ ├── 8.xf │ ├── 80.xf │ ├── 81.xf │ ├── 82.xf │ ├── 83.xf │ ├── 84.xf │ ├── 85.xf │ ├── 86.xf │ ├── 87.xf │ ├── 88.xf │ ├── 89.xf │ ├── 9.xf │ ├── 90.xf │ ├── 91.xf │ ├── 92.xf │ ├── 93.xf │ ├── 94.xf │ ├── 95.xf │ ├── 96.xf │ ├── 97.xf │ ├── 98.xf │ └── 99.xf └── viewpoints.png ├── featurelines.cpp ├── featurelines.h ├── include ├── Color.h ├── GLCamera.h ├── KDtree.h ├── Vec.h ├── XForm.h ├── bsphere.h ├── lineqn.h ├── mempool.h ├── meshalgo.h ├── strutil.h ├── timestamp.h └── trianglemesh.h ├── linedrawing_project.sh ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── threshdialog.cpp ├── threshdialog.h ├── threshdialog.ui ├── trianglemesh.pro ├── trianglemesh ├── GLCamera.cpp ├── KDtree.cpp ├── diffuse.cpp ├── trianglemesh_bounding.cpp ├── trianglemesh_connectivity.cpp ├── trianglemesh_curvature.cpp ├── trianglemesh_io.cpp ├── trianglemesh_normals.cpp ├── trianglemesh_pointareas.cpp ├── trianglemesh_stats.cpp └── trianglemesh_tstrips.cpp ├── trimeshview.cpp ├── trimeshview.h ├── trimeshview_draw_apparent_ridges.cpp ├── trimeshview_draw_base.cpp ├── trimeshview_draw_lines.cpp ├── trimeshview_draw_ridges_and_valleys.cpp ├── ui_mainwindow.h ├── ui_threshdialog.h └── ui_threshform.h /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | *.pro.user 16 | *.pro.user.* 17 | moc_*.cpp 18 | qrc_*.cpp 19 | Makefile 20 | release 21 | *-build-* 22 | 23 | .DS_Store 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # https://travis-ci.org 2 | 3 | language: cpp 4 | 5 | sudo: required 6 | dist: trusty 7 | 8 | before_install: 9 | - sudo add-apt-repository --yes ppa:beineri/opt-qt551-trusty 10 | - sudo apt-get update -qq 11 | 12 | install: 13 | - sudo apt-get -y install qt55[QTPACKAGE] 14 | 15 | script: 16 | - source /opt/qt55/bin/qt55-env.sh 17 | - mkdir release && cd release 18 | - /opt/qt55/bin/qmake ../trianglemesh.pro -o Makefile 19 | - make -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Zhang Dongdong 2 | All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Line Drawings View Tool [![Build Status](https://travis-ci.org/zddhub/trianglemesh.svg?branch=master)](https://travis-ci.org/zddhub/trianglemesh) 2 | ======================= 3 | 4 | This project serves [OpenSSE](https://github.com/zddhub/opensse), that gets line-drawing images for each model (support *.off and *.obj) using viewpoint matrix(under `../data/view/`). 5 | 6 | ![line drawings](data/teddy_line_drawings.gif "Line drawings") 7 | 8 | 9 | Demo 10 | ==== 11 | 12 | In [my demo](http://opensse.com), I used 102 viewpoints on globe to project line drawings. 13 | 14 | ### View points(red points) 15 | 16 | ![view points](data/viewpoints.png) 17 | 18 | ### Model 19 | 20 | ![teddy](data/teddy.png) 21 | 22 | ### Line drawings images 23 | 24 | ![line drawings](data/teddy_line_drawings.png) 25 | 26 | 27 | Compile 28 | ======= 29 | 30 | ```shell 31 | mkdir release; cd release 32 | qmake ../trianglemesh.pro -o Makefile 33 | make 34 | ``` 35 | 36 | You will get your executable tool under `bin` folder. 37 | 38 | Usage 39 | ===== 40 | ```shell 41 | gen_view_image modelfile xfdir viewnum imagedir 42 | ``` 43 | example: 44 | ```shell 45 | mkdir teddy_images 46 | ./gen_view_image ../../data/teddy.off ../../data/view/ 102 teddy_images 47 | ``` 48 | 49 | Support for OpenSSE 50 | =================== 51 | 52 | There is a tool `./linedrawing_project.sh` to prepare view images for [OpenSSE](https://github.com/zddhub/opensse/wiki/How-to-train-data#get-line-drawing-views), Use it to get 102 view images for each modal. After you compile code, and return root path to run: 53 | 54 | ```sh 55 | ./linedrawing_project.sh -d ~/Database/SHREC12 -p *.off 56 | ``` 57 | 58 | Troubleshooting 59 | =============== 60 | 61 | * Compile error on macOS like below: 62 | 63 | ```sh 64 | .../clang_64/lib/QtCore.framework/Headers/qsystemdetection.h:197:12: fatal error: 'TargetConditionals.h' file not found 65 | ``` 66 | 67 | How to fix: 68 | 69 | ``` 70 | macx : QMAKE_MAC_SDK=macosx10.13 # Change this to your macOS version if you are using macOS 71 | ``` 72 | 73 | Thanks 74 | ====== 75 | - [Szymon Rusinkiewicz](http://www.cs.princeton.edu/~smr/) 76 | - [Tilke Judd](http://people.csail.mit.edu/tjudd/) 77 | 78 | License 79 | ======= 80 | 81 | Code is under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 82 | 83 | Donate 84 | ====== 85 | 86 | I accept tips through [Alipay](http://img.blog.csdn.net/20140506233949640). Scan below qr code to donate: 87 | 88 | ![Alipay](data/alipay.png "Donation"). 89 | 90 | Contact me 91 | ========== 92 | 93 | If you have any question or idea, please [email to me](mailto:zddhub@gmail.com). 94 | -------------------------------------------------------------------------------- /add_license.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # zdd / zddhub@gmail.com 3 | if [ $# != 2 ] 4 | then 5 | echo "Usage: add_license project_dir license_file" 6 | exit 7 | fi 8 | 9 | for file in `find $1 -name "*.[h|c]*"` 10 | do 11 | echo "/*************************************************************************" > temp 12 | while read line 13 | do 14 | echo " * $line" >> temp 15 | done < $2 16 | echo "**************************************************************************/" >> temp 17 | cat $file >> temp 18 | mv -f temp $file 19 | done 20 | 21 | for file in `find $1 -name "*.pr[o|i]"` 22 | do 23 | echo "#-------------------------------------------------------------------------" > temp 24 | while read line 25 | do 26 | echo "# $line" >> temp 27 | done < $2 28 | echo "#-------------------------------------------------------------------------" >> temp 29 | cat $file >> temp 30 | mv -f temp $file 31 | done 32 | -------------------------------------------------------------------------------- /data/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/data/alipay.png -------------------------------------------------------------------------------- /data/linedrawings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/data/linedrawings.png -------------------------------------------------------------------------------- /data/teddy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/data/teddy.png -------------------------------------------------------------------------------- /data/teddy_line_drawings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/data/teddy_line_drawings.gif -------------------------------------------------------------------------------- /data/teddy_line_drawings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/data/teddy_line_drawings.png -------------------------------------------------------------------------------- /data/view/0.xf: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 0 1 0 0 3 | -0 0 1 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/1.xf: -------------------------------------------------------------------------------- 1 | 0.95106 0 0.30902 0 2 | 0 1 0 0 3 | -0.30902 0 0.95106 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/10.xf: -------------------------------------------------------------------------------- 1 | -1 0 1.2246e-016 0 2 | 0 1 0 0 3 | -1.2246e-016 0 -1 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/100.xf: -------------------------------------------------------------------------------- 1 | 1 -2.4493e-016 -1.4998e-032 0 2 | 0 6.1232e-017 -1 0 3 | 2.4493e-016 1 6.1232e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/101.xf: -------------------------------------------------------------------------------- 1 | 1 2.4493e-016 -1.4998e-032 0 2 | 0 6.1232e-017 1 0 3 | 2.4493e-016 -1 6.1232e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/11.xf: -------------------------------------------------------------------------------- 1 | -0.95106 0 -0.30902 0 2 | 0 1 0 0 3 | 0.30902 0 -0.95106 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/12.xf: -------------------------------------------------------------------------------- 1 | -0.80902 0 -0.58779 0 2 | 0 1 0 0 3 | 0.58779 0 -0.80902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/13.xf: -------------------------------------------------------------------------------- 1 | -0.58779 0 -0.80902 0 2 | 0 1 0 0 3 | 0.80902 0 -0.58779 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/14.xf: -------------------------------------------------------------------------------- 1 | -0.30902 0 -0.95106 0 2 | 0 1 0 0 3 | 0.95106 0 -0.30902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/15.xf: -------------------------------------------------------------------------------- 1 | -1.837e-016 0 -1 0 2 | 0 1 0 0 3 | 1 0 -1.837e-016 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/16.xf: -------------------------------------------------------------------------------- 1 | 0.30902 0 -0.95106 0 2 | 0 1 0 0 3 | 0.95106 0 0.30902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/17.xf: -------------------------------------------------------------------------------- 1 | 0.58779 0 -0.80902 0 2 | 0 1 0 0 3 | 0.80902 0 0.58779 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/18.xf: -------------------------------------------------------------------------------- 1 | 0.80902 0 -0.58779 0 2 | 0 1 0 0 3 | 0.58779 0 0.80902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/19.xf: -------------------------------------------------------------------------------- 1 | 0.95106 0 -0.30902 0 2 | 0 1 0 0 3 | 0.30902 0 0.95106 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/2.xf: -------------------------------------------------------------------------------- 1 | 0.80902 0 0.58779 0 2 | 0 1 0 0 3 | -0.58779 0 0.80902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/20.xf: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 0 0.86603 -0.5 0 3 | 0 0.5 0.86603 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/21.xf: -------------------------------------------------------------------------------- 1 | 0.95106 0.15451 0.26762 0 2 | 0 0.86603 -0.5 0 3 | -0.30902 0.47553 0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/22.xf: -------------------------------------------------------------------------------- 1 | 0.80902 0.29389 0.50904 0 2 | 0 0.86603 -0.5 0 3 | -0.58779 0.40451 0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/23.xf: -------------------------------------------------------------------------------- 1 | 0.58779 0.40451 0.70063 0 2 | 0 0.86603 -0.5 0 3 | -0.80902 0.29389 0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/24.xf: -------------------------------------------------------------------------------- 1 | 0.30902 0.47553 0.82364 0 2 | 0 0.86603 -0.5 0 3 | -0.95106 0.15451 0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/25.xf: -------------------------------------------------------------------------------- 1 | 6.1232e-017 0.5 0.86603 0 2 | 0 0.86603 -0.5 0 3 | -1 3.0616e-017 5.3029e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/26.xf: -------------------------------------------------------------------------------- 1 | -0.30902 0.47553 0.82364 0 2 | 0 0.86603 -0.5 0 3 | -0.95106 -0.15451 -0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/27.xf: -------------------------------------------------------------------------------- 1 | -0.58779 0.40451 0.70063 0 2 | 0 0.86603 -0.5 0 3 | -0.80902 -0.29389 -0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/28.xf: -------------------------------------------------------------------------------- 1 | -0.80902 0.29389 0.50904 0 2 | 0 0.86603 -0.5 0 3 | -0.58779 -0.40451 -0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/29.xf: -------------------------------------------------------------------------------- 1 | -0.95106 0.15451 0.26762 0 2 | 0 0.86603 -0.5 0 3 | -0.30902 -0.47553 -0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/3.xf: -------------------------------------------------------------------------------- 1 | 0.58779 0 0.80902 0 2 | 0 1 0 0 3 | -0.80902 0 0.58779 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/30.xf: -------------------------------------------------------------------------------- 1 | -1 6.1232e-017 1.0606e-016 0 2 | 0 0.86603 -0.5 0 3 | -1.2246e-016 -0.5 -0.86603 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/31.xf: -------------------------------------------------------------------------------- 1 | -0.95106 -0.15451 -0.26762 0 2 | 0 0.86603 -0.5 0 3 | 0.30902 -0.47553 -0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/32.xf: -------------------------------------------------------------------------------- 1 | -0.80902 -0.29389 -0.50904 0 2 | 0 0.86603 -0.5 0 3 | 0.58779 -0.40451 -0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/33.xf: -------------------------------------------------------------------------------- 1 | -0.58779 -0.40451 -0.70063 0 2 | 0 0.86603 -0.5 0 3 | 0.80902 -0.29389 -0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/34.xf: -------------------------------------------------------------------------------- 1 | -0.30902 -0.47553 -0.82364 0 2 | 0 0.86603 -0.5 0 3 | 0.95106 -0.15451 -0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/35.xf: -------------------------------------------------------------------------------- 1 | -1.837e-016 -0.5 -0.86603 0 2 | 0 0.86603 -0.5 0 3 | 1 -9.1849e-017 -1.5909e-016 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/36.xf: -------------------------------------------------------------------------------- 1 | 0.30902 -0.47553 -0.82364 0 2 | 0 0.86603 -0.5 0 3 | 0.95106 0.15451 0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/37.xf: -------------------------------------------------------------------------------- 1 | 0.58779 -0.40451 -0.70063 0 2 | 0 0.86603 -0.5 0 3 | 0.80902 0.29389 0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/38.xf: -------------------------------------------------------------------------------- 1 | 0.80902 -0.29389 -0.50904 0 2 | 0 0.86603 -0.5 0 3 | 0.58779 0.40451 0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/39.xf: -------------------------------------------------------------------------------- 1 | 0.95106 -0.15451 -0.26762 0 2 | 0 0.86603 -0.5 0 3 | 0.30902 0.47553 0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/4.xf: -------------------------------------------------------------------------------- 1 | 0.30902 0 0.95106 0 2 | 0 1 0 0 3 | -0.95106 0 0.30902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/40.xf: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 0 0.5 -0.86603 0 3 | 0 0.86603 0.5 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/41.xf: -------------------------------------------------------------------------------- 1 | 0.95106 0.26762 0.15451 0 2 | 0 0.5 -0.86603 0 3 | -0.30902 0.82364 0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/42.xf: -------------------------------------------------------------------------------- 1 | 0.80902 0.50904 0.29389 0 2 | 0 0.5 -0.86603 0 3 | -0.58779 0.70063 0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/43.xf: -------------------------------------------------------------------------------- 1 | 0.58779 0.70063 0.40451 0 2 | 0 0.5 -0.86603 0 3 | -0.80902 0.50904 0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/44.xf: -------------------------------------------------------------------------------- 1 | 0.30902 0.82364 0.47553 0 2 | 0 0.5 -0.86603 0 3 | -0.95106 0.26762 0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/45.xf: -------------------------------------------------------------------------------- 1 | 6.1232e-017 0.86603 0.5 0 2 | 0 0.5 -0.86603 0 3 | -1 5.3029e-017 3.0616e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/46.xf: -------------------------------------------------------------------------------- 1 | -0.30902 0.82364 0.47553 0 2 | 0 0.5 -0.86603 0 3 | -0.95106 -0.26762 -0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/47.xf: -------------------------------------------------------------------------------- 1 | -0.58779 0.70063 0.40451 0 2 | 0 0.5 -0.86603 0 3 | -0.80902 -0.50904 -0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/48.xf: -------------------------------------------------------------------------------- 1 | -0.80902 0.50904 0.29389 0 2 | 0 0.5 -0.86603 0 3 | -0.58779 -0.70063 -0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/49.xf: -------------------------------------------------------------------------------- 1 | -0.95106 0.26762 0.15451 0 2 | 0 0.5 -0.86603 0 3 | -0.30902 -0.82364 -0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/5.xf: -------------------------------------------------------------------------------- 1 | 6.1232e-017 0 1 0 2 | 0 1 0 0 3 | -1 0 6.1232e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/50.xf: -------------------------------------------------------------------------------- 1 | -1 1.0606e-016 6.1232e-017 0 2 | 0 0.5 -0.86603 0 3 | -1.2246e-016 -0.86603 -0.5 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/51.xf: -------------------------------------------------------------------------------- 1 | -0.95106 -0.26762 -0.15451 0 2 | 0 0.5 -0.86603 0 3 | 0.30902 -0.82364 -0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/52.xf: -------------------------------------------------------------------------------- 1 | -0.80902 -0.50904 -0.29389 0 2 | 0 0.5 -0.86603 0 3 | 0.58779 -0.70063 -0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/53.xf: -------------------------------------------------------------------------------- 1 | -0.58779 -0.70063 -0.40451 0 2 | 0 0.5 -0.86603 0 3 | 0.80902 -0.50904 -0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/54.xf: -------------------------------------------------------------------------------- 1 | -0.30902 -0.82364 -0.47553 0 2 | 0 0.5 -0.86603 0 3 | 0.95106 -0.26762 -0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/55.xf: -------------------------------------------------------------------------------- 1 | -1.837e-016 -0.86603 -0.5 0 2 | 0 0.5 -0.86603 0 3 | 1 -1.5909e-016 -9.1849e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/56.xf: -------------------------------------------------------------------------------- 1 | 0.30902 -0.82364 -0.47553 0 2 | 0 0.5 -0.86603 0 3 | 0.95106 0.26762 0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/57.xf: -------------------------------------------------------------------------------- 1 | 0.58779 -0.70063 -0.40451 0 2 | 0 0.5 -0.86603 0 3 | 0.80902 0.50904 0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/58.xf: -------------------------------------------------------------------------------- 1 | 0.80902 -0.50904 -0.29389 0 2 | 0 0.5 -0.86603 0 3 | 0.58779 0.70063 0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/59.xf: -------------------------------------------------------------------------------- 1 | 0.95106 -0.26762 -0.15451 0 2 | 0 0.5 -0.86603 0 3 | 0.30902 0.82364 0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/6.xf: -------------------------------------------------------------------------------- 1 | -0.30902 0 0.95106 0 2 | 0 1 0 0 3 | -0.95106 0 -0.30902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/60.xf: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 0 0.5 0.86603 0 3 | 0 -0.86603 0.5 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/61.xf: -------------------------------------------------------------------------------- 1 | 0.95106 -0.26762 0.15451 0 2 | 0 0.5 0.86603 0 3 | -0.30902 -0.82364 0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/62.xf: -------------------------------------------------------------------------------- 1 | 0.80902 -0.50904 0.29389 0 2 | 0 0.5 0.86603 0 3 | -0.58779 -0.70063 0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/63.xf: -------------------------------------------------------------------------------- 1 | 0.58779 -0.70063 0.40451 0 2 | 0 0.5 0.86603 0 3 | -0.80902 -0.50904 0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/64.xf: -------------------------------------------------------------------------------- 1 | 0.30902 -0.82364 0.47553 0 2 | 0 0.5 0.86603 0 3 | -0.95106 -0.26762 0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/65.xf: -------------------------------------------------------------------------------- 1 | 6.1232e-017 -0.86603 0.5 0 2 | 0 0.5 0.86603 0 3 | -1 -5.3029e-017 3.0616e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/66.xf: -------------------------------------------------------------------------------- 1 | -0.30902 -0.82364 0.47553 0 2 | 0 0.5 0.86603 0 3 | -0.95106 0.26762 -0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/67.xf: -------------------------------------------------------------------------------- 1 | -0.58779 -0.70063 0.40451 0 2 | 0 0.5 0.86603 0 3 | -0.80902 0.50904 -0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/68.xf: -------------------------------------------------------------------------------- 1 | -0.80902 -0.50904 0.29389 0 2 | 0 0.5 0.86603 0 3 | -0.58779 0.70063 -0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/69.xf: -------------------------------------------------------------------------------- 1 | -0.95106 -0.26762 0.15451 0 2 | 0 0.5 0.86603 0 3 | -0.30902 0.82364 -0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/7.xf: -------------------------------------------------------------------------------- 1 | -0.58779 0 0.80902 0 2 | 0 1 0 0 3 | -0.80902 0 -0.58779 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/70.xf: -------------------------------------------------------------------------------- 1 | -1 -1.0606e-016 6.1232e-017 0 2 | 0 0.5 0.86603 0 3 | -1.2246e-016 0.86603 -0.5 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/71.xf: -------------------------------------------------------------------------------- 1 | -0.95106 0.26762 -0.15451 0 2 | 0 0.5 0.86603 0 3 | 0.30902 0.82364 -0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/72.xf: -------------------------------------------------------------------------------- 1 | -0.80902 0.50904 -0.29389 0 2 | 0 0.5 0.86603 0 3 | 0.58779 0.70063 -0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/73.xf: -------------------------------------------------------------------------------- 1 | -0.58779 0.70063 -0.40451 0 2 | 0 0.5 0.86603 0 3 | 0.80902 0.50904 -0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/74.xf: -------------------------------------------------------------------------------- 1 | -0.30902 0.82364 -0.47553 0 2 | 0 0.5 0.86603 0 3 | 0.95106 0.26762 -0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/75.xf: -------------------------------------------------------------------------------- 1 | -1.837e-016 0.86603 -0.5 0 2 | 0 0.5 0.86603 0 3 | 1 1.5909e-016 -9.1849e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/76.xf: -------------------------------------------------------------------------------- 1 | 0.30902 0.82364 -0.47553 0 2 | 0 0.5 0.86603 0 3 | 0.95106 -0.26762 0.15451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/77.xf: -------------------------------------------------------------------------------- 1 | 0.58779 0.70063 -0.40451 0 2 | 0 0.5 0.86603 0 3 | 0.80902 -0.50904 0.29389 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/78.xf: -------------------------------------------------------------------------------- 1 | 0.80902 0.50904 -0.29389 0 2 | 0 0.5 0.86603 0 3 | 0.58779 -0.70063 0.40451 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/79.xf: -------------------------------------------------------------------------------- 1 | 0.95106 0.26762 -0.15451 0 2 | 0 0.5 0.86603 0 3 | 0.30902 -0.82364 0.47553 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/8.xf: -------------------------------------------------------------------------------- 1 | -0.80902 0 0.58779 0 2 | 0 1 0 0 3 | -0.58779 0 -0.80902 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/80.xf: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 0 0.86603 0.5 0 3 | 0 -0.5 0.86603 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/81.xf: -------------------------------------------------------------------------------- 1 | 0.95106 -0.15451 0.26762 0 2 | 0 0.86603 0.5 0 3 | -0.30902 -0.47553 0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/82.xf: -------------------------------------------------------------------------------- 1 | 0.80902 -0.29389 0.50904 0 2 | 0 0.86603 0.5 0 3 | -0.58779 -0.40451 0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/83.xf: -------------------------------------------------------------------------------- 1 | 0.58779 -0.40451 0.70063 0 2 | 0 0.86603 0.5 0 3 | -0.80902 -0.29389 0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/84.xf: -------------------------------------------------------------------------------- 1 | 0.30902 -0.47553 0.82364 0 2 | 0 0.86603 0.5 0 3 | -0.95106 -0.15451 0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/85.xf: -------------------------------------------------------------------------------- 1 | 6.1232e-017 -0.5 0.86603 0 2 | 0 0.86603 0.5 0 3 | -1 -3.0616e-017 5.3029e-017 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/86.xf: -------------------------------------------------------------------------------- 1 | -0.30902 -0.47553 0.82364 0 2 | 0 0.86603 0.5 0 3 | -0.95106 0.15451 -0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/87.xf: -------------------------------------------------------------------------------- 1 | -0.58779 -0.40451 0.70063 0 2 | 0 0.86603 0.5 0 3 | -0.80902 0.29389 -0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/88.xf: -------------------------------------------------------------------------------- 1 | -0.80902 -0.29389 0.50904 0 2 | 0 0.86603 0.5 0 3 | -0.58779 0.40451 -0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/89.xf: -------------------------------------------------------------------------------- 1 | -0.95106 -0.15451 0.26762 0 2 | 0 0.86603 0.5 0 3 | -0.30902 0.47553 -0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/9.xf: -------------------------------------------------------------------------------- 1 | -0.95106 0 0.30902 0 2 | 0 1 0 0 3 | -0.30902 0 -0.95106 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/90.xf: -------------------------------------------------------------------------------- 1 | -1 -6.1232e-017 1.0606e-016 0 2 | 0 0.86603 0.5 0 3 | -1.2246e-016 0.5 -0.86603 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/91.xf: -------------------------------------------------------------------------------- 1 | -0.95106 0.15451 -0.26762 0 2 | 0 0.86603 0.5 0 3 | 0.30902 0.47553 -0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/92.xf: -------------------------------------------------------------------------------- 1 | -0.80902 0.29389 -0.50904 0 2 | 0 0.86603 0.5 0 3 | 0.58779 0.40451 -0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/93.xf: -------------------------------------------------------------------------------- 1 | -0.58779 0.40451 -0.70063 0 2 | 0 0.86603 0.5 0 3 | 0.80902 0.29389 -0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/94.xf: -------------------------------------------------------------------------------- 1 | -0.30902 0.47553 -0.82364 0 2 | 0 0.86603 0.5 0 3 | 0.95106 0.15451 -0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/95.xf: -------------------------------------------------------------------------------- 1 | -1.837e-016 0.5 -0.86603 0 2 | 0 0.86603 0.5 0 3 | 1 9.1849e-017 -1.5909e-016 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/96.xf: -------------------------------------------------------------------------------- 1 | 0.30902 0.47553 -0.82364 0 2 | 0 0.86603 0.5 0 3 | 0.95106 -0.15451 0.26762 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/97.xf: -------------------------------------------------------------------------------- 1 | 0.58779 0.40451 -0.70063 0 2 | 0 0.86603 0.5 0 3 | 0.80902 -0.29389 0.50904 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/98.xf: -------------------------------------------------------------------------------- 1 | 0.80902 0.29389 -0.50904 0 2 | 0 0.86603 0.5 0 3 | 0.58779 -0.40451 0.70063 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/view/99.xf: -------------------------------------------------------------------------------- 1 | 0.95106 0.15451 -0.26762 0 2 | 0 0.86603 0.5 0 3 | 0.30902 -0.47553 0.82364 0 4 | 0 0 0 1 5 | -------------------------------------------------------------------------------- /data/viewpoints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/data/viewpoints.png -------------------------------------------------------------------------------- /featurelines.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/featurelines.cpp -------------------------------------------------------------------------------- /featurelines.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/featurelines.h -------------------------------------------------------------------------------- /include/Color.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef COLOR_H 18 | #define COLOR_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | Color.h 24 | Random class for encapsulating colors... 25 | 26 | Due to all the possible colorspace variants, here's the documentation of 27 | what is actually implemented: 28 | - CIE 1931 2-degree observer 29 | - D65 illuminant (including for CIELAB - it's not D50) 30 | - Rec. 709 primaries 31 | - Range of [0..1] for all spaces except CIELAB and hue in HSV 32 | - "RGB" means linear-scaled RGB with the above illuminant and primaries 33 | - HSV is single-hexcone, sRGB 34 | - Y'CbCr is JFIF-standard (Rec. 601 scaling, full excursion) starting from sRGB 35 | */ 36 | 37 | #include "Vec.h" 38 | #include 39 | #include 40 | #ifndef M_PI 41 | # define M_PI 3.14159265358979323846 42 | #endif 43 | 44 | 45 | class Color : public Vec<3,float> { 46 | public: 47 | Color() 48 | {} 49 | Color(const Vec<3,float> &v_) : Vec<3,float>(v_) 50 | {} 51 | Color(const Vec<3,double> &v_) : Vec<3,float>((float)v_[0], (float)v_[1], (float)v_[2]) 52 | {} 53 | Color(float r, float g, float b) : Vec<3,float>(r,g,b) 54 | {} 55 | Color(double r, double g, double b) : Vec<3,float>((float)r, (float)g, (float)b) 56 | {} 57 | explicit Color(const float *rgb) : Vec<3,float>(rgb[0], rgb[1], rgb[2]) 58 | {} 59 | explicit Color(const double *rgb) : Vec<3,float>((float)rgb[0], (float)rgb[1], (float)rgb[2]) 60 | {} 61 | 62 | // Implicit conversion from float would be bad, so we have an 63 | // explicit constructor and an assignment statement. 64 | explicit Color(float c) : Vec<3,float>(c,c,c) 65 | {} 66 | explicit Color(double c) : Vec<3,float>((float)c, (float)c, (float)c) 67 | {} 68 | Color &operator = (float c) 69 | { return *this = Color(c); } 70 | Color &operator = (double c) 71 | { return *this = Color(c); } 72 | 73 | // Assigning from ints divides by 255 74 | Color(int r, int g, int b) 75 | { 76 | const float mult = 1.0f / 255.0f; 77 | *this = Color(mult*r, mult*g, mult*b); 78 | } 79 | explicit Color(const int *rgb) 80 | { *this = Color(rgb[0], rgb[1], rgb[2]); } 81 | explicit Color(const unsigned char *rgb) 82 | { *this = Color(rgb[0], rgb[1], rgb[2]); } 83 | explicit Color(int c) 84 | { *this = Color(c,c,c); } 85 | Color &operator = (int c) 86 | { return *this = Color(c); } 87 | 88 | static Color black() 89 | { return Color(0.0f, 0.0f, 0.0f); } 90 | static Color white() 91 | { return Color(1.0f, 1.0f, 1.0f); } 92 | static Color red() 93 | { return Color(1.0f, 0.0f, 0.0f); } 94 | static Color green() 95 | { return Color(0.0f, 1.0f, 0.0f); } 96 | static Color blue() 97 | { return Color(0.0f, 0.0f, 1.0f); } 98 | static Color yellow() 99 | { return Color(1.0f, 1.0f, 0.0f); } 100 | static Color cyan() 101 | { return Color(0.0f, 1.0f, 1.0f); } 102 | static Color magenta() 103 | { return Color(1.0f, 0.0f, 1.0f); } 104 | 105 | // 3x3 color transform - matrix given in *row-major* order 106 | const Color col_transform(float m11, float m12, float m13, 107 | float m21, float m22, float m23, 108 | float m31, float m32, float m33) const 109 | { 110 | return Color(m11*v[0]+m12*v[1]+m13*v[2], 111 | m21*v[0]+m22*v[1]+m23*v[2], 112 | m31*v[0]+m32*v[1]+m33*v[2]); 113 | } 114 | 115 | private: 116 | const Color hsv2srgb() const 117 | { 118 | // From FvD 119 | float H = v[0], S = v[1], V = v[2]; 120 | if (S <= 0.0f) 121 | return Color(V,V,V); 122 | H = std::fmod(H, float(2.0 * M_PI)); 123 | if (H < 0.0f) 124 | H += float(2.0 * M_PI); 125 | H *= float(3.0 / M_PI); 126 | int i = int(std::floor(H)); 127 | float f = H - i; 128 | float p = V * (1.0f - S); 129 | float q = V * (1.0f - (S*f)); 130 | float t = V * (1.0f - (S*(1.0f-f))); 131 | switch(i) { 132 | case 0: return Color(V, t, p); 133 | case 1: return Color(q, V, p); 134 | case 2: return Color(p, V, t); 135 | case 3: return Color(p, q, V); 136 | case 4: return Color(t, p, V); 137 | default: return Color(V, p, q); 138 | } 139 | } 140 | const Color srgb2hsv() const 141 | { 142 | float V = std::max(std::max(v[0], v[1]), v[2]); 143 | float diff = V - std::min(std::min(v[0], v[1]), v[2]); 144 | float S = diff / V; 145 | float H = 0.0f; 146 | if (S == 0.0f) 147 | return Color(H, S, V); 148 | if (V == v[0]) 149 | H = (v[1] - v[2]) / diff; 150 | else if (V == v[1]) 151 | H = (v[2] - v[0]) / diff + 2.0f; 152 | else 153 | H = (v[0] - v[1]) / diff + 4.0f; 154 | H *= float(M_PI / 3.0); 155 | if (H < 0.0f) 156 | H += float(2.0 * M_PI); 157 | return Color(H, S, V); 158 | } 159 | 160 | static inline float cielab_nonlinearity(float x) 161 | { 162 | if (x > 216.0f / 24389.0f) 163 | return cbrt(x); 164 | else 165 | return 4.0f / 29.0f + (841.0f / 108.0f) * x; 166 | } 167 | static inline float inv_cielab_nonlinearity(float x) 168 | { 169 | if (x > (6.0f / 29.0f)) 170 | return cube(x); 171 | else 172 | return (x - 4.0f / 29.0f) * (108.0f / 841.0f); 173 | } 174 | const Color xyz2cielab() const 175 | { 176 | float fx = cielab_nonlinearity(v[0] * (1.0f / 0.95047f)); 177 | float fy = cielab_nonlinearity(v[1]); 178 | float fz = cielab_nonlinearity(v[2] * (1.0f / 1.08883f)); 179 | return Color(116.0f * fy - 16.0f, 180 | 500.0f * (fx - fy), 181 | 200.0f * (fy - fz)); 182 | } 183 | const Color cielab2xyz() const 184 | { 185 | float fy = (v[0] + 16.0f) * (1.0f / 116.0f); 186 | float fx = fy + v[1] * 0.002f; 187 | float fz = fy - v[2] * 0.005f; 188 | return Color(0.95047f * inv_cielab_nonlinearity(fx), 189 | inv_cielab_nonlinearity(fy), 190 | 1.08883f * inv_cielab_nonlinearity(fz)); 191 | } 192 | 193 | const Color xyz2rgb() const 194 | { 195 | return col_transform(3.24071f, -1.53726f, -0.498571f, 196 | -0.969258f, 1.87599f, 0.0415557f, 197 | 0.0556352f, -0.203996f, 1.05707f); 198 | } 199 | const Color rgb2xyz() const 200 | { 201 | return col_transform(0.412424f, 0.357579f, 0.180464f, 202 | 0.212656f, 0.715158f, 0.0721856f, 203 | 0.0193324f, 0.119193f, 0.950444f); 204 | } 205 | 206 | static inline float srgb_nonlinearity(float x) 207 | { 208 | if (x > 0.0031308f) 209 | return 1.055f * pow(x, 1.0f/2.4f) - 0.055f; 210 | else 211 | return x * 12.92f; 212 | } 213 | static inline float inv_srgb_nonlinearity(float x) 214 | { 215 | if (x > (0.0031308f * 12.92f)) 216 | return pow((x + 0.055f) * (1.0f / 1.055f), 2.4f); 217 | else 218 | return x * (1.0f / 12.92f); 219 | } 220 | const Color rgb2srgb() const 221 | { 222 | return Color(srgb_nonlinearity(v[0]), 223 | srgb_nonlinearity(v[1]), 224 | srgb_nonlinearity(v[2])); 225 | } 226 | const Color srgb2rgb() const 227 | { 228 | return Color(inv_srgb_nonlinearity(v[0]), 229 | inv_srgb_nonlinearity(v[1]), 230 | inv_srgb_nonlinearity(v[2])); 231 | } 232 | 233 | const Color srgb2ycbcr() const 234 | { 235 | return Color(0.0f, 0.5f, 0.5f) + col_transform( 236 | 0.299f, 0.587f, 0.114f, 237 | -0.168736f, -0.331264f, 0.5f, 238 | 0.5f, -0.418688f, -0.081312f); 239 | } 240 | const Color ycbcr2srgb() const 241 | { 242 | return Color(v[0], v[1] - 0.5f, v[2] - 0.5f).col_transform( 243 | 1.0f, 0.0f, 1.402f, 244 | 1.0f, -0.344136f, -0.714136f, 245 | 1.0f, 1.772f, 0.0f); 246 | } 247 | 248 | public: 249 | enum Colorspace { CIELAB, XYZ, RGB, SRGB, YCBCR, HSV }; 250 | const Color convert(Colorspace src, Colorspace dst) const 251 | { 252 | if (src == dst) 253 | return Color(*this); 254 | if (src == HSV) 255 | return Color::hsv(v[0],v[1],v[2]).convert(SRGB, dst); 256 | else if (dst == HSV) 257 | return convert(src, SRGB).srgb2hsv(); 258 | // Else we have a natural order in which to convert things 259 | int srcnum = int(src), dstnum = int(dst); 260 | if (srcnum < dstnum) switch (src) { 261 | case CIELAB: 262 | return (dst == XYZ) ? cielab2xyz() : 263 | cielab2xyz().convert(XYZ, dst); 264 | case XYZ: 265 | return (dst == RGB) ? xyz2rgb() : 266 | xyz2rgb().convert(RGB, dst); 267 | case RGB: 268 | return (dst == SRGB) ? rgb2srgb() : 269 | rgb2srgb().convert(SRGB, dst); 270 | default: 271 | return srgb2ycbcr(); 272 | } else switch (src) { 273 | case YCBCR: 274 | return (dst == SRGB) ? ycbcr2srgb() : 275 | ycbcr2srgb().convert(SRGB, dst); 276 | case SRGB: 277 | return (dst == RGB) ? srgb2rgb() : 278 | srgb2rgb().convert(RGB, dst); 279 | case RGB: 280 | return (dst == XYZ) ? rgb2xyz() : 281 | rgb2xyz().convert(XYZ, dst); 282 | default: 283 | return xyz2cielab(); 284 | } 285 | } 286 | 287 | // Linear to nonlinear - raises values to the power of 1/g 288 | const Color gamma(float g) const 289 | { 290 | float g1 = 1.0f / g; 291 | return Color(pow(v[0],g1), pow(v[1],g1), pow(v[2],g1)); 292 | } 293 | 294 | // Just apply the nonlinearity, not full colorspace conversion 295 | const Color gamma(Colorspace dst) const 296 | { 297 | switch (dst) { 298 | case CIELAB: 299 | return Color(cielab_nonlinearity(v[0]), 300 | cielab_nonlinearity(v[1]), 301 | cielab_nonlinearity(v[2])); 302 | case SRGB: 303 | case YCBCR: 304 | return Color(srgb_nonlinearity(v[0]), 305 | srgb_nonlinearity(v[1]), 306 | srgb_nonlinearity(v[2])); 307 | default: 308 | return Color(*this); 309 | } 310 | } 311 | 312 | // Nonlinear to linear - raises values to the power of g 313 | const Color ungamma(float g) const 314 | { 315 | return Color(pow(v[0],g), pow(v[1],g), pow(v[2],g)); 316 | } 317 | 318 | const Color ungamma(Colorspace dst) const 319 | { 320 | switch (dst) { 321 | case CIELAB: 322 | return Color(inv_cielab_nonlinearity(v[0]), 323 | inv_cielab_nonlinearity(v[1]), 324 | inv_cielab_nonlinearity(v[2])); 325 | case SRGB: 326 | case YCBCR: 327 | return Color(inv_srgb_nonlinearity(v[0]), 328 | inv_srgb_nonlinearity(v[1]), 329 | inv_srgb_nonlinearity(v[2])); 330 | default: 331 | return Color(*this); 332 | } 333 | } 334 | 335 | // For backwards compatibility with earlier versions of Color.h, 336 | // this stays as a static method. New code should use convert(). 337 | static Color hsv(float h, float s, float v) 338 | { 339 | return Color(h,s,v).hsv2srgb(); 340 | } 341 | }; 342 | 343 | #endif 344 | -------------------------------------------------------------------------------- /include/GLCamera.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef GLCAMERA_H 18 | #define GLCAMERA_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | GLCamera.h 24 | Manages OpenGL camera and trackball/arcball interaction 25 | */ 26 | 27 | #include "Vec.h" 28 | #include "XForm.h" 29 | #include "timestamp.h" 30 | 31 | 32 | namespace Mouse { 33 | enum button { NONE, ROTATE, MOVEXY, MOVEZ, WHEELUP, WHEELDOWN, LIGHT }; 34 | }; 35 | 36 | class GLCamera { 37 | public: 38 | enum Constraint { UNCONSTRAINED, 39 | XCONSTRAINED, YCONSTRAINED, ZCONSTRAINED }; 40 | 41 | private: 42 | int lastmousex, lastmousey; 43 | Mouse::button lastb; 44 | timestamp last_time; 45 | 46 | vec lightdir; 47 | 48 | bool dospin; 49 | point spincenter; 50 | vec spinaxis; 51 | float spinspeed; 52 | 53 | Constraint constraint_; 54 | float field_of_view, pixscale; 55 | mutable float surface_depth; 56 | float click_depth; 57 | float tb_screen_x, tb_screen_y, tb_screen_size; 58 | bool read_depth(int x, int y, point &p) const; 59 | 60 | void startspin(); 61 | vec mouse2tb(float x, float y); 62 | void rotate(int mousex, int mousey, xform &xf); 63 | void movexy(int mousex, int mousey, xform &xf); 64 | void movez(int mousex, int mousey, xform &xf); 65 | void wheel(Mouse::button updown, xform &xf); 66 | void relight(int mousex, int mousey); 67 | void mouse_click(int mousex, int mousey, 68 | const point &scene_center, float scene_size); 69 | 70 | public: 71 | GLCamera() : lastb(Mouse::NONE), lightdir(vec(0,0,1)), 72 | dospin(false), spinspeed(0), 73 | constraint_(UNCONSTRAINED), field_of_view(0.7f), 74 | surface_depth(0.0f), click_depth(0.0f) 75 | { 76 | lightdir[0] = lightdir[1] = 0; lightdir[2] = 1; 77 | last_time = now(); 78 | } 79 | 80 | void setupGL(const point &scene_center, float scene_size) const; 81 | 82 | void mouse(int mousex, int mousey, Mouse::button b, 83 | const point &scene_center, float scene_size, 84 | xform &xf); 85 | 86 | bool autospin(xform &xf); 87 | void stopspin() { dospin = false; } 88 | 89 | vec light() const { return lightdir; } 90 | void set_light(const vec &lightdir_) { lightdir = lightdir_; } 91 | 92 | float fov() const { return field_of_view; } 93 | void set_fov(float fov_) { field_of_view = fov_; } 94 | 95 | Constraint constraint() { return constraint_; } 96 | void set_constraint(Constraint c) { constraint_ = c; } 97 | }; 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /include/KDtree.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef KDTREE_H 18 | #define KDTREE_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | KDtree.h 24 | A K-D tree for points, with limited capabilities (find nearest point to 25 | a given point, or to a ray). 26 | 27 | Note that in order to be generic, this *doesn't* use Vecs and the like... 28 | */ 29 | 30 | #include 31 | 32 | class KDtree { 33 | private: 34 | class Node; 35 | Node *root; 36 | void build(const float *ptlist, size_t n); 37 | 38 | public: 39 | // Compatibility function for closest-compatible-point searches 40 | struct CompatFunc 41 | { 42 | virtual bool operator () (const float *p) const = 0; 43 | virtual ~CompatFunc() {} // To make the compiler shut up 44 | }; 45 | 46 | // Constructor from an array of points 47 | KDtree(const float *ptlist, size_t n) 48 | { build(ptlist, n); } 49 | 50 | // Constructor from a vector of points 51 | template KDtree(const std::vector &v) 52 | { build((const float *) &v[0], v.size()); } 53 | 54 | // Destructor - recursively frees the tree 55 | ~KDtree(); 56 | 57 | // The queries: returns closest point to a point or a ray, 58 | // provided it's within sqrt(maxdist2) and is compatible 59 | const float *closest_to_pt(const float *p, 60 | float maxdist2 = 0.0f, 61 | const CompatFunc *iscompat = NULL) const; 62 | const float *closest_to_ray(const float *p, const float *dir, 63 | float maxdist2 = 0.0f, 64 | const CompatFunc *iscompat = NULL) const; 65 | 66 | // Find the k nearest neighbors 67 | void find_k_closest_to_pt(std::vector &knn, 68 | int k, 69 | const float *p, 70 | float maxdist2 = 0.0f, 71 | const CompatFunc *iscompat = NULL) const; 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /include/XForm.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef XFORM_H 18 | #define XFORM_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | XForm.h 24 | Transformations (represented internally as column-major 4x4 matrices) 25 | 26 | Supports the following operations: 27 | xform xf, xf2; // Initialized to the identity 28 | XForm xf3; // Just "xform" is XForm 29 | xf=xform::trans(u,v,w); // An xform that translates 30 | xf=xform::rot(ang,ax); // An xform that rotates 31 | xf=xform::scale(s); // An xform that scales 32 | xf=xform::ortho(l,r,b,t,n,f); // Like GLortho 33 | xf=xform::frustum(l,r,b,t,n,f); // Like GLfrustum 34 | glMultMatrixd(xf); // Conversion to column-major array 35 | bool ok = xf.read("file.xf"); // Read xform from file 36 | xf.write("file.xf"); // Write xform to file 37 | xf=xf * xf2; // Matrix-matrix multiplication 38 | xf=inv(xf2); // Inverse 39 | vec v = xf * vec(1,2,3); // Matrix-vector multiplication 40 | xf2=rot_only(xf); // Just the upper 3x3 of xf 41 | xf2=trans_only(xf); // Just the translation of xf 42 | xf2=norm_xf(xf); // Inverse transpose, no translation 43 | invert(xf); // Inverts xform in place 44 | orthogonalize(xf); // Makes matrix orthogonal 45 | xf(1,2)=3.0; // Access by row/column 46 | xf[4]=5.0; // Access in column-major order 47 | xfname("file.ply") // Returns string("file.xf") 48 | */ 49 | 50 | #include 51 | #include 52 | #include 53 | #include "lineqn.h" 54 | #include "strutil.h" 55 | 56 | template 57 | class XForm { 58 | private: 59 | T m[16]; // Column-major (OpenGL) order 60 | 61 | public: 62 | // Constructors: defaults to identity 63 | XForm(const T m0 =1, const T m1 =0, const T m2 =0, const T m3 =0, 64 | const T m4 =0, const T m5 =1, const T m6 =0, const T m7 =0, 65 | const T m8 =0, const T m9 =0, const T m10=1, const T m11=0, 66 | const T m12=0, const T m13=0, const T m14=0, const T m15=1) 67 | { 68 | m[0] = m0; m[1] = m1; m[2] = m2; m[3] = m3; 69 | m[4] = m4; m[5] = m5; m[6] = m6; m[7] = m7; 70 | m[8] = m8; m[9] = m9; m[10] = m10; m[11] = m11; 71 | m[12] = m12; m[13] = m13; m[14] = m14; m[15] = m15; 72 | } 73 | template explicit XForm(const S &x) 74 | { for (int i = 0; i < 16; i++) m[i] = x[i]; } 75 | 76 | // Default destructor, copy constructor, assignment operator 77 | 78 | // Array reference and conversion to array - no bounds checking 79 | const T operator [] (int i) const 80 | { return m[i]; } 81 | T &operator [] (int i) 82 | { return m[i]; } 83 | operator const T * () const 84 | { return m; } 85 | operator const T * () 86 | { return m; } 87 | operator T * () 88 | { return m; } 89 | 90 | // Access by row/column 91 | const T operator () (int r, int c) const 92 | { return m[r + c * 4]; } 93 | T &operator () (int r, int c) 94 | { return m[r + c * 4]; } 95 | 96 | // Some partial compatibility with std::vector 97 | typedef T value_type; 98 | typedef T *pointer; 99 | typedef const T *const_pointer; 100 | typedef T *iterator; 101 | typedef const T *const_iterator; 102 | typedef T &reference; 103 | typedef const T &const_reference; 104 | typedef size_t size_type; 105 | typedef ptrdiff_t difference_type; 106 | 107 | size_t size() const 108 | { return 16; } 109 | T *begin() 110 | { return &(m[0]); } 111 | const T *begin() const 112 | { return &(m[0]); } 113 | T *end() 114 | { return begin() + size(); } 115 | const T *end() const 116 | { return begin() + size(); } 117 | 118 | 119 | // Static members - really just fancy constructors 120 | static XForm identity() 121 | { return XForm(); } 122 | static XForm trans(const T &tx, const T &ty, const T &tz) 123 | { return XForm(1,0,0,0,0,1,0,0,0,0,1,0,tx,ty,tz,1); } 124 | template static XForm trans(const S &t) 125 | { return XForm::trans(t[0], t[1], t[2]); } 126 | static XForm rot(const T &angle, 127 | const T &rx, const T &ry, const T &rz) 128 | { 129 | // Angle in radians, unlike OpenGL 130 | T l = sqrt(rx*rx+ry*ry+rz*rz); 131 | if (l == T(0)) 132 | return XForm(); 133 | T l1 = T(1)/l, x = rx*l1, y = ry*l1, z = rz*l1; 134 | T s = sin(angle), c = cos(angle); 135 | T xs = x*s, ys = y*s, zs = z*s, c1 = T(1)-c; 136 | T xx = c1*x*x, yy = c1*y*y, zz = c1*z*z; 137 | T xy = c1*x*y, xz = c1*x*z, yz = c1*y*z; 138 | return XForm(xx+c, xy+zs, xz-ys, 0, 139 | xy-zs, yy+c, yz+xs, 0, 140 | xz+ys, yz-xs, zz+c, 0, 141 | 0, 0, 0, 1); 142 | } 143 | template static XForm rot(const T &angle, const S &axis) 144 | { return XForm::rot(angle, axis[0], axis[1], axis[2]); } 145 | static XForm scale(const T &s) 146 | { return XForm(s,0,0,0,0,s,0,0,0,0,s,0,0,0,0,1); } 147 | static XForm scale(const T &sx, const T &sy, const T &sz) 148 | { return XForm(sx,0,0,0,0,sy,0,0,0,0,sz,0,0,0,0,1); } 149 | static XForm scale(const T &s, const T &dx, const T &dy, const T &dz) 150 | { 151 | T dlen2 = dx*dx + dy*dy + dz*dz; 152 | T s1 = (s - T(1)) / dlen2; 153 | return XForm(T(1) + s1*dx*dx, s1*dx*dy, s1*dx*dz, 0, 154 | s1*dx*dy, T(1) + s1*dy*dy, s1*dy*dz, 0, 155 | s1*dx*dz, s1*dy*dz, T(1) + s1*dz*dz, 0, 156 | 0, 0, 0, 1); 157 | } 158 | template static XForm scale(const T &s, const S &dir) 159 | { return XForm::scale(s, dir[0], dir[1], dir[2]); } 160 | static XForm ortho(const T &l, const T &r, const T &b, const T &t, 161 | const T &n, const T &f) 162 | { 163 | T rrl = T(1) / (r-l); 164 | T rtb = T(1) / (t-b); 165 | T rfn = T(1) / (f-n); 166 | return XForm(T(2)*rrl, 0, 0, 0, 167 | 0, T(2)*rtb, 0, 0, 168 | 0, 0, T(-2)*rfn, 0, 169 | -(r+l)*rrl, -(t+b)*rtb, -(f+n)*rfn, 1); 170 | } 171 | static XForm frustum(const T &l, const T &r, const T &b, const T &t, 172 | const T &n, const T &f) 173 | { 174 | T rrl = T(1) / (r-l); 175 | T rtb = T(1) / (t-b); 176 | T rfn = T(1) / (f-n); 177 | return XForm(T(2)*n*rrl, 0, 0, 0, 178 | 0, T(2)*n*rtb, 0, 0, 179 | (r+l)*rrl, (t+b)*rtb, -(f+n)*rfn, -1, 180 | 0, 0, T(-2)*f*n*rfn, 0); 181 | } 182 | // Returns y*x^T, thinking of y and x as column 3-vectors 183 | template static XForm outer(const S &y, const S &x) 184 | { 185 | XForm result; 186 | for (int i = 0; i < 3; i++) 187 | for (int j = 0; j < 3; j++) 188 | result[4*i+j] = x[i]*y[j]; 189 | return result; 190 | } 191 | 192 | // Read an XForm from a file. 193 | bool read(const std::string &filename) 194 | { 195 | std::ifstream f(filename.c_str()); 196 | XForm M; 197 | f >> M; 198 | f.close(); 199 | if (f.good()) { 200 | *this = M; 201 | return true; 202 | } 203 | return false; 204 | } 205 | 206 | // Write an XForm to a file 207 | bool write(const std::string &filename) const 208 | { 209 | std::ofstream f(filename.c_str()); 210 | f << *this; 211 | f.close(); 212 | return f.good(); 213 | } 214 | }; 215 | 216 | typedef XForm xform; 217 | typedef XForm fxform; 218 | 219 | 220 | // Binary operations 221 | template 222 | static inline XForm operator + (const XForm &xf1, const XForm &xf2) 223 | { 224 | return XForm( 225 | xf1[ 0] + xf2[ 0], xf1[ 1] + xf2[ 1], 226 | xf1[ 2] + xf2[ 2], xf1[ 3] + xf2[ 3], 227 | xf1[ 4] + xf2[ 4], xf1[ 5] + xf2[ 5], 228 | xf1[ 6] + xf2[ 6], xf1[ 7] + xf2[ 7], 229 | xf1[ 8] + xf2[ 8], xf1[ 9] + xf2[ 9], 230 | xf1[10] + xf2[10], xf1[11] + xf2[11], 231 | xf1[12] + xf2[12], xf1[13] + xf2[13], 232 | xf1[14] + xf2[14], xf1[15] + xf2[15] 233 | ); 234 | } 235 | 236 | template 237 | static inline XForm operator - (const XForm &xf1, const XForm &xf2) 238 | { 239 | return XForm( 240 | xf1[ 0] - xf2[ 0], xf1[ 1] - xf2[ 1], 241 | xf1[ 2] - xf2[ 2], xf1[ 3] - xf2[ 3], 242 | xf1[ 4] - xf2[ 4], xf1[ 5] - xf2[ 5], 243 | xf1[ 6] - xf2[ 6], xf1[ 7] - xf2[ 7], 244 | xf1[ 8] - xf2[ 8], xf1[ 9] - xf2[ 9], 245 | xf1[10] - xf2[10], xf1[11] - xf2[11], 246 | xf1[12] - xf2[12], xf1[13] - xf2[13], 247 | xf1[14] - xf2[14], xf1[15] - xf2[15] 248 | ); 249 | } 250 | 251 | template 252 | static inline XForm operator * (const XForm &xf1, const XForm &xf2) 253 | { 254 | return XForm( 255 | xf1[ 0]*xf2[ 0]+xf1[ 4]*xf2[ 1]+xf1[ 8]*xf2[ 2]+xf1[12]*xf2[ 3], 256 | xf1[ 1]*xf2[ 0]+xf1[ 5]*xf2[ 1]+xf1[ 9]*xf2[ 2]+xf1[13]*xf2[ 3], 257 | xf1[ 2]*xf2[ 0]+xf1[ 6]*xf2[ 1]+xf1[10]*xf2[ 2]+xf1[14]*xf2[ 3], 258 | xf1[ 3]*xf2[ 0]+xf1[ 7]*xf2[ 1]+xf1[11]*xf2[ 2]+xf1[15]*xf2[ 3], 259 | xf1[ 0]*xf2[ 4]+xf1[ 4]*xf2[ 5]+xf1[ 8]*xf2[ 6]+xf1[12]*xf2[ 7], 260 | xf1[ 1]*xf2[ 4]+xf1[ 5]*xf2[ 5]+xf1[ 9]*xf2[ 6]+xf1[13]*xf2[ 7], 261 | xf1[ 2]*xf2[ 4]+xf1[ 6]*xf2[ 5]+xf1[10]*xf2[ 6]+xf1[14]*xf2[ 7], 262 | xf1[ 3]*xf2[ 4]+xf1[ 7]*xf2[ 5]+xf1[11]*xf2[ 6]+xf1[15]*xf2[ 7], 263 | xf1[ 0]*xf2[ 8]+xf1[ 4]*xf2[ 9]+xf1[ 8]*xf2[10]+xf1[12]*xf2[11], 264 | xf1[ 1]*xf2[ 8]+xf1[ 5]*xf2[ 9]+xf1[ 9]*xf2[10]+xf1[13]*xf2[11], 265 | xf1[ 2]*xf2[ 8]+xf1[ 6]*xf2[ 9]+xf1[10]*xf2[10]+xf1[14]*xf2[11], 266 | xf1[ 3]*xf2[ 8]+xf1[ 7]*xf2[ 9]+xf1[11]*xf2[10]+xf1[15]*xf2[11], 267 | xf1[ 0]*xf2[12]+xf1[ 4]*xf2[13]+xf1[ 8]*xf2[14]+xf1[12]*xf2[15], 268 | xf1[ 1]*xf2[12]+xf1[ 5]*xf2[13]+xf1[ 9]*xf2[14]+xf1[13]*xf2[15], 269 | xf1[ 2]*xf2[12]+xf1[ 6]*xf2[13]+xf1[10]*xf2[14]+xf1[14]*xf2[15], 270 | xf1[ 3]*xf2[12]+xf1[ 7]*xf2[13]+xf1[11]*xf2[14]+xf1[15]*xf2[15] 271 | ); 272 | } 273 | 274 | 275 | // Component-wise equality and inequality (#include the usual caveats 276 | // about comparing floats for equality...) 277 | template 278 | static inline bool operator == (const XForm &xf1, const XForm &xf2) 279 | { 280 | for (int i = 0; i < 16; i++) 281 | if (xf1[i] != xf2[i]) 282 | return false; 283 | return true; 284 | } 285 | 286 | template 287 | static inline bool operator != (const XForm &xf1, const XForm &xf2) 288 | { 289 | for (int i = 0; i < 16; i++) 290 | if (xf1[i] != xf2[i]) 291 | return true; 292 | return false; 293 | } 294 | 295 | 296 | // Inverse 297 | template 298 | static inline XForm inv(const XForm &xf) 299 | { 300 | T A[4][4] = { { xf[0], xf[4], xf[8], xf[12] }, 301 | { xf[1], xf[5], xf[9], xf[13] }, 302 | { xf[2], xf[6], xf[10], xf[14] }, 303 | { xf[3], xf[7], xf[11], xf[15] } }; 304 | int ind[4]; 305 | bool ok = ludcmp(A, ind); 306 | if (!ok) 307 | return XForm(); 308 | T B[4][4] = { { 1, 0, 0, 0 }, 309 | { 0, 1, 0, 0 }, 310 | { 0, 0, 1, 0 }, 311 | { 0, 0, 0, 1 } }; 312 | for (int i = 0; i < 4; i++) 313 | lubksb(A, ind, B[i]); 314 | return XForm(B[0][0], B[0][1], B[0][2], B[0][3], 315 | B[1][0], B[1][1], B[1][2], B[1][3], 316 | B[2][0], B[2][1], B[2][2], B[2][3], 317 | B[3][0], B[3][1], B[3][2], B[3][3]); 318 | } 319 | 320 | template 321 | static inline void invert(XForm &xf) 322 | { 323 | xf = inv(xf); 324 | } 325 | 326 | template 327 | static inline XForm rot_only(const XForm &xf) 328 | { 329 | return XForm(xf[0], xf[1], xf[2], 0, 330 | xf[4], xf[5], xf[6], 0, 331 | xf[8], xf[9], xf[10], 0, 332 | 0, 0, 0, 1); 333 | } 334 | 335 | template 336 | static inline XForm trans_only(const XForm &xf) 337 | { 338 | return XForm(1, 0, 0, 0, 339 | 0, 1, 0, 0, 340 | 0, 0, 1, 0, 341 | xf[12], xf[13], xf[14], 1); 342 | } 343 | 344 | template 345 | static inline XForm norm_xf(const XForm &xf) 346 | { 347 | XForm M = inv(xf); 348 | M[12] = M[13] = M[14] = T(0); 349 | std::swap(M[1], M[4]); 350 | std::swap(M[2], M[8]); 351 | std::swap(M[6], M[9]); 352 | return M; 353 | } 354 | 355 | template 356 | static inline void orthogonalize(XForm &xf) 357 | { 358 | if (xf[15] == T(0)) // Yuck. Doesn't make sense... 359 | xf[15] = T(1); 360 | 361 | T q0 = xf[0] + xf[5] + xf[10] + xf[15]; 362 | T q1 = xf[6] - xf[9]; 363 | T q2 = xf[8] - xf[2]; 364 | T q3 = xf[1] - xf[4]; 365 | T l = sqrt(q0*q0+q1*q1+q2*q2+q3*q3); 366 | 367 | XForm M = XForm::rot(T(2)*acos(q0/l), q1, q2, q3); 368 | M[12] = xf[12]/xf[15]; 369 | M[13] = xf[13]/xf[15]; 370 | M[14] = xf[14]/xf[15]; 371 | 372 | xf = M; 373 | } 374 | 375 | 376 | // Matrix-vector multiplication 377 | template 378 | static inline const S operator * (const XForm &xf, const S &v) 379 | { 380 | T h = xf[3]*v[0] + xf[7]*v[1] + xf[11]*v[2] + xf[15]; 381 | h = T(1) / h; 382 | 383 | return S(float(h*(xf[0]*v[0] + xf[4]*v[1] + xf[8]*v[2] + xf[12])), 384 | float(h*(xf[1]*v[0] + xf[5]*v[1] + xf[9]*v[2] + xf[13])), 385 | float(h*(xf[2]*v[0] + xf[6]*v[1] + xf[10]*v[2] + xf[14]))); 386 | } 387 | 388 | // iostream operators 389 | template 390 | static inline std::ostream &operator << (std::ostream &os, const XForm &m) 391 | { 392 | for (int i = 0; i < 4; i++) { 393 | for (int j = 0; j < 4; j++) { 394 | os << m[i+4*j]; 395 | if (j == 3) 396 | os << std::endl; 397 | else 398 | os << " "; 399 | } 400 | } 401 | return os; 402 | } 403 | template 404 | static inline std::istream &operator >> (std::istream &is, XForm &m) 405 | { 406 | for (int i = 0; i < 4; i++) 407 | for (int j = 0; j < 4; j++) 408 | is >> m[i+4*j]; 409 | if (!is.good()) 410 | m = xform::identity(); 411 | 412 | return is; 413 | } 414 | 415 | // Generate a .xf filename from an input (scan) filename 416 | static inline std::string xfname(const std::string &filename) 417 | { 418 | return replace_ext(filename, "xf"); 419 | } 420 | 421 | #endif 422 | -------------------------------------------------------------------------------- /include/bsphere.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef BSPHERE_H 18 | #define BSPHERE_H 19 | // Copright (C) 1999 20 | // 21 | // This program is free software; you can redistribute it and/or modify 22 | // it under the terms of the GNU General Public License as published by 23 | // the Free Software Foundation; either version 2 of the License, or 24 | // (at your option) any later version. 25 | // 26 | // This program is distributed in the hope that it will be useful, 27 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | // GNU General Public License for more details. 30 | // 31 | // You should have received a copy of the GNU General Public License 32 | // along with this program; if not, write to the Free Software 33 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, 34 | // or download the License terms from prep.ai.mit.edu/pub/gnu/COPYING-2.0. 35 | // 36 | // Contact: 37 | // -------- 38 | // Bernd Gaertner 39 | // Institut f. Informatik 40 | // ETH Zuerich 41 | // ETH-Zentrum 42 | // CH-8092 Zuerich, Switzerland 43 | // http://www.inf.ethz.ch/personal/gaertner 44 | // 45 | 46 | 47 | #include "Vec.h" 48 | #include 49 | 50 | 51 | // Class for a basis of points supporting a bounding sphere 52 | template 53 | class Basis { 54 | private: 55 | int m, s; // size and number of support points 56 | T q0[D]; 57 | 58 | T z[D+1]; 59 | T f[D+1]; 60 | T v[D+1][D]; 61 | T a[D+1][D]; 62 | 63 | T c[D+1][D]; 64 | T sqr_r[D+1]; 65 | 66 | T *current_c; // points to some c[j] 67 | T current_sqr_r; 68 | 69 | public: 70 | const T *center() const { return current_c; } 71 | T squared_radius() const { return current_sqr_r; } 72 | int size() const { return m; } 73 | T excess(const Vec &p) const; 74 | void reset(); // generates empty sphere with m=s=0 75 | bool push(const Vec &p); 76 | void pop(); 77 | }; 78 | 79 | 80 | // Class for hoding and computing the bounding sphere 81 | template 82 | class Miniball { 83 | public: 84 | typedef typename std::list< Vec >::iterator It; 85 | 86 | private: 87 | std::list< Vec > L;// STL list keeping the points 88 | Basis B; // basis keeping the current ball 89 | It support_end; // past-the-end iterator of support set 90 | 91 | void move_to_front(It j); 92 | T max_excess(It t, It i, It &pivot) const; 93 | void mtf_mb(It k); 94 | void pivot_mb(It k); 95 | 96 | public: 97 | void check_in(const Vec &p) { L.push_back(p); } 98 | template 99 | void check_in(I first, I last) { L.insert(L.end(), first, last); } 100 | void build(bool pivoting = true); 101 | Vec center() const { return Vec(B.center()); } 102 | T squared_radius() const { return B.squared_radius(); } 103 | }; 104 | 105 | 106 | template 107 | T Basis::excess(const Vec &p) const 108 | { 109 | T e = -current_sqr_r; 110 | for (int k = 0; k < D; k++) 111 | e += sqr(p[k] - current_c[k]); 112 | return e; 113 | } 114 | 115 | 116 | template 117 | void Basis::reset() 118 | { 119 | m = s = 0; 120 | // we misuse c[0] for the center of the empty sphere 121 | for (int j = 0; j < D; j++) 122 | c[0][j] = 0; 123 | current_c = c[0]; 124 | current_sqr_r = -1; 125 | } 126 | 127 | 128 | template 129 | bool Basis::push(const Vec &p) 130 | { 131 | int i, j; 132 | const T eps = T(1.0e-13); 133 | if (m == 0) { 134 | for (i = 0; i < D; i++) 135 | q0[i] = p[i]; 136 | for (i = 0; i < D; i++) 137 | c[0][i] = q0[i]; 138 | sqr_r[0] = 0; 139 | } else { 140 | // set v_m to Q_m 141 | for (i = 0; i < D; i++) 142 | v[m][i] = p[i] - q0[i]; 143 | 144 | // compute the a_{m,i}, i < m 145 | for (i = 1; i < m; i++) { 146 | a[m][i] = 0; 147 | for (j = 0; j < D; j++) 148 | a[m][i] += v[i][j] * v[m][j]; 149 | a[m][i] *= (T(2) / z[i]); 150 | } 151 | 152 | // update v_m to Q_m-\bar{Q}_m 153 | for (i = 1; i < m; i++) { 154 | for (j = 0; j < D; j++) 155 | v[m][j] -= a[m][i] * v[i][j]; 156 | } 157 | 158 | // compute z_m 159 | z[m] = 0; 160 | for (j = 0; j < D; j++) 161 | z[m] += sqr(v[m][j]); 162 | z[m] *= T(2); 163 | 164 | // reject push if z_m too small 165 | if (z[m] < eps*current_sqr_r) 166 | return false; 167 | 168 | // update c, sqr_r 169 | T e = -sqr_r[m-1]; 170 | for (i = 0; i < D; i++) 171 | e += sqr(p[i] - c[m-1][i]); 172 | f[m] = e / z[m]; 173 | 174 | for (i = 0; i < D; i++) 175 | c[m][i] = c[m-1][i] + f[m]*v[m][i]; 176 | sqr_r[m] = sqr_r[m-1] + e*f[m]*T(0.5); 177 | } 178 | current_c = c[m]; 179 | current_sqr_r = sqr_r[m]; 180 | s = ++m; 181 | return true; 182 | } 183 | 184 | 185 | template 186 | void Basis::pop() 187 | { 188 | m--; 189 | } 190 | 191 | 192 | template 193 | void Miniball::move_to_front(It j) 194 | { 195 | if (support_end == j) 196 | support_end++; 197 | L.splice(L.begin(), L, j); 198 | } 199 | 200 | 201 | template 202 | T Miniball::max_excess(It t, It i, It &pivot) const 203 | { 204 | const T *c = B.center(), sqr_r = B.squared_radius(); 205 | T e, max_e = 0; 206 | for (It k = t; k != i; k++) { 207 | const Vec &p = *k; 208 | e = -sqr_r; 209 | for (int j = 0; j < D; j++) 210 | e += sqr(p[j] - c[j]); 211 | if (e > max_e) { 212 | max_e = e; 213 | pivot = k; 214 | } 215 | } 216 | return max_e; 217 | } 218 | 219 | 220 | template 221 | void Miniball::mtf_mb(It i) 222 | { 223 | support_end = L.begin(); 224 | if (B.size() == D+1) 225 | return; 226 | for (It k = L.begin(); k != i; ) { 227 | It j = k++; 228 | if (B.excess(*j) > 0) { 229 | if (B.push(*j)) { 230 | mtf_mb(j); 231 | B.pop(); 232 | move_to_front(j); 233 | } 234 | } 235 | } 236 | } 237 | 238 | 239 | template 240 | void Miniball::pivot_mb(It i) 241 | { 242 | It t = ++L.begin(); 243 | mtf_mb(t); 244 | T max_e, old_sqr_r = T(0); 245 | do { 246 | It pivot; 247 | max_e = max_excess(t, i, pivot); 248 | if (max_e > 0) { 249 | t = support_end; 250 | if (t == pivot) 251 | t++; 252 | old_sqr_r = B.squared_radius(); 253 | B.push(*pivot); 254 | mtf_mb(support_end); 255 | B.pop(); 256 | move_to_front(pivot); 257 | } 258 | } while (max_e > 0 && B.squared_radius() > old_sqr_r); 259 | } 260 | 261 | template 262 | void Miniball::build(bool pivoting /* = true */) 263 | { 264 | B.reset(); 265 | support_end = L.begin(); 266 | if (pivoting) 267 | pivot_mb(L.end()); 268 | else 269 | mtf_mb(L.end()); 270 | } 271 | 272 | #endif 273 | -------------------------------------------------------------------------------- /include/lineqn.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef LINEQN_H 18 | #define LINEQN_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | lineqn.h 24 | Solution of systems of linear equations and eigenvalue decomposition. 25 | Some are patterned after the code in Numerical Recipes, but with a bit of 26 | the fancy C++ template thing happening. 27 | */ 28 | 29 | 30 | // Windows defines min and max as macros, which prevents us from 31 | // using the type-safe versions from std:: 32 | // Also define NOMINMAX, which prevents future bad definitions. 33 | #undef min 34 | #undef max 35 | #ifndef NOMINMAX 36 | # define NOMINMAX 37 | #endif 38 | 39 | #include 40 | #include 41 | 42 | 43 | // Let gcc optimize conditional branches a bit better... 44 | #ifndef likely 45 | # if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 46 | # define likely(x) (x) 47 | # define unlikely(x) (x) 48 | # else 49 | # define likely(x) (__builtin_expect((x), 1)) 50 | # define unlikely(x) (__builtin_expect((x), 0)) 51 | # endif 52 | #endif 53 | 54 | 55 | // LU decomposition 56 | template 57 | static inline bool ludcmp(T a[N][N], int indx[N], T *d = NULL) 58 | { 59 | int i, j, k; 60 | T vv[N]; 61 | 62 | if (d) 63 | *d = 1; 64 | for (i = 0; i < N; i++) { 65 | T big = 0.0; 66 | for (j = 0; j < N; j++) { 67 | T tmp = std::fabs(a[i][j]); 68 | if (tmp > big) 69 | big = tmp; 70 | } 71 | if (big == 0.0) 72 | return false; 73 | vv[i] = 1.0 / big; 74 | } 75 | for (j = 0; j < N; j++) { 76 | for (i = 0; i < j; i++) { 77 | T sum = a[i][j]; 78 | for (k = 0; k < i; k++) 79 | sum -= a[i][k]*a[k][j]; 80 | a[i][j]=sum; 81 | } 82 | T big = 0.0; 83 | int imax = j; 84 | for (i = j; i < N; i++) { 85 | T sum = a[i][j]; 86 | for (k = 0; k < j; k++) 87 | sum -= a[i][k]*a[k][j]; 88 | a[i][j] = sum; 89 | T tmp = vv[i] * std::fabs(sum); 90 | if (tmp > big) { 91 | big = tmp; 92 | imax = i; 93 | } 94 | } 95 | if (imax != j) { 96 | for (k = 0; k < N; k++) 97 | std::swap(a[imax][k], a[j][k]); 98 | if (d) 99 | *d = -(*d); 100 | vv[imax] = vv[j]; 101 | } 102 | indx[j] = imax; 103 | if (a[j][j] == 0.0) 104 | return false; 105 | if (j != N-1) { 106 | T tmp = 1.0/(a[j][j]); 107 | for (i = j+1; i < N; i++) 108 | a[i][j] *= tmp; 109 | } 110 | } 111 | return true; 112 | } 113 | 114 | 115 | // Backsubstitution after ludcmp 116 | template 117 | static inline void lubksb(T a[N][N], int indx[N], T b[N]) 118 | { 119 | int ii = -1, i, j; 120 | for (i = 0; i < N; i++) { 121 | int ip = indx[i]; 122 | T sum = b[ip]; 123 | b[ip] = b[i]; 124 | if (ii != -1) 125 | for (j = ii; j < i; j++) 126 | sum -= a[i][j] * b[j]; 127 | else if (sum) 128 | ii = i; 129 | b[i] = sum; 130 | } 131 | for (i = N-1; i >= 0; i--) { 132 | T sum = b[i]; 133 | for (j = i+1; j < N; j++) 134 | sum -= a[i][j] * b[j]; 135 | b[i] = sum / a[i][i]; 136 | } 137 | } 138 | 139 | 140 | // Perform LDL^T decomposition of a symmetric positive definite matrix. 141 | // Like Cholesky, but no square roots. Overwrites lower triangle of matrix. 142 | template 143 | static inline bool ldltdc(T A[N][N], T rdiag[N]) 144 | { 145 | T v[N-1]; 146 | for (int i = 0; i < N; i++) { 147 | for (int k = 0; k < i; k++) 148 | v[k] = A[i][k] * rdiag[k]; 149 | for (int j = i; j < N; j++) { 150 | T sum = A[i][j]; 151 | for (int k = 0; k < i; k++) 152 | sum -= v[k] * A[j][k]; 153 | if (i == j) { 154 | if (unlikely(sum <= T(0))) 155 | return false; 156 | rdiag[i] = T(1) / sum; 157 | } else { 158 | A[j][i] = sum; 159 | } 160 | } 161 | } 162 | 163 | return true; 164 | } 165 | 166 | 167 | // Solve Ax=B after ldltdc 168 | template 169 | static inline void ldltsl(T A[N][N], T rdiag[N], T B[N], T x[N]) 170 | { 171 | int i; 172 | for (i = 0; i < N; i++) { 173 | T sum = B[i]; 174 | for (int k = 0; k < i; k++) 175 | sum -= A[i][k] * x[k]; 176 | x[i] = sum * rdiag[i]; 177 | } 178 | for (i = N - 1; i >= 0; i--) { 179 | T sum = 0; 180 | for (int k = i + 1; k < N; k++) 181 | sum += A[k][i] * x[k]; 182 | x[i] -= sum * rdiag[i]; 183 | } 184 | } 185 | 186 | 187 | // Eigenvector decomposition for real, symmetric matrices, 188 | // a la Bowdler et al. / EISPACK / JAMA 189 | // Entries of d are eigenvalues, sorted smallest to largest. 190 | // A changed in-place to have its columns hold the corresponding eigenvectors. 191 | // Note that A must be completely filled in on input. 192 | template 193 | static inline void eigdc(T A[N][N], T d[N]) 194 | { 195 | // Householder 196 | T e[N]; 197 | for (int j = 0; j < N; j++) { 198 | d[j] = A[N-1][j]; 199 | e[j] = 0.0; 200 | } 201 | for (int i = N-1; i > 0; i--) { 202 | T scale = 0.0; 203 | for (int k = 0; k < i; k++) 204 | scale += std::fabs(d[k]); 205 | if (scale == 0.0) { 206 | e[i] = d[i-1]; 207 | for (int j = 0; j < i; j++) { 208 | d[j] = A[i-1][j]; 209 | A[i][j] = A[j][i] = 0.0; 210 | } 211 | d[i] = 0.0; 212 | } else { 213 | T h(0); 214 | T invscale = T(1.0 / scale); 215 | for (int k = 0; k < i; k++) { 216 | d[k] *= invscale; 217 | h += sqr(d[k]); 218 | } 219 | T f = d[i-1]; 220 | T g = (f > 0.0) ? -std::sqrt(h) : std::sqrt(h); 221 | e[i] = scale * g; 222 | h -= f * g; 223 | d[i-1] = f - g; 224 | for (int j = 0; j < i; j++) 225 | e[j] = 0.0; 226 | for (int j = 0; j < i; j++) { 227 | f = d[j]; 228 | A[j][i] = f; 229 | g = e[j] + f * A[j][j]; 230 | for (int k = j+1; k < i; k++) { 231 | g += A[k][j] * d[k]; 232 | e[k] += A[k][j] * f; 233 | } 234 | e[j] = g; 235 | } 236 | f = 0.0; 237 | T invh = T(1.0 / h); 238 | for (int j = 0; j < i; j++) { 239 | e[j] *= invh; 240 | f += e[j] * d[j]; 241 | } 242 | T hh = f / (h + h); 243 | for (int j = 0; j < i; j++) 244 | e[j] -= hh * d[j]; 245 | for (int j = 0; j < i; j++) { 246 | f = d[j]; 247 | g = e[j]; 248 | for (int k = j; k < i; k++) 249 | A[k][j] -= f * e[k] + g * d[k]; 250 | d[j] = A[i-1][j]; 251 | A[i][j] = 0.0; 252 | } 253 | d[i] = h; 254 | } 255 | } 256 | 257 | for (int i = 0; i < N-1; i++) { 258 | A[N-1][i] = A[i][i]; 259 | A[i][i] = 1.0; 260 | T h = d[i+1]; 261 | if (h != 0.0) { 262 | T invh = T(1.0 / h); 263 | for (int k = 0; k <= i; k++) 264 | d[k] = A[k][i+1] * invh; 265 | for (int j = 0; j <= i; j++) { 266 | T g = 0.0; 267 | for (int k = 0; k <= i; k++) 268 | g += A[k][i+1] * A[k][j]; 269 | for (int k = 0; k <= i; k++) 270 | A[k][j] -= g * d[k]; 271 | } 272 | } 273 | for (int k = 0; k <= i; k++) 274 | A[k][i+1] = 0.0; 275 | } 276 | for (int j = 0; j < N; j++) { 277 | d[j] = A[N-1][j]; 278 | A[N-1][j] = 0.0; 279 | } 280 | A[N-1][N-1] = 1.0; 281 | 282 | // QL 283 | for (int i = 1; i < N; i++) 284 | e[i-1] = e[i]; 285 | e[N-1] = 0.0; 286 | T f = 0.0, tmp = 0.0; 287 | const T eps = T(pow(2.0, -52.0)); 288 | for (int l = 0; l < N; l++) { 289 | tmp = std::max(tmp, std::fabs(d[l]) + std::fabs(e[l])); 290 | int m = l; 291 | while (m < N) { 292 | if (std::fabs(e[m]) <= eps * tmp) 293 | break; 294 | m++; 295 | } 296 | if (m > l) { 297 | do { 298 | T g = d[l]; 299 | T p = (d[l+1] - g) / (e[l] + e[l]); 300 | T r = T(hypot(p, 1.0)); 301 | if (p < 0.0) 302 | r = -r; 303 | d[l] = e[l] / (p + r); 304 | d[l+1] = e[l] * (p + r); 305 | T dl1 = d[l+1]; 306 | T h = g - d[l]; 307 | for (int i = l+2; i < N; i++) 308 | d[i] -= h; 309 | f += h; 310 | p = d[m]; 311 | T c = 1.0, c2 = 1.0, c3 = 1.0; 312 | T el1 = e[l+1], s = 0.0, s2 = 0.0; 313 | for (int i = m - 1; i >= l; i--) { 314 | c3 = c2; 315 | c2 = c; 316 | s2 = s; 317 | g = c * e[i]; 318 | h = c * p; 319 | r = T(hypot(p, e[i])); 320 | e[i+1] = s * r; 321 | s = e[i] / r; 322 | c = p / r; 323 | p = c * d[i] - s * g; 324 | d[i+1] = h + s * (c * g + s * d[i]); 325 | for (int k = 0; k < N; k++) { 326 | h = A[k][i+1]; 327 | A[k][i+1] = s * A[k][i] + c * h; 328 | A[k][i] = c * A[k][i] - s * h; 329 | } 330 | } 331 | p = -s * s2 * c3 * el1 * e[l] / dl1; 332 | e[l] = s * p; 333 | d[l] = c * p; 334 | } while (std::fabs(e[l]) > eps * tmp); 335 | } 336 | d[l] += f; 337 | e[l] = 0.0; 338 | } 339 | 340 | // Sort 341 | for (int i = 0; i < N-1; i++) { 342 | int k = i; 343 | T p = d[i]; 344 | for (int j = i+1; j < N; j++) { 345 | if (d[j] < p) { 346 | k = j; 347 | p = d[j]; 348 | } 349 | } 350 | if (k == i) 351 | continue; 352 | d[k] = d[i]; 353 | d[i] = p; 354 | for (int j = 0; j < N; j++) { 355 | p = A[j][i]; 356 | A[j][i] = A[j][k]; 357 | A[j][k] = p; 358 | } 359 | } 360 | } 361 | 362 | 363 | // x <- A * d * A' * b 364 | template 365 | static inline void eigmult(T A[N][N], 366 | T d[N], 367 | T b[N], 368 | T x[N]) 369 | { 370 | T e[N]; 371 | for (int i = 0; i < N; i++) { 372 | e[i] = 0.0; 373 | for (int j = 0; j < N; j++) 374 | e[i] += A[j][i] * b[j]; 375 | e[i] *= d[i]; 376 | } 377 | for (int i = 0; i < N; i++) { 378 | x[i] = 0.0; 379 | for (int j = 0; j < N; j++) 380 | x[i] += A[i][j] * e[j]; 381 | } 382 | } 383 | 384 | #endif 385 | -------------------------------------------------------------------------------- /include/mempool.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef MEMPOOL_H 18 | #define MEMPOOL_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | mempool.h 24 | Replacement memory management for a class using a memory pool. 25 | 26 | Sample usage: 27 | class MyClass { 28 | private: 29 | static PoolAlloc memPool; 30 | public: 31 | void *operator new(size_t n) { return memPool.alloc(n); } 32 | void operator delete(void *p, size_t n) { memPool.free(p,n); } 33 | // ... 34 | }; 35 | 36 | PoolAlloc MyClass::memPool(sizeof(MyClass)); 37 | 38 | Does *no* error checking. 39 | Make sure sizeof(MyClass) is larger than sizeof(void *). 40 | Based on the description of the Pool class in _Effective C++_ by Scott Meyers. 41 | */ 42 | 43 | #include 44 | #include 45 | 46 | #define POOL_MEMBLOCK 4088 47 | 48 | 49 | class PoolAlloc { 50 | private: 51 | size_t itemsize; 52 | void *freelist; 53 | void grow_freelist() 54 | { 55 | size_t n = POOL_MEMBLOCK / itemsize; 56 | freelist = ::operator new(n * itemsize); 57 | for (size_t i = 0; i < n-1; i++) 58 | *(void **)((char *)freelist + itemsize*i) = 59 | (char *)freelist + itemsize*(i+1); 60 | *(void **)((char *)freelist + itemsize*(n-1)) = 0; 61 | } 62 | 63 | public: 64 | PoolAlloc(size_t size) : itemsize(size), freelist(0) {} 65 | void *alloc(size_t n) 66 | { 67 | if (n != itemsize) 68 | return ::operator new(n); 69 | if (!freelist) 70 | grow_freelist(); 71 | void *next = freelist; 72 | freelist = *(void **)next; 73 | return next; 74 | } 75 | void free(void *p, size_t n) 76 | { 77 | if (!p) 78 | return; 79 | else if (n != itemsize) 80 | ::operator delete(p); 81 | else { 82 | *(void **)p = freelist; 83 | freelist = p; 84 | } 85 | } 86 | void sort_freelist() 87 | { 88 | if (!freelist) 89 | return; 90 | std::vector v; 91 | void *p; 92 | for (p = freelist; *(void **)p; p = *(void **)p) 93 | v.push_back(p); 94 | std::sort(v.begin(), v.end()); 95 | p = freelist = v[0]; 96 | for (size_t i = 1; i < v.size(); i++) { 97 | *(void **)p = v[i]; 98 | p = *(void **)p; 99 | } 100 | *(void **)p = NULL; 101 | } 102 | }; 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /include/meshalgo.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef MESHALGO_H 18 | #define MESHALGO_H 19 | #include "trianglemesh.h" 20 | 21 | // Smooth the mesh geometry 22 | extern void smooth_mesh(TriangleMesh *themesh, float sigma); 23 | 24 | // Bilateral smoothing 25 | extern void bilateral_smooth_mesh(TriangleMesh *themesh, float sigma1, float sigma2); 26 | 27 | // Diffuse an arbitrary per-vertex vector (or scalar) field 28 | template 29 | extern void diffuse_vector(TriangleMesh *themesh, std::vector &field, float sigma); 30 | 31 | // Diffuse the normals across the mesh 32 | extern void diffuse_normals(TriangleMesh *themesh, float sigma); 33 | 34 | extern void zdd_diffuse_curv(TriangleMesh *themesh, float sigma); 35 | 36 | // Diffuse the curvatures across the mesh 37 | extern void diffuse_curv(TriangleMesh *themesh, float sigma); 38 | 39 | // Diffuse the curvature derivatives across the mesh 40 | extern void diffuse_dcurv(TriangleMesh *themesh, float sigma); 41 | 42 | // Given a curvature tensor, find principal directions and curvatures 43 | extern void diagonalize_curv(const vec &old_u, const vec &old_v, 44 | float ku, float kuv, float kv, 45 | const vec &new_norm, 46 | vec &pdir1, vec &pdir2, float &k1, float &k2); 47 | 48 | // Reproject a curvature tensor from the basis spanned by old_u and old_v 49 | // (which are assumed to be unit-length and perpendicular) to the 50 | // new_u, new_v basis. 51 | extern void proj_curv(const vec &old_u, const vec &old_v, 52 | float old_ku, float old_kuv, float old_kv, 53 | const vec &new_u, const vec &new_v, 54 | float &new_ku, float &new_kuv, float &new_kv); 55 | 56 | // Like the above, but for dcurv 57 | extern void proj_dcurv(const vec &old_u, const vec &old_v, 58 | const Vec<4> old_dcurv, 59 | const vec &new_u, const vec &new_v, 60 | Vec<4> &new_dcurv); 61 | 62 | 63 | #endif // MESHALGO_H 64 | -------------------------------------------------------------------------------- /include/strutil.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef STRUTIL_H 18 | #define STRUTIL_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | strutil.h 24 | Miscellaneous string-manipulation utilities 25 | 26 | Usage: 27 | std::string s("foo.bar"); 28 | std::string s2 = replace_ext(s, "baz"); // "foo.baz" 29 | begins_with("Foobar", "foo") // true 30 | ends_with("foobar", "baz") // false 31 | */ 32 | 33 | 34 | #include 35 | #include 36 | 37 | #ifdef _WIN32 38 | # ifndef strncasecmp 39 | # define strncasecmp _strnicmp 40 | # endif 41 | #endif 42 | 43 | 44 | // Replace the extension of a filename, else add one if none present 45 | static inline std::string replace_ext(const std::string &filename, 46 | const std::string &ext) 47 | { 48 | std::string x = filename; 49 | std::string::size_type dot = x.rfind(".", x.length()); 50 | if (dot != std::string::npos) 51 | x.erase(dot); 52 | return x + std::string(".") + ext; 53 | } 54 | 55 | 56 | // Does string s1 begin/end with s2? (Case-insensitive) 57 | static inline bool begins_with(const char *s1, const char *s2) 58 | { 59 | using namespace std; 60 | return !strncasecmp(s1, s2, strlen(s2)); 61 | } 62 | 63 | static inline bool begins_with(const std::string &s1, const std::string &s2) 64 | { 65 | return begins_with(s1.c_str(), s2.c_str()); 66 | } 67 | 68 | static inline bool ends_with(const char *s1, const char *s2) 69 | { 70 | using namespace std; 71 | size_t l1 = strlen(s1), l2 = strlen(s2); 72 | return (l1 >= l2) && !strncasecmp(s1 + l1 - l2, s2, l2); 73 | } 74 | 75 | static inline bool ends_with(const std::string &s1, const std::string &s2) 76 | { 77 | return ends_with(s1.c_str(), s2.c_str()); 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /include/timestamp.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef TIMESTAMP_H 18 | #define TIMESTAMP_H 19 | /* 20 | Szymon Rusinkiewicz 21 | Princeton University 22 | 23 | timestamp.h 24 | Wrapper around system-specific timestamps. 25 | */ 26 | 27 | 28 | #ifdef _WIN32 29 | 30 | # define WIN32_LEAN_AND_MEAN 31 | # include 32 | # include 33 | # define usleep(x) Sleep((x)/1000) 34 | 35 | struct timestamp { LARGE_INTEGER t; }; 36 | 37 | static inline double LI2d(const LARGE_INTEGER &li) 38 | { 39 | // Work around random compiler bugs... 40 | double d = li.HighPart; 41 | d *= 65536.0 * 65536.0; 42 | d += *(unsigned long *)(&(li.LowPart)); 43 | return d; 44 | } 45 | 46 | static inline float operator - (const timestamp &t1, const timestamp &t2) 47 | { 48 | static LARGE_INTEGER PerformanceFrequency; 49 | static int status = QueryPerformanceFrequency(&PerformanceFrequency); 50 | if (status == 0) return 1.0f; 51 | 52 | return float((LI2d(t1.t) - LI2d(t2.t)) / LI2d(PerformanceFrequency)); 53 | } 54 | 55 | static inline timestamp now() 56 | { 57 | timestamp t; 58 | QueryPerformanceCounter(&t.t); 59 | return t; 60 | } 61 | 62 | #else 63 | 64 | # include 65 | # include 66 | 67 | typedef struct timeval timestamp; 68 | 69 | static inline float operator - (const timestamp &t1, const timestamp &t2) 70 | { 71 | return (float)(t1.tv_sec - t2.tv_sec) + 72 | 1.0e-6f*(t1.tv_usec - t2.tv_usec); 73 | } 74 | 75 | static inline timestamp now() 76 | { 77 | timestamp t; 78 | gettimeofday(&t, 0); 79 | return t; 80 | } 81 | 82 | #endif 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /include/trianglemesh.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/include/trianglemesh.h -------------------------------------------------------------------------------- /linedrawing_project.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | underline () { 4 | echo "\033[4m$1\033[0m" 5 | } 6 | 7 | usage() { 8 | echo "Usage: `basename $0` -d rootdir -p pattern" 9 | echo " This command generates 102 line-drawing images from 102 views of each model under `underline rootdir` folder" 10 | echo " The options are as follows:" 11 | echo " -d\t root directory" 12 | echo " -p\t the pathname being examined matches `underline pattern`, support \"*.off\" or \"*.obj\" " 13 | exit 1 14 | } 15 | 16 | if [ $# -ne 4 ]; then 17 | usage; 18 | fi 19 | 20 | while getopts "d:p:" arg; do 21 | case $arg in 22 | d) 23 | rootdir=$OPTARG 24 | ;; 25 | p) 26 | pattern=$OPTARG 27 | ;; 28 | ?) 29 | usage; 30 | ;; 31 | esac 32 | done 33 | 34 | for model in $(find $rootdir -name "$pattern" | sed 's/^\.\///'); do 35 | view="${model%.*}view" 36 | mkdir -p $view 37 | release/bin/gen_view_image $model data/view 102 $view 38 | done 39 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | #------------------------------------------------- 3 | # @Author: zdd 4 | # @Email: zddhub@gmail.com 5 | # 6 | # rstc.cc in Qt 7 | # 8 | # Thanks: 9 | # Original by Tilke Judd 10 | # Tweaks by Szymon Rusinkiewicz 11 | # 12 | # apparentridge.h 13 | # Compute apparent ridges. 14 | # 15 | # Implements method of 16 | # Judd, T., Durand, F, and Adelson, E. 17 | # Apparent Ridges for Line Drawing, 18 | # ACM Trans. Graphics (Proc. SIGGRAPH), vol. 26, no. 3, 2007. 19 | #------------------------------------------------- 20 | */ 21 | 22 | /************************************************************************* 23 | * Copyright (c) 2014 Zhang Dongdong zddhub@gmail.com 24 | * All rights reserved. 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | **************************************************************************/ 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #include "mainwindow.h" 44 | #include "trianglemesh.h" 45 | 46 | //在windows下,本程序使用以下.bat程序调用 47 | /* 48 | * gen_view_image.exe cow.obj views 102 images 49 | */ 50 | 51 | void usage() { 52 | cout << "Usage: gen_view_image modelfile xfdir viewnum imagedir"< 21 | #include "trimeshview.h" 22 | 23 | #include "threshdialog.h" 24 | 25 | namespace Ui { 26 | class MainWindow; 27 | } 28 | 29 | class MainWindow : public QMainWindow 30 | { 31 | Q_OBJECT 32 | 33 | public: 34 | explicit MainWindow(QWidget *parent = 0); 35 | ~MainWindow(); 36 | 37 | public slots: 38 | void open(); 39 | void setThresh(); 40 | 41 | private slots: 42 | void on_actionEdges_triggered(); 43 | 44 | void on_actionNormals_triggered(); 45 | 46 | void on_actionPrincipal_1_triggered(); 47 | 48 | void on_actionPrincipal_2_triggered(); 49 | 50 | void on_actionNormalColor_triggered(); 51 | 52 | void on_actionCurv_Color_triggered(); 53 | 54 | void on_actionBoundaries_triggered(); 55 | 56 | void on_actionPreview_triggered(); 57 | 58 | void on_actionExterior_Silhouette_triggered(); 59 | 60 | void on_actionOccluding_Contours_triggered(); 61 | 62 | void on_actionSuggestive_Contours_triggered(); 63 | 64 | void on_actionRidges_triggered(); 65 | 66 | void on_actionValleys_triggered(); 67 | 68 | void on_actionApparent_Ridges_triggered(); 69 | 70 | void on_actionSave_Ridges_file_triggered(); 71 | 72 | void on_actionSave_Occluding_file_triggered(); 73 | 74 | void on_actionLines_triggered(); 75 | 76 | void on_actionFaces_triggered(); 77 | 78 | void on_actionLines_2_triggered(); 79 | 80 | void on_actionFaces_2_triggered(); 81 | 82 | void on_actionSave_RV_mesh_file_triggered(); 83 | 84 | void on_actionSave_OC_mesh_file_triggered(); 85 | 86 | void on_actionOpen_LD_file_triggered(); 87 | 88 | void on_actionThresh_triggered(); 89 | 90 | void on_actionSmooth_curv_triggered(); 91 | 92 | void on_actionSmooth_DCurv_triggered(); 93 | 94 | void on_actionSave_curv1_triggered(); 95 | 96 | void on_actionSave_Curv2_triggered(); 97 | 98 | void on_actionLaplace_Smooth_triggered(); 99 | 100 | void on_actionRidge_Valley_triggered(); 101 | 102 | private: 103 | Ui::MainWindow *ui; 104 | ThreshDialog *threshDialog; 105 | 106 | TriMeshView *meshView; 107 | }; 108 | 109 | #endif // MAINWINDOW_H 110 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | LineDrawing 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 0 22 | 800 23 | 23 24 | 25 | 26 | 27 | 28 | File 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Mesh 45 | 46 | 47 | 48 | 49 | 50 | Vector 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Lines 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Color 72 | 73 | 74 | 75 | 76 | 77 | 78 | Ridge-Valley 79 | 80 | 81 | 82 | 83 | 84 | 85 | Ocludding 86 | 87 | 88 | 89 | 90 | 91 | 92 | Thresh Control 93 | 94 | 95 | 96 | 97 | 98 | Improved Method 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | TestTime 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | Open 125 | 126 | 127 | 128 | 129 | true 130 | 131 | 132 | Edges 133 | 134 | 135 | 136 | 137 | true 138 | 139 | 140 | Normal 141 | 142 | 143 | 144 | 145 | true 146 | 147 | 148 | Principal 1 149 | 150 | 151 | 152 | 153 | true 154 | 155 | 156 | Principal 2 157 | 158 | 159 | 160 | 161 | true 162 | 163 | 164 | Norm Color 165 | 166 | 167 | 168 | 169 | true 170 | 171 | 172 | Curv Color 173 | 174 | 175 | 176 | 177 | true 178 | 179 | 180 | Boundaries 181 | 182 | 183 | 184 | 185 | true 186 | 187 | 188 | Preview 189 | 190 | 191 | 192 | 193 | true 194 | 195 | 196 | Exterior Silhouette 197 | 198 | 199 | 200 | 201 | true 202 | 203 | 204 | Occluding Contours 205 | 206 | 207 | 208 | 209 | true 210 | 211 | 212 | Suggestive Contours 213 | 214 | 215 | 216 | 217 | true 218 | 219 | 220 | Ridges 221 | 222 | 223 | 224 | 225 | true 226 | 227 | 228 | Valleys 229 | 230 | 231 | 232 | 233 | true 234 | 235 | 236 | Apparent Ridges 237 | 238 | 239 | 240 | 241 | Save Ridge-Valley file 242 | 243 | 244 | 245 | 246 | Save Occluding file 247 | 248 | 249 | 250 | 251 | true 252 | 253 | 254 | Lines 255 | 256 | 257 | 258 | 259 | true 260 | 261 | 262 | Faces 263 | 264 | 265 | 266 | 267 | true 268 | 269 | 270 | Lines 271 | 272 | 273 | 274 | 275 | true 276 | 277 | 278 | Faces 279 | 280 | 281 | 282 | 283 | Save RV mesh file 284 | 285 | 286 | 287 | 288 | Save OC mesh file 289 | 290 | 291 | 292 | 293 | Open LD file 294 | 295 | 296 | 297 | 298 | Thresh 299 | 300 | 301 | 302 | 303 | Our Method 304 | 305 | 306 | 307 | 308 | Smooth DCurv 309 | 310 | 311 | 312 | 313 | Save Curv1 314 | 315 | 316 | 317 | 318 | Save Curv2 319 | 320 | 321 | 322 | 323 | Laplace Smooth 324 | 325 | 326 | 327 | 328 | Ridge-Valley 329 | 330 | 331 | 332 | 333 | 334 | 335 | actionOpen 336 | triggered() 337 | MainWindow 338 | open() 339 | 340 | 341 | -1 342 | -1 343 | 344 | 345 | 399 346 | 299 347 | 348 | 349 | 350 | 351 | 352 | open() 353 | on_edges_trggered() 354 | setThresh() 355 | 356 | 357 | -------------------------------------------------------------------------------- /threshdialog.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #include "threshdialog.h" 18 | #include "ui_threshdialog.h" 19 | 20 | //ThreshDialog::ThreshDialog(QWidget *parent) : 21 | // QDialog(parent), 22 | // ui(new Ui::ThreshDialog) 23 | //{ 24 | // ui->setupUi(this); 25 | // this->setModal(false); 26 | 27 | // ui->ar_horizontalSlider->setRange(0, 1000); 28 | // ui->rv_horizontalSlider->setRange(0, 1000); 29 | // ui->sug_horizontalSlider->setRange(0, 1000); 30 | //} 31 | 32 | #define SLIDER_RANGE 1000 33 | 34 | ThreshDialog::ThreshDialog(TriMeshView *view, QWidget *parent) : 35 | QDialog(parent), 36 | ui(new Ui::ThreshDialog) 37 | { 38 | meshView = view; 39 | 40 | ui->setupUi(this); 41 | this->setModal(false); 42 | 43 | this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); 44 | 45 | ui->ar_horizontalSlider->setRange(0, SLIDER_RANGE); 46 | ui->rv_horizontalSlider->setRange(0, SLIDER_RANGE); 47 | ui->sug_horizontalSlider->setRange(0, SLIDER_RANGE); 48 | 49 | ui->ar_horizontalSlider->setValue((int) (meshView->getArThresh()*SLIDER_RANGE)/0.5); 50 | ui->rv_horizontalSlider->setValue((int) (meshView->getRvThresh()*SLIDER_RANGE)/0.5); 51 | ui->sug_horizontalSlider->setValue((int) (meshView->getSugThresh()*SLIDER_RANGE)/0.1); 52 | 53 | ui->ar_threshLabel->setText(QString("%1").arg(meshView->getArThresh())); 54 | ui->rv_threshLabel->setText(QString("%1").arg(meshView->getRvThresh())); 55 | ui->sug_threshLabel->setText(QString("%1").arg(meshView->getSugThresh())); 56 | } 57 | 58 | ThreshDialog::~ThreshDialog() 59 | { 60 | delete ui; 61 | } 62 | 63 | void ThreshDialog::on_sug_horizontalSlider_valueChanged(int value) 64 | { 65 | float sug = (0.1*value)/SLIDER_RANGE; 66 | meshView->setSugThresh(sug); 67 | meshView->update(); 68 | 69 | ui->sug_threshLabel->setText(QString("%1").arg(sug)); 70 | } 71 | 72 | void ThreshDialog::on_rv_horizontalSlider_valueChanged(int value) 73 | { 74 | float rv = (0.5*value)/SLIDER_RANGE; 75 | meshView->setRvThresh(rv); 76 | meshView->update(); 77 | 78 | ui->rv_threshLabel->setText(QString("%1").arg(rv)); 79 | } 80 | 81 | void ThreshDialog::on_ar_horizontalSlider_valueChanged(int value) 82 | { 83 | float ar = (0.5*value)/SLIDER_RANGE; 84 | meshView->setArThresh(ar); 85 | meshView->update(); 86 | 87 | ui->ar_threshLabel->setText(QString("%1").arg(ar)); 88 | } 89 | -------------------------------------------------------------------------------- /threshdialog.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | #ifndef THRESHDIALOG_H 18 | #define THRESHDIALOG_H 19 | 20 | #include "trimeshview.h" 21 | 22 | #include 23 | 24 | namespace Ui { 25 | class ThreshDialog; 26 | } 27 | 28 | class ThreshDialog : public QDialog 29 | { 30 | Q_OBJECT 31 | 32 | public: 33 | //explicit ThreshDialog(QWidget *parent = 0); 34 | ThreshDialog(TriMeshView *view, QWidget *parent = 0); 35 | ~ThreshDialog(); 36 | 37 | private slots: 38 | void on_sug_horizontalSlider_valueChanged(int value); 39 | 40 | void on_rv_horizontalSlider_valueChanged(int value); 41 | 42 | void on_ar_horizontalSlider_valueChanged(int value); 43 | 44 | private: 45 | TriMeshView *meshView; 46 | Ui::ThreshDialog *ui; 47 | }; 48 | 49 | #endif // THRESHDIALOG_H 50 | -------------------------------------------------------------------------------- /threshdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ThreshDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 445 10 | 327 11 | 12 | 13 | 14 | Thresh Dialog 15 | 16 | 17 | 18 | 19 | 70 20 | 20 21 | 311 22 | 81 23 | 24 | 25 | 26 | 27 | Calibri 28 | 12 29 | 50 30 | false 31 | false 32 | 33 | 34 | 35 | rv_thresh 36 | 37 | 38 | 39 | 40 | 20 41 | 40 42 | 261 43 | 21 44 | 45 | 46 | 47 | Qt::Horizontal 48 | 49 | 50 | 51 | 52 | 53 | 200 54 | 20 55 | 81 56 | 21 57 | 58 | 59 | 60 | 61 | Calibri 62 | 12 63 | 50 64 | false 65 | 66 | 67 | 68 | Qt::LeftToRight 69 | 70 | 71 | rv_thresh 72 | 73 | 74 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 75 | 76 | 77 | 78 | 79 | 80 | 81 | 70 82 | 120 83 | 311 84 | 81 85 | 86 | 87 | 88 | 89 | Calibri 90 | 12 91 | 50 92 | false 93 | false 94 | 95 | 96 | 97 | ar_thresh 98 | 99 | 100 | 101 | 102 | 20 103 | 40 104 | 261 105 | 19 106 | 107 | 108 | 109 | Qt::Horizontal 110 | 111 | 112 | 113 | 114 | 115 | 210 116 | 20 117 | 71 118 | 21 119 | 120 | 121 | 122 | 123 | Calibri 124 | 12 125 | 50 126 | false 127 | 128 | 129 | 130 | Qt::LeftToRight 131 | 132 | 133 | ar_thresh 134 | 135 | 136 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 137 | 138 | 139 | 140 | 141 | 142 | 143 | 70 144 | 220 145 | 311 146 | 81 147 | 148 | 149 | 150 | 151 | Calibri 152 | 12 153 | 50 154 | false 155 | false 156 | 157 | 158 | 159 | sug_thresh 160 | 161 | 162 | 163 | 164 | 20 165 | 40 166 | 261 167 | 19 168 | 169 | 170 | 171 | Qt::Horizontal 172 | 173 | 174 | 175 | 176 | 177 | 200 178 | 20 179 | 81 180 | 21 181 | 182 | 183 | 184 | 185 | Catriel 186 | 12 187 | 50 188 | false 189 | 190 | 191 | 192 | Qt::LeftToRight 193 | 194 | 195 | sug_thresh 196 | 197 | 198 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /trianglemesh.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------- 2 | # Copyright (c) 2014 Zhang Dongdong 3 | # All rights reserved. 4 | # email: zddhub@gmail.com 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | #------------------------------------------------------------------------- 18 | 19 | QT += core gui \ 20 | opengl 21 | 22 | CONFIG += console 23 | TARGET = gen_view_image 24 | TEMPLATE = app 25 | DESTDIR = ./bin 26 | 27 | macx : CONFIG -= app_bundle 28 | macx : QMAKE_MAC_SDK=macosx10.13 # Change this to your macOS version if you are using macOS 29 | 30 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 31 | 32 | INCLUDEPATH += $$PWD \ 33 | $$PWD/include 34 | 35 | SOURCES += main.cpp \ 36 | trimeshview.cpp \ 37 | trianglemesh/trianglemesh_io.cpp \ 38 | trianglemesh/trianglemesh_tstrips.cpp \ 39 | trianglemesh/trianglemesh_connectivity.cpp \ 40 | trianglemesh/trianglemesh_bounding.cpp \ 41 | trianglemesh/trianglemesh_normals.cpp \ 42 | trianglemesh/KDtree.cpp \ 43 | trianglemesh/GLCamera.cpp \ 44 | trianglemesh/trianglemesh_curvature.cpp \ 45 | trianglemesh/trianglemesh_pointareas.cpp \ 46 | trianglemesh/trianglemesh_stats.cpp \ 47 | mainwindow.cpp \ 48 | trimeshview_draw_base.cpp \ 49 | trimeshview_draw_lines.cpp \ 50 | trimeshview_draw_ridges_and_valleys.cpp \ 51 | trimeshview_draw_apparent_ridges.cpp \ 52 | featurelines.cpp \ 53 | threshdialog.cpp \ 54 | trianglemesh/diffuse.cpp 55 | 56 | HEADERS += \ 57 | trimeshview.h \ 58 | include/lineqn.h \ 59 | include/timestamp.h \ 60 | include/bsphere.h \ 61 | include/KDtree.h \ 62 | include/mempool.h \ 63 | include/Color.h \ 64 | mainwindow.h \ 65 | featurelines.h \ 66 | threshdialog.h \ 67 | include/meshalgo.h 68 | 69 | FORMS += \ 70 | mainwindow.ui \ 71 | threshdialog.ui 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /trianglemesh/GLCamera.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /* 18 | Szymon Rusinkiewicz 19 | Princeton University 20 | 21 | GLCamera.cc 22 | Manages OpenGL camera and trackball/arcball interaction 23 | */ 24 | 25 | #ifdef __APPLE__ 26 | #include 27 | #else 28 | #ifdef _WIN32 29 | #include 30 | #undef min 31 | #undef max 32 | #endif 33 | #include 34 | #endif 35 | 36 | #include "GLCamera.h" 37 | using namespace std; 38 | 39 | 40 | #ifndef M_PI 41 | # define M_PI 3.14159265358979323846 42 | #endif 43 | 44 | #define DOF 10.0f 45 | #define MAXDOF 10000.0f 46 | #define SPIN_TIME 0.1f 47 | #define SPIN_SPEED 0.05f 48 | #define TRACKBALL_R 0.8f 49 | #define DEPTH_FUDGE (1.0f + 0.2f * field_of_view) 50 | #define MOVEZ_MULT 5.0f 51 | #define WHEEL_MOVE 0.2f 52 | #define MAX_LIGHT (M_PI-0.001) 53 | 54 | 55 | // A few functions from GLU, for systems in which it's not included. 56 | // 57 | // (Specifically, Qt 4.8 no longer links to GLU, and just implementing 58 | // the functions we need is simpler than figuring out how to link GLU 59 | // in a way that's cross-platform.) 60 | // 61 | static inline GLint myGluProject(GLdouble objX, GLdouble objY, GLdouble objZ, 62 | const GLdouble *model, const GLdouble *proj, const GLint *view, 63 | GLdouble* winX, GLdouble* winY, GLdouble* winZ) 64 | { 65 | GLdouble x = model[0]*objX + model[4]*objY + model[8]*objZ + model[12]; 66 | GLdouble y = model[1]*objX + model[5]*objY + model[9]*objZ + model[13]; 67 | GLdouble z = model[2]*objX + model[6]*objY + model[10]*objZ + model[14]; 68 | GLdouble w = model[3]*objX + model[7]*objY + model[11]*objZ + model[15]; 69 | 70 | GLdouble W = proj[3]*x + proj[7]*y + proj[11]*z + proj[15]*w; 71 | if (W == 0.0) 72 | return GL_FALSE; 73 | GLdouble rW = 1.0 / W; 74 | 75 | GLdouble X = proj[0]*x + proj[4]*y + proj[8]*z + proj[12]*w; 76 | GLdouble Y = proj[1]*x + proj[5]*y + proj[9]*z + proj[13]*w; 77 | GLdouble Z = proj[2]*x + proj[6]*y + proj[10]*z + proj[14]*w; 78 | 79 | *winX = (0.5 + 0.5 * X * rW) * view[2] + view[0]; 80 | *winY = (0.5 + 0.5 * Y * rW) * view[3] + view[1]; 81 | *winZ = (0.5 + 0.5 * Z * rW); 82 | return GL_TRUE; 83 | } 84 | 85 | static inline GLint myGluUnProject(GLdouble winX, GLdouble winY, GLdouble winZ, 86 | const GLdouble *model, const GLdouble *proj, const GLint *view, 87 | GLdouble* objX, GLdouble* objY, GLdouble* objZ) 88 | { 89 | xform xf = inv(xform(proj) * xform(model)); 90 | vec v = xf * vec((winX - view[0]) / view[2] * 2.0 - 1.0, 91 | (winY - view[1]) / view[3] * 2.0 - 1.0, 92 | winZ * 2.0 - 1.0); 93 | *objX = v[0]; 94 | *objY = v[1]; 95 | *objZ = v[2]; 96 | return GL_TRUE; 97 | } 98 | 99 | 100 | // Read back the framebuffer at the given pixel, and determine 101 | // the 3D point there. If there's nothing there, reads back a 102 | // number of pixels farther and farther away. 103 | bool GLCamera::read_depth(int x, int y, point &p) const 104 | { 105 | GLdouble M[16], P[16]; GLint V[4]; 106 | glGetDoublev(GL_MODELVIEW_MATRIX, M); 107 | glGetDoublev(GL_PROJECTION_MATRIX, P); 108 | glGetIntegerv(GL_VIEWPORT, V); 109 | 110 | static const float dx[] = 111 | { 0, 1,-1,-1, 1, 3,-3, 0, 0, 6,-6,-6, 6, 25,-25, 0, 0 }; 112 | static const float dy[] = 113 | { 0, 1, 1,-1,-1, 0, 0, 3,-3, 6, 6,-6,-6, 0, 0, 25,-25 }; 114 | const float scale = 0.01f; 115 | const int displacements = sizeof(dx) / sizeof(float); 116 | 117 | int xmin = V[0], xmax = V[0]+V[2]-1, ymin = V[1], ymax = V[1]+V[3]-1; 118 | 119 | for (int i = 0 ; i < displacements; i++) { 120 | int xx = min(max(x + int(dx[i]*scale*V[2]), xmin), xmax); 121 | int yy = min(max(y + int(dy[i]*scale*V[3]), ymin), ymax); 122 | float d; 123 | glReadPixels(xx, yy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &d); 124 | 125 | static float maxd = 0.0f; 126 | if (!maxd) { 127 | glScissor(xx, yy, 1, 1); 128 | glEnable(GL_SCISSOR_TEST); 129 | glClearDepth(1); 130 | glClear(GL_DEPTH_BUFFER_BIT); 131 | glReadPixels(xx, yy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &maxd); 132 | if (maxd) { 133 | glClearDepth(d / maxd); 134 | glClear(GL_DEPTH_BUFFER_BIT); 135 | } 136 | glDisable(GL_SCISSOR_TEST); 137 | glClearDepth(1); 138 | if (!maxd) 139 | return false; 140 | } 141 | 142 | d /= maxd; 143 | if (d > 0.0001f && d < 0.9999f) { 144 | GLdouble X, Y, Z; 145 | myGluUnProject(xx, yy, d, M, P, V, &X, &Y, &Z); 146 | p = point((float)X, (float)Y, (float)Z); 147 | return true; 148 | } 149 | } 150 | return false; 151 | } 152 | 153 | 154 | // Mouse helper - decide whether to start auto-spin 155 | void GLCamera::startspin() 156 | { 157 | float dt = now() - last_time; 158 | if (dt < SPIN_TIME && fabs(spinspeed) > SPIN_SPEED) 159 | dospin = true; 160 | } 161 | 162 | 163 | // Mouse rotation helper - compute trackball position from mouse pos 164 | vec GLCamera::mouse2tb(float x, float y) 165 | { 166 | float r2 = x*x + y*y; 167 | float t = 0.5f * sqr(TRACKBALL_R); 168 | 169 | vec pos(x, y, 0); 170 | if (r2 < t) 171 | pos[2] = sqrt(2*t - r2); 172 | else 173 | pos[2] = t / sqrt(r2); 174 | return pos; 175 | } 176 | 177 | // Mouse helper - rotate 178 | void GLCamera::rotate(int mousex, int mousey, xform &xf) 179 | { 180 | float ox = (lastmousex - tb_screen_x) / tb_screen_size; 181 | float oy = (lastmousey - tb_screen_y) / tb_screen_size; 182 | float nx = ( mousex - tb_screen_x) / tb_screen_size; 183 | float ny = ( mousey - tb_screen_y) / tb_screen_size; 184 | 185 | vec pos1 = mouse2tb(ox, oy); 186 | vec pos2 = mouse2tb(nx, ny); 187 | if (constraint_ == XCONSTRAINED) pos1[1] = pos2[1] = 0.0f; 188 | if (constraint_ == YCONSTRAINED) pos1[0] = pos2[0] = 0.0f; 189 | if (constraint_ == ZCONSTRAINED) pos1[2] = pos2[2] = 0.0f; 190 | spinaxis = pos1 CROSS pos2; 191 | float spinamount = sqrt(sqr(nx-ox)+sqr(ny-oy)); 192 | 193 | xf = xform::trans(spincenter) * xform::rot(spinamount, spinaxis) * 194 | xform::trans(-spincenter) * xf; 195 | 196 | float dt = now() - last_time; 197 | if (dt > SPIN_TIME) 198 | spinspeed = spinamount / SPIN_TIME; 199 | else 200 | spinspeed = (spinamount / SPIN_TIME) + 201 | (1.0f-dt/SPIN_TIME)*spinspeed; 202 | } 203 | 204 | 205 | // Mouse helper - translate 206 | void GLCamera::movexy(int mousex, int mousey, xform &xf) 207 | { 208 | float dx = pixscale * click_depth * (mousex - lastmousex); 209 | float dy = pixscale * click_depth * (mousey - lastmousey); 210 | xf = xform::trans(dx, dy, 0) * xf; 211 | } 212 | 213 | 214 | // Mouse helper - translate in Z 215 | // In order to be extra-clever, though, this actually translates along the 216 | // direction of the center of the trackball 217 | void GLCamera::movez(int mousex, int mousey, xform &xf) 218 | { 219 | float delta = MOVEZ_MULT / field_of_view * pixscale * 220 | ((mousex-lastmousex) - (mousey-lastmousey)); 221 | float dz = click_depth * (exp(-delta) - 1.0f); 222 | //xf = xform::trans(0, 0, -dz) * xf; 223 | xf = xform::trans(dz * spincenter / len(spincenter)) * xf; 224 | 225 | surface_depth += dz; 226 | if (surface_depth < 0) 227 | surface_depth = 0; 228 | click_depth += dz; 229 | if (click_depth < 0) 230 | click_depth = 0; 231 | } 232 | 233 | 234 | // Mouse helper - wheel motion 235 | void GLCamera::wheel(Mouse::button updown, xform &xf) 236 | { 237 | float dz = click_depth * WHEEL_MOVE; 238 | if (updown == Mouse::WHEELDOWN) 239 | dz = -dz; 240 | //xf = xform::trans(0, 0, -dz) * xf; 241 | xf = xform::trans(dz * spincenter / len(spincenter)) * xf; 242 | 243 | surface_depth += dz; 244 | if (surface_depth < 0) 245 | surface_depth = 0; 246 | click_depth += dz; 247 | if (click_depth < 0) 248 | click_depth = 0; 249 | } 250 | 251 | 252 | // Mouse helper - change lighting direction 253 | void GLCamera::relight(int mousex, int mousey) 254 | { 255 | GLint V[4]; 256 | glGetIntegerv(GL_VIEWPORT, V); 257 | 258 | float x = 2.0f * float(mousex - V[0]) / float(V[2]) - 1.0f; 259 | float y = 2.0f * float(mousey - V[1]) / float(V[3]) - 1.0f; 260 | 261 | float theta = (float)MAX_LIGHT * min(sqrt(x*x+y*y), 1.0f); 262 | float phi = atan2(y, x); 263 | 264 | lightdir[0] = sin(theta)*cos(phi); 265 | lightdir[1] = sin(theta)*sin(phi); 266 | lightdir[2] = cos(theta); 267 | } 268 | 269 | 270 | // Handle a mouse click - sets up rotation center, pixscale, and click_depth 271 | void GLCamera::mouse_click(int mousex, int mousey, 272 | const point &scene_center, float scene_size) 273 | { 274 | GLdouble M[16], P[16]; GLint V[4]; 275 | #if 0 276 | glGetDoublev(GL_MODELVIEW_MATRIX, M); 277 | #else 278 | M[0] = M[5] = M[10] = M[15] = 1.0; 279 | M[1] = M[2] = M[3] = M[4] = 280 | M[6] = M[7] = M[8] = M[9] = 281 | M[11] = M[12] = M[13] = M[14] = 0; 282 | #endif 283 | glGetDoublev(GL_PROJECTION_MATRIX, P); 284 | glGetIntegerv(GL_VIEWPORT, V); 285 | 286 | // Assume glFrustum only... 287 | pixscale = 2.0f / float(max(P[0]*V[2], P[5]*V[3])); 288 | 289 | 290 | point surface_point; 291 | if (read_depth(mousex, mousey, surface_point)) 292 | click_depth = -surface_point[2]; 293 | else 294 | click_depth = surface_depth; 295 | 296 | 297 | GLdouble cx = 0.0, cy = 0.0, cz = 0.0; 298 | myGluProject(scene_center[0], scene_center[1], scene_center[2], 299 | M, P, V, 300 | &cx, &cy, &cz); 301 | 302 | double csize = max(V[2], V[3]); 303 | int xmin = V[0], xmax = V[0]+V[2], ymin = V[1], ymax = V[1]+V[3]; 304 | if (scene_center[2] < 0 && len(scene_center) > scene_size) { 305 | csize = -scene_size / scene_center[2] / pixscale; 306 | xmin = min(max((GLint) (cx - csize), V[0]), V[0]+V[2]); 307 | xmax = min(max((GLint) (cx + csize), V[0]), V[0]+V[2]); 308 | ymin = min(max((GLint) (cy - csize), V[1]), V[1]+V[3]); 309 | ymax = min(max((GLint) (cy + csize), V[1]), V[1]+V[3]); 310 | } 311 | 312 | GLdouble s[3]; 313 | myGluUnProject((xmin+xmax)/2, (ymin+ymax)/2, 1, 314 | M, P, V, 315 | &s[0], &s[1], &s[2]); 316 | spincenter = vec(s); 317 | normalize(spincenter); 318 | if (read_depth((xmin+xmax)/2, (ymin+ymax)/2, surface_point)) 319 | spincenter *= DEPTH_FUDGE * surface_point[2] / spincenter[2]; 320 | else 321 | spincenter *= -DEPTH_FUDGE * click_depth / spincenter[2]; 322 | 323 | float f = (float)csize / max(V[2], V[3]); 324 | f = min(max(2.0f * f - 1.0f, 0.0f), 1.0f); 325 | spincenter = f * spincenter + (1.0f - f) * scene_center; 326 | 327 | myGluProject(spincenter[0], spincenter[1], spincenter[2], 328 | M, P, V, 329 | &cx, &cy, &cz); 330 | tb_screen_x = (float)cx; 331 | tb_screen_y = (float)cy; 332 | tb_screen_size = (float)csize; 333 | tb_screen_size = min(tb_screen_size, 0.7f * min(V[2], V[3])); 334 | tb_screen_size = max(tb_screen_size, 0.3f * min(V[2], V[3])); 335 | } 336 | 337 | 338 | // Handle a mouse event 339 | void GLCamera::mouse(int mousex, int mousey, Mouse::button b, 340 | const point &scene_center, float scene_size, 341 | xform &xf) 342 | { 343 | if (b == Mouse::NONE && lastb == Mouse::NONE) 344 | return; 345 | 346 | GLint V[4]; 347 | glGetIntegerv(GL_VIEWPORT, V); 348 | mousey = V[1] + V[3] - 1 - mousey; 349 | 350 | dospin = false; 351 | if ((b != lastb) && (b != Mouse::NONE)) 352 | mouse_click(mousex, mousey, scene_center, scene_size); 353 | 354 | // Handle rotation 355 | if ((b == Mouse::ROTATE) && (lastb == Mouse::NONE)) 356 | spinspeed = 0; 357 | if ((b == Mouse::ROTATE) && (lastb == Mouse::ROTATE)) 358 | rotate(mousex, mousey, xf); 359 | if ((b == Mouse::NONE) && (lastb == Mouse::ROTATE)) 360 | startspin(); 361 | 362 | // Handle translation 363 | if ((b == Mouse::MOVEXY) && (lastb == Mouse::MOVEXY)) 364 | movexy(mousex, mousey, xf); 365 | if ((b == Mouse::MOVEZ) && (lastb == Mouse::MOVEZ)) 366 | movez(mousex, mousey, xf); 367 | if (b == Mouse::WHEELUP || b == Mouse::WHEELDOWN) 368 | wheel(b, xf); 369 | 370 | // Handle lighting 371 | if (b == Mouse::LIGHT) 372 | relight(mousex, mousey); 373 | 374 | 375 | lastmousex = mousex; lastmousey = mousey; lastb = b; 376 | last_time = now(); 377 | } 378 | 379 | 380 | // Idle loop - handles auto-rotate. Returns true iff auto-rotating 381 | bool GLCamera::autospin(xform &xf) 382 | { 383 | if (!dospin) 384 | return false; 385 | 386 | float dt = now() - last_time; 387 | float spinamount = spinspeed * dt; 388 | 389 | xf = xform::trans(spincenter) * xform::rot(spinamount, spinaxis) * 390 | xform::trans(-spincenter) * xf; 391 | 392 | last_time = now(); 393 | return true; 394 | } 395 | 396 | 397 | // Set up the OpenGL camera for rendering 398 | void GLCamera::setupGL(const point &scene_center, float scene_size) const 399 | { 400 | GLint V[4]; 401 | glGetIntegerv(GL_VIEWPORT, V); 402 | int width = V[2], height = V[3]; 403 | 404 | point surface_point; 405 | if (read_depth(width/2, height/2, surface_point)) 406 | surface_depth = -surface_point[2]; 407 | 408 | float fardist = max(-(scene_center[2] - scene_size), 409 | scene_size / DOF); 410 | float neardist = max(-(scene_center[2] + scene_size), 411 | scene_size / MAXDOF); 412 | surface_depth = min(surface_depth, fardist); 413 | surface_depth = max(surface_depth, neardist); 414 | surface_depth = max(surface_depth, fardist / MAXDOF); 415 | neardist = max(neardist, surface_depth / DOF); 416 | 417 | float diag = sqrt(float(sqr(width) + sqr(height))); 418 | float top = (float) height/diag * 0.5f*field_of_view * neardist; 419 | float bottom = -top; 420 | float right = (float) width/diag * 0.5f*field_of_view * neardist; 421 | float left = -right; 422 | 423 | glMatrixMode(GL_PROJECTION); 424 | glLoadIdentity(); 425 | glFrustum(left, right, bottom, top, neardist, fardist); 426 | 427 | glMatrixMode(GL_MODELVIEW); 428 | glLoadIdentity(); 429 | GLfloat light0_position[] = { lightdir[0], lightdir[1], lightdir[2], 0 }; 430 | GLfloat light1_position[] = { -lightdir[0], -lightdir[1], -lightdir[2], 0 }; 431 | GLfloat light2_position[] = { lightdir[2], 0, -lightdir[0], 0 }; 432 | GLfloat light3_position[] = { -lightdir[2], 0, lightdir[0], 0 }; 433 | GLfloat light4_position[] = { 0, lightdir[2], -lightdir[1], 0 }; 434 | GLfloat light5_position[] = { 0, -lightdir[2], lightdir[1], 0 }; 435 | glLightfv(GL_LIGHT0, GL_POSITION, light0_position); 436 | glLightfv(GL_LIGHT1, GL_POSITION, light1_position); 437 | glLightfv(GL_LIGHT2, GL_POSITION, light2_position); 438 | glLightfv(GL_LIGHT3, GL_POSITION, light3_position); 439 | glLightfv(GL_LIGHT4, GL_POSITION, light4_position); 440 | glLightfv(GL_LIGHT5, GL_POSITION, light5_position); 441 | } 442 | 443 | -------------------------------------------------------------------------------- /trianglemesh/KDtree.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /* 18 | Szymon Rusinkiewicz 19 | Princeton University 20 | 21 | KDtree.cc 22 | A K-D tree for points, with limited capabilities (find nearest point to 23 | a given point, or to a ray). 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "KDtree.h" 32 | #include "mempool.h" 33 | using namespace std; 34 | 35 | 36 | // Small utility fcns - including them keeps this file independent of Vec.h 37 | static inline float sqr(float x) 38 | { 39 | return x*x; 40 | } 41 | 42 | static inline float dist2(const float *x, const float *y) 43 | { 44 | return sqr(x[0]-y[0]) + sqr(x[1]-y[1]) + sqr(x[2]-y[2]); 45 | } 46 | 47 | static inline float dist2ray2(const float *x, const float *p, const float *d) 48 | { 49 | float xp0 = x[0]-p[0], xp1 = x[1]-p[1], xp2 = x[2]-p[2]; 50 | return sqr(xp0) + sqr(xp1) + sqr(xp2) - 51 | sqr(xp0*d[0] + xp1*d[1] + xp2*d[2]); 52 | } 53 | 54 | 55 | // A point together with a distance - default comparison is by "first", 56 | // i.e., distance 57 | typedef pair pt_with_d; 58 | 59 | 60 | // Class for nodes in the K-D tree 61 | class KDtree::Node { 62 | private: 63 | static PoolAlloc memPool; 64 | 65 | public: 66 | // A place to put all the stuff required while traversing the K-D 67 | // tree, so we don't have to pass tons of variables at each fcn call 68 | struct Traversal_Info { 69 | const float *p, *dir; 70 | const float *closest; 71 | float closest_d, closest_d2; 72 | const KDtree::CompatFunc *iscompat; 73 | size_t k; 74 | vector knn; 75 | }; 76 | 77 | enum { MAX_PTS_PER_NODE = 7 }; 78 | 79 | 80 | // The node itself 81 | 82 | int npts; // If this is 0, intermediate node. If nonzero, leaf. 83 | 84 | union { 85 | struct { 86 | float center[3]; 87 | float r; 88 | int splitaxis; 89 | Node *child1, *child2; 90 | } node; 91 | struct { 92 | const float *p[MAX_PTS_PER_NODE]; 93 | } leaf; 94 | }; 95 | 96 | Node(const float **pts, size_t n); 97 | ~Node(); 98 | 99 | void find_closest_to_pt(Traversal_Info &ti) const; 100 | void find_k_closest_to_pt(Traversal_Info &ti) const; 101 | void find_closest_to_ray(Traversal_Info &ti) const; 102 | 103 | void *operator new(size_t n) { return memPool.alloc(n); } 104 | void operator delete(void *p, size_t n) { memPool.free(p,n); } 105 | }; 106 | 107 | 108 | // Class static variable 109 | PoolAlloc KDtree::Node::memPool(sizeof(KDtree::Node)); 110 | 111 | 112 | // Create a KD tree from the points pointed to by the array pts 113 | KDtree::Node::Node(const float **pts, size_t n) 114 | { 115 | // Leaf nodes 116 | if (n <= MAX_PTS_PER_NODE) { 117 | npts = n; 118 | memcpy(leaf.p, pts, n * sizeof(float *)); 119 | return; 120 | } 121 | 122 | 123 | // Else, interior nodes 124 | npts = 0; 125 | 126 | // Find bbox 127 | float xmin = pts[0][0], xmax = pts[0][0]; 128 | float ymin = pts[0][1], ymax = pts[0][1]; 129 | float zmin = pts[0][2], zmax = pts[0][2]; 130 | for (size_t i = 1; i < n; i++) { 131 | if (pts[i][0] < xmin) xmin = pts[i][0]; 132 | if (pts[i][0] > xmax) xmax = pts[i][0]; 133 | if (pts[i][1] < ymin) ymin = pts[i][1]; 134 | if (pts[i][1] > ymax) ymax = pts[i][1]; 135 | if (pts[i][2] < zmin) zmin = pts[i][2]; 136 | if (pts[i][2] > zmax) zmax = pts[i][2]; 137 | } 138 | 139 | // Find node center and size 140 | node.center[0] = 0.5f * (xmin+xmax); 141 | node.center[1] = 0.5f * (ymin+ymax); 142 | node.center[2] = 0.5f * (zmin+zmax); 143 | float dx = xmax-xmin; 144 | float dy = ymax-ymin; 145 | float dz = zmax-zmin; 146 | node.r = 0.5f * sqrt(sqr(dx) + sqr(dy) + sqr(dz)); 147 | 148 | // Find longest axis 149 | node.splitaxis = 2; 150 | if (dx > dy) { 151 | if (dx > dz) 152 | node.splitaxis = 0; 153 | } else { 154 | if (dy > dz) 155 | node.splitaxis = 1; 156 | } 157 | 158 | // Partition 159 | const float splitval = node.center[node.splitaxis]; 160 | const float **left = pts, **right = pts + n - 1; 161 | while (1) { 162 | while ((*left)[node.splitaxis] < splitval) 163 | left++; 164 | while ((*right)[node.splitaxis] > splitval) 165 | right--; 166 | if (right < left) 167 | break; 168 | if ((*left)[node.splitaxis] == (*right)[node.splitaxis]) { 169 | // Several clustered equal points - ensure even split 170 | left += (right - left) / 2; 171 | break; 172 | } 173 | swap(*left, *right); 174 | left++; right--; 175 | } 176 | 177 | // Build subtrees 178 | node.child1 = new Node(pts, left-pts); 179 | node.child2 = new Node(left, n-(left-pts)); 180 | } 181 | 182 | 183 | // Destroy a KD tree node 184 | KDtree::Node::~Node() 185 | { 186 | if (!npts) { 187 | delete node.child1; 188 | delete node.child2; 189 | } 190 | } 191 | 192 | 193 | // Crawl the KD tree 194 | void KDtree::Node::find_closest_to_pt(KDtree::Node::Traversal_Info &ti) const 195 | { 196 | // Leaf nodes 197 | if (npts) { 198 | for (int i = 0; i < npts; i++) { 199 | float myd2 = dist2(leaf.p[i], ti.p); 200 | if ((myd2 < ti.closest_d2) && 201 | (!ti.iscompat || (*ti.iscompat)(leaf.p[i]))) { 202 | ti.closest_d2 = myd2; 203 | ti.closest_d = sqrt(ti.closest_d2); 204 | ti.closest = leaf.p[i]; 205 | } 206 | } 207 | return; 208 | } 209 | 210 | 211 | // Check whether to abort 212 | if (dist2(node.center, ti.p) >= sqr(node.r + ti.closest_d)) 213 | return; 214 | 215 | // Recursive case 216 | float myd = node.center[node.splitaxis] - ti.p[node.splitaxis]; 217 | if (myd >= 0.0f) { 218 | node.child1->find_closest_to_pt(ti); 219 | if (myd < ti.closest_d) 220 | node.child2->find_closest_to_pt(ti); 221 | } else { 222 | node.child2->find_closest_to_pt(ti); 223 | if (-myd < ti.closest_d) 224 | node.child1->find_closest_to_pt(ti); 225 | } 226 | } 227 | 228 | 229 | // Crawl the KD tree, retaining k closest points 230 | void KDtree::Node::find_k_closest_to_pt(KDtree::Node::Traversal_Info &ti) const 231 | { 232 | // Leaf nodes 233 | if (npts) { 234 | for (int i = 0; i < npts; i++) { 235 | float myd2 = dist2(leaf.p[i], ti.p); 236 | if ((myd2 < ti.closest_d2 || ti.knn.size() < ti.k) && 237 | (!ti.iscompat || (*ti.iscompat)(leaf.p[i]))) { 238 | float myd = sqrt(myd2); 239 | ti.knn.push_back(make_pair(myd, leaf.p[i])); 240 | push_heap(ti.knn.begin(), ti.knn.end()); 241 | if (ti.knn.size() > ti.k) { 242 | pop_heap(ti.knn.begin(), ti.knn.end()); 243 | ti.knn.pop_back(); 244 | } 245 | // Keep track of distance to k-th closest 246 | ti.closest_d = ti.knn[0].first; 247 | ti.closest_d2 = sqr(ti.closest_d); 248 | } 249 | } 250 | return; 251 | } 252 | 253 | 254 | // Check whether to abort 255 | if (dist2(node.center, ti.p) >= sqr(node.r + ti.closest_d) && 256 | ti.knn.size() == ti.k) 257 | return; 258 | 259 | // Recursive case 260 | float myd = node.center[node.splitaxis] - ti.p[node.splitaxis]; 261 | if (myd >= 0.0f) { 262 | node.child1->find_k_closest_to_pt(ti); 263 | if (myd < ti.closest_d || ti.knn.size() != ti.k) 264 | node.child2->find_k_closest_to_pt(ti); 265 | } else { 266 | node.child2->find_k_closest_to_pt(ti); 267 | if (-myd < ti.closest_d || ti.knn.size() != ti.k) 268 | node.child1->find_k_closest_to_pt(ti); 269 | } 270 | } 271 | 272 | 273 | // Crawl the KD tree to look for the closest point to 274 | // the line going through ti.p in the direction ti.dir 275 | void KDtree::Node::find_closest_to_ray(KDtree::Node::Traversal_Info &ti) const 276 | { 277 | // Leaf nodes 278 | if (npts) { 279 | for (int i = 0; i < npts; i++) { 280 | float myd2 = dist2ray2(leaf.p[i], ti.p, ti.dir); 281 | if ((myd2 < ti.closest_d2) && 282 | (!ti.iscompat || (*ti.iscompat)(leaf.p[i]))) { 283 | ti.closest_d2 = myd2; 284 | ti.closest_d = sqrt(ti.closest_d2); 285 | ti.closest = leaf.p[i]; 286 | } 287 | } 288 | return; 289 | } 290 | 291 | 292 | // Check whether to abort 293 | if (dist2ray2(node.center, ti.p, ti.dir) >= sqr(node.r + ti.closest_d)) 294 | return; 295 | 296 | // Recursive case 297 | if (ti.p[node.splitaxis] < node.center[node.splitaxis] ) { 298 | node.child1->find_closest_to_ray(ti); 299 | node.child2->find_closest_to_ray(ti); 300 | } else { 301 | node.child2->find_closest_to_ray(ti); 302 | node.child1->find_closest_to_ray(ti); 303 | } 304 | } 305 | 306 | 307 | // Create a KDtree from a list of points (i.e., ptlist is a list of 3*n floats) 308 | void KDtree::build(const float *ptlist, size_t n) 309 | { 310 | vector pts(n); 311 | for (size_t i = 0; i < n; i++) 312 | pts[i] = ptlist + i * 3; 313 | 314 | root = new Node(&(pts[0]), n); 315 | } 316 | 317 | 318 | // Delete a KDtree 319 | KDtree::~KDtree() 320 | { 321 | delete root; 322 | } 323 | 324 | 325 | // Return the closest point in the KD tree to p 326 | const float *KDtree::closest_to_pt(const float *p, float maxdist2 /* = 0.0f */, 327 | const CompatFunc *iscompat /* = NULL */) const 328 | { 329 | Node::Traversal_Info ti; 330 | 331 | ti.p = p; 332 | ti.iscompat = iscompat; 333 | ti.closest = NULL; 334 | if (maxdist2 <= 0.0f) 335 | maxdist2 = sqr(root->node.r); 336 | ti.closest_d2 = maxdist2; 337 | ti.closest_d = sqrt(ti.closest_d2); 338 | 339 | root->find_closest_to_pt(ti); 340 | 341 | return ti.closest; 342 | } 343 | 344 | 345 | // Return the closest point in the KD tree to the line 346 | // going through p in the direction dir 347 | const float *KDtree::closest_to_ray(const float *p, const float *dir, 348 | float maxdist2 /* = 0.0f */, 349 | const CompatFunc *iscompat /* = NULL */) const 350 | { 351 | Node::Traversal_Info ti; 352 | 353 | float one_over_dir_len = 1.0f / sqrt(sqr(dir[0])+sqr(dir[1])+sqr(dir[2])); 354 | float normalized_dir[3] = { dir[0] * one_over_dir_len, 355 | dir[1] * one_over_dir_len, 356 | dir[2] * one_over_dir_len }; 357 | ti.dir = normalized_dir; 358 | ti.p = p; 359 | ti.iscompat = iscompat; 360 | ti.closest = NULL; 361 | if (maxdist2 <= 0.0f) 362 | maxdist2 = sqr(root->node.r); 363 | ti.closest_d2 = maxdist2; 364 | ti.closest_d = sqrt(ti.closest_d2); 365 | 366 | root->find_closest_to_ray(ti); 367 | 368 | return ti.closest; 369 | } 370 | 371 | 372 | // Find the k nearest neighbors 373 | void KDtree::find_k_closest_to_pt(std::vector &knn, 374 | int k, 375 | const float *p, 376 | float maxdist2 /* = 0.0f */, 377 | const CompatFunc *iscompat /* = NULL */) const 378 | { 379 | Node::Traversal_Info ti; 380 | 381 | ti.p = p; 382 | ti.iscompat = iscompat; 383 | ti.closest = NULL; 384 | if (maxdist2 <= 0.0f) 385 | maxdist2 = sqr(root->node.r); 386 | ti.closest_d2 = maxdist2; 387 | ti.closest_d = sqrt(ti.closest_d2); 388 | ti.k = k; 389 | ti.knn.reserve(k+1); 390 | 391 | root->find_k_closest_to_pt(ti); 392 | 393 | size_t found = ti.knn.size(); 394 | if (!found) { 395 | knn.clear(); 396 | return; 397 | } 398 | 399 | knn.resize(found); 400 | sort_heap(ti.knn.begin(), ti.knn.end()); 401 | for (size_t i = 0; i < found; i++) 402 | knn[i] = ti.knn[i].second; 403 | } 404 | 405 | -------------------------------------------------------------------------------- /trianglemesh/diffuse.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /* 18 | Szymon Rusinkiewicz 19 | Princeton University 20 | 21 | diffuse.cc 22 | Smoothing of meshes and per-vertex fields 23 | */ 24 | 25 | #include "trianglemesh.h" 26 | #include "meshalgo.h" 27 | #include "timestamp.h" 28 | #include 29 | using namespace std; 30 | #define dprintf TriangleMesh::dprintf 31 | 32 | 33 | // Per-thread flags to keep track of the progress of the BFS 34 | static unsigned *flags = 0; 35 | static unsigned flags_size = 0, flag_curr = 0; 36 | #pragma omp threadprivate(flags, flags_size, flag_curr) 37 | 38 | 39 | // Approximation to Gaussian... Used in filtering 40 | static inline float wt(const point &p1, const point &p2, float invsigma2) 41 | { 42 | float d2 = invsigma2 * dist2(p1, p2); 43 | return (d2 >= 9.0f) ? 0.0f : exp(-0.5f*d2); 44 | //return (d2 >= 25.0f) ? 0.0f : exp(-0.5f*d2); 45 | } 46 | static inline float wt(const TriangleMesh *themesh, int v1, int v2, float invsigma2) 47 | { 48 | return wt(themesh->vertices[v1], themesh->vertices[v2], invsigma2); 49 | } 50 | 51 | // Approximation to Gaussian Laplace ... Used in filtering 52 | static inline float zdd_wt(const point &p1, const point &p2, float invsigma2, float laplace) 53 | { 54 | float d2 = invsigma2 * dist2(p1, p2); 55 | return (d2 >= 25.0f) ? 0.0f : laplace*exp(-0.5f*d2); 56 | //return (d2 >= 9.0f) ? 0.0f : laplace * exp(-0.5f*d2); 57 | //return (d2 >= 25.0f) ? 0.0f : exp(-0.5f*d2); 58 | } 59 | 60 | static inline float zdd_wt(const TriangleMesh *themesh, int v1, int v2, float invsigma2, float laplace) 61 | { 62 | return zdd_wt(themesh->vertices[v1], themesh->vertices[v2], invsigma2, laplace); 63 | } 64 | 65 | // Functor classes for adding scalar, vector, or tensor fields on the surface 66 | template 67 | struct AccumVec { 68 | const vector &field; 69 | AccumVec(const vector &field_) : field(field_) 70 | {} 71 | void operator() (const TriangleMesh *, int /* v0 */, T &f, 72 | float w, int v) const 73 | { 74 | f += w * field[v]; 75 | } 76 | }; 77 | 78 | struct AccumCurv { 79 | void operator() (const TriangleMesh *themesh, int v0, vec &c, 80 | float w, int v) const 81 | { 82 | vec ncurv; 83 | proj_curv(themesh->pdir1[v], themesh->pdir2[v], 84 | themesh->curv1[v], 0, themesh->curv2[v], 85 | themesh->pdir1[v0], themesh->pdir2[v0], 86 | ncurv[0], ncurv[1], ncurv[2]); 87 | c += w * ncurv; 88 | } 89 | }; 90 | 91 | struct AccumDCurv { 92 | void operator() (const TriangleMesh *themesh, int v0, Vec<4> &d, 93 | float w, int v) const 94 | { 95 | Vec<4> ndcurv; 96 | proj_dcurv(themesh->pdir1[v], themesh->pdir2[v], 97 | themesh->dcurv[v], 98 | themesh->pdir1[v0], themesh->pdir2[v0], 99 | ndcurv); 100 | d += w * ndcurv; 101 | } 102 | }; 103 | 104 | 105 | // Diffuse a vector field at 1 vertex, weighted by 106 | // a Gaussian of width 1/sqrt(invsigma2) 107 | template 108 | static void zdd_diffuse_vert_field(TriangleMesh *themesh, 109 | const ACCUM &accum, int v, float invsigma2, 110 | T &flt, float sigma2) 111 | { 112 | if (themesh->neighbors[v].empty()) { 113 | flt = T(); 114 | accum(themesh, v, flt, 1.0f, v); 115 | return; 116 | } 117 | 118 | flt = T(); 119 | 120 | accum(themesh, v, flt, themesh->pointareas[v], v); 121 | float sum_w = themesh->pointareas[v]; 122 | const vec &nv = themesh->normals[v]; 123 | 124 | unsigned nvert = themesh->vertices.size(); 125 | if (flags_size != nvert) { 126 | if (flags_size) 127 | delete [] flags; 128 | flags_size = nvert; 129 | flags = new unsigned[flags_size]; 130 | memset(flags, 0, flags_size * sizeof(unsigned)); 131 | flag_curr = 0; 132 | } 133 | flag_curr++; 134 | flags[v] = flag_curr; 135 | vector boundary = themesh->neighbors[v]; 136 | while (!boundary.empty()) { 137 | int n = boundary.back(); 138 | boundary.pop_back(); 139 | if (flags[n] == flag_curr) 140 | continue; 141 | flags[n] = flag_curr; 142 | if ((nv DOT themesh->normals[n]) <= 0.0f) 143 | continue; 144 | 145 | vec delta = themesh->vertices[v] - themesh->vertices[n]; 146 | normalize(delta); 147 | float laplace = len2(delta)*sigma2; 148 | // Gaussian weight 149 | float w = zdd_wt(themesh, n, v, invsigma2, laplace); 150 | if (w == 0.0f) 151 | continue; 152 | // Downweight things pointing in different directions 153 | w *= nv DOT themesh->normals[n]; 154 | // Surface area "belonging" to each point 155 | w *= themesh->pointareas[n]; 156 | // Accumulate weight times field at neighbor 157 | accum(themesh, v, flt, w, n); 158 | sum_w += w; 159 | for (int i = 0; i < themesh->neighbors[n].size(); i++) { 160 | int nn = themesh->neighbors[n][i]; 161 | if (flags[nn] == flag_curr) 162 | continue; 163 | boundary.push_back(nn); 164 | } 165 | } 166 | flt /= sum_w; 167 | } 168 | 169 | // Diffuse a vector field at 1 vertex, weighted by 170 | // a Gaussian of width 1/sqrt(invsigma2) 171 | template 172 | static void diffuse_vert_field(TriangleMesh *themesh, 173 | const ACCUM &accum, int v, float invsigma2, 174 | T &flt) 175 | { 176 | if (themesh->neighbors[v].empty()) { 177 | flt = T(); 178 | accum(themesh, v, flt, 1.0f, v); 179 | return; 180 | } 181 | 182 | flt = T(); 183 | accum(themesh, v, flt, themesh->pointareas[v], v); 184 | float sum_w = themesh->pointareas[v]; 185 | const vec &nv = themesh->normals[v]; 186 | 187 | unsigned nvert = themesh->vertices.size(); 188 | if (flags_size != nvert) { 189 | if (flags_size) 190 | delete [] flags; 191 | flags_size = nvert; 192 | flags = new unsigned[flags_size]; 193 | memset(flags, 0, flags_size * sizeof(unsigned)); 194 | flag_curr = 0; 195 | } 196 | flag_curr++; 197 | flags[v] = flag_curr; 198 | vector boundary = themesh->neighbors[v]; 199 | while (!boundary.empty()) { 200 | int n = boundary.back(); 201 | boundary.pop_back(); 202 | if (flags[n] == flag_curr) 203 | continue; 204 | flags[n] = flag_curr; 205 | if ((nv DOT themesh->normals[n]) <= 0.0f) 206 | continue; 207 | // Gaussian weight 208 | float w = wt(themesh, n, v, invsigma2); 209 | if (w == 0.0f) 210 | continue; 211 | // Downweight things pointing in different directions 212 | w *= nv DOT themesh->normals[n]; 213 | // Surface area "belonging" to each point 214 | w *= themesh->pointareas[n]; 215 | // Accumulate weight times field at neighbor 216 | accum(themesh, v, flt, w, n); 217 | sum_w += w; 218 | for (int i = 0; i < themesh->neighbors[n].size(); i++) { 219 | int nn = themesh->neighbors[n][i]; 220 | if (flags[nn] == flag_curr) 221 | continue; 222 | boundary.push_back(nn); 223 | } 224 | } 225 | flt /= sum_w; 226 | } 227 | 228 | 229 | // Smooth the mesh geometry. 230 | // XXX - this is perhaps not a great way to do this, 231 | // but it seems to work better than most other things I've tried... 232 | void smooth_mesh(TriangleMesh *themesh, float sigma) 233 | { 234 | themesh->need_faces(); 235 | diffuse_normals(themesh, 0.5f * sigma); 236 | int nv = themesh->vertices.size(); 237 | 238 | dprintf("\rSmoothing... "); 239 | timestamp t = now(); 240 | 241 | float invsigma2 = 1.0f / sqr(sigma); 242 | 243 | vector dflt(nv); 244 | #pragma omp parallel for 245 | for (int i = 0; i < nv; i++) { 246 | diffuse_vert_field(themesh, AccumVec(themesh->vertices), 247 | i, invsigma2, dflt[i]); 248 | // Just keep the displacement 249 | dflt[i] -= themesh->vertices[i]; 250 | } 251 | 252 | // Slightly better small-neighborhood approximation 253 | int nf = themesh->faces.size(); 254 | #pragma omp parallel for 255 | for (int i = 0; i < nf; i++) { 256 | point c = themesh->vertices[themesh->faces[i][0]] + 257 | themesh->vertices[themesh->faces[i][1]] + 258 | themesh->vertices[themesh->faces[i][2]]; 259 | c /= 3.0f; 260 | for (int j = 0; j < 3; j++) { 261 | int v = themesh->faces[i][j]; 262 | vec d = 0.5f * (c - themesh->vertices[v]); 263 | dflt[v] += themesh->cornerareas[i][j] / 264 | themesh->pointareas[themesh->faces[i][j]] * 265 | exp(-0.5f * invsigma2 * len2(d)) * d; 266 | } 267 | } 268 | 269 | // Filter displacement field 270 | vector dflt2(nv); 271 | #pragma omp parallel for 272 | for (int i = 0; i < nv; i++) { 273 | diffuse_vert_field(themesh, AccumVec(dflt), 274 | i, invsigma2, dflt2[i]); 275 | } 276 | 277 | // Update vertex positions 278 | #pragma omp parallel for 279 | for (int i = 0; i < nv; i++) 280 | themesh->vertices[i] += dflt[i] - dflt2[i]; // second Laplacian 281 | 282 | dprintf("Done. Filtering took %f sec.\n", now() - t); 283 | } 284 | 285 | 286 | // Filter a vertex using the method of [Jones et al. 2003] 287 | // For pass 1, do simple smoothing and write to mpoints 288 | // For pass 2, do bilateral, using mpoints, and write to themesh->vertices 289 | static void jones_filter(TriangleMesh *themesh, int v, 290 | float invsigma2_1, float invsigma2_2, bool pass1, 291 | vector &mpoints) 292 | { 293 | const point &p = pass1 ? themesh->vertices[v] : mpoints[v]; 294 | point &flt = pass1 ? mpoints[v] : themesh->vertices[v]; 295 | 296 | flt = point(); 297 | float sum_w = 0.0f; 298 | 299 | unsigned nfaces = themesh->faces.size(); 300 | if (flags_size != nfaces) { 301 | if (flags_size) 302 | delete [] flags; 303 | flags_size = nfaces; 304 | flags = new unsigned[flags_size]; 305 | memset(flags, 0, flags_size * sizeof(unsigned)); 306 | flag_curr = 0; 307 | } 308 | flag_curr++; 309 | vector boundary = themesh->adjacentfaces[v]; 310 | while (!boundary.empty()) { 311 | int f = boundary.back(); 312 | boundary.pop_back(); 313 | if (flags[f] == flag_curr) 314 | continue; 315 | flags[f] = flag_curr; 316 | 317 | int v0 = themesh->faces[f][0]; 318 | int v1 = themesh->faces[f][1]; 319 | int v2 = themesh->faces[f][2]; 320 | const point &p0 = themesh->vertices[v0]; 321 | const point &p1 = themesh->vertices[v1]; 322 | const point &p2 = themesh->vertices[v2]; 323 | point c = (p0 + p1 + p2) * (1.0f / 3.0f); 324 | 325 | float w = wt(p, c, invsigma2_1); 326 | if (w == 0.0f) 327 | continue; 328 | w *= len(trinorm(p0, p1, p2)); 329 | 330 | if (pass1) { 331 | flt += w * c; 332 | sum_w += w; 333 | } else { 334 | vec fn = trinorm(mpoints[v0], mpoints[v1], mpoints[v2]); 335 | normalize(fn); 336 | point prediction = p - fn * ((p - c) DOT fn); 337 | w *= wt(p, prediction, invsigma2_2); 338 | if (w == 0.0f) 339 | continue; 340 | flt += w * prediction; 341 | sum_w += w; 342 | } 343 | 344 | for (int i = 0; i < 3; i++) { 345 | int ae = themesh->across_edge[f][i]; 346 | if (ae < 0 || flags[ae] == flag_curr) 347 | continue; 348 | boundary.push_back(ae); 349 | } 350 | } 351 | if (sum_w == 0.0f) 352 | flt = p; 353 | else 354 | flt *= 1.0f / sum_w; 355 | } 356 | 357 | 358 | // Bilateral smoothing using the method of [Jones et al. 2003] 359 | void bilateral_smooth_mesh(TriangleMesh *themesh, float sigma1, float sigma2) 360 | { 361 | themesh->need_faces(); 362 | themesh->need_adjacentfaces(); 363 | themesh->need_across_edge(); 364 | int nv = themesh->vertices.size(), nf = themesh->faces.size(); 365 | 366 | dprintf("\rSmoothing... "); 367 | timestamp t = now(); 368 | 369 | float sigma3 = 0.5f * sigma1; 370 | float invsigma2_1 = 1.0f / sqr(sigma1); 371 | float invsigma2_2 = 1.0f / sqr(sigma2); 372 | float invsigma2_3 = 1.0f / sqr(sigma3); 373 | 374 | // Pass I: mollification 375 | vector mpoints(nv); 376 | #pragma omp parallel for 377 | for (int i = 0; i < nv; i++) 378 | jones_filter(themesh, i, invsigma2_3, 0.0f, true, mpoints); 379 | 380 | // Pass II: bilateral 381 | #pragma omp parallel for 382 | for (int i = 0; i < nv; i++) 383 | jones_filter(themesh, i, invsigma2_1, invsigma2_2, false, mpoints); 384 | 385 | dprintf("Done. Filtering took %f sec.\n", now() - t); 386 | } 387 | 388 | 389 | // Diffuse an arbitrary per-vertex vector field 390 | template 391 | void diffuse_vector(TriangleMesh *themesh, std::vector &field, float sigma) 392 | { 393 | themesh->need_normals(); 394 | themesh->need_pointareas(); 395 | themesh->need_neighbors(); 396 | int nv = themesh->vertices.size(); 397 | 398 | dprintf("\rSmoothing vector field... "); 399 | timestamp t = now(); 400 | 401 | float invsigma2 = 1.0f / sqr(sigma); 402 | 403 | vector flt(nv); 404 | AccumVec a(field); 405 | #pragma omp parallel for 406 | for (int i = 0; i < nv; i++) 407 | diffuse_vert_field(themesh, a, i, invsigma2, flt[i]); 408 | 409 | field = flt; 410 | 411 | dprintf("Done. Filtering took %f sec.\n", now() - t); 412 | } 413 | 414 | 415 | // Diffuse the normals across the mesh 416 | void diffuse_normals(TriangleMesh *themesh, float sigma) 417 | { 418 | themesh->need_normals(); 419 | themesh->need_pointareas(); 420 | themesh->need_neighbors(); 421 | int nv = themesh->vertices.size(); 422 | 423 | dprintf("\rSmoothing normals... "); 424 | timestamp t = now(); 425 | 426 | float invsigma2 = 1.0f / sqr(sigma); 427 | 428 | vector nflt(nv); 429 | AccumVec a(themesh->normals); 430 | #pragma omp parallel for 431 | for (int i = 0; i < nv; i++) { 432 | diffuse_vert_field(themesh, a, i, invsigma2, nflt[i]); 433 | normalize(nflt[i]); 434 | } 435 | 436 | themesh->normals = nflt; 437 | 438 | dprintf("Done. Filtering took %f sec.\n", now() - t); 439 | } 440 | 441 | // Diffuse the curvatures across the mesh 442 | void zdd_diffuse_curv(TriangleMesh *themesh, float sigma) 443 | { 444 | themesh->need_normals(); 445 | themesh->need_pointareas(); 446 | themesh->need_curvatures(); 447 | themesh->need_neighbors(); 448 | int nv = themesh->vertices.size(); 449 | 450 | dprintf("\rSmoothing curvatures... "); 451 | timestamp t = now(); 452 | 453 | float invsigma2 = 1.0f / sqr(sigma); 454 | 455 | float sigma2 = sqr(sigma); 456 | 457 | vector cflt(nv); 458 | #pragma omp parallel for 459 | for (int i = 0; i < nv; i++) 460 | zdd_diffuse_vert_field(themesh, AccumCurv(), i, invsigma2, cflt[i], sigma2); 461 | #pragma omp parallel for 462 | for (int i = 0; i < nv; i++) 463 | diagonalize_curv(themesh->pdir1[i], themesh->pdir2[i], 464 | cflt[i][0], cflt[i][1], cflt[i][2], 465 | themesh->normals[i], 466 | themesh->pdir1[i], themesh->pdir2[i], 467 | themesh->curv1[i], themesh->curv2[i]); 468 | 469 | dprintf("Done. Filtering took %f sec.\n", now() - t); 470 | } 471 | 472 | // Diffuse the curvatures across the mesh 473 | void diffuse_curv(TriangleMesh *themesh, float sigma) 474 | { 475 | themesh->need_normals(); 476 | themesh->need_pointareas(); 477 | themesh->need_curvatures(); 478 | themesh->need_neighbors(); 479 | int nv = themesh->vertices.size(); 480 | 481 | dprintf("\rSmoothing curvatures... "); 482 | timestamp t = now(); 483 | 484 | float invsigma2 = 1.0f / sqr(sigma); 485 | 486 | vector cflt(nv); 487 | #pragma omp parallel for 488 | for (int i = 0; i < nv; i++) 489 | diffuse_vert_field(themesh, AccumCurv(), i, invsigma2, cflt[i]); 490 | #pragma omp parallel for 491 | for (int i = 0; i < nv; i++) 492 | diagonalize_curv(themesh->pdir1[i], themesh->pdir2[i], 493 | cflt[i][0], cflt[i][1], cflt[i][2], 494 | themesh->normals[i], 495 | themesh->pdir1[i], themesh->pdir2[i], 496 | themesh->curv1[i], themesh->curv2[i]); 497 | 498 | dprintf("Done. Filtering took %f sec.\n", now() - t); 499 | } 500 | 501 | 502 | // Diffuse the curvature derivatives across the mesh 503 | void diffuse_dcurv(TriangleMesh *themesh, float sigma) 504 | { 505 | themesh->need_normals(); 506 | themesh->need_pointareas(); 507 | themesh->need_curvatures(); 508 | themesh->need_dcurv(); 509 | themesh->need_neighbors(); 510 | int nv = themesh->vertices.size(); 511 | 512 | dprintf("\rSmoothing curvature derivatives... "); 513 | timestamp t = now(); 514 | 515 | float invsigma2 = 1.0f / sqr(sigma); 516 | 517 | vector< Vec<4> > dflt(nv); 518 | #pragma omp parallel for 519 | for (int i = 0; i < nv; i++) 520 | diffuse_vert_field(themesh, AccumDCurv(), i, invsigma2, dflt[i]); 521 | 522 | themesh->dcurv = dflt; 523 | dprintf("Done. Filtering took %f sec.\n", now() - t); 524 | } 525 | 526 | 527 | // Instantiate a bunch of diffuse_vector forms 528 | template void diffuse_vector< float >(TriangleMesh *, vector< float > &, float); 529 | template void diffuse_vector< Vec<2,float> >(TriangleMesh *, vector< Vec<2,float> > &, float); 530 | template void diffuse_vector< Vec<3,float> >(TriangleMesh *, vector< Vec<3,float> > &, float); 531 | template void diffuse_vector< Vec<4,float> >(TriangleMesh *, vector< Vec<4,float> > &, float); 532 | -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_bounding.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | 18 | #include "trianglemesh.h" 19 | #include "bsphere.h" 20 | using namespace std; 21 | 22 | 23 | 24 | //use the Miniball code 25 | 26 | 27 | // Compute bounding sphere of the vertices. 28 | void TriangleMesh::need_bsphere() 29 | { 30 | if (vertices.empty() || bsphere.valid) 31 | return; 32 | 33 | dprintf("Computing bounding sphere... "); 34 | 35 | Miniball<3,float> mb; 36 | mb.check_in(vertices.begin(), vertices.end()); 37 | mb.build(); 38 | bsphere.center = mb.center(); 39 | bsphere.r = sqrt(mb.squared_radius()); 40 | bsphere.valid = true; 41 | 42 | dprintf("Done.\n center = (%g, %g, %g), radius = %g\n", 43 | bsphere.center[0], bsphere.center[1], 44 | bsphere.center[2], bsphere.r); 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_connectivity.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trianglemesh/trianglemesh_connectivity.cpp -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_curvature.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trianglemesh/trianglemesh_curvature.cpp -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_io.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trianglemesh/trianglemesh_io.cpp -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_normals.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /* 18 | Szymon Rusinkiewicz 19 | Princeton University 20 | 21 | TriMesh_normals.cc 22 | Compute per-vertex normals for TriMeshes 23 | 24 | For meshes, uses average of per-face normals, weighted according to: 25 | Max, N. 26 | "Weights for Computing Vertex Normals from Facet Normals," 27 | Journal of Graphics Tools, Vol. 4, No. 2, 1999. 28 | 29 | For raw point clouds, fits plane to k nearest neighbors. 30 | */ 31 | 32 | 33 | #include "trianglemesh.h" 34 | #include "KDtree.h" 35 | #include "lineqn.h" 36 | using namespace std; 37 | 38 | 39 | void TriangleMesh::need_normals() 40 | { 41 | // Nothing to do if we already have normals 42 | int nv = vertices.size(); 43 | if (int(normals.size()) == nv) 44 | return; 45 | 46 | dprintf("Computing normals... "); 47 | normals.clear(); 48 | normals.resize(nv); 49 | 50 | // TODO: direct handling of grids 51 | if (!tstrips.empty()) { 52 | // Compute from tstrips 53 | const int *t = &tstrips[0], *end = t + tstrips.size(); 54 | while (likely(t < end)) { 55 | int striplen = *t - 2; 56 | t += 3; 57 | bool flip = false; 58 | for (int i = 0; i < striplen; i++, t++, flip = !flip) { 59 | const point &p0 = vertices[*(t-2)]; 60 | const point &p1 = vertices[*(t-1)]; 61 | const point &p2 = vertices[* t ]; 62 | vec a = p0-p1, b = p1-p2, c = p2-p0; 63 | float l2a = len2(a), l2b = len2(b), l2c = len2(c); 64 | vec facenormal = flip ? (b CROSS a) : (a CROSS b); 65 | normals[*(t-2)] += facenormal * (1.0f / (l2a * l2c)); 66 | normals[*(t-1)] += facenormal * (1.0f / (l2b * l2a)); 67 | normals[* t ] += facenormal * (1.0f / (l2c * l2b)); 68 | } 69 | } 70 | } else if (need_faces(), !faces.empty()) { 71 | // Compute from faces 72 | int nf = faces.size(); 73 | #pragma omp parallel for 74 | for (int i = 0; i < nf; i++) { 75 | const point &p0 = vertices[faces[i][0]]; 76 | const point &p1 = vertices[faces[i][1]]; 77 | const point &p2 = vertices[faces[i][2]]; 78 | vec a = p0-p1, b = p1-p2, c = p2-p0; 79 | float l2a = len2(a), l2b = len2(b), l2c = len2(c); 80 | vec facenormal = a CROSS b; 81 | normals[faces[i][0]] += facenormal * (1.0f / (l2a * l2c)); 82 | normals[faces[i][1]] += facenormal * (1.0f / (l2b * l2a)); 83 | normals[faces[i][2]] += facenormal * (1.0f / (l2c * l2b)); 84 | } 85 | } else { 86 | // Find normals of a point cloud 87 | const int k = 6; 88 | const vec ref(0, 0, 1); 89 | KDtree kd(vertices); 90 | #pragma omp parallel for 91 | for (int i = 0; i < nv; i++) { 92 | vector knn; 93 | kd.find_k_closest_to_pt(knn, k, vertices[i]); 94 | int actual_k = knn.size(); 95 | if (actual_k < 3) { 96 | dprintf("Warning: not enough points for vertex %d\n", i); 97 | normals[i] = ref; 98 | continue; 99 | } 100 | // Compute covariance 101 | float C[3][3] = { {0,0,0}, {0,0,0}, {0,0,0} }; 102 | // The below loop starts at 1, since element 0 103 | // is just vertices[i] itself 104 | for (int j = 1; j < actual_k; j++) { 105 | vec d = point(knn[j]) - vertices[i]; 106 | for (int l = 0; l < 3; l++) 107 | for (int m = 0; m < 3; m++) 108 | C[l][m] += d[l] * d[m]; 109 | } 110 | float e[3]; 111 | eigdc(C, e); 112 | normals[i] = vec(C[0][0], C[1][0], C[2][0]); 113 | if ((normals[i] DOT ref) < 0.0f) 114 | normals[i] = -normals[i]; 115 | } 116 | } 117 | 118 | // Make them all unit-length 119 | #pragma omp parallel for 120 | for (int i = 0; i < nv; i++) 121 | normalize(normals[i]); 122 | 123 | dprintf("Done.\n"); 124 | } 125 | -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_pointareas.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /* 18 | Szymon Rusinkiewicz 19 | Princeton University 20 | 21 | TriMesh_pointareas.cc 22 | Compute the area "belonging" to each vertex or each corner 23 | of a triangle (defined as Voronoi area restricted to the 1-ring of 24 | a vertex, or to the triangle). 25 | 26 | for more voronoi area, see 27 | Meyer M., Discrete differential geometry operators for triangulated 2-manifolds 28 | */ 29 | 30 | 31 | #include "trianglemesh.h" 32 | 33 | // Compute per-vertex point areas 34 | void TriangleMesh::need_pointareas() 35 | { 36 | if (pointareas.size() == vertices.size()) 37 | return; 38 | need_faces(); 39 | 40 | dprintf("Computing point areas... "); 41 | 42 | int nf = faces.size(), nv = vertices.size(); 43 | pointareas.clear(); 44 | pointareas.resize(nv); 45 | cornerareas.clear(); 46 | cornerareas.resize(nf); 47 | 48 | #pragma omp parallel for 49 | for (int i = 0; i < nf; i++) { 50 | // Edges 51 | vec e[3] = { vertices[faces[i][2]] - vertices[faces[i][1]], 52 | vertices[faces[i][0]] - vertices[faces[i][2]], 53 | vertices[faces[i][1]] - vertices[faces[i][0]] }; 54 | 55 | // Compute corner weights 56 | float area = 0.5f * len(e[0] CROSS e[1]); 57 | float l2[3] = { len2(e[0]), len2(e[1]), len2(e[2]) }; 58 | float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]), 59 | l2[1] * (l2[2] + l2[0] - l2[1]), 60 | l2[2] * (l2[0] + l2[1] - l2[2]) }; 61 | if (ew[0] <= 0.0f) { 62 | cornerareas[i][1] = -0.25f * l2[2] * area / 63 | (e[0] DOT e[2]); 64 | cornerareas[i][2] = -0.25f * l2[1] * area / 65 | (e[0] DOT e[1]); 66 | cornerareas[i][0] = area - cornerareas[i][1] - 67 | cornerareas[i][2]; 68 | } else if (ew[1] <= 0.0f) { 69 | cornerareas[i][2] = -0.25f * l2[0] * area / 70 | (e[1] DOT e[0]); 71 | cornerareas[i][0] = -0.25f * l2[2] * area / 72 | (e[1] DOT e[2]); 73 | cornerareas[i][1] = area - cornerareas[i][2] - 74 | cornerareas[i][0]; 75 | } else if (ew[2] <= 0.0f) { 76 | cornerareas[i][0] = -0.25f * l2[1] * area / 77 | (e[2] DOT e[1]); 78 | cornerareas[i][1] = -0.25f * l2[0] * area / 79 | (e[2] DOT e[0]); 80 | cornerareas[i][2] = area - cornerareas[i][0] - 81 | cornerareas[i][1]; 82 | } else { 83 | float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]); 84 | for (int j = 0; j < 3; j++) 85 | cornerareas[i][j] = ewscale * (ew[(j+1)%3] + 86 | ew[(j+2)%3]); 87 | } 88 | #pragma omp atomic 89 | pointareas[faces[i][0]] += cornerareas[i][0]; 90 | #pragma omp atomic 91 | pointareas[faces[i][1]] += cornerareas[i][1]; 92 | #pragma omp atomic 93 | pointareas[faces[i][2]] += cornerareas[i][2]; 94 | } 95 | 96 | dprintf("Done.\n"); 97 | } 98 | 99 | -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_stats.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | 18 | #include "trianglemesh.h" 19 | #include 20 | #include 21 | using namespace std; 22 | 23 | // A characteristic "feature size" for the mesh. Computed as an approximation 24 | // to the median edge length 25 | float TriangleMesh::feature_size() 26 | { 27 | need_faces(); 28 | if (faces.empty()) 29 | return 0.0f; 30 | 31 | int nf = faces.size(); 32 | int nsamp = min(nf / 2, 333); 33 | 34 | vector samples; 35 | samples.reserve(nsamp * 3); 36 | 37 | for (int i = 0; i < nsamp; i++) { 38 | // Quick 'n dirty portable random number generator 39 | static unsigned randq = 0; 40 | randq = unsigned(1664525) * randq + unsigned(1013904223); 41 | 42 | int ind = randq % nf; 43 | const point &p0 = vertices[faces[ind][0]]; 44 | const point &p1 = vertices[faces[ind][1]]; 45 | const point &p2 = vertices[faces[ind][2]]; 46 | samples.push_back(dist2(p0,p1)); 47 | samples.push_back(dist2(p1,p2)); 48 | samples.push_back(dist2(p2,p0)); 49 | } 50 | nth_element(samples.begin(), 51 | samples.begin() + samples.size()/2, 52 | samples.end()); 53 | return sqrt(samples[samples.size()/2]); 54 | } 55 | -------------------------------------------------------------------------------- /trianglemesh/trianglemesh_tstrips.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trianglemesh/trianglemesh_tstrips.cpp -------------------------------------------------------------------------------- /trimeshview.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trimeshview.cpp -------------------------------------------------------------------------------- /trimeshview.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trimeshview.h -------------------------------------------------------------------------------- /trimeshview_draw_apparent_ridges.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | 18 | 19 | 20 | /* 21 | Tweaks by zdd again 22 | 23 | Original by Tilke Judd 24 | Tweaks by Szymon Rusinkiewicz 25 | 26 | apparentridge.cc 27 | Compute apparent ridges. 28 | 29 | Implements method of 30 | Judd, T., Durand, F, and Adelson, E. 31 | Apparent Ridges for Line Drawing, 32 | ACM Trans. Graphics (Proc. SIGGRAPH), vol. 26, no. 3, 2007. 33 | */ 34 | 35 | #include 36 | #include "trimeshview.h" 37 | using namespace std; 38 | 39 | 40 | // Compute largest eigenvalue and associated eigenvector of a 41 | // symmetric 2x2 matrix. Solves characteristic equation. 42 | // Inputs: three elements of matrix (upper-left, diag, lower-right) 43 | // Outputs: largest (in magnitude) eigenvector/value 44 | static void largest_eig_2x2(float m1, float m12, float m2, vec2 &e1, float &l1) 45 | { 46 | l1 = 0.5f * (m1 + m2); 47 | // The result of the below sqrt is positive, so to get the largest 48 | // eigenvalue we add it if we were positive already, else subtract 49 | if (l1 > 0.0f) 50 | l1 += sqrt(sqr(m12) + 0.25f * sqr(m2-m1)); 51 | else 52 | l1 -= sqrt(sqr(m12) + 0.25f * sqr(m2-m1)); 53 | 54 | // Find corresponding eigenvector 55 | e1 = vec2(m2 - l1, -m12); 56 | normalize(e1); 57 | } 58 | 59 | 60 | // Compute principal view-dependent curvatures and directions at vertex i. 61 | // ndotv = cosine of angle between normal and view direction 62 | // (u,v) = coordinates of w (projected view) in principal coordinates 63 | // Pass in u^2, u*v, and v^2, since those are readily available. 64 | // Fills in q1 and t1 (using the paper's notation). 65 | // Note that the latter is expressed in the (pdir1,pdir2) coordinate basis 66 | void TriMeshView::compute_viewdep_curv(const TriangleMesh *mesh, int i, float ndotv, 67 | float u2, float uv, float v2, 68 | float &q1, vec2 &t1) 69 | { 70 | // Find the entries in Q = S * P^-1 71 | // = S + (sec theta - 1) * S * w * w^T 72 | float sectheta_minus1 = 1.0f / fabs(ndotv) - 1.0f; 73 | float Q11 = mesh->curv1[i] * (1.0f + sectheta_minus1 * u2); 74 | float Q12 = mesh->curv1[i] * ( sectheta_minus1 * uv); 75 | float Q21 = mesh->curv2[i] * ( sectheta_minus1 * uv); 76 | float Q22 = mesh->curv2[i] * (1.0f + sectheta_minus1 * v2); 77 | 78 | // Find the three entries in the (symmetric) matrix Q^T Q 79 | float QTQ1 = Q11 * Q11 + Q21 * Q21; 80 | float QTQ12 = Q11 * Q12 + Q21 * Q22; 81 | float QTQ2 = Q12 * Q12 + Q22 * Q22; 82 | 83 | // Compute eigenstuff 84 | largest_eig_2x2(QTQ1, QTQ12, QTQ2, t1, q1); 85 | } 86 | 87 | 88 | // i+1 and i-1 modulo 3 89 | #define NEXT(i) ((i)<2 ? (i)+1 : (i)-2) 90 | #define PREV(i) ((i)>0 ? (i)-1 : (i)+2) 91 | 92 | 93 | // Compute D_{t_1} q_1 - the derivative of max view-dependent curvature 94 | // in the principal max view-dependent curvature direction. 95 | void TriMeshView::compute_Dt1q1(const TriangleMesh *mesh, int i, float ndotv, 96 | const vector &q1, const vector &t1, 97 | float &Dt1q1) 98 | { 99 | const point &v0 = mesh->vertices[i]; 100 | float this_viewdep_curv = q1[i]; 101 | vec world_t1 = t1[i][0] * mesh->pdir1[i] + t1[i][1] * mesh->pdir2[i]; 102 | vec world_t2 = mesh->normals[i] CROSS world_t1; 103 | float v0_dot_t2 = v0 DOT world_t2; 104 | 105 | Dt1q1 = 0.0f; 106 | int n = 0; 107 | 108 | int naf = mesh->adjacentfaces[i].size(); 109 | for (int j = 0; j < naf; j++) { 110 | // We're in a triangle adjacent to the vertex of interest. 111 | // The current vertex is v0 - let v1 and v2 be the other two 112 | int f = mesh->adjacentfaces[i][j]; 113 | int ind = mesh->faces[f].indexof(i); 114 | int i1 = mesh->faces[f][NEXT(ind)]; 115 | int i2 = mesh->faces[f][PREV(ind)]; 116 | const point &v1 = mesh->vertices[i1]; 117 | const point &v2 = mesh->vertices[i2]; 118 | 119 | // Find the point p on the segment between v1 and v2 such that 120 | // its vector from v0 is along t1, i.e. perpendicular to t2. 121 | // Linear combination: p = w1*v1 + w2*v2, where w2 = 1-w1 122 | float v1_dot_t2 = v1 DOT world_t2; 123 | float v2_dot_t2 = v2 DOT world_t2; 124 | float w1 = (v2_dot_t2 - v0_dot_t2) / (v2_dot_t2 - v1_dot_t2); 125 | 126 | // If w1 is not in [0..1) then we're not interested. 127 | // Incidentally, the computation of w1 can result in infinity, 128 | // but the comparison should do the right thing... 129 | if (w1 < 0.0f || w1 >= 1.0f) 130 | continue; 131 | 132 | // Construct the opposite point 133 | float w2 = 1.0f - w1; 134 | point p = w1 * v1 + w2 * v2; 135 | 136 | // And interpolate to find the view-dependent curvature at that point 137 | float interp_viewdep_curv = w1 * q1[i1] + w2 * q1[i2]; 138 | 139 | // Finally, take the *projected* view-dependent curvature derivative 140 | float proj_dist = (p - v0) DOT world_t1; 141 | proj_dist *= fabs(ndotv); 142 | Dt1q1 += (interp_viewdep_curv - this_viewdep_curv) / proj_dist; 143 | n++; 144 | 145 | // To save time, quit as soon as we have two estimates 146 | // (that's all we're going to get, anyway) 147 | if (n == 2) { 148 | Dt1q1 *= 0.5f; 149 | return; 150 | } 151 | } 152 | } 153 | 154 | 155 | // Draw part of an apparent ridge/valley curve on one triangle face. 156 | // v0,v1,v2 are the indices of the 3 vertices; this function assumes that the 157 | // curve connects points on the edges v0-v1 and v1-v2 158 | // (or connects point on v0-v1 to center if to_center is true) 159 | void TriMeshView::draw_segment_app_ridge(int v0, int v1, int v2, 160 | float emax0, float emax1, float emax2, 161 | float kmax0, float kmax1, float kmax2, 162 | const vec &tmax0, const vec &tmax1, const vec &tmax2, 163 | float thresh, bool to_center, bool do_test) 164 | { 165 | // Interpolate to find ridge/valley line segment endpoints 166 | // in this triangle and the curvatures there 167 | float w10 = fabs(emax0) / (fabs(emax0) + fabs(emax1)); 168 | float w01 = 1.0f - w10; 169 | point p01 = w01 * triMesh->vertices[v0] + w10 * triMesh->vertices[v1]; 170 | float k01 = fabs(w01 * kmax0 + w10 * kmax1); 171 | 172 | point p12; 173 | float k12; 174 | if (to_center) { 175 | // Connect first point to center of triangle 176 | p12 = (triMesh->vertices[v0] + 177 | triMesh->vertices[v1] + 178 | triMesh->vertices[v2]) / 3.0f; 179 | k12 = fabs(kmax0 + kmax1 + kmax2) / 3.0f; 180 | } else { 181 | // Connect first point to second one (on next edge) 182 | float w21 = fabs(emax1) / (fabs(emax1) + fabs(emax2)); 183 | float w12 = 1.0f - w21; 184 | p12 = w12 * triMesh->vertices[v1] + w21 * triMesh->vertices[v2]; 185 | k12 = fabs(w12 * kmax1 + w21 * kmax2); 186 | } 187 | 188 | // Don't draw below threshold 189 | k01 -= thresh; 190 | if (k01 < 0.0f) 191 | k01 = 0.0f; 192 | k12 -= thresh; 193 | if (k12 < 0.0f) 194 | k12 = 0.0f; 195 | 196 | // Skip lines that you can't see... 197 | if (k01 == 0.0f && k12 == 0.0f) 198 | return; 199 | 200 | // Perform test: do the tmax-es point *towards* the segment? (Fig 6) 201 | if (do_test) { 202 | // Find the vector perpendicular to the segment (p01 <-> p12) 203 | vec perp = trinorm(triMesh->vertices[v0], 204 | triMesh->vertices[v1], 205 | triMesh->vertices[v2]) CROSS (p01 - p12); 206 | // We want tmax1 to point opposite to perp, and 207 | // tmax0 and tmax2 to point along it. Otherwise, exit out. 208 | if ((tmax0 DOT perp) <= 0.0f || 209 | (tmax1 DOT perp) >= 0.0f || 210 | (tmax2 DOT perp) <= 0.0f) 211 | return; 212 | } 213 | 214 | // Fade lines 215 | if (true) { 216 | k01 /= (k01 + thresh); 217 | k12 /= (k12 + thresh); 218 | } else { 219 | k01 = k12 = 1.0f; 220 | } 221 | 222 | // Draw the line segment 223 | glColor4f(currcolor[0], currcolor[1], currcolor[2], k01); 224 | glVertex3fv(p01); 225 | glColor4f(currcolor[0], currcolor[1], currcolor[2], k12); 226 | glVertex3fv(p12); 227 | } 228 | 229 | 230 | // Draw apparent ridges in a triangle 231 | void TriMeshView::draw_face_app_ridges(int v0, int v1, int v2, 232 | const vector &ndotv, const vector &q1, 233 | const vector &t1, const vector &Dt1q1, 234 | bool do_bfcull, bool do_test, float thresh) 235 | { 236 | #if 0 237 | // Backface culling is turned off: getting contours from the 238 | // apparent ridge definition requires us to process faces that 239 | // may be (just barely) backfacing... 240 | if (likely(do_bfcull && 241 | ndotv[v0] <= 0.0f && ndotv[v1] <= 0.0f && ndotv[v2] <= 0.0f)) 242 | return; 243 | #endif 244 | 245 | // Trivial reject if this face isn't getting past the threshold anyway 246 | const float &kmax0 = q1[v0]; 247 | const float &kmax1 = q1[v1]; 248 | const float &kmax2 = q1[v2]; 249 | if (kmax0 <= thresh && kmax1 <= thresh && kmax2 <= thresh) 250 | return; 251 | 252 | // The "tmax" are the principal directions of view-dependent curvature, 253 | // flipped to point in the direction in which the curvature 254 | // is increasing. 255 | const float &emax0 = Dt1q1[v0]; 256 | const float &emax1 = Dt1q1[v1]; 257 | const float &emax2 = Dt1q1[v2]; 258 | vec world_t1_0 = t1[v0][0] * triMesh->pdir1[v0] + 259 | t1[v0][1] * triMesh->pdir2[v0]; 260 | vec world_t1_1 = t1[v1][0] * triMesh->pdir1[v1] + 261 | t1[v1][1] * triMesh->pdir2[v1]; 262 | vec world_t1_2 = t1[v2][0] * triMesh->pdir1[v2] + 263 | t1[v2][1] * triMesh->pdir2[v2]; 264 | vec tmax0 = Dt1q1[v0] * world_t1_0; 265 | vec tmax1 = Dt1q1[v1] * world_t1_1; 266 | vec tmax2 = Dt1q1[v2] * world_t1_2; 267 | 268 | // We have a "zero crossing" if the tmaxes along an edge 269 | // point in opposite directions 270 | bool z01 = ((tmax0 DOT tmax1) <= 0.0f); 271 | bool z12 = ((tmax1 DOT tmax2) <= 0.0f); 272 | bool z20 = ((tmax2 DOT tmax0) <= 0.0f); 273 | 274 | if (z01 + z12 + z20 < 2) 275 | return; 276 | 277 | // Draw line segment 278 | if (!z01) { 279 | draw_segment_app_ridge(v1, v2, v0, 280 | emax1, emax2, emax0, 281 | kmax1, kmax2, kmax0, 282 | tmax1, tmax2, tmax0, 283 | thresh, false, do_test); 284 | } else if (!z12) { 285 | draw_segment_app_ridge(v2, v0, v1, 286 | emax2, emax0, emax1, 287 | kmax2, kmax0, kmax1, 288 | tmax2, tmax0, tmax1, 289 | thresh, false, do_test); 290 | } else if (!z20) { 291 | draw_segment_app_ridge(v0, v1, v2, 292 | emax0, emax1, emax2, 293 | kmax0, kmax1, kmax2, 294 | tmax0, tmax1, tmax2, 295 | thresh, false, do_test); 296 | } else { 297 | // All three edges have crossings -- connect all to center 298 | draw_segment_app_ridge(v1, v2, v0, 299 | emax1, emax2, emax0, 300 | kmax1, kmax2, kmax0, 301 | tmax1, tmax2, tmax0, 302 | thresh, true, do_test); 303 | draw_segment_app_ridge(v2, v0, v1, 304 | emax2, emax0, emax1, 305 | kmax2, kmax0, kmax1, 306 | tmax2, tmax0, tmax1, 307 | thresh, true, do_test); 308 | draw_segment_app_ridge(v0, v1, v2, 309 | emax0, emax1, emax2, 310 | kmax0, kmax1, kmax2, 311 | tmax0, tmax1, tmax2, 312 | thresh, true, do_test); 313 | } 314 | } 315 | 316 | 317 | // Draw apparent ridges of the mesh 318 | void TriMeshView::draw_mesh_app_ridges(const vector &ndotv, const vector &q1, 319 | const vector &t1, const vector &Dt1q1, 320 | bool do_bfcull, bool do_test, float thresh) 321 | { 322 | const int *t = &triMesh->tstrips[0]; 323 | const int *stripend = t; 324 | const int *end = t + triMesh->tstrips.size(); 325 | 326 | // Walk through triangle strips 327 | while (1) { 328 | if (unlikely(t >= stripend)) { 329 | if (unlikely(t >= end)) 330 | return; 331 | // New strip: each strip is stored as 332 | // length followed by indices 333 | stripend = t + 1 + *t; 334 | // Skip over length plus first two indices of 335 | // first face 336 | t += 3; 337 | } 338 | 339 | draw_face_app_ridges(*(t-2), *(t-1), *t, 340 | ndotv, q1, t1, Dt1q1, 341 | do_bfcull, do_test, thresh); 342 | t++; 343 | } 344 | } 345 | 346 | void TriMeshView::draw_apparent_ridges(const vector &ndotv, const vector &q1, 347 | const vector &t1, const vector &Dt1q1, 348 | float thresh) 349 | { 350 | glLineWidth(2.5); 351 | glBegin(GL_LINES); 352 | draw_mesh_app_ridges(ndotv, q1, t1, Dt1q1, true, 353 | true, thresh); 354 | glEnd(); 355 | } 356 | -------------------------------------------------------------------------------- /trimeshview_draw_base.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trimeshview_draw_base.cpp -------------------------------------------------------------------------------- /trimeshview_draw_lines.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trimeshview_draw_lines.cpp -------------------------------------------------------------------------------- /trimeshview_draw_ridges_and_valleys.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zddhub/trianglemesh/1e15ddd82bbbfc75226e8ab6e46c487edc8bafcb/trimeshview_draw_ridges_and_valleys.cpp -------------------------------------------------------------------------------- /ui_mainwindow.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /******************************************************************************** 18 | ** Form generated from reading UI file 'mainwindow.ui' 19 | ** 20 | ** Created: Fri Jul 19 08:24:26 2013 21 | ** by: Qt User Interface Compiler version 4.7.4 22 | ** 23 | ** WARNING! All changes made in this file will be lost when recompiling UI file! 24 | ********************************************************************************/ 25 | 26 | #ifndef UI_MAINWINDOW_H 27 | #define UI_MAINWINDOW_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | QT_BEGIN_NAMESPACE 41 | 42 | class Ui_MainWindow 43 | { 44 | public: 45 | QAction *actionOpen; 46 | QAction *actionEdges; 47 | QAction *actionNormals; 48 | QAction *actionPrincipal_1; 49 | QAction *actionPrincipal_2; 50 | QAction *actionNormalColor; 51 | QAction *actionCurv_Color; 52 | QAction *actionBoundaries; 53 | QAction *actionPreview; 54 | QAction *actionExterior_Silhouette; 55 | QAction *actionOccluding_Contours; 56 | QAction *actionSuggestive_Contours; 57 | QAction *actionRidges; 58 | QAction *actionValleys; 59 | QAction *actionApparent_Ridges; 60 | QAction *actionSave_Ridges_file; 61 | QAction *actionSave_Occluding_file; 62 | QAction *actionLines; 63 | QAction *actionFaces; 64 | QAction *actionLines_2; 65 | QAction *actionFaces_2; 66 | QAction *actionSave_RV_mesh_file; 67 | QAction *actionSave_OC_mesh_file; 68 | QAction *actionOpen_LD_file; 69 | QAction *actionThresh; 70 | QAction *actionSmooth_curv; 71 | QAction *actionSmooth_DCurv; 72 | QAction *actionSave_curv1; 73 | QAction *actionSave_Curv2; 74 | QAction *actionLaplace_Smooth; 75 | QAction *actionRidge_Valley; 76 | QWidget *centralwidget; 77 | QMenuBar *menubar; 78 | QMenu *menuFile; 79 | QMenu *menuVectors; 80 | QMenu *menuVector; 81 | QMenu *menuLines; 82 | QMenu *menuColor; 83 | QMenu *menuRV; 84 | QMenu *menuOcludding; 85 | QMenu *menuThresh; 86 | QMenu *menuImproved_Method; 87 | QMenu *menuTestTime; 88 | QStatusBar *statusbar; 89 | 90 | void setupUi(QMainWindow *MainWindow) 91 | { 92 | if (MainWindow->objectName().isEmpty()) 93 | MainWindow->setObjectName(QString::fromUtf8("MainWindow")); 94 | MainWindow->resize(800, 600); 95 | actionOpen = new QAction(MainWindow); 96 | actionOpen->setObjectName(QString::fromUtf8("actionOpen")); 97 | actionEdges = new QAction(MainWindow); 98 | actionEdges->setObjectName(QString::fromUtf8("actionEdges")); 99 | actionEdges->setCheckable(true); 100 | actionNormals = new QAction(MainWindow); 101 | actionNormals->setObjectName(QString::fromUtf8("actionNormals")); 102 | actionNormals->setCheckable(true); 103 | actionPrincipal_1 = new QAction(MainWindow); 104 | actionPrincipal_1->setObjectName(QString::fromUtf8("actionPrincipal_1")); 105 | actionPrincipal_1->setCheckable(true); 106 | actionPrincipal_2 = new QAction(MainWindow); 107 | actionPrincipal_2->setObjectName(QString::fromUtf8("actionPrincipal_2")); 108 | actionPrincipal_2->setCheckable(true); 109 | actionNormalColor = new QAction(MainWindow); 110 | actionNormalColor->setObjectName(QString::fromUtf8("actionNormalColor")); 111 | actionNormalColor->setCheckable(true); 112 | actionCurv_Color = new QAction(MainWindow); 113 | actionCurv_Color->setObjectName(QString::fromUtf8("actionCurv_Color")); 114 | actionCurv_Color->setCheckable(true); 115 | actionBoundaries = new QAction(MainWindow); 116 | actionBoundaries->setObjectName(QString::fromUtf8("actionBoundaries")); 117 | actionBoundaries->setCheckable(true); 118 | actionPreview = new QAction(MainWindow); 119 | actionPreview->setObjectName(QString::fromUtf8("actionPreview")); 120 | actionPreview->setCheckable(true); 121 | actionExterior_Silhouette = new QAction(MainWindow); 122 | actionExterior_Silhouette->setObjectName(QString::fromUtf8("actionExterior_Silhouette")); 123 | actionExterior_Silhouette->setCheckable(true); 124 | actionOccluding_Contours = new QAction(MainWindow); 125 | actionOccluding_Contours->setObjectName(QString::fromUtf8("actionOccluding_Contours")); 126 | actionOccluding_Contours->setCheckable(true); 127 | actionSuggestive_Contours = new QAction(MainWindow); 128 | actionSuggestive_Contours->setObjectName(QString::fromUtf8("actionSuggestive_Contours")); 129 | actionSuggestive_Contours->setCheckable(true); 130 | actionRidges = new QAction(MainWindow); 131 | actionRidges->setObjectName(QString::fromUtf8("actionRidges")); 132 | actionRidges->setCheckable(true); 133 | actionValleys = new QAction(MainWindow); 134 | actionValleys->setObjectName(QString::fromUtf8("actionValleys")); 135 | actionValleys->setCheckable(true); 136 | actionApparent_Ridges = new QAction(MainWindow); 137 | actionApparent_Ridges->setObjectName(QString::fromUtf8("actionApparent_Ridges")); 138 | actionApparent_Ridges->setCheckable(true); 139 | actionSave_Ridges_file = new QAction(MainWindow); 140 | actionSave_Ridges_file->setObjectName(QString::fromUtf8("actionSave_Ridges_file")); 141 | actionSave_Occluding_file = new QAction(MainWindow); 142 | actionSave_Occluding_file->setObjectName(QString::fromUtf8("actionSave_Occluding_file")); 143 | actionLines = new QAction(MainWindow); 144 | actionLines->setObjectName(QString::fromUtf8("actionLines")); 145 | actionLines->setCheckable(true); 146 | actionFaces = new QAction(MainWindow); 147 | actionFaces->setObjectName(QString::fromUtf8("actionFaces")); 148 | actionFaces->setCheckable(true); 149 | actionLines_2 = new QAction(MainWindow); 150 | actionLines_2->setObjectName(QString::fromUtf8("actionLines_2")); 151 | actionLines_2->setCheckable(true); 152 | actionFaces_2 = new QAction(MainWindow); 153 | actionFaces_2->setObjectName(QString::fromUtf8("actionFaces_2")); 154 | actionFaces_2->setCheckable(true); 155 | actionSave_RV_mesh_file = new QAction(MainWindow); 156 | actionSave_RV_mesh_file->setObjectName(QString::fromUtf8("actionSave_RV_mesh_file")); 157 | actionSave_OC_mesh_file = new QAction(MainWindow); 158 | actionSave_OC_mesh_file->setObjectName(QString::fromUtf8("actionSave_OC_mesh_file")); 159 | actionOpen_LD_file = new QAction(MainWindow); 160 | actionOpen_LD_file->setObjectName(QString::fromUtf8("actionOpen_LD_file")); 161 | actionThresh = new QAction(MainWindow); 162 | actionThresh->setObjectName(QString::fromUtf8("actionThresh")); 163 | actionSmooth_curv = new QAction(MainWindow); 164 | actionSmooth_curv->setObjectName(QString::fromUtf8("actionSmooth_curv")); 165 | actionSmooth_DCurv = new QAction(MainWindow); 166 | actionSmooth_DCurv->setObjectName(QString::fromUtf8("actionSmooth_DCurv")); 167 | actionSave_curv1 = new QAction(MainWindow); 168 | actionSave_curv1->setObjectName(QString::fromUtf8("actionSave_curv1")); 169 | actionSave_Curv2 = new QAction(MainWindow); 170 | actionSave_Curv2->setObjectName(QString::fromUtf8("actionSave_Curv2")); 171 | actionLaplace_Smooth = new QAction(MainWindow); 172 | actionLaplace_Smooth->setObjectName(QString::fromUtf8("actionLaplace_Smooth")); 173 | actionRidge_Valley = new QAction(MainWindow); 174 | actionRidge_Valley->setObjectName(QString::fromUtf8("actionRidge_Valley")); 175 | centralwidget = new QWidget(MainWindow); 176 | centralwidget->setObjectName(QString::fromUtf8("centralwidget")); 177 | MainWindow->setCentralWidget(centralwidget); 178 | menubar = new QMenuBar(MainWindow); 179 | menubar->setObjectName(QString::fromUtf8("menubar")); 180 | menubar->setGeometry(QRect(0, 0, 800, 23)); 181 | menuFile = new QMenu(menubar); 182 | menuFile->setObjectName(QString::fromUtf8("menuFile")); 183 | menuVectors = new QMenu(menubar); 184 | menuVectors->setObjectName(QString::fromUtf8("menuVectors")); 185 | menuVector = new QMenu(menubar); 186 | menuVector->setObjectName(QString::fromUtf8("menuVector")); 187 | menuLines = new QMenu(menubar); 188 | menuLines->setObjectName(QString::fromUtf8("menuLines")); 189 | menuColor = new QMenu(menubar); 190 | menuColor->setObjectName(QString::fromUtf8("menuColor")); 191 | menuRV = new QMenu(menubar); 192 | menuRV->setObjectName(QString::fromUtf8("menuRV")); 193 | menuOcludding = new QMenu(menubar); 194 | menuOcludding->setObjectName(QString::fromUtf8("menuOcludding")); 195 | menuThresh = new QMenu(menubar); 196 | menuThresh->setObjectName(QString::fromUtf8("menuThresh")); 197 | menuImproved_Method = new QMenu(menubar); 198 | menuImproved_Method->setObjectName(QString::fromUtf8("menuImproved_Method")); 199 | menuTestTime = new QMenu(menubar); 200 | menuTestTime->setObjectName(QString::fromUtf8("menuTestTime")); 201 | MainWindow->setMenuBar(menubar); 202 | statusbar = new QStatusBar(MainWindow); 203 | statusbar->setObjectName(QString::fromUtf8("statusbar")); 204 | MainWindow->setStatusBar(statusbar); 205 | 206 | menubar->addAction(menuFile->menuAction()); 207 | menubar->addAction(menuVectors->menuAction()); 208 | menubar->addAction(menuVector->menuAction()); 209 | menubar->addAction(menuLines->menuAction()); 210 | menubar->addAction(menuColor->menuAction()); 211 | menubar->addAction(menuRV->menuAction()); 212 | menubar->addAction(menuOcludding->menuAction()); 213 | menubar->addAction(menuThresh->menuAction()); 214 | menubar->addAction(menuImproved_Method->menuAction()); 215 | menubar->addAction(menuTestTime->menuAction()); 216 | menuFile->addAction(actionOpen); 217 | menuFile->addAction(actionOpen_LD_file); 218 | menuFile->addSeparator(); 219 | menuFile->addAction(actionSave_Ridges_file); 220 | menuFile->addAction(actionSave_Occluding_file); 221 | menuFile->addSeparator(); 222 | menuFile->addAction(actionSave_RV_mesh_file); 223 | menuFile->addAction(actionSave_OC_mesh_file); 224 | menuFile->addSeparator(); 225 | menuFile->addAction(actionSave_curv1); 226 | menuFile->addAction(actionSave_Curv2); 227 | menuVectors->addAction(actionEdges); 228 | menuVector->addAction(actionNormals); 229 | menuVector->addAction(actionPrincipal_1); 230 | menuVector->addAction(actionPrincipal_2); 231 | menuVector->addAction(actionPreview); 232 | menuLines->addAction(actionBoundaries); 233 | menuLines->addAction(actionExterior_Silhouette); 234 | menuLines->addAction(actionOccluding_Contours); 235 | menuLines->addAction(actionSuggestive_Contours); 236 | menuLines->addAction(actionRidges); 237 | menuLines->addAction(actionValleys); 238 | menuLines->addAction(actionApparent_Ridges); 239 | menuColor->addAction(actionNormalColor); 240 | menuColor->addAction(actionCurv_Color); 241 | menuRV->addAction(actionLines); 242 | menuRV->addAction(actionFaces); 243 | menuOcludding->addAction(actionLines_2); 244 | menuOcludding->addAction(actionFaces_2); 245 | menuThresh->addAction(actionThresh); 246 | menuImproved_Method->addAction(actionSmooth_curv); 247 | menuImproved_Method->addAction(actionSmooth_DCurv); 248 | menuImproved_Method->addAction(actionLaplace_Smooth); 249 | menuTestTime->addAction(actionRidge_Valley); 250 | 251 | retranslateUi(MainWindow); 252 | QObject::connect(actionOpen, SIGNAL(triggered()), MainWindow, SLOT(open())); 253 | 254 | QMetaObject::connectSlotsByName(MainWindow); 255 | } // setupUi 256 | 257 | void retranslateUi(QMainWindow *MainWindow) 258 | { 259 | MainWindow->setWindowTitle(QApplication::translate("MainWindow", "LineDrawing", 0)); 260 | actionOpen->setText(QApplication::translate("MainWindow", "Open", 0)); 261 | actionEdges->setText(QApplication::translate("MainWindow", "Edges", 0)); 262 | actionNormals->setText(QApplication::translate("MainWindow", "Normal", 0)); 263 | actionPrincipal_1->setText(QApplication::translate("MainWindow", "Principal 1", 0)); 264 | actionPrincipal_2->setText(QApplication::translate("MainWindow", "Principal 2", 0)); 265 | actionNormalColor->setText(QApplication::translate("MainWindow", "Norm Color", 0)); 266 | actionCurv_Color->setText(QApplication::translate("MainWindow", "Curv Color", 0)); 267 | actionBoundaries->setText(QApplication::translate("MainWindow", "Boundaries", 0)); 268 | actionPreview->setText(QApplication::translate("MainWindow", "Preview", 0)); 269 | actionExterior_Silhouette->setText(QApplication::translate("MainWindow", "Exterior Silhouette", 0)); 270 | actionOccluding_Contours->setText(QApplication::translate("MainWindow", "Occluding Contours", 0)); 271 | actionSuggestive_Contours->setText(QApplication::translate("MainWindow", "Suggestive Contours", 0)); 272 | actionRidges->setText(QApplication::translate("MainWindow", "Ridges", 0)); 273 | actionValleys->setText(QApplication::translate("MainWindow", "Valleys", 0)); 274 | actionApparent_Ridges->setText(QApplication::translate("MainWindow", "Apparent Ridges", 0)); 275 | actionSave_Ridges_file->setText(QApplication::translate("MainWindow", "Save Ridge-Valley file", 0)); 276 | actionSave_Occluding_file->setText(QApplication::translate("MainWindow", "Save Occluding file", 0)); 277 | actionLines->setText(QApplication::translate("MainWindow", "Lines", 0)); 278 | actionFaces->setText(QApplication::translate("MainWindow", "Faces", 0)); 279 | actionLines_2->setText(QApplication::translate("MainWindow", "Lines", 0)); 280 | actionFaces_2->setText(QApplication::translate("MainWindow", "Faces", 0)); 281 | actionSave_RV_mesh_file->setText(QApplication::translate("MainWindow", "Save RV mesh file", 0)); 282 | actionSave_OC_mesh_file->setText(QApplication::translate("MainWindow", "Save OC mesh file", 0)); 283 | actionOpen_LD_file->setText(QApplication::translate("MainWindow", "Open LD file", 0)); 284 | actionThresh->setText(QApplication::translate("MainWindow", "Thresh", 0)); 285 | actionSmooth_curv->setText(QApplication::translate("MainWindow", "Our Method", 0)); 286 | actionSmooth_DCurv->setText(QApplication::translate("MainWindow", "Smooth DCurv", 0)); 287 | actionSave_curv1->setText(QApplication::translate("MainWindow", "Save Curv1", 0)); 288 | actionSave_Curv2->setText(QApplication::translate("MainWindow", "Save Curv2", 0)); 289 | actionLaplace_Smooth->setText(QApplication::translate("MainWindow", "Laplace Smooth", 0)); 290 | actionRidge_Valley->setText(QApplication::translate("MainWindow", "Ridge-Valley", 0)); 291 | menuFile->setTitle(QApplication::translate("MainWindow", "File", 0)); 292 | menuVectors->setTitle(QApplication::translate("MainWindow", "Mesh", 0)); 293 | menuVector->setTitle(QApplication::translate("MainWindow", "Vector", 0)); 294 | menuLines->setTitle(QApplication::translate("MainWindow", "Lines", 0)); 295 | menuColor->setTitle(QApplication::translate("MainWindow", "Color", 0)); 296 | menuRV->setTitle(QApplication::translate("MainWindow", "Ridge-Valley", 0)); 297 | menuOcludding->setTitle(QApplication::translate("MainWindow", "Ocludding", 0)); 298 | menuThresh->setTitle(QApplication::translate("MainWindow", "Thresh Control", 0)); 299 | menuImproved_Method->setTitle(QApplication::translate("MainWindow", "Improved Method", 0)); 300 | menuTestTime->setTitle(QApplication::translate("MainWindow", "TestTime", 0)); 301 | } // retranslateUi 302 | 303 | }; 304 | 305 | namespace Ui { 306 | class MainWindow: public Ui_MainWindow {}; 307 | } // namespace Ui 308 | 309 | QT_END_NAMESPACE 310 | 311 | #endif // UI_MAINWINDOW_H 312 | -------------------------------------------------------------------------------- /ui_threshdialog.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /******************************************************************************** 18 | ** Form generated from reading UI file 'threshdialog.ui' 19 | ** 20 | ** Created: Tue May 14 20:58:18 2013 21 | ** by: Qt User Interface Compiler version 4.7.4 22 | ** 23 | ** WARNING! All changes made in this file will be lost when recompiling UI file! 24 | ********************************************************************************/ 25 | 26 | #ifndef UI_THRESHDIALOG_H 27 | #define UI_THRESHDIALOG_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | QT_BEGIN_NAMESPACE 40 | 41 | class Ui_ThreshDialog 42 | { 43 | public: 44 | QGroupBox *groupBox; 45 | QSlider *rv_horizontalSlider; 46 | QLabel *rv_threshLabel; 47 | QGroupBox *groupBox_2; 48 | QSlider *ar_horizontalSlider; 49 | QLabel *ar_threshLabel; 50 | QGroupBox *groupBox_3; 51 | QSlider *sug_horizontalSlider; 52 | QLabel *sug_threshLabel; 53 | 54 | void setupUi(QDialog *ThreshDialog) 55 | { 56 | if (ThreshDialog->objectName().isEmpty()) 57 | ThreshDialog->setObjectName(QString::fromUtf8("ThreshDialog")); 58 | ThreshDialog->resize(445, 327); 59 | groupBox = new QGroupBox(ThreshDialog); 60 | groupBox->setObjectName(QString::fromUtf8("groupBox")); 61 | groupBox->setGeometry(QRect(70, 20, 311, 81)); 62 | QFont font; 63 | font.setFamily(QString::fromUtf8("Calibri")); 64 | font.setPointSize(12); 65 | font.setBold(false); 66 | font.setItalic(false); 67 | font.setWeight(50); 68 | groupBox->setFont(font); 69 | rv_horizontalSlider = new QSlider(groupBox); 70 | rv_horizontalSlider->setObjectName(QString::fromUtf8("rv_horizontalSlider")); 71 | rv_horizontalSlider->setGeometry(QRect(20, 40, 261, 21)); 72 | rv_horizontalSlider->setOrientation(Qt::Horizontal); 73 | rv_threshLabel = new QLabel(groupBox); 74 | rv_threshLabel->setObjectName(QString::fromUtf8("rv_threshLabel")); 75 | rv_threshLabel->setGeometry(QRect(200, 20, 81, 21)); 76 | QFont font1; 77 | font1.setFamily(QString::fromUtf8("Calibri")); 78 | font1.setPointSize(12); 79 | font1.setBold(false); 80 | font1.setWeight(50); 81 | rv_threshLabel->setFont(font1); 82 | rv_threshLabel->setLayoutDirection(Qt::LeftToRight); 83 | rv_threshLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); 84 | groupBox_2 = new QGroupBox(ThreshDialog); 85 | groupBox_2->setObjectName(QString::fromUtf8("groupBox_2")); 86 | groupBox_2->setGeometry(QRect(70, 120, 311, 81)); 87 | groupBox_2->setFont(font); 88 | ar_horizontalSlider = new QSlider(groupBox_2); 89 | ar_horizontalSlider->setObjectName(QString::fromUtf8("ar_horizontalSlider")); 90 | ar_horizontalSlider->setGeometry(QRect(20, 40, 261, 19)); 91 | ar_horizontalSlider->setOrientation(Qt::Horizontal); 92 | ar_threshLabel = new QLabel(groupBox_2); 93 | ar_threshLabel->setObjectName(QString::fromUtf8("ar_threshLabel")); 94 | ar_threshLabel->setGeometry(QRect(210, 20, 71, 21)); 95 | ar_threshLabel->setFont(font1); 96 | ar_threshLabel->setLayoutDirection(Qt::LeftToRight); 97 | ar_threshLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); 98 | groupBox_3 = new QGroupBox(ThreshDialog); 99 | groupBox_3->setObjectName(QString::fromUtf8("groupBox_3")); 100 | groupBox_3->setGeometry(QRect(70, 220, 311, 81)); 101 | groupBox_3->setFont(font); 102 | sug_horizontalSlider = new QSlider(groupBox_3); 103 | sug_horizontalSlider->setObjectName(QString::fromUtf8("sug_horizontalSlider")); 104 | sug_horizontalSlider->setGeometry(QRect(20, 40, 261, 19)); 105 | sug_horizontalSlider->setOrientation(Qt::Horizontal); 106 | sug_threshLabel = new QLabel(groupBox_3); 107 | sug_threshLabel->setObjectName(QString::fromUtf8("sug_threshLabel")); 108 | sug_threshLabel->setGeometry(QRect(200, 20, 81, 21)); 109 | QFont font2; 110 | font2.setFamily(QString::fromUtf8("Catriel")); 111 | font2.setPointSize(12); 112 | font2.setBold(false); 113 | font2.setWeight(50); 114 | sug_threshLabel->setFont(font2); 115 | sug_threshLabel->setLayoutDirection(Qt::LeftToRight); 116 | sug_threshLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); 117 | 118 | retranslateUi(ThreshDialog); 119 | 120 | QMetaObject::connectSlotsByName(ThreshDialog); 121 | } // setupUi 122 | 123 | void retranslateUi(QDialog *ThreshDialog) 124 | { 125 | ThreshDialog->setWindowTitle(QApplication::translate("ThreshDialog", "Thresh Dialog", 0)); 126 | groupBox->setTitle(QApplication::translate("ThreshDialog", "rv_thresh", 0)); 127 | rv_threshLabel->setText(QApplication::translate("ThreshDialog", "rv_thresh", 0)); 128 | groupBox_2->setTitle(QApplication::translate("ThreshDialog", "ar_thresh", 0)); 129 | ar_threshLabel->setText(QApplication::translate("ThreshDialog", "ar_thresh", 0)); 130 | groupBox_3->setTitle(QApplication::translate("ThreshDialog", "sug_thresh", 0)); 131 | sug_threshLabel->setText(QApplication::translate("ThreshDialog", "sug_thresh", 0)); 132 | } // retranslateUi 133 | 134 | }; 135 | 136 | namespace Ui { 137 | class ThreshDialog: public Ui_ThreshDialog {}; 138 | } // namespace Ui 139 | 140 | QT_END_NAMESPACE 141 | 142 | #endif // UI_THRESHDIALOG_H 143 | -------------------------------------------------------------------------------- /ui_threshform.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Copyright (c) 2014 Zhang Dongdong 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | **************************************************************************/ 17 | /******************************************************************************** 18 | ** Form generated from reading UI file 'threshform.ui' 19 | ** 20 | ** Created: Fri May 10 15:37:54 2013 21 | ** by: Qt User Interface Compiler version 4.7.4 22 | ** 23 | ** WARNING! All changes made in this file will be lost when recompiling UI file! 24 | ********************************************************************************/ 25 | 26 | #ifndef UI_THRESHFORM_H 27 | #define UI_THRESHFORM_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | QT_BEGIN_NAMESPACE 40 | 41 | class Ui_ThreshForm 42 | { 43 | public: 44 | QWidget *widget; 45 | QGridLayout *gridLayout; 46 | QLabel *label; 47 | QSlider *rv_horizontalSlider; 48 | QLabel *label_2; 49 | QSlider *ar_horizontalSlider; 50 | QLabel *label_3; 51 | QSlider *sug_horizontalSlider; 52 | 53 | void setupUi(QWidget *ThreshForm) 54 | { 55 | if (ThreshForm->objectName().isEmpty()) 56 | ThreshForm->setObjectName(QString::fromUtf8("ThreshForm")); 57 | ThreshForm->resize(272, 153); 58 | widget = new QWidget(ThreshForm); 59 | widget->setObjectName(QString::fromUtf8("widget")); 60 | widget->setGeometry(QRect(60, 40, 146, 71)); 61 | gridLayout = new QGridLayout(widget); 62 | gridLayout->setObjectName(QString::fromUtf8("gridLayout")); 63 | gridLayout->setContentsMargins(0, 0, 0, 0); 64 | label = new QLabel(widget); 65 | label->setObjectName(QString::fromUtf8("label")); 66 | 67 | gridLayout->addWidget(label, 0, 0, 1, 1); 68 | 69 | rv_horizontalSlider = new QSlider(widget); 70 | rv_horizontalSlider->setObjectName(QString::fromUtf8("rv_horizontalSlider")); 71 | rv_horizontalSlider->setOrientation(Qt::Horizontal); 72 | 73 | gridLayout->addWidget(rv_horizontalSlider, 0, 1, 1, 1); 74 | 75 | label_2 = new QLabel(widget); 76 | label_2->setObjectName(QString::fromUtf8("label_2")); 77 | 78 | gridLayout->addWidget(label_2, 1, 0, 1, 1); 79 | 80 | ar_horizontalSlider = new QSlider(widget); 81 | ar_horizontalSlider->setObjectName(QString::fromUtf8("ar_horizontalSlider")); 82 | ar_horizontalSlider->setOrientation(Qt::Horizontal); 83 | 84 | gridLayout->addWidget(ar_horizontalSlider, 1, 1, 1, 1); 85 | 86 | label_3 = new QLabel(widget); 87 | label_3->setObjectName(QString::fromUtf8("label_3")); 88 | 89 | gridLayout->addWidget(label_3, 2, 0, 1, 1); 90 | 91 | sug_horizontalSlider = new QSlider(widget); 92 | sug_horizontalSlider->setObjectName(QString::fromUtf8("sug_horizontalSlider")); 93 | sug_horizontalSlider->setOrientation(Qt::Horizontal); 94 | 95 | gridLayout->addWidget(sug_horizontalSlider, 2, 1, 1, 1); 96 | 97 | 98 | retranslateUi(ThreshForm); 99 | 100 | QMetaObject::connectSlotsByName(ThreshForm); 101 | } // setupUi 102 | 103 | void retranslateUi(QWidget *ThreshForm) 104 | { 105 | ThreshForm->setWindowTitle(QApplication::translate("ThreshForm", "Form", 0, QApplication::UnicodeUTF8)); 106 | label->setText(QApplication::translate("ThreshForm", "rv_thresh", 0, QApplication::UnicodeUTF8)); 107 | label_2->setText(QApplication::translate("ThreshForm", "ar_thresh", 0, QApplication::UnicodeUTF8)); 108 | label_3->setText(QApplication::translate("ThreshForm", "sug_thresh", 0, QApplication::UnicodeUTF8)); 109 | } // retranslateUi 110 | 111 | }; 112 | 113 | namespace Ui { 114 | class ThreshForm: public Ui_ThreshForm {}; 115 | } // namespace Ui 116 | 117 | QT_END_NAMESPACE 118 | 119 | #endif // UI_THRESHFORM_H 120 | --------------------------------------------------------------------------------