commit aa25b1eaefda5f0e51af94039a22c9a887124767 Author: ccolin Date: Tue Sep 22 08:41:49 2020 +0200 initial commit diff --git a/data/bunnyLowPoly.obj b/data/bunnyLowPoly.obj new file mode 100644 index 0000000..d5d81ee --- /dev/null +++ b/data/bunnyLowPoly.obj @@ -0,0 +1,13134 @@ +g +v -0.327136 0.279459 -0.003642 +v -0.345661 0.263044 0.027913 +v -0.344438 0.287930 0.020316 +v -0.325991 0.082009 0.017316 +v -0.323291 0.085689 -0.008220 +v -0.330055 0.061707 0.004226 +v 0.028802 0.177252 0.049284 +v 0.022428 0.165757 0.074483 +v 0.031478 0.157405 0.100597 +v -0.245710 0.492421 -0.338221 +v -0.241616 0.471469 -0.301132 +v -0.215945 0.485002 -0.351021 +v -0.001057 0.154930 0.099953 +v 0.015263 0.140765 0.123091 +v -0.175565 -0.305697 0.198646 +v -0.151932 -0.293836 0.201942 +v -0.172488 -0.290977 0.183347 +v 0.173557 0.212599 0.043188 +v 0.136426 0.207472 0.046206 +v 0.164035 0.207560 0.075044 +v -0.146675 0.346355 0.096397 +v -0.150319 0.339792 0.121561 +v -0.137477 0.341393 0.079480 +v -0.310449 -0.108743 -0.000535 +v -0.317107 -0.099174 0.043785 +v -0.325028 -0.084176 0.008774 +v -0.221054 0.323353 -0.290032 +v -0.225839 0.331003 -0.316543 +v -0.209819 0.337796 -0.320837 +v -0.340433 -0.043808 0.030583 +v -0.345153 -0.021155 0.051759 +v -0.343894 -0.033329 0.015337 +v 0.529377 -0.147557 0.051570 +v 0.522909 -0.151798 0.071500 +v 0.529093 -0.167995 0.076373 +v -0.014732 0.487689 -0.101773 +v -0.049264 0.464741 -0.098200 +v -0.025672 0.477128 -0.082210 +v 0.131080 0.202852 0.076657 +v -0.295800 -0.130876 -0.011504 +v -0.310467 -0.105978 -0.025887 +v -0.231433 0.436453 -0.207885 +v -0.245603 0.439932 -0.213018 +v -0.225987 0.411225 -0.155166 +v -0.193132 0.391153 -0.171971 +v -0.199530 0.374135 -0.127852 +v -0.189777 0.362829 -0.135201 +v -0.196056 0.459443 -0.344228 +v -0.208910 0.452053 -0.302301 +v -0.193428 0.429684 -0.294043 +v -0.115226 -0.349957 -0.126588 +v -0.098598 -0.360590 -0.144528 +v -0.120028 -0.362994 -0.124828 +v -0.217398 0.440458 -0.240273 +v -0.234741 0.450021 -0.246989 +v -0.204544 0.428024 -0.233964 +v -0.224203 0.456584 -0.283901 +v -0.225603 0.386528 -0.107739 +v -0.234410 0.390940 -0.110941 +v -0.212365 0.365712 -0.090095 +v -0.244977 0.416423 -0.161032 +v 0.010349 -0.011899 -0.200726 +v -0.011034 0.004593 -0.191830 +v 0.018057 0.024458 -0.192740 +v 0.094233 0.192964 0.073809 +v 0.065383 0.176401 0.085877 +v 0.088302 0.169218 0.121254 +v -0.365106 0.211122 0.064205 +v -0.350687 0.235907 0.074613 +v -0.360635 0.217212 0.037695 +v 0.138009 0.195109 -0.064932 +v 0.104469 0.198723 -0.018197 +v 0.165825 0.209976 -0.020122 +v -0.234989 -0.359349 -0.058086 +v -0.231580 -0.341014 -0.058960 +v -0.222194 -0.354789 -0.084212 +v -0.357575 0.129471 0.128531 +v -0.363612 0.150919 0.139660 +v -0.362206 0.154369 0.119358 +v -0.313982 -0.085363 0.077560 +v -0.324024 -0.074046 0.061984 +v 0.120761 0.205097 0.011486 +v 0.151093 0.210201 0.008662 +v -0.036836 -0.280575 -0.154741 +v -0.038005 -0.269629 -0.122129 +v -0.025890 -0.270427 -0.129447 +v -0.268617 0.353922 -0.006383 +v -0.282705 0.355552 0.035987 +v -0.251144 0.360018 0.031368 +v -0.217168 0.116688 -0.109636 +v -0.234457 0.123659 -0.100450 +v -0.213895 0.140086 -0.105022 +v -0.343422 0.025787 0.025804 +v -0.332116 0.063550 0.027151 +v 0.166179 0.200915 -0.059769 +v -0.337763 0.323613 0.100385 +v -0.307862 0.321493 0.145850 +v -0.326995 0.332952 0.099386 +v 0.176977 0.006028 0.264431 +v 0.208088 0.003754 0.259239 +v 0.202371 0.018462 0.245057 +v -0.297218 0.351754 0.062893 +v -0.270678 0.354601 0.091471 +v -0.372826 0.183088 0.060105 +v -0.366825 0.187424 0.026318 +v 0.198313 0.215281 0.017162 +v -0.253572 0.462957 -0.277841 +v 0.045607 0.182952 0.044682 +v -0.295842 0.346325 0.099522 +v -0.298529 0.338581 0.121720 +v 0.189895 0.209468 -0.038174 +v 0.205306 0.213881 -0.010872 +v -0.301317 -0.115607 0.044263 +v -0.297986 -0.128242 0.012478 +v -0.212867 0.392996 -0.134580 +v -0.189807 0.412607 -0.247763 +v -0.347498 0.222097 -0.018474 +v -0.340037 0.242624 -0.011232 +v -0.332317 0.227815 -0.039296 +v 0.222637 0.205818 -0.047967 +v 0.251209 0.018090 -0.189456 +v 0.274175 -0.001202 -0.197802 +v 0.245987 0.005898 -0.206438 +v -0.223045 0.362368 -0.065103 +v -0.242437 0.376775 -0.085494 +v 0.119993 0.187459 0.109428 +v -0.255822 0.362168 -0.068783 +v -0.251445 0.355664 -0.039580 +v 0.198897 0.204701 0.093314 +v 0.159108 0.200643 0.099115 +v 0.174998 0.191180 0.119222 +v -0.339358 -0.001775 -0.006590 +v -0.344461 0.002661 0.030630 +v -0.340900 0.023790 0.003074 +v -0.261239 0.432442 -0.211719 +v -0.338401 0.094874 0.021439 +v -0.350740 0.103835 0.041888 +v -0.350953 0.109571 0.007250 +v 0.145274 0.184506 0.125087 +v 0.156994 0.171912 0.144261 +v -0.115409 0.340129 0.016347 +v -0.112598 0.369510 0.002035 +v -0.125463 0.342125 0.022904 +v -0.366205 0.136028 0.084542 +v -0.372513 0.158852 0.085759 +v -0.368969 0.134161 0.056780 +v -0.293697 0.179603 0.254620 +v -0.282492 0.196839 0.260491 +v -0.296970 0.206391 0.254401 +v -0.270991 0.217100 0.256433 +v -0.287070 0.232186 0.247738 +v -0.237859 0.507235 -0.381164 +v -0.253873 0.500265 -0.353496 +v -0.231563 0.505221 -0.367543 +v -0.282090 0.313010 0.179649 +v -0.282067 0.329307 0.154185 +v -0.095284 0.400362 -0.017576 +v -0.122037 0.386540 -0.011268 +v -0.154082 0.353709 0.060678 +v -0.360847 0.115601 0.047063 +v -0.277040 0.167387 0.254514 +v -0.279137 0.260486 0.232020 +v -0.272167 0.298166 0.201269 +v -0.293957 0.259045 0.226290 +v -0.167733 0.351712 0.102328 +v -0.170550 0.340365 0.140811 +v -0.254671 0.403953 -0.145213 +v -0.000225 -0.303222 0.240597 +v 0.000041 -0.324215 0.249640 +v 0.027810 -0.296210 0.249091 +v -0.356636 0.217265 0.009383 +v -0.127896 -0.146978 -0.141261 +v -0.141093 -0.100963 -0.170146 +v -0.117223 -0.115046 -0.160884 +v -0.193398 0.192332 -0.103953 +v -0.232821 0.205363 -0.105217 +v -0.220245 0.235092 -0.102695 +v -0.149404 0.369788 -0.005142 +v -0.156563 0.356987 0.023234 +v -0.138588 0.354701 0.021043 +v -0.263082 0.177476 0.260125 +v -0.264647 0.254154 0.237265 +v 0.441216 -0.021628 -0.069091 +v 0.428954 -0.016636 -0.097515 +v 0.427058 0.013642 -0.076941 +v -0.324880 -0.074483 -0.015863 +v -0.328401 -0.064010 0.019903 +v 0.032600 0.179839 -0.026555 +v 0.045324 0.186295 0.011503 +v -0.342046 -0.016566 0.008981 +v -0.373317 0.157464 0.052302 +v -0.196564 0.344063 -0.083686 +v 0.229891 0.214383 0.015555 +v 0.219093 0.213993 0.045923 +v -0.253135 0.288774 0.212326 +v -0.126018 -0.281189 0.034310 +v -0.112881 -0.272205 0.047937 +v -0.116408 -0.250769 0.031935 +v 0.233919 0.211045 -0.016389 +v -0.268091 0.127344 0.250686 +v -0.252225 0.152012 0.261950 +v -0.245054 0.206001 0.251743 +v -0.255722 0.235648 0.245960 +v 0.096613 -0.046620 -0.279790 +v 0.106803 -0.026023 -0.269996 +v 0.128906 -0.057636 -0.278585 +v -0.051733 0.319248 -0.043992 +v -0.034337 0.327583 -0.065487 +v -0.023161 0.335823 -0.054241 +v -0.361219 0.177547 0.000646 +v -0.337987 0.258773 0.009400 +v -0.328513 0.255920 -0.026531 +v -0.042270 -0.240278 -0.117870 +v -0.043971 -0.217838 -0.121420 +v -0.024118 -0.235665 -0.115743 +v -0.006368 -0.041280 -0.201901 +v -0.032937 -0.038504 -0.194447 +v -0.247033 0.136364 0.259818 +v -0.260377 0.320181 0.177954 +v -0.244469 0.309230 0.192946 +v -0.329966 0.209149 -0.048068 +v -0.344845 0.196910 -0.026602 +v -0.336168 -0.043944 -0.024812 +v -0.176640 0.228483 -0.096132 +v -0.200693 0.266777 -0.098850 +v -0.179275 0.266960 -0.090509 +v -0.234215 0.161628 0.261236 +v -0.244942 0.270581 0.224034 +v -0.258238 0.114639 0.246480 +v -0.242620 0.119400 0.251755 +v -0.179505 0.446961 -0.417787 +v -0.179204 0.472515 -0.411603 +v -0.175937 0.442070 -0.412825 +v -0.331289 -0.018143 -0.028611 +v 0.001181 0.420368 -0.149389 +v 0.045625 0.431592 -0.164641 +v 0.015618 0.395193 -0.140794 +v 0.438263 0.014824 -0.047394 +v 0.427890 0.049793 -0.037648 +v 0.439462 0.025433 -0.023832 +v 0.481401 -0.250426 -0.073639 +v 0.496381 -0.255665 -0.057123 +v 0.487993 -0.275832 -0.047312 +v -0.017071 0.391679 -0.134893 +v -0.203889 0.297912 -0.165539 +v -0.191602 0.312077 -0.172597 +v -0.187349 0.305780 -0.130830 +v 0.206429 0.101738 0.191652 +v 0.223476 0.127321 0.175237 +v 0.188956 0.124940 0.183814 +v 0.455552 -0.277875 -0.076327 +v 0.424890 0.061228 -0.009112 +v 0.437460 0.034003 0.002513 +v 0.506399 -0.231175 -0.057365 +v -0.130064 0.245418 -0.063249 +v -0.113324 0.247952 -0.041919 +v -0.114352 0.225559 -0.059876 +v 0.088054 0.196485 0.045096 +v 0.205578 0.210207 0.071588 +v -0.225579 0.000364 0.195397 +v -0.232006 0.034299 0.181605 +v -0.249626 0.001368 0.184068 +v -0.229974 0.134214 0.257922 +v 0.192311 -0.253279 0.260491 +v 0.196381 -0.266262 0.255417 +v 0.205613 -0.247986 0.262110 +v -0.221633 0.292118 0.200790 +v 0.477018 -0.303411 0.032685 +v 0.436514 -0.326088 -0.000695 +v 0.459989 -0.311391 -0.014676 +v 0.522679 -0.208138 -0.042297 +v 0.523364 -0.231370 -0.029680 +v 0.449752 -0.084105 -0.049846 +v 0.453007 -0.048605 -0.030495 +v 0.457389 -0.105187 -0.012615 +v -0.170639 -0.317570 0.082126 +v -0.142788 -0.308609 0.059574 +v -0.176888 -0.339006 0.062976 +v -0.326156 0.056781 -0.018120 +v -0.313858 0.085010 -0.031540 +v -0.308990 0.071270 -0.048978 +v -0.259520 -0.169082 0.007055 +v -0.271647 -0.149772 -0.023560 +v -0.256065 -0.168350 -0.025722 +v -0.212956 0.023584 0.192237 +v -0.215667 0.071825 0.171114 +v -0.241959 0.060165 0.168190 +v -0.225656 0.079605 0.168101 +v 0.145068 -0.028155 0.282530 +v 0.176829 -0.035964 0.280593 +v 0.150969 -0.011497 0.276706 +v 0.239749 -0.028669 0.266782 +v 0.263413 -0.012449 0.250562 +v 0.240352 0.001787 0.247272 +v 0.222336 -0.206059 0.270125 +v 0.199919 -0.191865 0.280433 +v 0.203381 -0.208824 0.274166 +v -0.218349 0.190826 0.242771 +v -0.219672 0.163690 0.256292 +v 0.460821 -0.123026 0.006441 +v 0.457555 -0.097343 0.033885 +v -0.358207 0.190743 0.161905 +v -0.349435 0.212746 0.171829 +v -0.349671 0.220585 0.130149 +v -0.339092 0.300529 0.004894 +v -0.321513 0.306826 -0.014481 +v 0.179558 0.195209 -0.072646 +v 0.209671 0.192828 0.115760 +v -0.199683 0.050407 0.186649 +v -0.198189 0.348032 -0.292478 +v -0.201449 0.358801 -0.348009 +v -0.188371 0.376823 -0.307168 +v 0.186404 -0.296795 0.221334 +v 0.180432 -0.283463 0.236793 +v 0.142823 -0.288047 0.227040 +v 0.227552 0.152401 0.159034 +v 0.219861 0.175805 0.139423 +v 0.204751 0.146754 0.164581 +v -0.109674 0.271384 -0.022184 +v -0.099496 0.289938 -0.028351 +v -0.102125 0.297794 -0.004038 +v -0.372478 0.182952 0.077684 +v -0.110554 0.304368 -0.064448 +v -0.077747 0.330530 -0.087042 +v -0.074285 0.310423 -0.066113 +v 0.448322 -0.002235 0.017576 +v 0.450780 -0.009158 -0.016631 +v 0.455417 -0.048114 -0.003695 +v 0.100476 0.191960 -0.045729 +v -0.337308 -0.049101 -0.005591 +v 0.256944 0.199988 -0.045575 +v 0.095987 -0.333961 0.120078 +v 0.076908 -0.329957 0.179295 +v 0.061231 -0.335397 0.111159 +v 0.231858 -0.257585 0.252369 +v 0.238657 -0.301586 0.212693 +v 0.219536 -0.286440 0.236421 +v 0.213298 -0.314238 0.216627 +v 0.543193 -0.198085 0.008355 +v 0.537629 -0.169873 -0.003164 +v 0.539058 -0.159796 0.014209 +v 0.510581 -0.258518 -0.034517 +v -0.196228 0.373095 -0.373940 +v -0.195342 0.385535 -0.390391 +v -0.181732 0.411183 -0.388069 +v -0.219158 -0.016566 0.196933 +v -0.216919 -0.043501 0.203655 +v -0.203269 -0.024451 0.206992 +v 0.283608 0.048399 0.214051 +v 0.306196 0.053083 0.200572 +v 0.272810 0.071400 0.193525 +v 0.204899 -0.052226 0.283522 +v 0.212525 -0.020830 0.269742 +v 0.230340 -0.237047 0.258134 +v 0.214881 -0.225428 0.262116 +v -0.215579 0.273617 0.205669 +v -0.203859 0.321552 0.171959 +v 0.445286 -0.058936 -0.065960 +v 0.447808 -0.064996 -0.048570 +v 0.432899 -0.080620 -0.092848 +v 0.002416 0.179922 0.044570 +v 0.264972 0.203738 -0.012502 +v 0.298299 0.190212 0.013269 +v 0.297962 0.187323 -0.020642 +v -0.193510 -0.097815 0.195131 +v -0.199724 -0.062793 0.207158 +v -0.232207 -0.078937 0.186425 +v -0.228934 -0.053779 0.195675 +v -0.194030 0.015698 0.197973 +v 0.439734 -0.114419 -0.076397 +v 0.453650 -0.121076 -0.038056 +v 0.181578 -0.217601 0.268371 +v 0.179127 -0.204305 0.276298 +v 0.158730 -0.199432 0.275495 +v 0.241185 0.034889 0.226373 +v 0.214568 0.038144 0.214855 +v 0.226672 0.021723 0.232558 +v 0.208945 -0.131526 0.279098 +v 0.229637 -0.134710 0.277698 +v 0.217067 -0.110958 0.279263 +v 0.036865 0.443783 -0.120380 +v -0.002375 0.420788 -0.087313 +v 0.004897 0.409352 -0.084933 +v 0.156858 -0.221045 0.265465 +v 0.158724 -0.240497 0.264975 +v 0.040250 0.482899 -0.122684 +v 0.006545 0.457204 -0.091023 +v 0.006179 0.442614 -0.096924 +v -0.119786 -0.232162 0.040465 +v -0.137537 -0.235239 0.007546 +v -0.082969 0.201860 0.066916 +v -0.090777 0.224619 0.046313 +v -0.097972 0.223509 0.081660 +v -0.310243 0.159974 -0.075488 +v -0.283868 0.149873 -0.086971 +v -0.302977 0.124397 -0.067183 +v -0.184609 -0.065841 0.207648 +v -0.185684 -0.023949 0.212893 +v -0.164679 0.030902 0.198918 +v 0.440041 -0.254206 0.138472 +v 0.442811 -0.273947 0.131685 +v 0.466149 -0.250633 0.128460 +v 0.069530 0.444374 -0.177470 +v 0.097606 0.468911 -0.206875 +v 0.102101 0.429376 -0.182798 +v 0.175323 -0.231884 0.269245 +v -0.182618 0.405814 -0.398336 +v 0.385154 0.108436 0.091825 +v 0.381314 0.100994 0.110686 +v 0.405999 0.068943 0.101914 +v -0.170928 0.002195 0.207536 +v -0.174089 0.056060 0.188173 +v -0.192577 0.089735 0.168527 +v 0.411576 -0.278330 0.134013 +v 0.408598 -0.268105 0.134987 +v 0.393961 -0.264225 0.132258 +v -0.147880 0.272961 -0.070012 +v -0.129143 0.270203 -0.056255 +v -0.344379 0.255288 0.094578 +v -0.352140 0.256186 0.068009 +v -0.348874 0.239694 0.030122 +v 0.062832 0.145390 0.141497 +v 0.334549 -0.329000 -0.077230 +v 0.355525 -0.341558 -0.055079 +v 0.315269 -0.345001 -0.065812 +v -0.182795 -0.191008 -0.080154 +v -0.167408 -0.201670 -0.067484 +v -0.197669 -0.197636 -0.052120 +v -0.163870 -0.104177 0.200312 +v -0.169452 -0.086480 0.202178 +v -0.167278 -0.037429 0.213000 +v -0.164313 -0.018609 0.214335 +v 0.241569 0.059385 0.204110 +v -0.158317 0.084177 0.170996 +v 0.229312 -0.051712 0.278029 +v -0.220706 0.472249 -0.391259 +v -0.206092 0.415826 -0.399860 +v -0.215626 0.414397 -0.381087 +v -0.157608 -0.066379 0.207548 +v -0.150295 0.006737 0.204488 +v -0.165488 0.106481 0.160582 +v 0.182742 -0.240089 0.269304 +v 0.161465 -0.061393 0.284408 +v -0.257973 0.323401 -0.217389 +v -0.256348 0.333495 -0.222676 +v -0.247677 0.314782 -0.223267 +v 0.434116 -0.213136 0.128761 +v 0.424210 -0.198510 0.122813 +v 0.412692 -0.228777 0.130776 +v 0.209293 0.059397 0.197967 +v -0.204302 -0.346803 -0.096026 +v -0.220275 -0.340849 -0.082730 +v -0.209430 -0.323412 -0.083096 +v -0.152109 -0.041824 0.210542 +v 0.246968 -0.286305 0.221051 +v -0.090789 -0.162614 0.180671 +v -0.097671 -0.196325 0.163364 +v -0.078615 -0.201446 0.180134 +v -0.224014 0.356857 -0.043785 +v -0.004560 0.177222 0.061145 +v -0.135316 -0.327245 -0.115743 +v -0.184260 -0.325089 -0.097190 +v -0.115604 -0.307581 -0.112636 +v -0.164330 -0.126582 0.189892 +v -0.141358 -0.121053 0.194281 +v -0.144389 -0.017688 0.212681 +v -0.142528 0.050047 0.191782 +v 0.215443 -0.160523 0.275383 +v 0.215395 0.084206 0.192715 +v 0.191124 0.083545 0.198551 +v -0.184095 0.308775 -0.098702 +v -0.182027 0.309720 -0.079008 +v -0.188295 0.284917 -0.097704 +v 0.254930 0.052303 0.214695 +v 0.168323 -0.259517 0.260716 +v 0.198407 0.029455 0.223803 +v -0.235497 0.333324 -0.317370 +v -0.226979 0.352799 -0.349917 +v -0.211089 0.163075 -0.106074 +v -0.181449 0.164150 -0.105276 +v -0.142109 -0.077868 0.212267 +v -0.140685 0.074194 0.179425 +v 0.183563 -0.108093 0.290274 +v 0.172021 -0.083780 0.286511 +v 0.149084 -0.095358 0.288968 +v 0.542106 -0.197908 0.038645 +v 0.542898 -0.173512 0.029094 +v 0.539147 -0.174186 0.056018 +v -0.127719 -0.318155 0.219267 +v -0.153586 -0.320523 0.220041 +v -0.031141 0.158409 0.109995 +v 0.002422 0.122814 0.140640 +v -0.200126 0.232375 -0.101242 +v -0.204562 0.285951 -0.127793 +v -0.218762 0.287829 -0.141964 +v -0.139976 -0.147079 0.175898 +v -0.134796 -0.086320 0.209999 +v -0.132533 -0.058091 0.214317 +v -0.140667 0.026342 0.200276 +v -0.135983 0.114213 0.152365 +v 0.453751 -0.223154 0.135519 +v 0.425031 -0.239965 0.135655 +v 0.310833 -0.022602 0.230331 +v 0.306090 0.008391 0.223998 +v 0.284435 0.011374 0.226775 +v -0.127247 -0.298053 0.207294 +v 0.404210 -0.340660 0.034062 +v 0.394499 -0.346466 0.004527 +v -0.141730 -0.276428 0.174067 +v -0.168530 -0.346413 -0.109541 +v -0.129604 -0.102009 0.202521 +v -0.128511 -0.025207 0.209810 +v 0.138080 -0.265884 0.247732 +v 0.262402 0.009194 0.234507 +v 0.263844 0.032976 0.226851 +v 0.456982 -0.196531 0.125069 +v 0.456409 -0.169572 0.104903 +v 0.307779 -0.052397 0.238541 +v 0.289728 -0.025296 0.234288 +v 0.437678 -0.168190 0.106002 +v 0.438310 -0.185391 0.112169 +v 0.454235 -0.151763 0.085647 +v 0.497173 -0.280185 -0.023672 +v 0.520328 -0.257562 -0.010606 +v 0.519282 -0.263835 0.009318 +v 0.304200 0.030944 0.216851 +v -0.057516 -0.289790 -0.159443 +v -0.036859 -0.293883 -0.196562 +v -0.064799 -0.306199 -0.180507 +v -0.116957 0.234413 0.109487 +v -0.097328 0.210248 0.097313 +v 0.133785 -0.206874 0.273250 +v 0.109632 -0.198156 0.268023 +v 0.113365 -0.222622 0.258146 +v 0.013166 -0.330169 0.261436 +v 0.008453 -0.346390 0.256616 +v -0.111328 -0.081931 0.208008 +v -0.122397 0.001634 0.206083 +v -0.122958 0.026738 0.198870 +v -0.115592 0.083320 0.172768 +v -0.109969 0.107739 0.153984 +v 0.150213 -0.175391 0.278354 +v 0.183510 -0.152950 0.280758 +v 0.154631 -0.150782 0.282607 +v 0.303089 0.071749 0.184735 +v 0.300301 0.101484 0.168320 +v 0.273590 0.121290 0.165290 +v 0.415840 0.067998 0.067341 +v 0.403778 0.091336 0.057660 +v -0.115575 -0.112429 0.201357 +v -0.120005 0.057802 0.184871 +v 0.200350 -0.094956 0.281579 +v 0.236985 0.070437 0.190164 +v -0.126857 -0.275778 0.175325 +v -0.106366 -0.288083 0.189732 +v -0.109715 -0.268430 0.165319 +v -0.105267 -0.052923 0.214435 +v -0.113366 -0.037429 0.213466 +v -0.104133 -0.024203 0.209148 +v 0.260855 0.109175 0.172797 +v 0.183457 -0.011698 0.273776 +v 0.171507 0.095996 0.197216 +v -0.181437 0.348865 -0.165798 +v -0.183026 0.363196 -0.158822 +v -0.183699 0.333649 -0.140127 +v -0.110932 -0.307629 0.209184 +v 0.533394 -0.189331 0.073910 +v -0.216022 0.300488 -0.191281 +v -0.222614 0.307464 -0.223219 +v -0.208443 0.316218 -0.239989 +v -0.106366 0.055162 0.184599 +v 0.459799 -0.239008 0.135430 +v -0.272917 0.344281 0.129039 +v -0.260430 0.337565 0.149589 +v -0.134754 0.294197 -0.060006 +v -0.112769 0.284622 -0.044506 +v -0.244310 -0.353129 -0.011929 +v -0.241215 -0.340288 -0.029951 +v -0.238155 -0.358717 -0.028628 +v -0.103005 0.007511 0.207530 +v -0.096932 0.033259 0.196697 +v 0.389962 -0.307327 0.117574 +v 0.375762 -0.294444 0.125625 +v 0.166492 -0.135832 0.290132 +v 0.146533 -0.135844 0.288986 +v 0.163243 -0.310239 0.227371 +v 0.145682 -0.296205 0.227141 +v 0.095686 -0.310765 0.250190 +v -0.095686 -0.275997 0.177665 +v -0.091593 -0.239882 0.168568 +v -0.113525 -0.256067 0.147598 +v -0.095822 -0.115961 0.198356 +v -0.108191 -0.128448 0.192709 +v -0.096383 0.066013 0.183802 +v -0.087346 0.081926 0.175461 +v -0.206730 0.277634 -0.108844 +v -0.192418 0.290074 -0.120770 +v -0.076152 -0.260633 0.176784 +v -0.083855 -0.075593 0.202208 +v -0.085656 -0.060212 0.207394 +v -0.078769 -0.001899 0.200383 +v -0.084067 -0.024688 0.202037 +v -0.356246 0.296825 0.078133 +v -0.352465 0.301693 0.034020 +v -0.357829 0.284504 0.051635 +v 0.237936 -0.275897 0.238069 +v -0.074073 0.431473 -0.039615 +v -0.079212 -0.303517 0.198681 +v -0.078290 -0.044458 0.203366 +v -0.086666 0.150913 0.109960 +v -0.105379 0.133092 0.133091 +v 0.118628 0.512965 -0.219096 +v 0.123667 0.494860 -0.227939 +v 0.112278 0.508405 -0.225116 +v 0.184337 0.054849 0.205126 +v -0.214232 0.353798 -0.358216 +v -0.209896 0.345002 -0.343466 +v -0.091404 0.378022 -0.007369 +v -0.348661 0.320725 0.023542 +v -0.332742 0.327441 0.006512 +v -0.073872 -0.283694 0.184511 +v -0.220470 0.426116 -0.194984 +v 0.384209 -0.097608 -0.157606 +v 0.365702 -0.078045 -0.171829 +v 0.383524 -0.068151 -0.163501 +v -0.081569 -0.139429 0.194216 +v -0.081964 -0.096787 0.196649 +v -0.075674 0.025066 0.196898 +v -0.077162 0.053963 0.190737 +v -0.069312 0.136914 0.127562 +v 0.067108 0.412973 -0.157470 +v 0.091303 0.401325 -0.150310 +v -0.001595 0.351010 -0.098820 +v 0.017490 0.368589 -0.118425 +v 0.040840 0.364430 -0.099830 +v -0.083412 0.364867 -0.010902 +v -0.074096 0.394183 -0.019366 +v -0.068284 -0.107426 0.199384 +v -0.060906 0.100811 0.158444 +v -0.054119 0.127084 0.138283 +v -0.107760 0.281485 -0.000452 +v -0.117713 0.295467 0.030896 +v 0.496074 -0.287321 0.008142 +v 0.470721 -0.197293 0.125802 +v -0.063789 -0.150930 0.193601 +v -0.063889 -0.083272 0.197329 +v -0.065833 0.072014 0.179608 +v -0.195229 0.316590 -0.206444 +v 0.225254 -0.180051 0.274963 +v 0.185678 -0.173902 0.280693 +v -0.060983 0.427090 -0.034098 +v -0.112166 -0.246433 0.042562 +v -0.063198 -0.230472 0.181622 +v -0.064244 -0.050028 0.197795 +v -0.060729 0.019868 0.193330 +v -0.360918 0.191617 0.122287 +v -0.184561 0.404532 -0.346833 +v 0.178566 0.036797 0.208162 +v -0.059453 -0.307646 0.195403 +v -0.046074 -0.219651 0.183713 +v -0.047291 -0.189650 0.190991 +v -0.049252 -0.100733 0.200064 +v -0.181779 0.433990 -0.364282 +v -0.186971 -0.295336 0.151060 +v -0.166776 -0.282961 0.148396 +v 0.161152 0.061908 0.206727 +v 0.128688 0.072339 0.203230 +v 0.138074 0.058978 0.205415 +v -0.045802 -0.288360 0.184977 +v -0.041136 -0.263339 0.178698 +v -0.042299 -0.155573 0.193725 +v -0.048307 -0.068227 0.203507 +v -0.048732 -0.032981 0.201593 +v -0.050551 0.041186 0.186212 +v -0.103276 0.243386 -0.013253 +v -0.101918 0.250267 0.024782 +v 0.131116 0.437599 -0.187441 +v 0.122255 0.422353 -0.181907 +v 0.126378 0.437723 -0.199692 +v -0.001052 0.345203 -0.081064 +v 0.010160 0.356314 -0.060490 +v -0.032358 -0.118696 0.194676 +v -0.030238 0.003039 0.203968 +v -0.046068 0.068807 0.172472 +v -0.025246 0.101992 0.153612 +v -0.040581 0.118667 0.142530 +v -0.030297 0.139329 0.127734 +v -0.055950 0.162343 0.101838 +v -0.319859 0.343886 0.066916 +v -0.328690 0.340395 0.038226 +v -0.340799 0.333815 0.065197 +v -0.056836 0.408637 -0.031334 +v -0.039441 0.442543 -0.045043 +v -0.036020 0.459023 -0.058570 +v 0.165299 0.141432 0.173075 +v 0.184360 0.165249 0.151810 +v 0.146202 0.158480 0.157664 +v -0.047255 -0.311734 0.191540 +v 0.535981 -0.189508 -0.018327 +v 0.535827 -0.204831 -0.018959 +v -0.034355 0.435998 -0.045622 +v -0.023852 -0.157250 0.190979 +v -0.031454 -0.082871 0.201499 +v -0.032872 -0.053738 0.204163 +v -0.032872 -0.037181 0.202385 +v -0.026357 -0.015148 0.207861 +v -0.028064 0.027340 0.196620 +v -0.029806 0.065924 0.174817 +v 0.184307 -0.128094 0.287356 +v 0.428806 0.045250 0.044476 +v 0.441411 0.013040 0.048823 +v 0.302126 -0.356408 -0.064666 +v 0.304767 -0.352131 -0.075789 +v -0.029363 -0.287527 0.187198 +v -0.018447 -0.263811 0.172697 +v -0.018938 -0.242688 0.171362 +v -0.019310 -0.203206 0.180128 +v -0.011129 -0.109434 0.190370 +v -0.005795 0.081418 0.171616 +v 0.242077 0.087768 0.182496 +v 0.233719 0.107391 0.181599 +v 0.164992 -0.115010 0.293369 +v -0.032293 0.420687 -0.055121 +v -0.022700 -0.072616 0.200028 +v -0.011093 -0.053141 0.197943 +v -0.012162 -0.039030 0.204659 +v -0.014189 0.051139 0.187181 +v -0.018979 0.455928 -0.059255 +v 0.011831 0.478569 -0.086675 +v -0.130797 0.339964 0.042320 +v -0.142882 0.349946 0.042007 +v -0.008920 -0.162153 0.183554 +v -0.012192 -0.076284 0.193761 +v 0.131789 0.001291 0.268153 +v 0.149551 0.012809 0.258099 +v -0.003869 -0.026336 0.207471 +v 0.140206 0.128490 0.178592 +v 0.139568 0.098389 0.194871 +v 0.003337 -0.240815 0.163293 +v 0.005363 -0.193194 0.170901 +v 0.011447 -0.005266 0.211299 +v 0.001843 0.010240 0.210294 +v -0.241616 0.321776 -0.285396 +v -0.242910 0.334836 -0.298851 +v -0.364616 0.164735 0.162283 +v 0.002239 -0.089274 0.193442 +v 0.011985 0.040123 0.198374 +v 0.493268 -0.182254 0.113604 +v 0.481885 -0.164740 0.105151 +v 0.311891 -0.339792 -0.081229 +v 0.011430 -0.151391 0.179094 +v 0.011365 -0.118212 0.189827 +v 0.007076 -0.057766 0.204943 +v 0.011447 -0.027931 0.207849 +v 0.016764 0.015367 0.205037 +v 0.453520 -0.041522 0.024067 +v 0.447838 -0.014102 0.051877 +v 0.386536 -0.255476 0.140043 +v 0.143443 -0.063490 0.284237 +v -0.008370 0.471404 -0.068783 +v 0.006994 0.489857 -0.084383 +v 0.021513 -0.089882 0.228287 +v 0.022352 -0.065410 0.234483 +v 0.525272 -0.183253 -0.037932 +v 0.528981 -0.160157 -0.019638 +v 0.247824 0.210348 0.031262 +v 0.018778 -0.201464 0.167883 +v 0.018465 -0.240000 0.163842 +v 0.421605 0.042143 -0.065298 +v 0.405208 0.078719 -0.051447 +v 0.248657 0.184027 0.122908 +v 0.244103 0.159697 0.151627 +v 0.457974 -0.124644 0.054960 +v 0.453190 -0.069958 0.062917 +v -0.198573 0.336248 -0.267196 +v -0.189582 0.338321 -0.243787 +v 0.020438 -0.263917 0.202556 +v 0.007897 -0.285891 0.228582 +v 0.027827 -0.279783 0.237891 +v 0.024419 -0.166383 0.180884 +v 0.032825 0.020861 0.207695 +v 0.037083 0.100001 0.168408 +v 0.031371 0.053668 0.195864 +v 0.181425 0.145638 -0.133854 +v 0.189186 0.127108 -0.155863 +v 0.173114 0.122613 -0.154871 +v 0.191596 -0.066957 0.285873 +v -0.220653 0.260569 -0.099558 +v -0.183605 0.336797 -0.186827 +v 0.031383 -0.227371 0.177989 +v 0.034419 -0.192651 0.186614 +v 0.041945 -0.161108 0.213407 +v -0.363121 0.151563 0.192450 +v -0.366287 0.147776 0.170500 +v -0.360682 0.135779 0.189921 +v 0.399100 -0.225558 0.145023 +v 0.027284 -0.011173 0.212208 +v 0.059382 0.083533 0.187045 +v 0.036918 0.122548 0.147941 +v 0.049801 -0.267568 0.221842 +v -0.143833 0.318226 -0.065032 +v -0.111623 0.323672 -0.074968 +v 0.478105 -0.147356 0.086728 +v 0.235437 0.199444 0.101052 +v 0.277506 0.199846 0.024735 +v 0.040167 0.004044 0.209018 +v 0.051319 -0.287474 0.253025 +v 0.048620 -0.260852 0.206012 +v 0.037757 -0.251489 0.187783 +v -0.193593 0.305774 0.173867 +v 0.049086 0.045280 0.203761 +v 0.075071 0.380969 -0.119429 +v 0.100163 0.392765 -0.132306 +v 0.040255 0.506733 -0.111526 +v 0.027833 0.507176 -0.101189 +v 0.041779 0.523515 -0.121650 +v 0.029552 -0.311190 0.261472 +v 0.055011 -0.302188 0.261052 +v 0.052063 -0.278259 0.242641 +v 0.092543 0.054223 0.200064 +v 0.094865 0.028049 0.209402 +v 0.115657 0.034830 0.207583 +v -0.336399 0.013938 -0.019910 +v -0.023787 0.176443 0.074347 +v 0.075591 0.533131 -0.154676 +v 0.094327 0.528400 -0.183744 +v 0.082159 0.542340 -0.171463 +v 0.052087 0.017878 0.210974 +v 0.250406 -0.168923 0.265412 +v -0.211999 0.505310 -0.387898 +v -0.124831 -0.260474 0.091182 +v -0.123756 -0.229651 0.104094 +v -0.116579 -0.244354 0.063224 +v 0.060829 0.111721 0.170257 +v -0.171738 0.284769 -0.075848 +v 0.283242 -0.038610 0.244980 +v 0.290767 -0.068275 0.249487 +v 0.066772 -0.257384 0.219102 +v 0.056653 -0.226497 0.215114 +v -0.043197 -0.131969 -0.156838 +v -0.024118 -0.142436 -0.159850 +v -0.024845 -0.167546 -0.144628 +v 0.280631 0.161480 0.131874 +v 0.265775 0.165633 0.138537 +v 0.282078 0.140115 0.153535 +v 0.064751 0.041127 0.204683 +v 0.484254 -0.223715 0.123758 +v 0.481956 -0.205965 0.125199 +v 0.080611 -0.278909 0.234979 +v -0.355182 0.314865 0.042650 +v -0.353375 0.317057 0.073585 +v -0.347515 0.328729 0.039597 +v 0.282911 0.187353 -0.052138 +v -0.128883 -0.271791 0.147191 +v -0.154147 -0.282831 0.123102 +v -0.080706 0.301917 -0.043342 +v 0.077510 0.058228 0.199378 +v -0.033977 -0.343040 -0.228973 +v -0.055301 -0.332532 -0.215098 +v -0.016404 -0.319897 -0.228654 +v 0.243920 -0.110539 0.272943 +v 0.232525 -0.085210 0.273640 +v 0.092561 -0.294746 0.245748 +v 0.077841 -0.267367 0.223862 +v 0.084286 -0.255990 0.232788 +v 0.012599 0.179461 -0.007606 +v 0.240340 0.208145 0.068907 +v -0.231746 0.272371 -0.103421 +v 0.051780 -0.070277 0.274916 +v 0.062607 -0.092204 0.277415 +v 0.071149 -0.069149 0.284521 +v 0.140962 -0.125589 0.288980 +v 0.277276 -0.011681 0.241530 +v 0.085632 -0.046750 0.281709 +v 0.065909 -0.042231 0.274904 +v 0.072708 0.022396 0.209337 +v 0.085573 0.121119 0.170139 +v 0.359406 -0.139843 -0.179166 +v 0.339659 -0.147321 -0.194506 +v 0.334644 -0.124556 -0.200767 +v 0.220511 -0.069556 0.280073 +v -0.065295 0.454445 -0.078146 +v 0.079064 -0.104525 0.277846 +v 0.083801 -0.074577 0.286334 +v 0.088196 -0.241530 0.243704 +v 0.075845 -0.222640 0.240490 +v 0.081273 -0.150759 0.266050 +v 0.094144 -0.143369 0.271454 +v 0.094150 -0.019844 0.276251 +v 0.070050 -0.018060 0.264461 +v 0.266319 0.193313 0.094867 +v 0.115899 -0.362013 -0.177819 +v 0.105196 -0.359255 -0.165828 +v 0.044355 -0.363573 -0.190602 +v 0.094510 0.076173 0.196703 +v 0.101528 0.144392 0.160682 +v 0.105184 -0.279334 0.229391 +v 0.091344 -0.202952 0.255860 +v 0.099384 -0.240727 0.246084 +v 0.097074 -0.174829 0.263929 +v 0.098185 -0.109865 0.280244 +v 0.094121 -0.072303 0.282855 +v 0.103690 -0.031859 0.281313 +v 0.099153 -0.003505 0.265483 +v -0.307035 0.304569 -0.035285 +v -0.304513 0.276370 -0.046054 +v 0.262302 0.203195 0.062852 +v 0.107665 0.122595 0.176442 +v 0.110961 0.162236 0.144946 +v 0.472133 -0.294852 -0.039857 +v 0.440195 -0.138844 -0.066627 +v 0.102810 -0.143499 0.269629 +v 0.110896 -0.058824 0.284822 +v 0.112154 -0.270013 0.238842 +v 0.114086 -0.129937 0.278809 +v 0.116963 -0.090402 0.287368 +v 0.108451 0.055463 0.203295 +v 0.115604 0.086569 0.197441 +v 0.330468 0.092322 0.163494 +v 0.122468 -0.245110 0.253462 +v 0.123437 -0.155089 0.273138 +v 0.125439 -0.111277 0.285537 +v 0.117937 -0.016631 0.277952 +v 0.119951 -0.037535 0.281266 +v 0.448175 -0.014723 -0.040182 +v 0.139096 0.046449 0.204742 +v -0.040982 -0.110999 -0.163583 +v -0.149917 -0.276594 0.162779 +v 0.116909 -0.179803 0.270941 +v 0.133980 -0.066107 0.286812 +v 0.139669 0.029721 0.227058 +v 0.090476 0.010872 0.242711 +v 0.147230 0.035646 0.208351 +v -0.336782 0.047046 0.049969 +v 0.273064 -0.291952 0.205232 +v 0.271269 -0.309903 0.209461 +v 0.248775 -0.054075 0.269848 +v 0.062395 0.515050 -0.137918 +v -0.087989 0.431296 -0.049102 +v 0.362383 0.031339 0.179307 +v 0.338413 0.033720 0.193058 +v 0.354385 0.009047 0.196159 +v -0.001040 0.371648 -0.042155 +v 0.034295 0.373426 -0.062197 +v 0.028873 0.380715 -0.056515 +v 0.245645 -0.212764 0.256563 +v 0.243193 -0.191658 0.265571 +v 0.093766 -0.354033 0.242682 +v 0.128192 -0.349709 0.238547 +v 0.079460 -0.347866 0.255016 +v 0.328377 0.016749 0.210507 +v 0.324644 0.000245 0.220312 +v 0.507374 -0.180069 0.105913 +v 0.502820 -0.199591 0.113527 +v 0.285640 -0.130634 0.252682 +v 0.291151 -0.114443 0.256587 +v 0.267311 -0.109452 0.266823 +v 0.505820 -0.217601 0.109889 +v 0.419904 -0.182054 0.133717 +v 0.405799 -0.201535 0.149542 +v 0.442699 -0.040116 -0.074549 +v -0.049116 -0.340412 0.199780 +v -0.071734 -0.347890 0.206697 +v 0.519814 -0.186011 0.095907 +v 0.490297 -0.247526 0.111507 +v -0.047143 0.366273 -0.115950 +v -0.014413 0.364654 -0.118579 +v 0.267199 -0.251974 0.233585 +v 0.298895 -0.259080 0.211169 +v 0.297619 -0.236362 0.228434 +v 0.341520 -0.281018 -0.150494 +v 0.329292 -0.301556 -0.117374 +v 0.314366 -0.296458 -0.156991 +v 0.343788 -0.199863 -0.185132 +v 0.366937 -0.204754 -0.160565 +v 0.365301 -0.223762 -0.151025 +v 0.046286 0.388985 -0.072274 +v 0.011312 0.391171 -0.065883 +v 0.269957 -0.199644 0.244850 +v 0.282043 -0.170777 0.247856 +v 0.260495 -0.182981 0.256309 +v -0.114080 0.274184 0.042780 +v -0.097423 -0.348888 -0.132023 +v -0.236011 0.253971 0.229214 +v 0.272220 -0.229374 0.239073 +v 0.253554 -0.227436 0.253196 +v -0.107329 0.318699 0.013140 +v 0.044928 -0.343454 0.266374 +v 0.025039 -0.348493 0.261690 +v 0.048708 -0.351747 0.258814 +v -0.227895 0.231832 0.231642 +v 0.382206 0.085535 -0.094738 +v 0.408374 0.057330 -0.072375 +v 0.400937 0.050484 -0.100486 +v -0.207445 0.166513 0.245529 +v -0.156267 -0.264366 -0.026218 +v -0.147011 -0.246380 -0.009909 +v -0.152924 -0.240750 -0.039633 +v 0.303219 0.137723 0.148981 +v 0.385756 0.011061 0.168586 +v 0.356954 0.066970 0.162679 +v 0.353906 0.049734 0.171214 +v 0.289173 -0.218186 0.235186 +v -0.034833 0.382074 -0.043945 +v -0.222667 0.088843 0.176944 +v 0.043274 0.392594 -0.139129 +v 0.514710 -0.248294 0.083573 +v 0.489588 -0.273634 0.089185 +v -0.280165 -0.150771 0.016311 +v -0.210505 0.143736 0.250692 +v -0.209825 0.218110 0.215197 +v -0.023764 0.412034 -0.069291 +v -0.202123 0.131952 0.234424 +v -0.218024 0.125750 0.248689 +v -0.214563 0.112583 0.230289 +v -0.009569 0.379847 -0.040483 +v -0.195076 0.161008 0.230124 +v 0.449238 -0.116156 0.083319 +v 0.450797 -0.298632 0.097272 +v 0.473710 -0.298934 0.068576 +v -0.187905 0.146571 0.213750 +v -0.195920 0.183702 0.222102 +v 0.524882 -0.199585 0.089504 +v 0.518934 -0.225706 0.090036 +v 0.409248 -0.174274 0.154072 +v 0.396661 -0.168415 0.169714 +v 0.392939 -0.198185 0.168680 +v 0.413283 -0.001344 0.138638 +v 0.416272 0.035905 0.109286 +v 0.401303 0.023708 0.140516 +v -0.030982 -0.009158 -0.192474 +v -0.047539 0.023649 -0.182893 +v -0.203316 0.106995 0.196519 +v -0.223913 0.099641 0.214246 +v -0.191520 0.121290 0.198014 +v -0.202282 0.265407 0.190554 +v 0.534097 -0.229297 0.002383 +v 0.517404 -0.162567 0.088128 +v 0.411274 -0.115376 0.153588 +v 0.402585 -0.090408 0.166270 +v 0.393707 -0.130569 0.173855 +v 0.354172 -0.074595 0.209562 +v 0.352069 -0.042355 0.207831 +v 0.337007 -0.039573 0.222132 +v 0.506322 -0.155850 0.091371 +v -0.190126 0.207861 0.192686 +v 0.321123 -0.215764 0.217501 +v 0.329913 -0.185993 0.213567 +v 0.313550 -0.202639 0.225835 +v 0.397677 -0.063455 0.170635 +v 0.411085 -0.045433 0.154385 +v 0.387404 -0.048723 0.186212 +v -0.179163 0.168669 0.200914 +v 0.055460 0.067330 -0.185339 +v 0.084037 0.067998 -0.183425 +v 0.066110 0.044902 -0.191635 +v 0.289893 -0.092528 0.258193 +v 0.108014 0.493868 -0.187099 +v 0.118658 0.500549 -0.207011 +v -0.195560 0.233054 0.182502 +v 0.258214 -0.033005 0.261944 +v 0.303066 -0.185066 0.229604 +v 0.468152 -0.272967 0.112913 +v 0.067740 0.431851 -0.130369 +v 0.116561 0.449690 -0.169248 +v 0.090760 0.471770 -0.163642 +v -0.192170 0.103729 0.171049 +v 0.433508 -0.096403 0.118950 +v -0.186558 0.251626 0.163205 +v -0.045395 0.048192 -0.175379 +v -0.011944 0.062622 -0.175421 +v 0.419863 -0.147002 0.139819 +v 0.343646 -0.259097 0.175449 +v 0.368981 -0.249965 0.164593 +v 0.355200 -0.230703 0.185119 +v 0.299285 -0.321173 0.198421 +v 0.312304 -0.324995 0.187819 +v 0.317821 -0.304557 0.188167 +v 0.336705 -0.288579 0.172644 +v 0.295983 -0.300847 0.200601 +v 0.311961 -0.277946 0.186921 +v 0.345253 -0.299087 0.160097 +v 0.329263 -0.276511 -0.169662 +v -0.176711 0.128975 0.180778 +v -0.166545 0.146495 0.186058 +v -0.169865 0.189497 0.187376 +v -0.176906 0.216202 0.176418 +v -0.182913 0.241100 0.163335 +v -0.184662 0.269748 0.164900 +v 0.327632 -0.237590 0.201056 +v -0.177893 0.295455 0.165916 +v -0.040214 0.072853 -0.171451 +v -0.154495 0.166690 0.184186 +v -0.149350 -0.339638 0.223106 +v -0.116868 -0.335923 0.219952 +v -0.010615 -0.170216 -0.162059 +v 0.299581 -0.207790 0.233479 +v 0.088143 0.384726 -0.110711 +v 0.058850 0.376256 -0.081170 +v 0.056635 0.368902 -0.093988 +v 0.105893 0.419925 -0.136860 +v 0.119278 0.419571 -0.148249 +v -0.216022 0.367212 -0.372322 +v -0.202784 0.374448 -0.381879 +v -0.152700 0.120729 0.162118 +v 0.049051 0.465149 -0.132791 +v 0.078036 0.505623 -0.160388 +v 0.283077 -0.276103 0.204553 +v 0.322807 0.126299 0.144645 +v -0.152026 0.183430 0.179437 +v -0.159959 0.270616 0.138171 +v -0.170296 0.281544 0.155945 +v -0.165098 0.326153 0.150274 +v -0.061934 0.323578 -0.026632 +v 0.086530 0.402075 -0.108076 +v 0.050669 0.397668 -0.089322 +v 0.078491 0.389599 -0.093073 +v -0.145783 0.133269 0.166595 +v -0.139084 0.150813 0.167765 +v -0.143757 0.203077 0.162726 +v -0.159622 0.221678 0.164622 +v -0.146804 0.248855 0.135395 +v -0.160190 0.257976 0.141101 +v -0.161985 0.302378 0.146252 +v 0.516766 -0.161917 -0.037784 +v -0.047781 0.335929 -0.092559 +v -0.135818 0.166560 0.168503 +v -0.111918 -0.143233 0.179756 +v -0.082868 -0.332810 0.209426 +v 0.027166 0.357342 -0.078240 +v 0.066476 0.411803 -0.112465 +v -0.123962 0.324617 0.049615 +v 0.294028 -0.353750 -0.104715 +v 0.326587 -0.063136 0.231801 +v 0.333457 -0.097207 0.230236 +v 0.262355 -0.335090 0.209408 +v -0.130171 0.218783 0.141343 +v -0.151347 0.295142 0.134030 +v -0.086087 -0.354264 0.203602 +v -0.137182 -0.355445 0.211617 +v -0.131405 -0.358085 0.199254 +v 0.313456 -0.243680 0.212958 +v -0.118948 -0.277096 -0.100303 +v -0.089815 -0.281703 -0.113032 +v -0.122639 0.180034 0.150853 +v -0.147023 0.323849 0.122973 +v -0.108681 -0.349006 0.217997 +v 0.269379 -0.089173 0.264077 +v 0.354361 -0.306152 0.136499 +v 0.379371 0.073727 0.135070 +v 0.355850 0.096369 0.146234 +v 0.398563 -0.141532 0.165780 +v 0.381255 -0.166140 0.181221 +v 0.308175 -0.152673 0.236007 +v 0.318193 -0.118330 0.237832 +v 0.322322 -0.148296 0.224246 +v -0.124618 0.133316 0.146015 +v -0.139114 0.280522 0.117733 +v 0.437176 -0.056857 0.111194 +v -0.236211 0.308462 -0.216432 +v -0.239490 0.301208 -0.180855 +v 0.312599 -0.088193 0.244401 +v -0.109195 0.150370 0.136529 +v -0.140177 0.303861 0.114532 +v -0.019658 0.350242 -0.043709 +v 0.361692 -0.194996 0.191953 +v 0.357622 -0.169360 0.196342 +v 0.053942 0.521607 -0.124899 +v -0.117689 -0.130598 -0.149401 +v 0.378981 -0.128064 0.185698 +v 0.359861 -0.144923 0.192591 +v 0.404664 -0.324711 -0.058523 +v 0.442782 -0.299188 -0.060910 +v 0.439905 -0.314941 -0.041269 +v -0.171100 -0.318852 0.208186 +v -0.129350 0.250249 0.113510 +v 0.126868 0.426523 -0.167813 +v 0.118114 0.409458 -0.148863 +v 0.375632 -0.008538 0.188078 +v 0.415185 0.077437 0.024174 +v 0.379341 -0.197335 0.181528 +v 0.074734 0.480530 -0.154132 +v 0.012818 -0.259410 -0.184447 +v 0.033386 -0.258182 -0.212262 +v 0.030308 -0.280510 -0.207915 +v -0.108433 0.175622 0.134255 +v -0.108262 0.202687 0.125282 +v 0.262084 -0.064801 0.260001 +v 0.355371 -0.124597 0.203182 +v 0.354456 -0.018007 0.205976 +v 0.366612 -0.095588 0.202840 +v 0.337190 -0.116044 0.220726 +v 0.382496 -0.216585 0.172845 +v 0.377664 -0.036696 0.195905 +v 0.364013 -0.060377 0.200607 +v -0.133803 0.322727 0.094614 +v -0.354468 0.122318 0.092481 +v -0.093382 0.182090 0.105949 +v 0.325092 0.064885 0.179147 +v 0.343746 -0.208091 0.203224 +v -0.353611 0.276547 0.074902 +v -0.353056 0.258560 0.049154 +v 0.338401 -0.160511 0.205876 +v 0.335743 -0.145496 0.209639 +v -0.098433 0.159307 0.116859 +v 0.173935 -0.329041 0.225723 +v 0.324041 -0.258176 0.189041 +v 0.334591 -0.243078 -0.181582 +v 0.355850 -0.236102 -0.160027 +v 0.342335 -0.258477 -0.172975 +v -0.153072 -0.290528 0.105234 +v -0.184792 -0.303966 0.114850 +v -0.044249 0.387024 -0.126452 +v 0.426744 -0.027883 0.123097 +v -0.250004 -0.007670 -0.140594 +v -0.262639 0.025155 -0.123913 +v -0.244658 0.015249 -0.138715 +v 0.324484 -0.357430 -0.029892 +v 0.355992 -0.350761 -0.032409 +v 0.392408 -0.025662 0.178001 +v 0.527823 -0.250219 0.036224 +v 0.537399 -0.226479 0.025361 +v 0.379282 -0.067335 0.192491 +v -0.036103 0.409405 -0.133948 +v -0.013946 -0.347553 0.236515 +v -0.023427 -0.334304 0.228499 +v -0.033782 -0.350022 0.211139 +v -0.327804 -0.073934 0.036176 +v 0.433189 -0.150410 0.113817 +v 0.212938 -0.337990 0.217483 +v -0.157378 -0.151473 -0.138609 +v -0.121050 -0.167345 -0.125047 +v -0.121233 -0.340010 -0.122938 +v -0.093920 -0.321811 -0.123570 +v -0.234552 0.288638 -0.141515 +v 0.470739 -0.138124 -0.018008 +v 0.418120 -0.296772 0.123705 +v 0.051024 -0.322313 0.265435 +v 0.032683 -0.332680 0.266469 +v 0.434022 -0.293842 0.118087 +v 0.300165 -0.336383 -0.127339 +v 0.313999 -0.309087 -0.139318 +v 0.312339 -0.323429 -0.109352 +v -0.324183 -0.090083 0.031847 +v 0.106088 0.524478 -0.216007 +v 0.103199 0.530030 -0.204376 +v 0.253920 -0.143304 0.266942 +v -0.193504 0.339326 0.150221 +v 0.533228 -0.219881 0.066278 +v 0.518036 -0.259912 0.064335 +v 0.531657 -0.234371 0.056697 +v 0.521934 -0.142200 -0.006017 +v 0.517652 -0.149034 -0.024399 +v 0.501585 -0.136771 -0.013282 +v 0.518065 -0.266138 0.038480 +v 0.528993 -0.141739 0.023766 +v 0.537924 -0.157528 0.042072 +v -0.192276 0.416960 -0.408484 +v -0.184172 0.474127 -0.416647 +v -0.188082 0.489851 -0.410197 +v 0.080109 -0.332384 0.256085 +v 0.085426 -0.363685 -0.198913 +v -0.277843 0.434504 -0.251714 +v -0.261375 0.447593 -0.247674 +v 0.060776 0.536179 -0.142277 +v 0.369058 -0.113852 0.198764 +v -0.088102 0.341340 -0.000275 +v -0.012877 0.441143 -0.144711 +v 0.039222 0.501364 -0.164074 +v 0.024023 0.461569 -0.162963 +v -0.290112 -0.138691 0.041026 +v -0.080937 0.326939 -0.008297 +v -0.178548 0.457824 -0.397627 +v -0.185253 0.482084 -0.395004 +v -0.185087 0.454534 -0.365269 +v 0.331708 -0.310328 -0.094904 +v 0.013692 -0.353141 0.049030 +v -0.021590 -0.357134 0.150794 +v 0.008134 -0.359698 0.043141 +v -0.003036 0.043898 -0.185486 +v 0.312635 0.153601 0.128944 +v 0.296810 0.155160 0.135377 +v 0.274334 -0.139459 0.257939 +v -0.186452 0.406357 -0.404313 +v -0.336847 -0.004108 0.086799 +v -0.340126 0.010961 0.071057 +v -0.340510 -0.027753 0.071801 +v 0.001695 -0.282187 -0.200856 +v 0.446739 -0.078765 0.091577 +v 0.425327 -0.000068 0.115825 +v -0.251729 0.081365 0.178196 +v 0.450939 -0.142660 0.079634 +v -0.085001 0.303937 -0.020075 +v -0.062755 0.358192 -0.015326 +v -0.068426 0.366781 -0.022727 +v -0.076382 -0.013571 -0.185610 +v -0.117542 -0.007611 -0.182001 +v -0.117902 0.008486 -0.183968 +v 0.116602 -0.339886 0.243521 +v 0.122604 -0.334877 -0.016661 +v 0.086383 -0.336076 0.006890 +v 0.099992 -0.333938 -0.078872 +v -0.125162 0.305077 0.058392 +v -0.002103 -0.297953 -0.219315 +v 0.410625 -0.332857 -0.035179 +v 0.140596 -0.331930 0.235564 +v -0.061556 0.381578 -0.032562 +v 0.424712 -0.098678 -0.101968 +v -0.038968 0.356408 -0.027642 +v -0.309410 0.338924 -0.008084 +v -0.281736 0.344305 -0.029898 +v -0.307348 0.328067 -0.028569 +v 0.429178 -0.057134 -0.107545 +v -0.237546 0.174293 -0.104219 +v -0.032913 0.371188 -0.028729 +v 0.129544 0.484825 -0.220443 +v 0.127565 0.467116 -0.221158 +v -0.039606 0.394673 -0.051996 +v -0.176623 0.432129 -0.403097 +v 0.016427 0.505192 -0.099806 +v -0.245981 0.294900 -0.145928 +v -0.022553 -0.253108 -0.114574 +v -0.072566 0.173247 0.079563 +v -0.264765 0.404219 -0.159903 +v -0.270088 0.424698 -0.212534 +v -0.273076 0.398265 -0.176053 +v 0.104617 0.400563 -0.124338 +v -0.056535 -0.271106 -0.120120 +v 0.092910 0.536315 -0.199923 +v -0.336162 0.095536 0.055917 +v -0.092006 0.222463 -0.005485 +v -0.120596 -0.063555 -0.181050 +v -0.126975 -0.041115 -0.182734 +v -0.105173 -0.026282 -0.182326 +v -0.334621 0.285502 0.157469 +v -0.343948 0.285579 0.129216 +v -0.342187 0.255961 0.168993 +v -0.192429 0.377691 -0.349722 +v -0.329671 -0.051605 0.078984 +v -0.343812 0.022698 0.050046 +v -0.184254 0.342297 -0.224738 +v -0.182400 0.365027 -0.253020 +v -0.179635 0.364070 -0.206716 +v -0.180687 0.386894 -0.254562 +v -0.181342 0.382901 -0.205889 +v -0.359376 0.123653 0.158266 +v -0.172116 -0.335149 0.213809 +v -0.187533 -0.331492 0.198817 +v -0.182063 -0.347010 0.205970 +v -0.319310 0.092104 0.091489 +v -0.324768 0.077998 0.054317 +v -0.170911 -0.352237 0.211812 +v 0.078621 -0.336561 0.066119 +v 0.031791 -0.338563 0.064571 +v -0.319505 0.061057 0.084123 +v -0.312730 0.077608 0.092629 +v -0.368568 0.174635 0.101383 +v -0.362808 0.206775 0.095305 +v -0.071161 -0.288951 -0.122991 +v -0.355017 0.224094 0.092381 +v -0.183894 0.404798 -0.293417 +v -0.343386 0.244242 0.126464 +v 0.514131 -0.190624 -0.049379 +v -0.363245 0.128992 0.016778 +v 0.327432 -0.228742 -0.196727 +v 0.391203 -0.320198 0.105854 +v 0.355170 -0.330914 0.107420 +v 0.382555 -0.335970 0.081984 +v -0.014626 -0.359361 0.164593 +v -0.063399 -0.358629 0.142654 +v 0.362241 -0.052556 -0.174003 +v 0.393040 -0.045734 -0.154516 +v 0.129657 0.460524 -0.196390 +v 0.132811 0.459171 -0.211223 +v -0.365401 0.148160 0.012803 +v -0.360664 0.175456 0.187470 +v -0.346092 0.200053 0.200678 +v -0.137590 -0.290877 0.086025 +v -0.186954 0.335002 -0.108017 +v 0.293491 -0.336029 -0.154676 +v -0.121978 -0.275335 0.074412 +v -0.008423 -0.200341 -0.144734 +v 0.282462 -0.336608 -0.170914 +v 0.266579 -0.356195 -0.163400 +v 0.189375 0.023944 -0.197324 +v 0.225425 0.015054 -0.199946 +v 0.199559 0.010405 -0.221253 +v 0.407547 -0.091459 -0.131958 +v 0.410424 -0.062805 -0.138981 +v 0.399921 -0.077909 -0.149324 +v 0.376742 -0.244980 -0.118466 +v 0.395095 -0.230951 -0.106611 +v 0.380322 -0.260852 -0.096209 +v 0.255113 -0.349804 -0.181848 +v -0.328088 0.027973 -0.032462 +v 0.404972 -0.130474 -0.128089 +v 0.390813 -0.162088 -0.146093 +v 0.382088 -0.132146 -0.154079 +v 0.028134 -0.298343 -0.220089 +v -0.318536 -0.059095 0.098228 +v -0.337793 0.108909 -0.019059 +v -0.126674 -0.264313 0.118123 +v -0.335637 -0.050536 0.037907 +v 0.426792 -0.038143 -0.111272 +v 0.412467 -0.029703 -0.127587 +v 0.144955 0.041588 -0.192380 +v 0.133750 0.027996 -0.197294 +v 0.110754 0.045357 -0.194169 +v -0.177904 -0.361984 -0.108519 +v -0.192187 -0.362710 -0.100752 +v 0.350445 -0.096852 -0.185959 +v 0.365431 -0.114916 -0.176189 +v 0.414529 0.011262 -0.099411 +v 0.393323 0.017765 -0.124391 +v 0.400866 0.034346 -0.111632 +v -0.128357 -0.225280 0.070519 +v -0.344952 0.151226 -0.032645 +v -0.348626 0.126370 -0.019927 +v 0.394097 -0.112931 -0.138721 +v -0.332240 0.001704 -0.029644 +v 0.389419 -0.188551 -0.139973 +v 0.409295 -0.179390 -0.119270 +v 0.331797 -0.172980 -0.192669 +v 0.356759 -0.161444 -0.174068 +v 0.350782 -0.181876 -0.175716 +v -0.352300 0.162957 -0.017423 +v -0.062353 0.187217 -0.078110 +v -0.064628 0.195339 -0.047105 +v -0.034697 0.188841 -0.051358 +v 0.158293 0.184452 -0.094502 +v 0.205229 0.191783 -0.079841 +v 0.170089 0.163761 -0.114780 +v 0.116531 0.454977 -0.212026 +v 0.119751 0.480300 -0.226208 +v 0.115049 0.012845 0.251294 +v 0.303792 -0.343478 0.178846 +v 0.324065 -0.327352 0.165981 +v -0.345123 0.263032 0.119671 +v -0.345324 0.255400 0.148219 +v 0.402892 -0.007274 -0.122412 +v 0.359849 -0.251891 -0.149295 +v 0.359855 -0.264963 -0.136099 +v -0.351928 0.277935 0.100172 +v 0.285835 -0.353956 -0.140198 +v -0.237777 -0.104006 0.171368 +v -0.202991 -0.122577 0.177907 +v 0.079235 0.534821 -0.189603 +v 0.037491 0.003996 -0.202085 +v 0.071662 0.008155 -0.216368 +v 0.031891 -0.008290 -0.221140 +v 0.422119 -0.133168 -0.108318 +v 0.419922 -0.159542 -0.109984 +v -0.287141 0.049237 -0.092606 +v -0.256974 0.074897 -0.106901 +v 0.424624 -0.181380 -0.086486 +v 0.396324 -0.208310 -0.124143 +v 0.352258 -0.278301 -0.129341 +v 0.356706 -0.281945 -0.103711 +v 0.117766 0.409901 -0.161203 +v -0.274748 0.463684 -0.298468 +v -0.280696 0.460488 -0.305798 +v 0.413537 -0.208759 -0.091407 +v 0.282752 -0.343808 0.200548 +v 0.315854 -0.343359 0.142070 +v 0.297165 -0.351700 0.162986 +v -0.176451 -0.300009 0.019921 +v -0.157555 -0.287882 0.011893 +v -0.114683 -0.267337 0.059804 +v 0.152581 -0.362403 -0.186951 +v 0.192500 -0.356774 -0.190879 +v 0.222478 -0.359662 -0.176644 +v 0.413596 -0.220761 -0.084514 +v 0.411375 -0.237732 -0.089972 +v -0.047415 -0.080602 -0.174966 +v -0.026995 -0.105931 -0.167895 +v -0.202566 -0.292708 -0.026531 +v -0.183522 -0.287321 -0.010984 +v -0.156728 -0.274455 -0.010470 +v -0.354302 0.273269 0.039130 +v -0.237003 0.106753 0.238612 +v -0.200782 -0.341965 0.099853 +v -0.196322 -0.318367 0.113374 +v -0.188472 -0.328232 0.095293 +v 0.067770 -0.013376 -0.258053 +v 0.073293 -0.031563 -0.271963 +v 0.046629 -0.033749 -0.266263 +v 0.387375 0.058175 -0.113853 +v 0.379584 0.044612 -0.128987 +v -0.276691 -0.142867 0.072492 +v 0.440673 -0.019619 0.091489 +v -0.288671 0.127132 0.234578 +v -0.281577 0.138768 0.245570 +v 0.090954 0.032775 -0.193590 +v 0.149386 -0.356721 -0.196544 +v 0.165370 -0.348221 0.229326 +v 0.321489 -0.191316 -0.201411 +v -0.040994 -0.183229 -0.135142 +v -0.061302 -0.150079 -0.152538 +v 0.331785 -0.337145 0.120385 +v 0.082921 0.016986 -0.200679 +v -0.186080 0.426831 -0.323483 +v -0.122415 -0.289920 0.061263 +v -0.125286 -0.293765 0.051015 +v 0.430921 -0.151296 -0.089842 +v -0.105881 0.245063 0.060631 +v 0.124571 0.018008 -0.217259 +v 0.165943 0.019029 -0.215322 +v 0.135687 0.009425 -0.235447 +v 0.304424 -0.304321 -0.174287 +v 0.496688 -0.176920 -0.056473 +v 0.497976 -0.213650 -0.070496 +v 0.479529 -0.198292 -0.073922 +v 0.372661 -0.180305 -0.162573 +v -0.344083 0.307895 0.110137 +v 0.401138 0.094431 -0.030613 +v 0.286089 -0.300339 -0.189710 +v 0.133927 -0.331687 -0.130251 +v 0.070239 -0.333259 -0.137351 +v 0.118534 -0.336052 -0.145875 +v -0.048218 -0.352887 0.197547 +v -0.056588 -0.357447 0.185733 +v -0.325158 0.115105 -0.040401 +v -0.066665 -0.360277 -0.214483 +v -0.045725 -0.362769 -0.225009 +v -0.248462 0.337471 -0.264349 +v -0.253430 0.323082 -0.246079 +v -0.311359 -0.085009 -0.039899 +v -0.027733 -0.356809 -0.235654 +v 0.428245 0.025492 0.089941 +v 0.206771 -0.348817 -0.194500 +v -0.130909 0.288438 0.089853 +v 0.197491 -0.347146 -0.140783 +v 0.233051 -0.351676 -0.128172 +v 0.210475 -0.339508 -0.129997 +v -0.184561 -0.314811 0.033063 +v 0.173923 -0.017351 -0.256121 +v 0.146302 -0.013618 -0.259122 +v 0.179310 -0.000097 -0.242807 +v 0.432746 -0.187252 -0.068464 +v 0.446013 -0.025774 0.077076 +v 0.503824 -0.280037 0.049821 +v -0.044958 -0.058764 -0.182923 +v -0.025341 -0.088518 -0.185333 +v -0.123667 0.275366 0.067696 +v -0.119987 0.252713 0.086314 +v -0.297490 -0.101779 0.104419 +v -0.309286 -0.082764 0.106114 +v -0.298647 -0.108217 0.084259 +v -0.063523 -0.039685 -0.184151 +v -0.031738 -0.058274 -0.186809 +v 0.495253 -0.280622 0.071777 +v 0.030810 -0.364423 -0.208931 +v -0.012174 -0.363880 -0.211282 +v -0.011719 -0.363715 -0.229020 +v 0.297117 -0.283611 -0.184086 +v -0.191159 0.402494 -0.206521 +v -0.020840 -0.065835 -0.197005 +v -0.218627 0.467925 -0.321428 +v -0.194597 0.498275 -0.400368 +v -0.198555 0.494240 -0.383551 +v -0.198354 0.342214 -0.065487 +v -0.244771 0.286482 -0.118354 +v -0.268268 0.486437 -0.331777 +v -0.083606 0.199261 -0.044110 +v -0.082088 0.213018 0.012383 +v 0.519973 -0.136830 0.047783 +v 0.505271 -0.140079 0.072841 +v -0.247139 0.359374 0.078972 +v -0.244109 0.350950 0.121325 +v 0.031070 0.517130 -0.133440 +v -0.182636 0.347831 0.128696 +v -0.216423 0.350649 0.125135 +v 0.514303 -0.133511 0.009572 +v 0.508579 -0.130067 0.036472 +v 0.503245 -0.131709 0.056874 +v 0.484142 -0.136015 0.068700 +v -0.016793 0.477216 -0.075470 +v 0.488602 -0.128088 0.021557 +v 0.482612 -0.128673 0.042042 +v 0.489836 -0.131632 0.000091 +v 0.468932 -0.132802 0.046933 +v -0.017550 0.468102 -0.132094 +v 0.464442 -0.126942 0.019968 +v -0.009073 0.081424 -0.165338 +v -0.182736 0.359297 0.053070 +v -0.003834 0.184352 0.005691 +v -0.175689 -0.334091 0.079267 +v -0.317733 0.342846 0.021291 +v -0.176859 0.357460 0.079551 +v -0.204143 0.357200 0.100231 +v -0.052578 0.183720 0.062362 +v -0.024348 0.178959 -0.072085 +v -0.015246 0.183100 -0.043336 +v 0.003763 0.174830 -0.046969 +v -0.233630 0.357478 -0.012662 +v -0.074504 0.439318 -0.096593 +v -0.206246 0.355262 -0.011185 +v -0.216199 0.360106 0.030872 +v -0.179936 0.358186 0.012112 +v -0.029795 0.192527 0.004728 +v -0.069412 0.201441 0.001302 +v -0.037562 0.190554 0.037045 +v -0.209252 0.411077 -0.175557 +v -0.037958 0.171563 0.090166 +v -0.362773 0.143281 0.104868 +v -0.191136 -0.305136 0.170854 +v -0.118510 -0.182774 0.148904 +v -0.118894 -0.204730 0.132229 +v -0.261150 0.498227 -0.362989 +v -0.274122 0.484352 -0.350106 +v -0.070091 0.192976 0.046029 +v -0.077416 0.182432 0.069379 +v -0.226595 0.342031 0.146588 +v -0.167768 0.360626 -0.006666 +v -0.200049 0.500962 -0.406446 +v -0.220629 0.361022 0.070578 +v -0.201662 0.346863 -0.048056 +v 0.172056 0.033986 0.216054 +v -0.262013 0.381525 -0.115117 +v -0.188649 0.348936 -0.035894 +v 0.021164 0.440753 -0.160783 +v -0.342400 0.244094 0.099847 +v -0.230618 0.332285 0.163441 +v -0.173096 0.357359 -0.027854 +v -0.197167 -0.328078 0.179348 +v -0.202654 -0.320411 0.155147 +v -0.210428 -0.341440 0.143221 +v 0.034071 0.174511 -0.052693 +v -0.047314 0.195522 -0.023714 +v -0.198549 -0.315762 0.133304 +v 0.363157 0.120232 0.115985 +v 0.031720 -0.037163 -0.260681 +v 0.024903 -0.063017 -0.268242 +v 0.011902 -0.057819 -0.252323 +v 0.397428 0.103250 0.008520 +v -0.325311 0.034771 0.096663 +v -0.332122 0.040584 0.076615 +v 0.382460 0.118466 0.075304 +v -0.283236 0.426388 -0.263186 +v 0.383027 0.121449 0.048032 +v -0.071651 -0.233467 -0.120806 +v -0.060144 -0.198144 -0.129146 +v -0.155594 0.375647 -0.028870 +v 0.386938 0.098950 -0.066692 +v 0.341177 0.129022 0.128879 +v 0.338631 0.147469 0.107851 +v -0.212513 -0.314297 0.007038 +v -0.213393 -0.301279 -0.008586 +v 0.271611 0.022798 -0.188386 +v 0.264115 0.043549 -0.180920 +v 0.294406 0.030282 -0.184157 +v 0.378379 0.128378 0.001456 +v 0.364013 0.139891 0.069539 +v 0.353564 0.144215 0.091536 +v 0.378042 0.126258 -0.027193 +v 0.356972 0.150009 0.019194 +v 0.340639 0.160205 0.067034 +v 0.366323 0.120268 -0.072233 +v 0.370257 0.130369 -0.043496 +v -0.319505 0.044281 -0.045221 +v -0.216240 0.506267 -0.397184 +v -0.218296 0.501376 -0.400876 +v 0.356251 0.148219 -0.017352 +v 0.322027 0.167476 0.093473 +v -0.095160 0.208942 -0.043466 +v -0.353818 0.117421 0.183660 +v 0.304436 0.173105 0.099569 +v 0.171472 0.025137 0.241004 +v 0.333882 0.168734 0.005508 +v 0.325943 0.174293 0.038208 +v 0.311199 0.179916 0.072085 +v 0.283596 0.175373 0.114455 +v 0.336138 0.153849 -0.053668 +v 0.327402 0.168917 -0.024653 +v 0.296479 0.190088 0.051611 +v 0.284488 0.188835 0.082002 +v 0.308636 0.176006 -0.046957 +v -0.062566 0.051896 -0.176514 +v -0.318790 0.262701 -0.038800 +v -0.007750 -0.224377 -0.124958 +v -0.017296 -0.199148 -0.130558 +v -0.153816 -0.225534 -0.024405 +v 0.047592 -0.003931 0.226290 +v -0.200640 -0.349898 0.181492 +v -0.280094 0.468031 -0.328764 +v -0.143284 -0.211240 0.082516 +v -0.159416 -0.207902 0.080077 +v 0.076530 0.013666 0.223272 +v -0.006805 -0.274721 0.197730 +v -0.019339 -0.298993 0.214854 +v -0.005104 -0.264154 0.178935 +v 0.011843 -0.253504 0.168863 +v -0.241977 -0.021415 0.191652 +v -0.121245 -0.252287 -0.097196 +v -0.090323 -0.259180 -0.111520 +v -0.046712 0.434386 -0.123895 +v 0.064143 -0.006979 0.251277 +v 0.028985 -0.103669 0.232179 +v 0.042742 -0.096764 0.262771 +v 0.023338 -0.042473 0.229545 +v -0.159044 -0.169619 -0.112784 +v 0.022251 -0.129435 0.198421 +v 0.041301 -0.135342 0.228192 +v -0.109768 -0.230018 0.145159 +v 0.033911 -0.026601 0.235109 +v -0.149988 0.174972 -0.095920 +v 0.056039 -0.336194 -0.026815 +v 0.020018 -0.337393 -0.006566 +v -0.005281 -0.335858 -0.055942 +v 0.003674 -0.038722 -0.216196 +v 0.049193 -0.026855 0.255358 +v -0.253607 0.025173 0.173004 +v 0.064456 -0.194423 0.231329 +v -0.037338 -0.309785 0.200471 +v -0.228456 0.030111 -0.141161 +v 0.042482 -0.054258 0.263840 +v -0.102780 0.423588 -0.068376 +v 0.057291 -0.123971 0.258772 +v -0.272887 0.368955 -0.136943 +v -0.267252 0.367301 -0.106824 +v -0.311312 0.225251 0.236657 +v -0.037338 -0.324640 0.208203 +v 0.036611 -0.079173 0.262098 +v -0.194261 -0.029590 -0.164836 +v -0.194544 0.001941 -0.160459 +v -0.175908 -0.005957 -0.165781 +v -0.226241 -0.056266 -0.155042 +v -0.224587 -0.012655 -0.150836 +v -0.211993 -0.023843 -0.156389 +v -0.140980 -0.250532 -0.076764 +v -0.126680 -0.207554 -0.106363 +v -0.128765 -0.210448 0.101377 +v -0.146615 -0.196998 0.111531 +v -0.018631 -0.320494 0.232593 +v -0.122314 -0.247242 0.116109 +v -0.001819 -0.285017 0.213850 +v -0.138972 -0.187364 0.133623 +v 0.065933 -0.163104 0.251135 +v -0.270578 0.345628 -0.067023 +v -0.311046 0.260480 0.211730 +v -0.301536 0.295089 0.186366 +v 0.335512 0.139554 -0.083184 +v -0.302576 0.157623 0.238140 +v -0.310845 0.179745 0.244495 +v -0.326115 0.156554 0.232510 +v -0.207994 -0.339467 0.121519 +v -0.309510 0.149708 0.237035 +v -0.312895 0.203012 0.244749 +v -0.324726 0.190052 0.233408 +v -0.019629 -0.112535 -0.185610 +v -0.274465 -0.076592 0.158000 +v -0.267353 -0.104378 0.145891 +v -0.236436 -0.334168 -0.048895 +v -0.243920 -0.348067 -0.044282 +v 0.369371 -0.310304 -0.081064 +v 0.392986 -0.318527 -0.070042 +v -0.271931 -0.056626 0.167587 +v -0.318949 0.129282 0.230898 +v -0.327390 0.219067 0.222888 +v -0.259414 -0.030169 0.180346 +v -0.192429 0.043295 -0.156731 +v -0.204078 0.070390 -0.138030 +v -0.173256 0.072670 -0.154120 +v -0.288789 -0.027145 0.150883 +v -0.340143 0.143346 0.221571 +v -0.304389 0.125868 0.233142 +v -0.209477 0.385293 -0.389221 +v -0.146184 -0.350070 0.220484 +v 0.044006 0.039461 -0.194252 +v 0.055820 0.019077 -0.197034 +v -0.239313 -0.329136 -0.017925 +v -0.227162 -0.314841 -0.034653 +v -0.303184 0.191818 -0.081099 +v -0.308742 0.228902 -0.063420 +v -0.292221 0.212752 -0.079682 +v -0.329671 0.253652 0.196508 +v 0.301364 0.007901 -0.188050 +v 0.325417 0.016779 -0.176360 +v 0.320556 -0.006985 -0.184653 +v -0.205005 -0.355339 0.120308 +v -0.130590 -0.255506 0.015833 +v -0.286834 0.241519 -0.077957 +v -0.239655 -0.344919 -0.002083 +v -0.236194 -0.329697 -0.005526 +v -0.229289 -0.313707 -0.013938 +v -0.337119 0.187518 0.219096 +v -0.016049 -0.225387 -0.118715 +v -0.010018 -0.256971 -0.117775 +v -0.201851 0.024298 -0.152809 +v -0.209973 -0.350194 0.146488 +v -0.281925 -0.002070 0.155862 +v -0.201526 -0.356792 0.145868 +v -0.329547 -0.037033 0.093509 +v -0.325866 -0.020435 0.104915 +v -0.322966 0.010890 0.108483 +v -0.223399 -0.335001 0.010156 +v -0.152493 0.367620 -0.049899 +v -0.224634 -0.352799 0.017676 +v -0.310892 -0.052237 0.119163 +v -0.310816 0.045634 0.112163 +v -0.211621 -0.188362 -0.063786 +v -0.263147 0.049373 0.159613 +v -0.213080 -0.336927 0.026489 +v -0.308565 -0.006229 0.129057 +v -0.068751 0.395884 -0.114515 +v -0.156515 -0.052710 -0.178079 +v -0.143792 -0.078287 -0.179591 +v -0.290614 0.015473 0.145289 +v 0.194408 -0.358676 -0.151557 +v -0.065549 -0.001172 -0.186727 +v 0.310845 0.162774 -0.070774 +v -0.323734 0.304368 0.152265 +v -0.194816 -0.350164 0.051026 +v -0.295588 -0.083751 0.131171 +v -0.298441 0.038339 0.129305 +v 0.073801 0.541749 -0.173064 +v -0.132693 -0.270675 0.018621 +v -0.323338 0.280298 0.181935 +v -0.192418 -0.336289 0.044564 +v -0.294483 -0.061925 0.142099 +v -0.283219 0.065080 0.135867 +v -0.271889 0.070750 0.151739 +v 0.167715 0.062575 -0.186118 +v 0.165228 0.085293 -0.180595 +v 0.199429 0.072623 -0.175173 +v -0.254795 0.250663 -0.092854 +v -0.279982 0.267699 -0.080644 +v -0.263738 0.279187 -0.087768 +v -0.282486 -0.111301 0.119310 +v -0.003154 -0.354825 -0.234555 +v 0.027237 -0.357282 -0.225429 +v 0.146414 0.059445 -0.188381 +v -0.354131 0.163264 0.207128 +v -0.084770 0.019667 -0.181806 +v -0.121889 0.406068 -0.043124 +v 0.013285 -0.094117 -0.260492 +v 0.030113 -0.112175 -0.270711 +v 0.029889 -0.141792 -0.262867 +v -0.284447 0.179721 -0.089593 +v 0.240819 -0.360170 -0.144563 +v 0.221279 -0.360413 -0.164292 +v -0.186700 0.103729 -0.133818 +v -0.274914 0.108555 0.230998 +v 0.195123 0.105453 -0.170376 +v -0.338962 0.124420 0.214677 +v 0.023314 -0.086302 -0.269772 +v 0.355419 -0.298201 -0.089995 +v -0.190492 0.452898 -0.416210 +v 0.280974 0.111295 -0.144994 +v 0.312434 0.084951 -0.142537 +v 0.283018 0.087012 -0.153991 +v 0.134819 0.109600 -0.161197 +v 0.111203 0.120422 -0.150842 +v 0.144672 0.131668 -0.144179 +v -0.203280 0.481269 -0.410852 +v 0.152510 0.104626 -0.169307 +v 0.137962 0.083049 -0.184506 +v 0.130371 0.095902 -0.174801 +v 0.226784 0.189249 -0.084212 +v 0.239785 0.153801 -0.129879 +v 0.222070 0.134208 -0.149637 +v 0.210552 0.149200 -0.135744 +v 0.497574 -0.150463 -0.034972 +v 0.227564 -0.003966 -0.228790 +v 0.327420 0.044187 -0.161634 +v 0.353841 0.016312 -0.156808 +v -0.230027 0.435012 -0.355735 +v -0.169239 -0.309164 -0.092718 +v -0.252958 0.490294 -0.371932 +v -0.243808 0.478020 -0.369681 +v 0.033870 -0.206579 -0.235772 +v 0.053971 -0.245547 -0.231466 +v -0.228013 0.379250 -0.345362 +v -0.219755 0.381708 -0.373663 +v -0.256189 0.454865 -0.334334 +v -0.236141 0.402671 -0.321398 +v -0.271558 0.464316 -0.336207 +v -0.249998 0.434380 -0.318037 +v -0.237287 0.366757 -0.302626 +v -0.235550 0.351978 -0.323867 +v -0.254275 0.408691 -0.279335 +v 0.000278 -0.269204 -0.168090 +v -0.274772 0.443594 -0.308149 +v -0.282988 0.444575 -0.297841 +v -0.246413 0.373131 -0.254934 +v -0.274654 0.418968 -0.270693 +v -0.250264 0.390013 -0.261898 +v 0.210540 0.171841 -0.109151 +v 0.260577 0.139944 -0.136028 +v 0.252821 0.119961 -0.150246 +v -0.171743 -0.297894 -0.077862 +v -0.206399 -0.312124 -0.069723 +v -0.240010 0.315615 -0.258064 +v -0.249313 0.351181 -0.230331 +v 0.010922 0.115661 -0.147050 +v -0.014974 0.096487 -0.160240 +v 0.009504 0.129701 -0.134238 +v 0.332624 -0.358162 0.011598 +v 0.307620 -0.349952 -0.001563 +v 0.310142 -0.357707 -0.020116 +v 0.246046 -0.357004 -0.119985 +v 0.254859 -0.359414 -0.088643 +v 0.227977 -0.357500 -0.071247 +v 0.094593 0.134675 -0.138904 +v 0.110329 0.065936 -0.185533 +v 0.027408 -0.177783 -0.240497 +v 0.012363 -0.131467 -0.250474 +v 0.001187 -0.107272 -0.247296 +v -0.000272 -0.087236 -0.243551 +v -0.279976 0.407722 -0.241448 +v 0.389401 -0.017174 -0.145928 +v 0.370570 -0.015928 -0.160984 +v 0.014761 -0.158881 -0.234265 +v -0.000024 -0.125176 -0.232671 +v 0.046133 -0.010564 -0.242665 +v 0.020509 -0.030128 -0.241950 +v 0.002634 -0.057613 -0.233657 +v -0.262627 0.378766 -0.212398 +v 0.226323 0.115188 -0.161823 +v 0.246241 0.033643 -0.184051 +v 0.221225 0.027931 -0.185161 +v 0.226134 0.039757 -0.178865 +v 0.005050 -0.162360 -0.216811 +v -0.011997 -0.108146 -0.217124 +v -0.008335 -0.078198 -0.225346 +v -0.280348 0.405749 -0.221140 +v 0.016268 -0.194818 -0.218482 +v -0.012281 -0.091908 -0.213804 +v -0.254292 0.362363 -0.202114 +v 0.012552 -0.201410 -0.200643 +v -0.008429 -0.137191 -0.200342 +v -0.277743 0.387201 -0.195221 +v 0.180202 0.035545 -0.188475 +v 0.021466 -0.243125 -0.201996 +v 0.000667 -0.177930 -0.187843 +v -0.077003 -0.348805 -0.196709 +v -0.084782 -0.357046 -0.179644 +v -0.065667 -0.347854 -0.214442 +v -0.058307 -0.316920 -0.195581 +v -0.041171 -0.311379 -0.212315 +v 0.009055 -0.219013 -0.179337 +v -0.295871 0.080408 0.120450 +v -0.086076 0.403008 -0.101762 +v -0.103135 0.410787 -0.083338 +v -0.264990 0.362977 -0.179981 +v 0.003402 -0.337541 -0.231395 +v 0.143727 -0.346951 -0.202173 +v 0.203209 -0.333583 0.099528 +v 0.215189 -0.328864 0.143074 +v 0.168559 -0.333471 0.094991 +v -0.264263 0.323672 -0.152939 +v 0.263761 0.171995 -0.093835 +v 0.239773 0.167293 -0.111514 +v -0.081592 -0.331758 -0.178079 +v -0.017780 -0.281567 -0.185185 +v -0.016752 -0.136334 -0.176455 +v -0.020137 -0.297923 -0.213668 +v -0.251038 0.311167 -0.172987 +v -0.263596 0.331753 -0.170890 +v -0.258734 0.347897 -0.165533 +v -0.258392 0.339934 -0.168031 +v 0.088887 0.518665 -0.207253 +v 0.075455 0.491748 -0.196520 +v 0.057675 0.499698 -0.181824 +v -0.090275 -0.344854 -0.158474 +v 0.096483 -0.355067 -0.207460 +v -0.271877 0.361612 -0.165527 +v 0.046552 0.520172 -0.159324 +v -0.075910 -0.314439 -0.159744 +v 0.005369 -0.254443 -0.157866 +v 0.002191 -0.225546 -0.158805 +v -0.151400 -0.362137 -0.119412 +v -0.274494 0.362676 -0.151504 +v 0.356086 0.043082 -0.146595 +v 0.372684 0.027695 -0.139820 +v 0.019434 0.054495 -0.188316 +v -0.256537 0.307730 -0.137168 +v -0.082738 -0.311462 -0.137298 +v -0.000650 -0.236114 -0.138444 +v 0.337414 0.121579 -0.102004 +v 0.341691 0.103398 -0.115537 +v 0.305044 0.117976 -0.130859 +v -0.092928 -0.357690 0.181285 +v -0.274311 -0.125123 -0.084915 +v -0.254653 -0.120344 -0.108708 +v -0.241545 -0.139660 -0.097586 +v -0.310928 0.093976 0.115040 +v -0.261369 0.335693 -0.138479 +v -0.093394 -0.332497 -0.136252 +v -0.001199 -0.256303 -0.135484 +v 0.209996 0.051612 -0.180542 +v 0.122680 -0.003482 -0.253020 +v 0.095113 -0.007788 -0.256162 +v 0.351473 0.078553 -0.128018 +v 0.333734 0.083497 -0.133671 +v -0.267926 0.344181 -0.129648 +v -0.248580 -0.089770 -0.134675 +v -0.270513 -0.072333 -0.121095 +v -0.252609 -0.063833 -0.142968 +v -0.015665 -0.354488 0.223922 +v 0.082437 0.000192 -0.242978 +v -0.009262 0.486833 -0.122135 +v 0.253105 0.189143 -0.072268 +v 0.207645 -0.336531 -0.075878 +v 0.197917 -0.353431 -0.039721 +v 0.179387 -0.341168 -0.025267 +v -0.267589 0.313613 -0.106251 +v -0.275209 -0.043336 -0.122536 +v -0.288635 -0.018320 -0.109098 +v -0.265025 -0.024481 -0.134043 +v -0.281004 0.000346 -0.116074 +v 0.017532 0.094437 -0.159791 +v -0.270200 0.344565 -0.107084 +v -0.286745 -0.064707 -0.105205 +v -0.296734 0.011333 -0.094065 +v -0.263938 0.328020 -0.106741 +v 0.107181 0.087703 -0.172544 +v -0.292676 -0.041215 -0.099529 +v 0.029647 0.164912 -0.079882 +v -0.009699 0.164351 -0.088359 +v 0.057775 -0.356697 -0.218606 +v 0.036776 -0.341067 -0.225659 +v 0.280011 -0.051399 -0.224472 +v 0.261540 -0.023955 -0.226350 +v 0.283100 -0.029933 -0.213692 +v 0.084918 -0.327405 -0.216279 +v -0.305759 -0.011161 -0.089995 +v 0.277506 0.146400 -0.120888 +v -0.256708 0.288278 -0.095689 +v 0.296863 -0.019554 -0.200478 +v 0.318110 -0.050654 -0.200685 +v 0.472470 -0.157853 -0.043443 +v 0.043847 -0.334304 -0.118980 +v 0.136343 -0.036100 -0.269364 +v -0.271452 0.332739 -0.086427 +v 0.054922 0.092695 -0.169792 +v 0.023190 0.072617 -0.179154 +v -0.284158 -0.089386 -0.094880 +v -0.307709 -0.033696 -0.086829 +v 0.068851 -0.334783 -0.080290 +v 0.080287 0.116553 -0.155083 +v 0.044774 0.117882 -0.145467 +v 0.075957 0.144746 -0.119087 +v 0.228213 0.099157 -0.168959 +v -0.144684 -0.225629 -0.073249 +v -0.135186 -0.208056 -0.098342 +v -0.258256 -0.146269 -0.066952 +v -0.304773 -0.069409 -0.079262 +v 0.083937 0.094608 -0.169148 +v -0.272947 0.303512 -0.079174 +v -0.151914 -0.268915 -0.062504 +v -0.291778 -0.109712 -0.071105 +v -0.302280 -0.084501 -0.067655 +v -0.317703 -0.030825 -0.071217 +v -0.312989 0.015214 -0.072806 +v -0.294040 0.083202 -0.065381 +v -0.265049 0.093663 -0.090503 +v -0.161471 -0.280285 -0.052203 +v 0.142380 0.160783 -0.120581 +v -0.211461 -0.162691 -0.093675 +v -0.241291 -0.166188 -0.057726 +v -0.306740 0.044140 -0.072906 +v -0.295499 0.099647 -0.058671 +v -0.277891 0.321593 -0.068234 +v -0.117790 0.404975 -0.069191 +v -0.189387 -0.293168 -0.050596 +v -0.137283 -0.279659 -0.088418 +v -0.155423 -0.210590 -0.059829 +v -0.147484 -0.196460 -0.087443 +v -0.282829 -0.126747 -0.058446 +v -0.318158 -0.067123 -0.053916 +v -0.321531 0.006471 -0.057383 +v -0.292912 0.282543 -0.062498 +v -0.326504 -0.048681 -0.048038 +v -0.322505 -0.020559 -0.053733 +v 0.112804 0.159549 -0.110823 +v 0.005157 -0.361423 0.033412 +v -0.135132 0.363479 -0.068145 +v -0.224829 -0.317245 -0.052315 +v -0.213446 -0.302123 -0.044158 +v -0.331141 0.144663 -0.054506 +v -0.336015 0.175946 -0.050064 +v -0.321643 0.173838 -0.069604 +v -0.326434 0.191931 -0.062233 +v 0.336900 -0.032904 -0.187554 +v 0.354243 -0.023772 -0.173779 +v -0.288765 0.326147 -0.049881 +v -0.300567 -0.113338 -0.043047 +v 0.367144 0.075139 -0.118774 +v -0.143503 0.385843 -0.045327 +v -0.287542 -0.132471 -0.035486 +v 0.339812 -0.062728 -0.190212 +v 0.228745 -0.020671 -0.240367 +v 0.253453 -0.042355 -0.235742 +v 0.364515 0.100598 -0.101809 +v 0.130909 0.177789 -0.099476 +v 0.068307 0.153051 -0.109860 +v 0.313036 0.133045 -0.112613 +v 0.436018 -0.203106 -0.073881 +v 0.292870 0.155195 -0.098820 +v 0.265096 -0.007487 -0.209563 +v 0.446497 -0.150168 -0.047855 +v 0.280832 -0.359060 -0.039899 +v 0.274689 -0.348162 -0.031818 +v 0.266957 -0.351328 -0.030489 +v 0.206712 -0.331717 -0.101201 +v 0.175967 -0.333920 -0.039296 +v 0.289940 0.065540 -0.158179 +v 0.296509 0.052179 -0.167653 +v 0.286798 0.042994 -0.180383 +v 0.060132 0.165125 -0.089599 +v -0.027792 0.148964 -0.116304 +v -0.029210 0.163536 -0.102441 +v 0.454531 -0.180470 -0.060644 +v 0.154873 -0.329703 0.163340 +v 0.171182 0.100285 -0.169579 +v 0.455877 -0.149843 -0.035652 +v 0.456687 -0.212072 -0.081672 +v -0.024236 -0.360330 0.080898 +v 0.088249 0.176856 -0.075015 +v -0.182016 0.325468 -0.063083 +v -0.176817 0.341836 -0.047548 +v -0.020745 -0.362403 0.020021 +v -0.036233 -0.363561 -0.026449 +v -0.167089 0.308686 -0.064613 +v -0.162546 0.331918 -0.057342 +v 0.033988 -0.317558 -0.225966 +v 0.020190 0.150647 -0.106706 +v 0.112526 0.180424 -0.084177 +v 0.418646 -0.292525 -0.080196 +v -0.152469 0.283163 -0.066686 +v -0.147667 0.251413 -0.077478 +v -0.151902 0.229221 -0.086693 +v -0.111735 0.086994 -0.162756 +v -0.098521 0.097142 -0.156720 +v -0.085119 0.078896 -0.164487 +v 0.182358 -0.352757 -0.004658 +v -0.170987 0.149046 -0.108856 +v -0.137088 0.229587 -0.077035 +v -0.014431 0.137174 -0.123907 +v 0.258120 0.056544 -0.171097 +v -0.132374 0.172444 -0.096853 +v -0.124837 0.156028 -0.117238 +v -0.144117 0.121065 -0.139968 +v -0.172948 0.132164 -0.120528 +v 0.105734 -0.339538 -0.209350 +v 0.198921 -0.031445 -0.252092 +v -0.123714 0.201523 -0.077786 +v -0.115852 0.188924 -0.081914 +v -0.149823 0.196863 -0.090084 +v -0.105155 0.204524 -0.061270 +v -0.110619 0.134096 -0.138526 +v -0.099768 0.175722 -0.103120 +v -0.105167 0.115915 -0.147771 +v -0.097842 0.150405 -0.129140 +v -0.082124 0.159502 -0.121792 +v -0.090252 0.189367 -0.082304 +v -0.079844 0.134285 -0.140440 +v -0.064787 0.170796 -0.109925 +v -0.066624 0.110717 -0.149076 +v -0.062034 0.180572 -0.094916 +v -0.263708 0.075417 0.165863 +v 0.206659 0.084242 -0.172798 +v -0.053588 0.136412 -0.134226 +v 0.251203 -0.348321 0.210300 +v -0.051172 0.155822 -0.121798 +v -0.041620 0.174098 -0.096729 +v 0.479558 -0.219060 -0.080751 +v -0.032400 -0.353691 0.082593 +v 0.242916 0.082789 -0.168480 +v -0.035666 0.122631 -0.143080 +v -0.036759 0.096439 -0.161215 +v 0.324206 -0.088258 -0.203786 +v -0.041939 -0.352952 0.090561 +v -0.270808 0.110970 -0.080727 +v -0.234723 0.073048 -0.121367 +v -0.251693 0.147587 -0.100031 +v -0.264724 0.129713 -0.092192 +v -0.260453 0.186774 -0.100852 +v -0.270005 0.208145 -0.094549 +v 0.465198 -0.249493 -0.083757 +v -0.124902 0.064778 -0.167287 +v -0.141530 0.090580 -0.157848 +v 0.446875 -0.247431 -0.090863 +v 0.446036 -0.232516 -0.089109 +v 0.442150 -0.265926 -0.088802 +v -0.099100 -0.133723 -0.148598 +v 0.316138 -0.216721 -0.207117 +v -0.216990 -0.088872 -0.154629 +v -0.080771 0.367874 -0.104686 +v -0.164578 0.022745 -0.167003 +v -0.226991 -0.135023 -0.118041 +v -0.196186 -0.130339 -0.144037 +v -0.196706 -0.147640 -0.125886 +v -0.113188 0.356072 -0.084129 +v -0.230358 -0.115294 -0.135201 +v 0.402089 -0.282518 -0.089523 +v -0.157520 0.054069 -0.162886 +v -0.139598 0.017252 -0.180010 +v -0.159794 0.003004 -0.175232 +v 0.412562 -0.256859 -0.092978 +v -0.158364 -0.125010 -0.156956 +v -0.195442 -0.363974 -0.083728 +v -0.241982 0.234401 -0.099287 +v -0.185489 -0.051901 -0.166685 +v -0.142268 0.041263 -0.170985 +v -0.138198 -0.021374 -0.183992 +v -0.159995 -0.025136 -0.177199 +v -0.077091 -0.103474 -0.165846 +v -0.134760 -0.180411 -0.108537 +v 0.382809 -0.274455 -0.091200 +v -0.192896 -0.079604 -0.165149 +v -0.104936 -0.095074 -0.169089 +v -0.088273 0.058375 -0.174298 +v -0.114996 -0.076036 -0.179662 +v -0.085432 0.351388 -0.096558 +v -0.080830 -0.077873 -0.174393 +v -0.192991 -0.174900 -0.094443 +v -0.104984 -0.229781 -0.113830 +v -0.091380 -0.208753 -0.125141 +v -0.102018 -0.179496 -0.130422 +v -0.081681 -0.191723 -0.132549 +v -0.063299 -0.363354 0.105677 +v -0.172334 -0.091052 -0.167907 +v -0.082100 -0.046785 -0.182615 +v -0.077818 -0.128826 -0.159035 +v 0.263094 -0.329632 -0.186337 +v 0.163881 -0.048221 -0.268827 +v -0.203375 -0.114130 -0.152396 +v 0.319044 -0.165975 -0.208789 +v 0.314744 -0.132837 -0.212351 +v -0.116549 0.032869 -0.181156 +v 0.303993 -0.258914 -0.200508 +v -0.086141 -0.152023 -0.147546 +v 0.298210 -0.095476 -0.217336 +v 0.302150 -0.240833 -0.213580 +v 0.299480 -0.195616 -0.214666 +v 0.300065 -0.166424 -0.220951 +v 0.289072 -0.147923 -0.227148 +v 0.277034 -0.126558 -0.229174 +v 0.276786 -0.259977 -0.209386 +v 0.273431 -0.208877 -0.222664 +v 0.283661 -0.234064 -0.220532 +v 0.059542 -0.050761 -0.277026 +v 0.269940 -0.180665 -0.229812 +v 0.275923 -0.109836 -0.228341 +v -0.340522 0.108749 0.087567 +v 0.266661 -0.292997 -0.199397 +v 0.256561 -0.069255 -0.235222 +v 0.175854 -0.348439 0.023010 +v 0.162351 -0.336744 0.023612 +v 0.263188 -0.274975 -0.210289 +v 0.247446 -0.239191 -0.229292 +v 0.252544 -0.120031 -0.238837 +v 0.251935 -0.163033 -0.235984 +v 0.256685 -0.149134 -0.239836 +v 0.247358 -0.090331 -0.242535 +v 0.247015 -0.301367 -0.200691 +v 0.232431 -0.296104 -0.202185 +v 0.244132 -0.271260 -0.217378 +v 0.245089 -0.222067 -0.230633 +v 0.229229 -0.195421 -0.237373 +v 0.241716 -0.189024 -0.237402 +v 0.214787 -0.316879 -0.195611 +v 0.221320 -0.175822 -0.245802 +v 0.210120 -0.333784 -0.196225 +v 0.216234 -0.159093 -0.246794 +v 0.222560 -0.144066 -0.251484 +v 0.235863 -0.123333 -0.250734 +v 0.227493 -0.058546 -0.247373 +v 0.223464 -0.041564 -0.248064 +v 0.219288 -0.261112 -0.225458 +v 0.216057 -0.217365 -0.236002 +v 0.229082 -0.093007 -0.252606 +v 0.224545 -0.237289 -0.233976 +v 0.212654 -0.126511 -0.257550 +v 0.213416 -0.101330 -0.256712 +v 0.210073 -0.291650 -0.211695 +v 0.206216 -0.277940 -0.224909 +v 0.203729 -0.205114 -0.245317 +v 0.195135 -0.061954 -0.259240 +v 0.188655 -0.146181 -0.257025 +v 0.191779 -0.264614 -0.232771 +v 0.187680 -0.249942 -0.233698 +v 0.196830 -0.234377 -0.238542 +v 0.182830 -0.305898 -0.201860 +v 0.182943 -0.095931 -0.264816 +v 0.178489 -0.294184 -0.214761 +v 0.177189 -0.210814 -0.250515 +v 0.179062 -0.180878 -0.257190 +v 0.157053 -0.335373 -0.203567 +v 0.174118 -0.279766 -0.230243 +v 0.170869 -0.125583 -0.265436 +v 0.181655 -0.072268 -0.268354 +v 0.158140 -0.168716 -0.259429 +v 0.137235 -0.317150 -0.206509 +v 0.162629 -0.255843 -0.239275 +v 0.158128 -0.073166 -0.274769 +v 0.153266 -0.233278 -0.247438 +v 0.152617 -0.099924 -0.274828 +v 0.149179 -0.151603 -0.265708 +v 0.136278 -0.305638 -0.207862 +v 0.132226 -0.284267 -0.229965 +v 0.147938 -0.206295 -0.258401 +v 0.140567 -0.120391 -0.273334 +v 0.065531 -0.337387 -0.155178 +v 0.135439 -0.295537 -0.221453 +v 0.135859 -0.267792 -0.236989 +v 0.133815 -0.184174 -0.265218 +v 0.128505 -0.234991 -0.252246 +v 0.121540 -0.245600 -0.250763 +v 0.129822 -0.210708 -0.256871 +v 0.133384 -0.093580 -0.277356 +v 0.121924 -0.160564 -0.269158 +v 0.125096 -0.132967 -0.275915 +v 0.097157 -0.103610 -0.280818 +v 0.117996 -0.073650 -0.280812 +v 0.102934 -0.255866 -0.243911 +v 0.111416 -0.211381 -0.261786 +v 0.105993 -0.152921 -0.277427 +v 0.027172 -0.339284 0.039313 +v 0.095680 -0.350300 -0.159732 +v 0.103306 0.495977 -0.219593 +v 0.081622 -0.306831 -0.216870 +v 0.091155 -0.296157 -0.218128 +v 0.098722 -0.189289 -0.271219 +v 0.001152 -0.336631 0.137870 +v 0.089555 -0.123410 -0.283021 +v 0.090506 -0.082788 -0.284923 +v -0.212046 -0.362338 -0.089895 +v 0.082673 -0.277450 -0.229138 +v 0.084870 -0.200282 -0.265684 +v 0.413856 -0.319850 0.094082 +v 0.077995 -0.145118 -0.280540 +v 0.239874 -0.349402 -0.026709 +v 0.207616 -0.360212 -0.024068 +v 0.240582 -0.360017 -0.043319 +v 0.070162 -0.218298 -0.253817 +v 0.079395 -0.170830 -0.275891 +v 0.074888 -0.069923 -0.283889 +v 0.059169 0.471002 -0.183271 +v -0.186729 -0.357867 0.085393 +v -0.195637 -0.354978 0.089917 +v 0.064710 -0.106835 -0.284084 +v 0.058945 -0.286629 -0.218559 +v 0.054751 -0.165609 -0.269270 +v -0.227446 -0.358564 0.004421 +v 0.048106 -0.132335 -0.278349 +v 0.047137 -0.109942 -0.280198 +v 0.047249 -0.079710 -0.279861 +v -0.291146 0.108679 0.222061 +v -0.168536 -0.189118 0.116599 +v 0.268782 -0.358883 0.074093 +v 0.275433 -0.356360 0.165012 +v 0.262131 -0.356455 0.133386 +v 0.234557 -0.356148 0.160759 +v 0.256383 -0.354441 0.198303 +v 0.086885 -0.356591 0.204588 +v 0.203617 -0.350566 0.218410 +v 0.213222 -0.361411 0.000694 +v 0.202778 -0.360655 0.016022 +v 0.077670 -0.356313 0.237549 +v 0.014897 -0.354996 0.245133 +v 0.315624 -0.346136 0.029124 +v 0.311176 -0.350719 0.053868 +v 0.287489 -0.357577 0.076739 +v 0.449256 -0.318680 0.041103 +v 0.175849 -0.343672 0.046856 +v 0.194231 -0.347742 0.071653 +v 0.177697 -0.336891 0.067205 +v 0.201242 -0.357636 0.057890 +v 0.189594 -0.356650 0.038899 +v 0.427902 -0.322496 0.069125 +v 0.028690 -0.357506 0.203342 +v 0.128026 -0.335680 0.038521 +v 0.170314 -0.350152 -0.147552 +v 0.325535 -0.356567 0.051328 +v 0.243760 -0.343389 0.128614 +v 0.136148 -0.355439 0.227135 +v 0.167484 -0.356166 0.215965 +v 0.302794 -0.354464 0.112051 +v 0.262615 -0.359154 0.073095 +v -0.195117 -0.355528 0.179289 +v 0.222306 -0.336791 -0.113499 +v 0.360552 -0.355604 0.004639 +v 0.165801 -0.332178 -0.069870 +v 0.128469 -0.332520 -0.097668 +v 0.237227 -0.339898 0.146795 +v 0.233695 -0.356969 0.088647 +v -0.288021 0.082611 0.148089 +v -0.319268 0.099387 0.126215 +v -0.155080 -0.221494 -0.001911 +v 0.281281 -0.351735 0.190388 +v 0.213310 -0.356579 0.203271 +v 0.220912 -0.354695 -0.014771 +v -0.341413 0.114166 0.114573 +v 0.375378 -0.350666 -0.011959 +v 0.351041 -0.355215 0.041156 +v 0.237351 -0.344316 0.114786 +v 0.323515 -0.350223 0.096214 +v -0.346399 0.110403 0.140557 +v -0.026770 -0.350217 0.038120 +v -0.348945 0.109169 0.169354 +v 0.228603 -0.345250 -0.093392 +v -0.321720 0.095311 0.148768 +v 0.277920 -0.358936 -0.070981 +v 0.267199 -0.358540 -0.139082 +v -0.334290 0.098247 0.165951 +v 0.177449 -0.330813 -0.114775 +v -0.331850 0.102199 0.194931 +v 0.169575 -0.335350 -0.137091 +v -0.198655 -0.358257 0.038149 +v -0.346287 0.116954 0.199195 +v -0.316415 0.092157 0.179797 +v 0.117488 -0.328734 0.175993 +v 0.381917 -0.346939 0.042633 +v 0.172121 -0.361074 -0.167641 +v -0.293662 0.085594 0.170476 +v -0.304690 0.097119 0.207754 +v -0.314017 0.110451 0.221293 +v 0.224970 -0.331835 0.121088 +v 0.210652 -0.342975 0.092770 +v -0.279220 0.086870 0.197695 +v 0.360605 -0.348109 0.063927 +v 0.046428 -0.330860 0.173801 +v -0.264458 -0.159548 0.053566 +v -0.226583 -0.189650 -0.032332 +v -0.270891 -0.137126 0.102517 +v -0.235881 -0.191564 -0.001474 +v -0.245852 -0.181924 0.017954 +v -0.245787 -0.181823 0.036365 +v -0.259815 0.096646 0.222439 +v 0.223523 -0.354275 0.090177 +v -0.246531 -0.177942 0.057565 +v -0.239478 -0.166329 0.093981 +v -0.253572 -0.151190 0.107591 +v -0.241333 0.093905 0.214488 +v -0.196700 -0.203968 -0.028445 +v -0.220706 -0.201375 0.008910 +v -0.231232 -0.187919 0.063555 +v -0.255078 -0.134349 0.132199 +v -0.164342 -0.212332 -0.038014 +v -0.223789 -0.363059 -0.054625 +v -0.220511 -0.200637 0.037240 +v -0.177574 -0.213679 -0.005656 +v -0.197179 -0.210862 0.023701 +v -0.209418 -0.201895 0.053466 +v -0.227274 -0.156258 0.130415 +v -0.198744 -0.364311 -0.036786 +v -0.210635 -0.194990 0.073998 +v -0.234386 -0.139825 0.146760 +v -0.237021 -0.125713 0.159016 +v -0.213541 -0.362303 -0.001905 +v -0.211780 -0.177417 0.107762 +v 0.232047 -0.356414 0.053667 +v -0.146403 -0.364169 -0.107356 +v -0.161991 -0.364571 -0.054737 +v -0.177024 -0.214701 0.044239 +v -0.206157 -0.147545 0.156553 +v -0.180734 -0.361287 0.046378 +v -0.161855 -0.220803 0.025875 +v -0.183386 -0.206248 0.067335 +v -0.190120 -0.191333 0.098045 +v -0.191886 -0.172089 0.134550 +v -0.127294 -0.364358 -0.064158 +v -0.156539 -0.363620 0.029478 +v -0.159758 -0.168787 0.153582 +v -0.173598 -0.141922 0.174871 +v -0.096531 -0.363620 -0.129093 +v -0.077298 -0.363378 -0.182899 +v -0.049039 -0.363650 -0.192929 +v -0.081976 -0.363756 -0.127457 +v -0.130135 -0.363845 0.029165 +v -0.182163 -0.359367 0.134875 +v -0.089785 -0.363726 -0.058736 +v -0.093802 -0.364335 -0.032397 +v -0.134908 -0.365469 0.040158 +v -0.145080 -0.360637 0.104106 +v -0.135889 -0.164557 0.164723 +v -0.058549 -0.361358 -0.124326 +v -0.119148 -0.363484 -0.006005 +v -0.085627 -0.363142 -0.015474 +v -0.094062 -0.352243 -0.005727 +v -0.157768 -0.358912 0.160765 +v -0.177698 -0.357317 0.194606 +v -0.023740 -0.362368 -0.174594 +v -0.059607 -0.362250 -0.064560 +v -0.034207 -0.351470 -0.142106 +v -0.050150 -0.348552 -0.096812 +v -0.118121 -0.160192 0.167452 +v -0.002422 -0.351989 -0.166891 +v -0.013155 -0.340264 -0.148899 +v -0.040681 -0.334700 -0.096623 +v 0.022824 -0.361925 -0.179591 +v -0.047503 -0.347654 0.010280 +v -0.092685 -0.358770 0.126782 +v -0.122084 -0.358617 0.151131 +v 0.030155 -0.350058 -0.168079 +v 0.002510 -0.333985 -0.136453 +v -0.011714 -0.336614 -0.056556 +v 0.019664 -0.335379 -0.155113 +v -0.044060 -0.361765 -0.002945 +v -0.140939 -0.223703 0.046909 +vn -0.8249 -0.1275 -0.5506 +vn -0.9689 0.2379 -0.0681 +vn -0.2067 0.9089 0.3623 +vn 0.3857 0.8209 0.4211 +vn -0.0739 0.8265 0.5581 +vn -0.4285 0.6926 0.5802 +vn -0.1264 0.9849 0.1180 +vn -0.1249 0.9847 0.1212 +vn -0.1333 0.9831 0.1258 +vn 0.7836 0.5640 0.2606 +vn -0.8632 -0.5044 -0.0208 +vn 0.2981 -0.9014 -0.3139 +vn -0.9676 -0.2478 0.0494 +vn 0.8303 0.4254 0.3600 +vn -0.5367 0.8307 0.1483 +vn -0.1343 0.9830 0.1255 +vn -0.8454 -0.5311 -0.0573 +vn 0.0677 0.9027 0.4250 +vn 0.8102 0.4977 0.3095 +vn 0.7158 0.6165 0.3281 +vn -0.6780 0.1527 -0.7190 +vn 0.3838 0.8838 0.2677 +vn 0.3813 0.8831 0.2734 +vn 0.3808 0.8831 0.2742 +vn 0.6378 0.7494 0.1775 +vn 0.0669 0.6697 0.7396 +vn 0.1217 0.9049 0.4078 +vn -0.1942 0.2491 -0.9488 +vn -0.2007 0.2506 -0.9471 +vn -0.2004 0.2496 -0.9474 +vn 0.1182 0.9409 0.3173 +vn 0.1220 0.9401 0.3183 +vn 0.1164 0.9413 0.3168 +vn -0.3309 0.8598 0.3890 +vn -0.8590 0.5112 -0.0274 +vn -0.1867 0.9601 -0.2081 +vn -0.1872 0.9600 -0.2083 +vn -0.1828 0.9614 -0.2055 +vn -0.8982 0.1472 -0.4142 +vn -0.9704 -0.2184 -0.1034 +vn -0.9691 -0.2234 -0.1049 +vn -0.9701 -0.2189 -0.1044 +vn -0.8726 -0.4156 0.2566 +vn -0.8714 -0.4207 0.2523 +vn -0.8699 -0.4230 0.2535 +vn -0.1739 0.9800 -0.0966 +vn -0.1826 0.9771 -0.1096 +vn -0.1313 0.9384 -0.3197 +vn -0.0781 0.9414 0.3282 +vn -0.1522 0.9844 -0.0885 +vn -0.3827 0.2300 -0.8948 +vn -0.9512 0.2887 -0.1087 +vn -0.1578 0.9623 -0.2213 +vn -0.1563 0.9625 -0.2216 +vn -0.1477 0.9638 -0.2218 +vn -0.5752 0.7072 0.4112 +vn 0.1654 0.7171 0.6770 +vn 0.5380 0.8054 0.2488 +vn -0.1700 0.9840 0.0541 +vn -0.1616 0.9855 0.0519 +vn -0.1632 0.9852 0.0525 +vn -0.9504 0.2812 -0.1327 +vn -0.0966 0.9937 -0.0572 +vn -0.1071 0.9943 0.0006 +vn 0.2717 0.8506 0.4502 +vn -0.2438 0.9328 0.2654 +vn -0.3816 0.8862 0.2629 +vn -0.0696 0.9902 -0.1207 +vn -0.8678 -0.4863 0.1024 +vn 0.6899 0.6205 0.3729 +vn 0.7846 0.5962 0.1702 +vn 0.7819 0.6022 0.1612 +vn 0.7825 0.6015 0.1610 +vn 0.8084 0.4530 0.3759 +vn -0.7787 0.4406 -0.4467 +vn 0.0530 0.9807 -0.1884 +vn 0.0589 0.9815 -0.1820 +vn 0.0608 0.9812 -0.1834 +vn 0.3647 0.6998 -0.6142 +vn 0.1012 0.8554 0.5081 +vn -0.8375 -0.5462 -0.0163 +vn -0.2683 0.9037 0.3337 +vn -0.5459 0.7967 0.2592 +vn -0.0268 0.8961 0.4429 +vn -0.9908 -0.0088 -0.1348 +vn -0.3722 0.8440 0.3862 +vn -0.6993 -0.7059 -0.1126 +vn -0.0690 0.8140 0.5768 +vn 0.5614 0.3184 0.7639 +vn 0.5485 0.7155 0.4327 +vn -0.9561 -0.2703 0.1134 +vn -0.4112 -0.0428 0.9105 +vn -0.1961 0.2984 0.9341 +vn -0.2032 0.3173 0.9263 +vn -0.0976 0.9770 0.1896 +vn -0.3945 0.7741 0.4951 +vn -0.1058 0.5750 0.8113 +vn 0.5527 0.8315 0.0566 +vn -0.7759 -0.6231 -0.0984 +vn 0.5524 0.7620 0.3380 +vn -0.1585 -0.2245 0.9615 +vn -0.3320 0.6325 0.6998 +vn 0.3093 0.9079 0.2828 +vn 0.3023 0.9082 0.2894 +vn 0.3016 0.9083 0.2899 +vn -0.4151 0.8207 0.3926 +vn -0.3525 0.3665 0.8611 +vn -0.8887 0.4013 -0.2219 +vn 0.0181 -0.5278 -0.8491 +vn 0.0526 0.0623 -0.9967 +vn 0.1662 0.8826 0.4398 +vn -0.2140 -0.2323 0.9488 +vn 0.1373 0.1190 0.9834 +vn -0.0913 0.5030 0.8595 +vn 0.8973 0.2852 -0.3370 +vn -0.9893 -0.1336 -0.0583 +vn -0.9891 -0.1382 -0.0501 +vn -0.9893 -0.1345 -0.0573 +vn -0.2443 0.9662 -0.0822 +vn -0.2419 0.9673 -0.0766 +vn -0.2439 0.9664 -0.0810 +vn 0.7826 0.6012 0.1614 +vn -0.9963 -0.0390 -0.0765 +vn -0.9837 0.0693 -0.1658 +vn 0.7177 0.6185 0.3199 +vn 0.0296 0.9993 0.0234 +vn -0.0422 0.4647 0.8844 +vn -0.1237 0.6411 0.7575 +vn -0.0329 0.5913 0.8058 +vn -0.7775 0.2892 0.5584 +vn -0.3486 0.8549 0.3843 +vn 0.4113 0.7458 0.5240 +vn 0.3103 0.9079 0.2817 +vn 0.0803 0.9924 -0.0936 +vn -0.0989 0.8680 0.4866 +vn -0.3789 -0.1716 0.9094 +vn 0.2324 0.1361 0.9631 +vn 0.0647 0.4497 0.8908 +vn 0.1570 0.3597 -0.9198 +vn 0.5253 -0.8453 0.0974 +vn -0.9162 -0.3710 -0.1515 +vn -0.9645 0.2414 -0.1072 +vn -0.9469 0.1692 -0.2733 +vn -0.9446 0.1707 -0.2803 +vn -0.9450 0.1703 -0.2794 +vn -0.9125 0.3114 -0.2653 +vn 0.1510 -0.1428 -0.9782 +vn -0.2531 0.1826 -0.9500 +vn -0.2477 0.1837 -0.9513 +vn -0.2482 0.1832 -0.9512 +vn -0.3040 -0.2270 0.9252 +vn 0.2861 0.2816 0.9159 +vn -0.1021 0.7485 0.6552 +vn -0.8408 0.0841 -0.5349 +vn -0.9798 0.0332 -0.1973 +vn 0.3553 0.1588 -0.9212 +vn 0.3571 0.1590 -0.9204 +vn 0.3495 0.1587 -0.9234 +vn 0.0011 0.0720 0.9974 +vn 0.0884 0.2290 0.9694 +vn 0.1711 0.4854 0.8574 +vn -0.0666 0.7010 0.7101 +vn -0.1567 -0.4567 0.8757 +vn 0.8559 0.1121 -0.5049 +vn -0.1249 0.9601 0.2503 +vn -0.9568 -0.1095 -0.2692 +vn -0.1991 -0.4169 -0.8869 +vn 0.0806 0.5648 0.8213 +vn 0.9242 0.3285 -0.1949 +vn 0.5317 -0.5390 -0.6533 +vn -0.1240 -0.3835 -0.9152 +vn -0.2130 0.9101 0.3554 +vn 0.7009 -0.6930 -0.1685 +vn 0.6985 -0.6940 -0.1745 +vn 0.6986 -0.6936 -0.1757 +vn 0.0949 -0.1038 0.9901 +vn 0.0946 -0.1040 0.9901 +vn 0.0946 -0.1035 0.9901 +vn 0.1881 0.4385 0.8788 +vn 0.5951 -0.4987 -0.6302 +vn 0.9152 0.3980 -0.0636 +vn 0.9153 0.3980 -0.0617 +vn 0.9157 0.3973 -0.0597 +vn 0.6654 -0.2789 -0.6924 +vn 0.6808 0.4386 -0.5866 +vn -0.2221 0.9744 0.0336 +vn -0.0512 0.9887 0.1411 +vn -0.3997 0.2792 0.8731 +vn 0.0478 -0.4183 0.9070 +vn 0.0968 -0.1047 0.9898 +vn 0.0281 -0.3562 0.9340 +vn 0.2196 0.5959 0.7724 +vn 0.5130 -0.8575 -0.0400 +vn 0.8244 -0.2515 -0.5070 +vn 0.9811 0.0151 -0.1927 +vn -0.6039 0.6217 -0.4988 +vn -0.8931 0.1968 -0.4044 +vn -0.7360 -0.6548 -0.1722 +vn -0.7682 -0.6331 -0.0948 +vn -0.3300 0.3011 0.8947 +vn -0.2607 0.3635 0.8944 +vn -0.1756 0.1518 0.9727 +vn 0.1284 0.2865 0.9494 +vn 0.2062 0.5249 0.8258 +vn 0.2400 -0.2930 0.9255 +vn 0.2371 0.4240 0.8741 +vn 0.9869 0.1582 -0.0303 +vn -0.9363 0.3438 0.0713 +vn -0.9371 0.3421 0.0697 +vn -0.9369 0.3425 0.0700 +vn -0.7139 -0.1261 -0.6888 +vn 0.0203 0.9217 -0.3873 +vn 0.0045 0.8848 0.4659 +vn -0.3260 0.3835 0.8641 +vn 0.9172 -0.3776 -0.1271 +vn -0.0711 -0.7688 0.6356 +vn 0.0252 0.6469 0.7621 +vn 0.8836 -0.4090 0.2277 +vn -0.9997 0.0134 0.0212 +vn -0.9997 0.0131 0.0203 +vn -0.9997 0.0132 0.0210 +vn 0.0869 -0.7114 -0.6974 +vn 0.0867 -0.7112 -0.6976 +vn 0.0871 -0.7125 -0.6963 +vn 0.9567 0.2909 0.0099 +vn -0.9997 0.0094 0.0236 +vn 0.9902 0.1326 0.0443 +vn 0.9900 0.1362 0.0359 +vn 0.9903 0.1321 0.0436 +vn -0.7211 -0.6916 0.0410 +vn -0.3349 0.8728 0.3551 +vn -0.2273 0.9526 -0.2024 +vn -0.2270 0.9528 -0.2015 +vn -0.2280 0.9517 -0.2055 +vn -0.8898 -0.4541 0.0454 +vn 0.1787 0.9584 -0.2224 +vn -0.3070 0.3373 0.8899 +vn 0.0220 -0.9970 0.0745 +vn 0.0211 -0.9970 0.0749 +vn 0.0169 -0.9970 0.0758 +vn 0.1785 -0.4166 0.8914 +vn 0.0134 -0.8379 0.5456 +vn -0.0522 -0.7661 0.6406 +vn 0.1616 -0.0171 0.9867 +vn 0.9793 0.1296 -0.1557 +vn 0.8140 -0.2940 -0.5009 +vn 0.8585 -0.4303 -0.2791 +vn 0.6873 -0.5284 -0.4984 +vn -0.0347 0.9970 0.0697 +vn -0.4615 0.1785 0.8690 +vn 0.0488 0.1086 0.9929 +vn 0.2483 0.7073 0.6619 +vn 0.1982 0.3559 0.9133 +vn 0.1984 0.3555 0.9134 +vn 0.2008 0.3524 0.9140 +vn 0.1923 -0.0793 0.9781 +vn 0.5642 0.3782 0.7339 +vn 0.9885 0.1076 -0.1059 +vn 0.9269 -0.0730 -0.3681 +vn 0.9281 -0.0789 -0.3640 +vn 0.9267 -0.0718 -0.3690 +vn -0.3032 0.9479 0.0981 +vn -0.2412 0.9676 -0.0754 +vn 0.0171 0.9080 0.4185 +vn 0.0271 0.9102 0.4132 +vn 0.0189 0.9084 0.4177 +vn -0.1459 0.9642 -0.2217 +vn 0.4279 0.9002 -0.0809 +vn -0.3684 -0.3597 0.8572 +vn -0.4125 -0.2066 0.8872 +vn -0.2166 -0.0158 0.9761 +vn -0.4060 0.2882 0.8672 +vn -0.2298 0.1480 0.9619 +vn -0.1700 0.2810 0.9445 +vn -0.1701 0.2809 0.9445 +vn -0.1694 0.2806 0.9448 +vn 0.3379 0.4207 0.8419 +vn 0.2390 0.5204 0.8198 +vn 0.9394 -0.0102 -0.3427 +vn -0.1588 -0.5270 0.8349 +vn -0.2461 0.6209 0.7442 +vn 0.2578 -0.2437 0.9350 +vn 0.0625 -0.0327 0.9975 +vn 0.4194 0.4296 0.7997 +vn 0.4193 0.4324 0.7983 +vn 0.4227 0.4291 0.7983 +vn 0.0277 0.9105 0.4126 +vn -0.1122 -0.0355 0.9931 +vn 0.2485 -0.4503 0.8576 +vn 0.7590 -0.2604 0.5967 +vn -0.8060 -0.3609 0.4693 +vn -0.8059 -0.3610 0.4692 +vn -0.8063 -0.3612 0.4685 +vn 0.8628 0.4683 0.1903 +vn -0.9897 0.0329 -0.1396 +vn -0.4737 -0.2911 -0.8312 +vn -0.0987 -0.3388 0.9357 +vn -0.3174 -0.0252 0.9480 +vn -0.1752 0.2795 0.9440 +vn 0.3764 -0.2535 0.8911 +vn -0.3639 -0.5143 -0.7766 +vn -0.3425 0.2059 0.9167 +vn 0.8634 -0.4738 0.1733 +vn 0.7843 0.5058 0.3592 +vn -0.2332 0.2639 0.9359 +vn -0.3062 0.3539 0.8837 +vn -0.1320 0.3472 0.9285 +vn -0.1491 0.4359 0.8875 +vn -0.2209 -0.1561 0.9627 +vn 0.2020 -0.5384 0.8181 +vn 0.5989 0.1968 -0.7763 +vn -0.9594 0.0228 0.2810 +vn -0.8856 0.4644 0.0034 +vn -0.2567 0.8562 0.4483 +vn 0.2327 -0.7349 -0.6370 +vn -0.3045 -0.8781 -0.3691 +vn -0.2046 -0.1662 0.9646 +vn -0.1172 -0.3338 0.9353 +vn -0.0619 -0.1482 0.9870 +vn -0.0891 -0.1139 0.9895 +vn -0.0516 -0.0626 0.9967 +vn -0.1960 0.3209 0.9266 +vn 0.2793 0.7206 0.6346 +vn -0.2262 0.6571 0.7191 +vn -0.2306 0.6564 0.7183 +vn -0.2231 0.6575 0.7196 +vn 0.9835 0.0480 -0.1745 +vn 0.0213 0.5125 0.8584 +vn 0.1980 0.3561 0.9132 +vn -0.3194 0.8668 0.3829 +vn -0.8756 -0.1572 -0.4567 +vn -0.0015 -0.2572 0.9663 +vn -0.0000 -0.1851 0.9827 +vn -0.1322 0.2700 0.9537 +vn 0.0823 0.2701 0.9593 +vn 0.0035 0.4240 0.9057 +vn 0.5523 -0.1475 0.8205 +vn -0.0128 0.1559 0.9877 +vn -0.6396 -0.2732 -0.7185 +vn -0.1284 0.2977 0.9460 +vn -0.1505 0.5919 0.7919 +vn -0.5346 0.3161 -0.7838 +vn 0.1172 -0.1460 0.9823 +vn 0.3945 -0.5968 0.6988 +vn -0.6771 -0.2220 0.7016 +vn 0.3974 0.8839 0.2466 +vn 0.5841 0.7255 0.3640 +vn -0.3020 0.4366 -0.8474 +vn -0.0720 -0.4194 0.9050 +vn 0.0631 0.3281 0.9425 +vn 0.0653 0.3319 0.9410 +vn 0.0631 0.3286 0.9423 +vn -0.0328 0.3822 0.9235 +vn 0.0016 0.5207 0.8537 +vn 0.0493 -0.1161 0.9920 +vn 0.2274 0.1478 0.9625 +vn 0.9806 -0.1776 -0.0834 +vn 0.9798 -0.1764 -0.0944 +vn 0.9798 -0.1768 -0.0933 +vn 0.1100 0.6900 0.7154 +vn -0.1646 -0.2943 0.9414 +vn -0.1949 0.8559 0.4790 +vn -0.1532 -0.8298 -0.5366 +vn 0.0248 0.0574 -0.9980 +vn -0.2865 -0.1895 0.9392 +vn -0.3296 -0.0575 0.9424 +vn 0.0660 0.3316 0.9411 +vn -0.1578 0.4594 0.8741 +vn -0.0831 -0.1865 0.9789 +vn 0.0231 0.1636 0.9863 +vn 0.9901 0.0221 0.1388 +vn -0.1730 -0.1494 0.9735 +vn -0.0268 0.5622 0.8266 +vn 0.2819 0.7647 0.5795 +vn 0.2233 0.0713 -0.9721 +vn 0.1699 -0.9403 -0.2949 +vn -0.0170 -0.5774 0.8163 +vn -0.0571 -0.4026 0.9136 +vn -0.1031 -0.3394 0.9350 +vn -0.2700 0.0310 0.9623 +vn -0.2402 -0.0643 0.9686 +vn 0.1194 -0.1256 0.9849 +vn 0.1221 -0.1264 0.9844 +vn 0.1228 -0.1265 0.9843 +vn 0.0863 -0.0840 0.9927 +vn -0.0143 0.2165 0.9762 +vn -0.0149 0.2170 0.9761 +vn -0.0141 0.2166 0.9762 +vn 0.0110 0.3381 0.9411 +vn 0.1271 0.4529 0.8825 +vn -0.0206 -0.5148 0.8571 +vn -0.1706 0.2990 0.9389 +vn 0.1534 0.2203 0.9633 +vn 0.1538 0.2203 0.9632 +vn 0.1526 0.2198 0.9635 +vn -0.0978 0.5110 0.8540 +vn 0.4388 -0.8980 0.0316 +vn 0.4349 -0.9000 0.0275 +vn 0.4394 -0.8977 0.0320 +vn -0.2744 0.8575 0.4351 +vn -0.3430 0.2684 -0.9002 +vn 0.0421 -0.4185 0.9072 +vn 0.1188 -0.1253 0.9850 +vn 0.3326 0.3712 0.8669 +vn -0.3056 -0.3523 0.8846 +vn 0.2937 0.2767 0.9150 +vn 0.0948 0.5610 0.8224 +vn -0.2893 0.5694 0.7695 +vn 0.1478 0.2486 0.9573 +vn 0.0800 0.3390 0.9374 +vn 0.0934 0.7360 0.6705 +vn 0.7358 -0.6561 -0.1680 +vn 0.3485 0.5347 0.7698 +vn -0.5486 0.7410 -0.3872 +vn 0.8041 0.4695 0.3646 +vn -0.3286 -0.3962 0.8573 +vn -0.6741 -0.0235 0.7382 +vn -0.6663 -0.0265 0.7452 +vn -0.6735 -0.0233 0.7388 +vn 0.1138 -0.1640 0.9799 +vn 0.1138 -0.1629 0.9801 +vn 0.1136 -0.1631 0.9800 +vn 0.1149 -0.1573 0.9808 +vn -0.0707 0.1439 0.9871 +vn -0.0302 0.1442 0.9891 +vn -0.0160 0.2175 0.9759 +vn 0.0699 0.2769 0.9584 +vn 0.0668 0.3412 0.9376 +vn -0.0199 0.6243 0.7809 +vn 0.0977 0.5926 0.7996 +vn -0.0241 0.5398 0.8414 +vn -0.0605 -0.1118 0.9919 +vn 0.0495 -0.1787 0.9827 +vn 0.2650 0.4849 0.8334 +vn -0.1320 -0.7332 0.6671 +vn 0.1527 0.2195 0.9636 +vn 0.8349 0.5136 0.1980 +vn -0.1530 -0.3112 0.9379 +vn 0.1191 0.4451 0.8875 +vn 0.0906 0.4148 0.9054 +vn 0.0968 0.4133 0.9054 +vn 0.0895 0.4145 0.9056 +vn 0.0280 0.5414 0.8403 +vn 0.0942 -0.0455 0.9945 +vn -0.0792 0.7686 0.6348 +vn -0.0802 0.7682 0.6351 +vn -0.0849 0.7749 0.6264 +vn 0.1208 0.3742 0.9194 +vn 0.0298 0.7806 0.6243 +vn -0.0700 -0.2033 0.9766 +vn 0.1492 -0.3848 0.9109 +vn 0.0385 -0.2239 0.9739 +vn -0.1169 0.1489 0.9819 +vn 0.0214 0.1327 0.9909 +vn 0.1421 0.3952 0.9076 +vn 0.0451 0.4915 0.8697 +vn 0.8723 -0.3499 -0.3416 +vn 0.1999 0.2140 0.9562 +vn 0.1076 0.2721 0.9562 +vn 0.9916 0.0523 0.1184 +vn 0.2928 0.6392 0.7111 +vn 0.9041 0.1354 0.4053 +vn 0.2680 -0.9282 -0.2581 +vn -0.0147 0.0547 0.9984 +vn 0.0134 0.3018 0.9533 +vn 0.0979 0.4126 0.9056 +vn 0.0852 0.3759 0.9227 +vn -0.2318 0.1626 0.9591 +vn -0.1642 0.0725 0.9838 +vn 0.1213 0.0408 0.9918 +vn 0.3771 -0.3160 0.8706 +vn -0.1244 0.3756 0.9184 +vn -0.2409 0.8699 0.4305 +vn -0.0819 0.9942 -0.0701 +vn 0.1728 -0.7094 -0.6833 +vn -0.9412 -0.1769 -0.2877 +vn -0.1527 0.2697 0.9508 +vn -0.0214 0.3920 0.9197 +vn 0.1172 0.5184 0.8471 +vn -0.0274 0.4129 0.9104 +vn -0.0419 -0.7168 0.6960 +vn -0.0476 -0.7131 0.6994 +vn -0.0480 -0.7153 0.6972 +vn 0.0270 -0.5082 0.8608 +vn 0.0814 0.4879 0.8691 +vn -0.0519 -0.4159 0.9079 +vn -0.2217 0.6577 0.7199 +vn 0.2932 0.3812 0.8768 +vn -0.1459 0.7607 0.6324 +vn -0.7690 0.4348 0.4687 +vn 0.0616 0.9809 -0.1844 +vn 0.0534 -0.4553 0.8887 +vn 0.1067 -0.2260 0.9683 +vn 0.2083 0.1691 0.9633 +vn -0.0906 0.0540 0.9944 +vn -0.2552 0.3023 0.9184 +vn -0.0451 0.6154 0.7870 +vn 0.4916 -0.8270 -0.2728 +vn 0.1569 0.5868 0.7944 +vn -0.3816 0.5285 0.7583 +vn -0.3445 0.1127 0.9320 +vn -0.1352 0.9906 0.0192 +vn 0.2396 -0.1623 0.9572 +vn 0.2403 -0.2575 0.9359 +vn 0.3337 -0.0089 0.9426 +vn 0.2963 0.0382 0.9543 +vn -0.9680 0.2447 -0.0560 +vn 0.3491 -0.7055 0.6168 +vn -0.1517 0.6381 0.7548 +vn 0.1497 0.6797 0.7181 +vn -0.1764 0.8754 0.4500 +vn 0.2599 -0.2811 0.9238 +vn 0.3599 0.0696 0.9304 +vn 0.3320 0.1581 0.9299 +vn 0.3331 0.1594 0.9293 +vn 0.3330 0.1594 0.9293 +vn 0.3332 0.1598 0.9292 +vn 0.3711 0.2844 0.8840 +vn -0.3127 0.3525 0.8820 +vn 0.4041 0.5370 0.7405 +vn 0.3885 0.4894 -0.7807 +vn 0.2449 0.1611 0.9561 +vn 0.2525 0.4183 0.8725 +vn -0.0744 -0.8661 -0.4943 +vn 0.1778 0.5090 0.8422 +vn 0.2126 0.4364 0.8743 +vn 0.2029 0.4359 0.8768 +vn 0.2112 0.4363 0.8747 +vn -0.7543 0.2153 -0.6202 +vn -0.7569 0.2157 -0.6169 +vn -0.7545 0.2153 -0.6200 +vn -0.0454 0.5890 0.8069 +vn 0.1194 0.6467 0.7533 +vn -0.1898 0.2950 0.9365 +vn 0.3687 0.8528 0.3700 +vn 0.4895 -0.1602 -0.8572 +vn 0.1954 -0.0541 0.9792 +vn 0.3886 -0.2009 0.8992 +vn 0.0381 0.1235 0.9916 +vn -0.1043 0.3658 0.9248 +vn -0.0209 0.4734 0.8806 +vn -0.0588 0.4894 0.8701 +vn -0.0936 0.7323 0.6745 +vn -0.0903 0.7344 0.6726 +vn -0.0899 0.7344 0.6727 +vn -0.1488 -0.7235 -0.6741 +vn 0.2503 -0.8292 -0.4998 +vn 0.5208 0.0796 0.8499 +vn 0.5160 0.0819 0.8527 +vn 0.5141 0.0831 0.8537 +vn 0.2402 0.4753 0.8464 +vn -0.8688 0.2974 -0.3959 +vn -0.2385 -0.0575 0.9694 +vn 0.0723 0.2115 0.9747 +vn 0.0230 0.6513 0.7585 +vn 0.0134 0.6065 0.7950 +vn -0.0446 0.7037 0.7091 +vn -0.0462 0.7027 0.7100 +vn -0.0446 0.7041 0.7087 +vn 0.8953 -0.2248 0.3845 +vn 0.6134 -0.7749 -0.1526 +vn -0.0288 0.3681 0.9293 +vn 0.0186 -0.3432 0.9391 +vn -0.9084 -0.0466 -0.4154 +vn 0.0262 0.9987 -0.0433 +vn -0.0379 0.9913 0.1263 +vn -0.2394 -0.4170 0.8768 +vn -0.0545 -0.1371 0.9891 +vn -0.1157 0.1051 0.9877 +vn 0.1427 -0.2392 0.9604 +vn 0.0614 0.4956 0.8664 +vn 0.1095 0.5764 0.8098 +vn 0.4424 -0.8475 -0.2933 +vn 0.1514 0.0549 0.9869 +vn 0.1777 0.3422 0.9227 +vn 0.2012 0.4358 0.8773 +vn -0.1158 0.6255 0.7716 +vn -0.9373 0.0959 0.3350 +vn -0.3561 -0.1417 0.9237 +vn 0.2333 -0.0112 0.9723 +vn 0.4864 -0.2275 0.8436 +vn 0.3867 0.0546 0.9206 +vn 0.4244 0.1836 0.8867 +vn 0.2966 0.2137 0.9308 +vn 0.4217 0.2691 0.8659 +vn -0.9973 0.0394 -0.0624 +vn 0.9355 -0.3534 0.0072 +vn 0.2617 0.0781 0.9620 +vn -0.1339 0.8209 0.5552 +vn -0.0654 -0.0099 0.9978 +vn 0.2444 0.5195 0.8188 +vn 0.0295 -0.2345 0.9717 +vn -0.1927 -0.1475 0.9701 +vn 0.0106 -0.1307 0.9914 +vn 0.3166 0.0446 0.9475 +vn 0.2301 0.0171 0.9730 +vn 0.2624 0.0937 0.9604 +vn 0.9965 -0.0593 0.0588 +vn -0.5083 0.8538 0.1127 +vn -0.0706 0.1129 0.9911 +vn -0.0953 0.4555 0.8851 +vn 0.0586 0.4423 0.8950 +vn 0.0376 0.3208 0.9464 +vn -0.0642 -0.1311 0.9893 +vn -0.0226 -0.0769 0.9968 +vn -0.3544 -0.0169 0.9349 +vn -0.2875 0.0485 0.9566 +vn -0.3154 0.0763 0.9459 +vn 0.1177 0.2635 0.9575 +vn 0.9888 0.1365 -0.0600 +vn -0.1816 -0.1052 0.9777 +vn -0.1691 0.5871 0.7917 +vn 0.7716 -0.5588 -0.3040 +vn 0.5214 -0.8367 0.1677 +vn -0.0336 0.2492 0.9679 +vn 0.1359 -0.1651 0.9769 +vn -0.0696 0.0972 0.9928 +vn -0.2885 -0.0926 0.9530 +vn -0.2865 0.0842 0.9544 +vn -0.1203 0.3656 0.9230 +vn 0.3680 0.3656 0.8550 +vn 0.3659 0.2756 0.8889 +vn 0.0905 0.5797 0.8098 +vn 0.1132 0.5863 0.8021 +vn -0.0478 0.7227 0.6895 +vn -0.4349 0.9001 0.0243 +vn 0.0219 -0.4633 0.8859 +vn 0.3189 0.2101 0.9242 +vn -0.0861 0.6427 0.7613 +vn -0.0043 0.6679 0.7442 +vn -0.9943 0.0858 -0.0630 +vn 0.3620 0.2321 0.9028 +vn 0.3629 0.2309 0.9028 +vn 0.3621 0.2346 0.9021 +vn -0.0459 -0.1190 0.9918 +vn -0.0107 -0.0229 0.9997 +vn 0.9654 0.0011 -0.2606 +vn 0.3503 0.1911 0.9170 +vn 0.1377 -0.0993 0.9855 +vn 0.0261 -0.1063 0.9940 +vn 0.0413 -0.0890 0.9952 +vn -0.0919 0.0529 0.9944 +vn -0.0213 0.1067 0.9941 +vn -0.1043 -0.2104 0.9720 +vn -0.3567 0.1221 0.9262 +vn -0.2481 0.3009 0.9208 +vn -0.2419 0.3006 0.9226 +vn -0.2430 0.3008 0.9222 +vn -0.1026 0.4858 0.8680 +vn -0.0485 0.4512 0.8911 +vn -0.0336 0.5097 0.8597 +vn 0.0871 0.6057 0.7909 +vn 0.2563 -0.2557 0.9322 +vn 0.9232 0.3735 0.0903 +vn 0.6424 -0.7540 -0.1374 +vn -0.8577 0.4427 -0.2613 +vn 0.2399 0.4237 0.8735 +vn 0.3671 -0.0650 0.9279 +vn 0.2610 -0.2164 0.9408 +vn 0.2598 -0.2177 0.9408 +vn 0.2605 -0.2167 0.9408 +vn 0.2710 -0.1957 0.9425 +vn 0.1106 -0.1886 0.9758 +vn 0.2729 -0.1866 0.9438 +vn -0.2218 0.5149 0.8281 +vn 0.0833 0.5525 0.8294 +vn 0.0402 0.0435 0.9982 +vn 0.2941 0.1683 0.9408 +vn 0.2112 -0.1338 0.9683 +vn 0.2104 -0.1344 0.9683 +vn 0.2097 -0.1354 0.9683 +vn 0.7355 -0.2829 0.6156 +vn -0.1423 0.2658 0.9535 +vn -0.1429 0.2662 0.9533 +vn -0.1429 0.2753 0.9507 +vn 0.2564 0.0669 0.9642 +vn 0.1413 -0.0636 0.9879 +vn 0.2512 -0.0760 0.9650 +vn 0.2706 0.1028 0.9572 +vn -0.1249 -0.2041 0.9710 +vn -0.2284 0.4711 0.8520 +vn 0.0295 0.5721 0.8197 +vn -0.0567 -0.1571 0.9860 +vn 0.2412 -0.5463 0.8021 +vn 0.1242 0.4932 0.8610 +vn 0.6158 0.4196 0.6669 +vn -0.3269 -0.0718 0.9423 +vn 0.7483 -0.3050 0.5890 +vn 0.6333 0.7693 0.0843 +vn 0.2540 -0.2074 0.9447 +vn 0.3918 -0.1746 0.9033 +vn 0.3952 -0.0809 0.9150 +vn 0.4323 -0.2445 0.8679 +vn 0.2757 -0.0616 0.9593 +vn -0.1365 -0.4341 0.8904 +vn -0.0082 0.6647 0.7471 +vn 0.0058 0.3061 0.9520 +vn 0.4571 -0.1791 0.8712 +vn -0.0689 -0.1727 0.9826 +vn -0.2045 0.4918 0.8464 +vn -0.0394 0.5656 0.8237 +vn 0.0838 0.6271 0.7744 +vn 0.0831 0.6267 0.7749 +vn 0.0828 0.6250 0.7762 +vn 0.1985 0.7825 0.5901 +vn 0.1416 0.0621 0.9880 +vn -0.0289 0.4760 0.8790 +vn 0.3063 -0.9067 -0.2899 +vn 0.1939 0.6652 0.7210 +vn -0.8675 -0.4946 -0.0533 +vn -0.0425 0.9715 0.2331 +vn -0.0596 0.9626 0.2644 +vn 0.3348 0.0672 0.9399 +vn 0.4117 -0.1938 0.8905 +vn 0.4167 -0.0994 0.9036 +vn 0.2176 -0.0455 0.9750 +vn -0.0530 -0.1410 0.9886 +vn -0.1356 0.1796 0.9744 +vn -0.2490 0.3007 0.9206 +vn -0.8596 -0.4055 -0.3110 +vn -0.9549 0.2326 -0.1845 +vn 0.4072 -0.1778 0.8959 +vn -0.0715 -0.1038 0.9920 +vn -0.1316 -0.1702 0.9766 +vn -0.1825 -0.0495 0.9820 +vn -0.1715 0.4147 0.8937 +vn -0.1827 0.4527 0.8728 +vn 0.1310 0.4987 0.8569 +vn 0.0886 0.2469 0.9650 +vn 0.7324 -0.5800 -0.3565 +vn -0.9630 -0.2407 -0.1217 +vn 0.3481 -0.1623 0.9233 +vn 0.3215 -0.2268 0.9194 +vn 0.2691 -0.1124 0.9565 +vn -0.0967 -0.3065 0.9469 +vn -0.0278 -0.1325 0.9908 +vn -0.4038 -0.2583 0.8776 +vn -0.0952 -0.0827 0.9920 +vn -0.4172 -0.4161 0.8080 +vn -0.0435 -0.1890 0.9810 +vn 0.2263 0.2937 0.9287 +vn -0.1625 0.4864 0.8585 +vn -0.0875 0.6079 0.7892 +vn 0.9880 0.1414 0.0629 +vn 0.3818 -0.4118 0.8274 +vn 0.5205 -0.1043 0.8475 +vn -0.0152 0.0489 0.9987 +vn 0.6349 0.1170 0.7637 +vn -0.8938 -0.0811 0.4412 +vn -0.0394 -0.1506 0.9878 +vn 0.8857 0.1924 -0.4225 +vn 0.2676 0.2702 0.9249 +vn -0.0857 0.7747 0.6265 +vn 0.0740 0.3560 0.9316 +vn 0.0171 0.4004 0.9162 +vn -0.8869 0.2038 -0.4146 +vn -0.6886 -0.7135 -0.1298 +vn 0.1608 0.9845 0.0697 +vn 0.1208 -0.1616 0.9794 +vn -0.0305 -0.1040 0.9941 +vn 0.0932 -0.2045 0.9744 +vn 0.3924 0.9007 -0.1863 +vn 0.3971 0.8962 -0.1980 +vn 0.3922 0.9007 -0.1866 +vn -0.3005 0.9418 0.1509 +vn 0.2562 0.2197 0.9413 +vn 0.8137 0.4857 -0.3193 +vn 0.1631 0.7399 0.6527 +vn 0.1435 -0.0941 0.9852 +vn -0.0492 0.2822 0.9581 +vn -0.3538 -0.4830 -0.8010 +vn -0.3694 0.8738 0.3163 +vn 0.9941 0.0756 0.0782 +vn 0.9940 0.0832 0.0710 +vn 0.9941 0.0769 0.0770 +vn 0.7231 -0.6548 -0.2197 +vn -0.4453 0.7783 0.4426 +vn -0.4161 -0.2564 0.8724 +vn -0.4380 -0.2775 0.8551 +vn -0.2295 0.2114 0.9501 +vn -0.1490 0.4918 0.8579 +vn -0.2546 0.5160 0.8179 +vn -0.2082 0.6121 0.7628 +vn -0.2374 0.7002 -0.6733 +vn 0.1277 -0.1112 0.9856 +vn 0.0138 0.0696 -0.9975 +vn 0.2506 0.5843 0.7719 +vn 0.0627 -0.4421 0.8948 +vn 0.9122 -0.3812 -0.1503 +vn 0.9120 -0.3816 -0.1504 +vn 0.9126 -0.3807 -0.1490 +vn -0.7057 -0.0682 0.7053 +vn -0.8448 -0.2147 0.4901 +vn -0.9693 -0.1771 0.1704 +vn -0.0140 0.7805 0.6250 +vn 0.7109 -0.0870 0.6979 +vn -0.1124 -0.1497 0.9823 +vn 0.0488 0.2785 0.9592 +vn -0.2941 0.5138 0.8059 +vn -0.1499 0.6639 0.7326 +vn -0.1338 0.7401 0.6591 +vn 0.2433 0.3115 0.9186 +vn 0.2258 0.1736 0.9586 +vn -0.1436 0.0587 0.9879 +vn -0.0039 0.3070 0.9517 +vn 0.1441 0.1339 0.9805 +vn -0.1748 0.8840 0.4335 +vn -0.1840 -0.4782 -0.8588 +vn -0.2100 -0.4705 -0.8570 +vn -0.2083 -0.4752 -0.8549 +vn -0.2078 -0.4769 -0.8540 +vn -0.1628 0.7151 0.6798 +vn 0.0316 0.8897 0.4555 +vn 0.3310 0.9435 -0.0128 +vn -0.0472 0.2431 0.9689 +vn -0.1651 0.0055 0.9863 +vn -0.1652 0.0051 0.9863 +vn -0.1666 0.0042 0.9860 +vn -0.1112 0.3328 0.9364 +vn -0.3402 0.5921 0.7305 +vn 0.3038 0.3094 0.9011 +vn 0.1959 0.0508 0.9793 +vn 0.0829 0.6246 0.7765 +vn 0.0827 0.6253 0.7759 +vn 0.1693 0.0145 0.9855 +vn -0.0630 -0.0643 0.9959 +vn 0.2113 0.1524 0.9655 +vn -0.3284 0.5323 0.7803 +vn -0.1471 0.9066 0.3956 +vn -0.1553 0.8381 0.5230 +vn 0.4458 0.8442 0.2976 +vn 0.4961 0.4150 0.7626 +vn -0.2565 0.3178 0.9128 +vn 0.9682 0.0968 -0.2306 +vn 0.1553 -0.8602 -0.4857 +vn 0.7714 -0.2700 0.5763 +vn 0.7777 -0.2668 0.5692 +vn 0.7716 -0.2700 0.5759 +vn 0.6016 0.3719 0.7070 +vn -0.1217 0.7581 0.6407 +vn -0.3385 0.5758 0.7443 +vn -0.1432 0.4461 0.8835 +vn -0.1734 0.7428 0.6467 +vn -0.1460 0.8733 0.4648 +vn -0.0264 0.3339 0.9423 +vn 0.2369 0.9689 -0.0714 +vn -0.9799 0.0160 -0.1988 +vn -0.9593 0.2612 -0.1073 +vn 0.2567 0.8401 0.4779 +vn 0.8245 0.2936 0.4837 +vn -0.1267 0.2395 0.9626 +vn 0.2219 -0.2075 0.9528 +vn 0.0616 0.2653 0.9622 +vn 0.3191 0.0107 0.9477 +vn 0.4778 0.7469 0.4624 +vn 0.4697 0.7510 0.4641 +vn 0.4771 0.7471 0.4629 +vn 0.9887 -0.1490 -0.0164 +vn 0.9886 -0.1497 -0.0164 +vn 0.9881 -0.1532 -0.0142 +vn 0.0190 0.8155 0.5785 +vn -0.9688 0.1237 -0.2146 +vn -0.1866 0.4351 0.8808 +vn -0.3090 0.4983 0.8101 +vn 0.7877 0.1570 -0.5957 +vn -0.0817 0.4589 0.8847 +vn 0.6354 0.2710 0.7230 +vn 0.1973 0.4810 0.8542 +vn 0.7736 0.2450 -0.5844 +vn -0.5519 0.5612 0.6169 +vn -0.7390 -0.1575 0.6550 +vn 0.2457 0.9547 -0.1679 +vn 0.2568 0.9654 -0.0452 +vn -0.3836 -0.4706 -0.7946 +vn 0.5933 0.7550 0.2793 +vn 0.4527 0.6503 0.6101 +vn 0.4527 0.6571 0.6028 +vn 0.4549 0.6490 0.6098 +vn 0.0207 0.2502 0.9680 +vn 0.0109 0.2556 0.9667 +vn 0.0117 0.2548 0.9669 +vn -0.0097 -0.0821 0.9966 +vn 0.9475 -0.3137 0.0624 +vn 0.1934 0.7269 0.6589 +vn 0.1385 0.8868 0.4408 +vn -0.4299 0.8191 0.3798 +vn -0.8734 0.4867 0.0166 +vn 0.0204 0.7852 0.6189 +vn 0.3914 0.9012 -0.1862 +vn -0.2841 0.9490 -0.1370 +vn 0.3876 -0.8940 -0.2247 +vn 0.0187 0.2838 0.9587 +vn -0.0466 0.4105 0.9107 +vn -0.3766 0.6211 0.6873 +vn -0.3596 0.6183 0.6988 +vn -0.4024 0.3174 -0.8587 +vn 0.2111 -0.1334 0.9683 +vn 0.2273 0.0756 0.9709 +vn 0.2598 0.6825 0.6832 +vn 0.2419 0.6638 0.7077 +vn -0.0572 0.6854 0.7259 +vn -0.0695 0.3656 0.9282 +vn -0.6080 -0.0975 0.7879 +vn -0.2585 0.9609 0.0990 +vn 0.1711 0.9810 0.0914 +vn 0.1081 -0.9148 -0.3891 +vn -0.4361 -0.1136 0.8927 +vn -0.1202 0.5930 0.7962 +vn -0.0448 0.4640 0.8847 +vn -0.1456 -0.0785 0.9862 +vn 0.2519 0.4650 0.8487 +vn 0.3975 0.9160 0.0539 +vn -0.2549 0.2809 0.9253 +vn -0.2544 0.2802 0.9256 +vn -0.2571 0.2702 0.9278 +vn 0.0910 0.8389 0.5367 +vn 0.0508 0.2611 0.9640 +vn -0.1895 0.5096 0.8393 +vn -0.2391 0.6388 0.7312 +vn 0.6292 -0.0742 -0.7737 +vn 0.0087 0.5649 0.8251 +vn 0.2842 -0.1696 0.9436 +vn -0.4920 0.8690 0.0528 +vn -0.5783 -0.2750 0.7681 +vn 0.0724 0.9804 0.1830 +vn 0.0783 0.9592 0.2715 +vn 0.0813 0.9599 0.2682 +vn 0.0810 0.9598 0.2688 +vn -0.2343 -0.2306 0.9444 +vn -0.1922 -0.2233 0.9556 +vn -0.0689 0.1680 0.9834 +vn 0.4020 0.9148 -0.0397 +vn 0.9313 0.0111 -0.3641 +vn 0.2042 0.6529 0.7294 +vn 0.2195 0.0035 0.9756 +vn 0.2150 0.0838 0.9730 +vn -0.6691 -0.3237 0.6690 +vn -0.2502 -0.2506 0.9352 +vn -0.2514 -0.2480 0.9356 +vn -0.2490 -0.2506 0.9355 +vn -0.2582 0.2699 0.9276 +vn -0.3732 0.4211 0.8267 +vn 0.2416 0.9267 0.2877 +vn -0.0163 -0.9778 0.2088 +vn -0.0198 -0.9783 0.2063 +vn -0.0163 -0.9775 0.2103 +vn -0.0046 0.1518 0.9884 +vn -0.1889 0.3175 0.9292 +vn -0.3589 0.5519 0.7527 +vn -0.2656 0.7732 0.5759 +vn 0.0168 -0.5796 0.8147 +vn -0.1339 0.0547 0.9895 +vn 0.1594 0.1122 0.9808 +vn 0.1403 -0.0506 0.9888 +vn -0.3594 -0.4414 0.8222 +vn 0.1689 0.7045 0.6893 +vn -0.5380 -0.2131 0.8155 +vn -0.1802 -0.2822 0.9423 +vn -0.2510 -0.2472 0.9359 +vn -0.1838 -0.2286 0.9560 +vn -0.1472 -0.0844 0.9855 +vn 0.3641 -0.3068 0.8794 +vn 0.2889 0.1384 0.9473 +vn -0.1868 0.2518 0.9496 +vn -0.3199 0.5881 0.7428 +vn -0.8745 0.1028 -0.4740 +vn 0.3437 0.9375 0.0547 +vn -0.2638 0.5425 0.7975 +vn -0.3867 0.7162 0.5809 +vn 0.5952 -0.7728 -0.2205 +vn 0.9254 -0.1256 -0.3577 +vn -0.1180 0.5228 0.8443 +vn -0.1307 -0.5746 0.8079 +vn 0.1945 -0.2708 0.9428 +vn -0.1200 0.0043 0.9928 +vn 0.0476 0.3394 0.9394 +vn -0.2669 0.5142 0.8151 +vn 0.2752 -0.2549 0.9270 +vn 0.2229 0.2940 0.9295 +vn -0.0680 0.1242 0.9899 +vn 0.1805 0.6425 0.7447 +vn -0.4100 -0.4799 0.7756 +vn -0.3721 -0.3725 0.8502 +vn 0.5529 -0.7718 -0.3141 +vn 0.1985 -0.2105 0.9572 +vn -0.3311 -0.3251 0.8858 +vn -0.3352 -0.3241 0.8846 +vn -0.3303 -0.3251 0.8861 +vn -0.2651 -0.0954 0.9595 +vn -0.1560 0.0495 0.9865 +vn -0.0692 0.1102 0.9915 +vn 0.0841 0.8257 0.5578 +vn -0.2087 0.1663 0.9637 +vn -0.1393 0.2140 0.9669 +vn -0.1540 0.4316 0.8889 +vn -0.2499 0.4459 0.8595 +vn -0.2797 0.8149 0.5076 +vn 0.2796 0.4840 0.8292 +vn -0.0150 0.5393 0.8420 +vn -0.1182 0.2845 0.9514 +vn -0.3453 -0.3644 0.8649 +vn -0.3432 -0.3227 0.8821 +vn -0.2376 -0.1316 0.9624 +vn -0.3326 -0.3242 0.8856 +vn -0.1970 -0.2243 0.9544 +vn -0.1962 -0.1645 0.9667 +vn -0.1095 0.3108 0.9441 +vn -0.1353 0.5738 0.8078 +vn 0.9920 0.0879 -0.0908 +vn 0.0479 0.1158 0.9921 +vn -0.2289 0.8202 0.5243 +vn 0.3480 -0.3331 0.8763 +vn -0.0906 -0.1492 0.9846 +vn -0.0343 0.0772 0.9964 +vn 0.0731 0.5328 0.8431 +vn 0.7085 -0.6513 -0.2719 +vn -0.2341 -0.4180 0.8778 +vn -0.2307 -0.4160 0.8796 +vn -0.2340 -0.4179 0.8778 +vn 0.0778 0.9593 0.2715 +vn 0.2462 0.9635 0.1053 +vn 0.0527 0.1427 0.9884 +vn 0.0594 0.1619 0.9850 +vn 0.9459 0.2752 -0.1718 +vn 0.9465 0.2745 -0.1697 +vn 0.9466 0.2744 -0.1695 +vn 0.0152 0.2085 0.9779 +vn -0.0340 0.0446 0.9984 +vn -0.1822 0.2221 0.9578 +vn -0.1746 0.7015 0.6909 +vn -0.9854 -0.1380 -0.0997 +vn 0.2837 0.5790 0.7644 +vn -0.2906 -0.2651 -0.9194 +vn -0.1490 0.5606 0.8146 +vn -0.1427 0.4730 0.8694 +vn -0.1411 0.4749 0.8687 +vn -0.1409 0.4753 0.8685 +vn -0.1539 0.5501 0.8208 +vn -0.1254 0.5846 0.8016 +vn -0.1303 0.5848 0.8006 +vn -0.0486 -0.4170 0.9076 +vn -0.0407 -0.7164 0.6965 +vn -0.0162 0.1718 0.9850 +vn 0.0517 0.6513 0.7570 +vn 0.0709 0.0374 0.9968 +vn -0.1083 -0.6667 0.7374 +vn -0.1530 0.9835 0.0965 +vn -0.2325 -0.0621 0.9706 +vn -0.2133 -0.0305 0.9765 +vn -0.3316 -0.1349 0.9337 +vn -0.0670 -0.1142 0.9912 +vn -0.0644 0.0679 0.9956 +vn -0.0291 0.1767 0.9838 +vn -0.3303 -0.0778 0.9407 +vn -0.1432 0.4732 0.8693 +vn 0.8627 -0.2215 -0.4547 +vn 0.1950 -0.0196 0.9806 +vn 0.1880 -0.0912 0.9779 +vn -0.1333 -0.6914 0.7100 +vn -0.3806 -0.3337 0.8624 +vn -0.3364 -0.3244 0.8841 +vn -0.3235 -0.1749 0.9299 +vn -0.0417 0.0520 0.9978 +vn -0.1044 0.1453 0.9839 +vn -0.1031 0.1433 0.9843 +vn -0.1022 0.1410 0.9847 +vn -0.1040 0.1459 0.9838 +vn -0.0462 0.5065 0.8610 +vn -0.1870 0.8688 0.4585 +vn -0.0602 0.3276 0.9429 +vn -0.1494 0.7560 0.6373 +vn -0.1548 0.7797 0.6067 +vn 0.2860 0.3074 0.9076 +vn 0.3218 0.3108 0.8944 +vn -0.2109 -0.0482 0.9763 +vn 0.2539 0.0350 0.9666 +vn -0.0165 0.3352 0.9420 +vn 0.5930 0.0128 -0.8051 +vn -0.0316 0.9561 0.2913 +vn -0.0317 0.9565 0.2901 +vn -0.0274 0.9559 0.2925 +vn -0.1252 0.5845 0.8017 +vn 0.9112 0.2012 -0.3596 +vn 0.3008 0.1309 0.9447 +vn -0.1016 -0.6904 0.7162 +vn -0.2272 -0.4139 0.8815 +vn 0.0147 -0.4630 0.8862 +vn -0.0488 -0.1350 0.9896 +vn -0.1955 -0.4729 0.8592 +vn 0.2120 0.1802 0.9605 +vn 0.0107 -0.9601 -0.2793 +vn 0.0845 0.0977 0.9916 +vn -0.2965 -0.0521 0.9536 +vn 0.0450 -0.4237 0.9047 +vn -0.2738 -0.1158 0.9548 +vn -0.1916 0.0282 0.9811 +vn -0.1877 0.0675 0.9799 +vn -0.0263 0.1423 0.9895 +vn -0.9579 0.2869 0.0125 +vn -0.9602 0.2786 0.0191 +vn -0.9580 0.2864 0.0112 +vn 0.1499 0.2125 0.9656 +vn 0.0657 0.2081 0.9759 +vn 0.3804 -0.0864 0.9208 +vn 0.3792 -0.0836 0.9215 +vn 0.3783 -0.0817 0.9221 +vn 0.7781 -0.2665 0.5688 +vn 0.3779 -0.0807 0.9223 +vn -0.3411 0.8050 0.4853 +vn 0.4844 0.4103 0.7727 +vn 0.4837 -0.2852 0.8275 +vn 0.4067 -0.3183 0.8563 +vn 0.1699 -0.7886 0.5910 +vn 0.4385 0.3837 0.8127 +vn 0.3579 -0.1868 -0.9149 +vn 0.4366 0.2367 0.8680 +vn 0.3156 -0.3229 0.8923 +vn 0.5544 -0.0751 0.8289 +vn 0.8221 -0.1490 0.5495 +vn 0.9746 0.0328 -0.2217 +vn 0.2260 0.1987 0.9537 +vn 0.7265 -0.0178 0.6870 +vn 0.5735 -0.2552 0.7784 +vn 0.5772 -0.2534 0.7763 +vn 0.5737 -0.2554 0.7782 +vn -0.0939 -0.5213 -0.8482 +vn -0.0943 -0.5213 -0.8481 +vn -0.0966 -0.5214 -0.8478 +vn 0.4022 -0.5396 0.7397 +vn 0.5227 0.0789 0.8488 +vn 0.3146 0.3106 0.8970 +vn 0.5248 -0.7965 -0.3002 +vn 0.6297 -0.3911 -0.6712 +vn 0.9206 0.1185 -0.3722 +vn 0.1572 0.7920 0.5899 +vn 0.4873 -0.2898 0.8238 +vn 0.9255 0.3272 0.1906 +vn -0.2419 0.7197 -0.6508 +vn 0.4245 0.3181 0.8477 +vn 0.2567 0.4111 0.8747 +vn 0.5531 -0.3104 0.7731 +vn 0.9108 -0.1017 0.4000 +vn -0.0031 -0.6742 0.7385 +vn 0.4641 0.3310 0.8216 +vn 0.5224 0.2798 0.8055 +vn 0.8081 0.4863 -0.3322 +vn 0.5751 0.3422 0.7431 +vn -0.9344 0.2665 0.2364 +vn 0.2364 0.4426 0.8650 +vn 0.2282 0.4404 0.8683 +vn 0.2319 0.4412 0.8670 +vn 0.4638 0.3260 0.8238 +vn 0.3366 -0.1858 0.9231 +vn 0.3353 -0.1867 0.9234 +vn 0.3352 -0.1872 0.9234 +vn 0.1638 0.7406 0.6517 +vn 0.2090 -0.7106 0.6718 +vn 0.2116 -0.7106 0.6710 +vn 0.2092 -0.7106 0.6718 +vn -0.0686 -0.6219 -0.7801 +vn 0.6413 -0.5086 0.5745 +vn -0.6563 -0.7376 -0.1587 +vn 0.6472 0.0848 0.7576 +vn 0.7602 0.3290 0.5603 +vn 0.3566 0.3269 0.8752 +vn 0.5924 -0.1100 0.7981 +vn 0.4596 0.4515 0.7648 +vn 0.6692 -0.5390 0.5116 +vn 0.6969 -0.3604 0.6201 +vn 0.5845 0.2971 0.7551 +vn 0.0220 0.9063 0.4221 +vn 0.7853 0.0346 0.6182 +vn 0.7353 0.1880 0.6511 +vn 0.9583 0.0428 0.2824 +vn 0.5487 -0.7074 0.4456 +vn 0.8520 -0.1026 0.5134 +vn 0.8481 -0.1538 0.5070 +vn 0.7974 0.2273 0.5590 +vn 0.6893 0.3792 0.6173 +vn 0.6866 0.3994 0.6075 +vn 0.7897 -0.1678 0.5901 +vn 0.7455 -0.0356 0.6656 +vn 0.7520 -0.1165 0.6488 +vn 0.7897 0.3393 0.5110 +vn 0.2276 0.4398 0.8688 +vn -0.1214 0.2213 -0.9676 +vn 0.5452 -0.7787 0.3104 +vn 0.7400 -0.5561 0.3783 +vn 0.7853 0.1829 0.5914 +vn 0.9507 -0.2393 -0.1973 +vn 0.6803 0.2929 0.6719 +vn 0.7735 -0.0517 0.6317 +vn 0.6942 0.0837 0.7149 +vn 0.4213 0.2282 0.8777 +vn 0.4956 0.4628 0.7350 +vn 0.7079 -0.6200 0.3384 +vn 0.8694 -0.3447 0.3541 +vn 0.7708 0.4094 0.4881 +vn 0.6574 -0.0953 0.7475 +vn 0.8038 -0.0648 0.5914 +vn 0.8340 0.2112 0.5098 +vn 0.7722 0.0936 0.6284 +vn 0.0570 0.2949 -0.9538 +vn 0.0654 0.2887 -0.9552 +vn 0.0575 0.2944 -0.9539 +vn 0.5775 -0.2528 0.7763 +vn 0.3861 -0.0454 0.9213 +vn 0.8087 0.2697 0.5228 +vn 0.4899 -0.0074 0.8717 +vn 0.8841 -0.0826 0.4600 +vn 0.7757 0.3731 0.5090 +vn 0.8997 0.0801 0.4292 +vn 0.3073 0.3014 0.9026 +vn 0.5039 -0.2955 0.8117 +vn 0.6288 -0.5151 0.5825 +vn 0.4906 0.3734 0.7873 +vn 0.4647 -0.8295 0.3098 +vn 0.2700 -0.1784 0.9462 +vn 0.8402 0.3260 0.4333 +vn 0.8428 -0.0052 0.5382 +vn 0.8425 -0.0039 0.5387 +vn 0.6929 -0.6117 0.3817 +vn 0.8789 0.0650 0.4726 +vn -0.1306 0.3004 -0.9448 +vn 0.8693 -0.0838 0.4871 +vn 0.4840 -0.4521 0.7492 +vn 0.5910 -0.1730 0.7879 +vn 0.5104 0.2075 0.8345 +vn 0.5356 0.1252 0.8351 +vn 0.6050 -0.3574 0.7115 +vn 0.5160 -0.6994 -0.4944 +vn 0.7740 -0.4106 0.4819 +vn 0.6652 -0.5411 0.5146 +vn 0.7912 0.0414 0.6102 +vn 0.4930 0.3087 0.8134 +vn 0.5761 0.4357 0.6916 +vn 0.5947 0.4082 0.6926 +vn 0.6296 0.4750 0.6148 +vn 0.7489 0.2672 0.6065 +vn 0.8272 -0.1375 0.5449 +vn 0.8180 0.0604 0.5721 +vn 0.5279 -0.4583 0.7151 +vn 0.8377 -0.1910 0.5116 +vn 0.6361 -0.6760 -0.3720 +vn 0.4433 -0.1878 0.8765 +vn 0.7258 -0.5843 0.3630 +vn 0.3755 -0.1351 0.9169 +vn -0.0755 0.1723 -0.9821 +vn 0.5069 0.6052 0.6139 +vn 0.2872 0.2337 0.9289 +vn 0.5313 -0.2417 0.8120 +vn 0.5557 0.2643 0.7882 +vn -0.2033 0.7611 0.6159 +vn 0.0150 0.1613 0.9868 +vn 0.0860 0.0908 0.9922 +vn 0.5274 -0.6529 -0.5437 +vn -0.7568 -0.3227 -0.5684 +vn 0.4648 0.4861 0.7401 +vn -0.0077 0.1693 0.9855 +vn 0.4280 -0.0273 0.9034 +vn 0.5594 -0.7570 0.3376 +vn 0.5667 0.5051 0.6509 +vn -0.0937 -0.7270 -0.6802 +vn 0.4340 -0.4723 0.7672 +vn 0.4304 -0.4787 0.7652 +vn 0.4333 -0.4736 0.7668 +vn 0.3581 -0.5185 0.7765 +vn 0.4297 -0.4799 0.7649 +vn 0.7177 -0.0400 0.6952 +vn 0.3618 -0.6101 0.7049 +vn 0.2788 0.6127 0.7395 +vn 0.1916 0.4562 0.8690 +vn 0.5808 0.2287 0.7812 +vn 0.4151 0.4021 0.8161 +vn 0.4507 0.1815 0.8740 +vn 0.7295 -0.1390 0.6697 +vn 0.6897 -0.3646 0.6256 +vn 0.6293 -0.1955 0.7521 +vn 0.5408 0.1919 0.8190 +vn 0.4715 -0.8614 -0.1888 +vn 0.4631 -0.7570 0.4609 +vn 0.2846 0.6566 0.6985 +vn 0.4036 -0.4969 0.7682 +vn 0.5630 -0.2671 0.7821 +vn 0.5627 -0.2639 0.7834 +vn 0.5626 -0.2667 0.7825 +vn 0.5632 -0.2634 0.7832 +vn 0.4857 0.4387 0.7561 +vn 0.4087 0.4366 0.8015 +vn 0.5275 0.3721 0.7637 +vn 0.2883 0.6349 0.7168 +vn 0.4615 0.4974 0.7346 +vn 0.5959 0.2163 0.7734 +vn 0.5415 0.3035 0.7840 +vn 0.6088 0.1689 0.7751 +vn 0.7809 -0.0211 0.6243 +vn 0.7782 -0.0044 0.6280 +vn 0.7738 0.3123 -0.5512 +vn 0.0927 -0.7255 -0.6820 +vn 0.6333 -0.1668 0.7557 +vn 0.6388 0.1213 0.7598 +vn 0.8382 -0.0836 0.5389 +vn -0.1066 -0.6399 0.7610 +vn 0.3714 0.2612 0.8910 +vn 0.1947 0.4986 0.8447 +vn 0.2639 0.3030 0.9157 +vn 0.2631 0.3029 0.9160 +vn 0.2575 0.2968 0.9196 +vn 0.5021 -0.7847 0.3635 +vn 0.2303 0.7522 0.6173 +vn 0.2294 0.7509 0.6193 +vn 0.2304 0.7525 0.6169 +vn 0.8781 0.4574 0.1404 +vn 0.7103 0.2580 0.6549 +vn 0.5965 0.4404 0.6711 +vn 0.5777 -0.7984 -0.1698 +vn 0.3316 0.6077 0.7216 +vn 0.6484 0.0959 0.7552 +vn 0.9101 -0.4065 -0.0802 +vn 0.9102 -0.4063 -0.0801 +vn 0.9099 -0.4067 -0.0816 +vn 0.4305 0.2015 0.8798 +vn 0.4296 0.1992 0.8808 +vn 0.4292 0.1988 0.8810 +vn 0.3030 -0.0528 0.9515 +vn 0.6728 -0.5310 0.5152 +vn 0.5665 0.4499 0.6904 +vn 0.7079 -0.1314 0.6940 +vn 0.0593 -0.9702 0.2349 +vn 0.7471 -0.6027 -0.2804 +vn 0.4490 0.2904 0.8450 +vn 0.3161 0.6208 0.7174 +vn 0.5054 0.3167 0.8027 +vn 0.9149 0.3986 -0.0635 +vn 0.5988 -0.2862 0.7480 +vn -0.3416 0.3267 -0.8812 +vn -0.3360 0.3213 -0.8853 +vn -0.3371 0.3222 -0.8846 +vn 0.4551 0.0814 0.8867 +vn 0.6707 0.2559 0.6962 +vn 0.7825 0.1177 0.6115 +vn 0.2913 0.0418 0.9557 +vn 0.2922 0.0405 0.9555 +vn 0.2922 0.0400 0.9555 +vn 0.2893 0.0998 0.9520 +vn 0.6698 0.2385 0.7033 +vn 0.6705 0.2404 0.7018 +vn 0.6699 0.2391 0.7029 +vn 0.7447 -0.5035 0.4382 +vn 0.6975 0.4494 0.5581 +vn 0.7587 -0.1336 0.6376 +vn 0.5387 -0.2006 0.8183 +vn 0.6635 -0.2444 0.7071 +vn 0.6671 -0.2394 0.7055 +vn 0.6631 -0.2326 0.7114 +vn 0.5875 -0.5397 0.6030 +vn 0.5009 -0.0103 0.8655 +vn 0.6654 -0.2997 0.6837 +vn 0.4913 0.1884 0.8504 +vn 0.7265 -0.1416 0.6724 +vn 0.2910 0.0424 0.9558 +vn 0.4526 -0.2833 0.8455 +vn 0.8582 0.0210 0.5129 +vn -0.3682 -0.9038 -0.2179 +vn 0.5288 -0.2161 0.8208 +vn 0.5414 -0.1821 0.8208 +vn 0.4306 0.2020 0.8797 +vn 0.7096 -0.1791 0.6815 +vn 0.7804 0.0528 0.6230 +vn 0.8401 0.1106 0.5311 +vn 0.8512 0.0720 0.5198 +vn 0.4839 -0.5898 0.6465 +vn 0.5436 -0.0571 0.8374 +vn 0.6161 0.1024 0.7810 +vn -0.0193 0.7139 0.7000 +vn 0.4344 0.5496 0.7136 +vn 0.7651 -0.3047 0.5672 +vn 0.4885 -0.2731 0.8288 +vn 0.3915 0.1998 0.8982 +vn 0.2381 0.4212 0.8751 +vn 0.4235 0.4274 0.7987 +vn 0.4229 0.4238 0.8010 +vn 0.8197 -0.0716 0.5683 +vn -0.8958 0.4264 -0.1254 +vn 0.6964 -0.2571 0.6700 +vn 0.6947 0.2959 0.6556 +vn 0.6930 0.2956 0.6575 +vn 0.6928 0.2960 0.6576 +vn 0.6054 0.2705 0.7486 +vn 0.3095 -0.5708 -0.7605 +vn 0.5857 -0.1011 0.8042 +vn 0.4021 -0.0832 0.9118 +vn 0.5293 0.0811 0.8445 +vn 0.4540 -0.7263 -0.5161 +vn -0.4435 0.5217 0.7288 +vn 0.6710 0.2406 0.7014 +vn 0.3893 0.1623 0.9067 +vn 0.5564 -0.0531 0.8292 +vn 0.5567 -0.0445 0.8295 +vn 0.5563 -0.0554 0.8291 +vn 0.6697 0.4822 0.5648 +vn 0.9391 -0.1274 0.3191 +vn 0.5734 0.3531 0.7393 +vn 0.4913 -0.1472 0.8585 +vn 0.9016 0.4267 0.0716 +vn 0.8990 0.4305 0.0807 +vn 0.8990 0.4304 0.0809 +vn 0.9940 0.0842 0.0701 +vn 0.6852 -0.0349 0.7275 +vn 0.3341 -0.3272 0.8839 +vn 0.5357 -0.2443 0.8083 +vn 0.4031 0.1892 0.8954 +vn 0.7808 -0.1808 0.5980 +vn 0.1794 -0.7918 -0.5839 +vn 0.5904 0.1212 0.7979 +vn -0.8039 -0.0050 -0.5947 +vn 0.7638 0.0350 0.6445 +vn 0.7701 0.1963 0.6069 +vn 0.6965 0.2958 0.6537 +vn 0.7319 0.4407 0.5198 +vn 0.7665 0.1610 0.6217 +vn 0.5015 -0.4880 0.7144 +vn 0.6078 0.0254 0.7937 +vn 0.5413 -0.2914 0.7887 +vn 0.5396 0.2885 0.7910 +vn 0.5579 0.1309 0.8195 +vn 0.6240 -0.2501 0.7404 +vn 0.5568 -0.0421 0.8296 +vn 0.7193 0.4574 0.5228 +vn 0.5425 -0.0505 0.8385 +vn 0.6637 -0.2145 0.7166 +vn 0.5529 0.2599 0.7917 +vn 0.6034 0.0819 0.7932 +vn 0.4793 0.4915 0.7271 +vn 0.3016 -0.2877 0.9090 +vn 0.9003 0.1334 0.4144 +vn -0.7981 -0.5696 0.1963 +vn 0.3710 -0.0547 0.9270 +vn 0.8566 0.1575 0.4914 +vn -0.3465 0.7943 0.4990 +vn 0.4132 0.3444 0.8430 +vn 0.8116 -0.5558 -0.1801 +vn 0.4018 0.3931 0.8271 +vn 0.5452 -0.0504 0.8368 +vn 0.5465 -0.0472 0.8361 +vn 0.5451 -0.0496 0.8369 +vn -0.9754 -0.1901 0.1118 +vn 0.5213 0.1998 0.8297 +vn 0.6282 0.1264 0.7677 +vn 0.5758 -0.1014 0.8113 +vn 0.4787 0.1023 0.8720 +vn 0.4757 0.0907 0.8749 +vn 0.4756 0.0924 0.8748 +vn 0.8565 0.0880 0.5086 +vn 0.8738 0.0174 0.4860 +vn 0.7950 0.4306 0.4272 +vn 0.2121 0.0352 0.9766 +vn 0.2132 0.0324 0.9765 +vn 0.2124 0.0346 0.9766 +vn 0.5110 -0.3942 0.7639 +vn 0.7357 0.4216 0.5301 +vn 0.4761 -0.5038 0.7208 +vn 0.5638 0.0181 0.8257 +vn 0.5312 0.0125 0.8471 +vn 0.6285 0.3605 0.6892 +vn 0.7601 -0.3185 0.5664 +vn 0.8370 -0.0389 0.5458 +vn 0.6360 0.0351 0.7709 +vn 0.7164 -0.0293 -0.6971 +vn 0.7855 -0.5654 -0.2516 +vn 0.8794 0.0325 0.4750 +vn -0.4557 0.8072 -0.3751 +vn -0.2030 -0.4195 -0.8848 +vn 0.4751 -0.4382 0.7630 +vn 0.6005 0.1141 0.7915 +vn 0.6002 0.1164 0.7913 +vn 0.6007 0.1131 0.7915 +vn 0.2280 0.4087 0.8837 +vn 0.7035 -0.3939 0.5915 +vn 0.7035 -0.3940 0.5915 +vn 0.5284 -0.2565 0.8093 +vn 0.8525 0.1376 0.5043 +vn 0.5797 -0.3119 0.7528 +vn 0.5579 -0.2835 0.7800 +vn -0.5566 0.1960 -0.8073 +vn 0.8774 0.2488 0.4102 +vn 0.1634 -0.9129 -0.3740 +vn 0.1169 0.0736 0.9904 +vn 0.3151 0.4329 0.8446 +vn 0.1260 -0.0467 0.9909 +vn 0.8212 -0.0043 0.5707 +vn 0.7875 -0.0992 0.6083 +vn 0.5822 -0.7105 -0.3952 +vn 0.4604 -0.2544 0.8504 +vn 0.7786 0.2844 0.5594 +vn 0.3811 0.4558 0.8044 +vn 0.9108 -0.4047 -0.0817 +vn 0.9109 -0.4046 -0.0813 +vn 0.2279 0.0566 0.9720 +vn 0.5325 -0.7043 0.4694 +vn 0.4996 0.0915 0.8614 +vn 0.5609 -0.0756 0.8244 +vn -0.2542 -0.2227 -0.9412 +vn -0.7672 -0.1758 0.6168 +vn 0.4595 -0.6680 0.5853 +vn 0.6273 0.2830 0.7255 +vn -0.9891 -0.1388 -0.0484 +vn 0.8862 -0.0490 0.4606 +vn 0.2136 0.0320 0.9764 +vn 0.4669 -0.0067 0.8843 +vn 0.2469 0.1056 0.9633 +vn 0.7422 0.2785 0.6095 +vn 0.6697 0.3816 0.6371 +vn 0.6409 -0.2551 0.7240 +vn 0.0235 -0.6178 -0.7860 +vn 0.5803 -0.3093 0.7534 +vn 0.4301 -0.1854 0.8835 +vn 0.7970 -0.3187 0.5130 +vn 0.9992 -0.0183 0.0360 +vn 0.9825 0.1270 -0.1364 +vn 0.9948 0.0485 -0.0900 +vn 0.4351 -0.5419 0.7190 +vn 0.7456 0.3861 0.5431 +vn 0.3335 -0.9222 -0.1958 +vn 0.6263 -0.3766 0.6826 +vn 0.6946 0.2941 0.6565 +vn -0.2421 0.3317 -0.9118 +vn 0.2484 0.7419 0.6228 +vn 0.2490 0.7413 0.6232 +vn 0.2485 0.7418 0.6229 +vn 0.5586 -0.0530 0.8278 +vn -0.0584 -0.9040 -0.4235 +vn 0.6882 0.5334 0.4919 +vn 0.5691 0.1666 0.8052 +vn 0.9993 0.0360 -0.0096 +vn 0.7560 0.6479 -0.0934 +vn 0.6275 0.0083 0.7785 +vn -0.0067 -0.4894 0.8721 +vn 0.0373 0.0336 0.9987 +vn -0.0676 0.2166 0.9739 +vn -0.0669 0.2169 0.9739 +vn -0.0629 0.2238 0.9726 +vn -0.0633 0.2243 0.9725 +vn 0.5309 -0.6254 0.5718 +vn 0.8278 -0.5215 -0.2068 +vn 0.8374 -0.5088 -0.1999 +vn 0.8365 -0.5109 -0.1982 +vn 0.2040 0.8208 0.5336 +vn 0.3413 0.1279 0.9312 +vn -0.9577 -0.2520 0.1392 +vn 0.6357 0.7460 -0.1983 +vn 0.3898 -0.0494 0.9196 +vn 0.6409 0.1007 0.7610 +vn 0.5523 -0.4420 0.7068 +vn 0.5442 -0.4454 0.7110 +vn 0.5438 -0.4461 0.7108 +vn 0.2481 0.6887 0.6813 +vn 0.8505 -0.2854 0.4418 +vn 0.2260 0.4759 0.8500 +vn 0.6174 -0.2304 0.7522 +vn 0.2976 0.6254 0.7213 +vn 0.8535 0.0755 0.5155 +vn 0.3271 0.3232 0.8880 +vn 0.8632 -0.3521 0.3619 +vn 0.7723 -0.2166 0.5972 +vn 0.3665 0.8410 -0.3980 +vn 0.8522 -0.5232 -0.0058 +vn 0.8725 0.4886 -0.0043 +vn 0.4680 -0.4376 -0.7678 +vn 0.2510 0.5480 0.7980 +vn 0.8895 0.2815 0.3600 +vn 0.9021 -0.0790 0.4242 +vn 0.4568 0.7554 0.4697 +vn 0.7119 0.4107 -0.5697 +vn 0.3157 0.0312 0.9484 +vn 0.0077 -0.9979 0.0640 +vn 0.0103 -0.9979 0.0646 +vn 0.0077 -0.9976 0.0684 +vn -0.6394 0.7393 0.2111 +vn 0.3186 0.3962 0.8611 +vn 0.8893 0.3469 -0.2981 +vn 0.2956 -0.2382 0.9251 +vn 0.6234 0.4608 0.6316 +vn 0.7744 -0.2538 0.5795 +vn 0.7160 -0.0666 0.6949 +vn 0.3194 0.6430 0.6961 +vn 0.6413 -0.1198 0.7579 +vn 0.1476 0.5197 0.8415 +vn 0.2926 -0.0419 0.9553 +vn 0.1603 0.2093 0.9646 +vn 0.9043 -0.0457 0.4245 +vn 0.5243 -0.3483 0.7770 +vn 0.7763 -0.0365 0.6293 +vn 0.9070 -0.3115 -0.2835 +vn 0.9070 -0.3114 -0.2835 +vn 0.8180 -0.0455 0.5734 +vn 0.5166 0.0670 0.8536 +vn 0.3057 0.3093 0.9005 +vn 0.2481 0.7422 0.6226 +vn 0.7997 0.0398 0.5991 +vn 0.5017 -0.1583 0.8504 +vn 0.7164 -0.0922 0.6916 +vn 0.6698 0.2433 0.7015 +vn 0.6785 -0.5718 0.4613 +vn 0.6765 -0.5793 0.4548 +vn 0.6789 -0.5707 0.4620 +vn 0.9430 0.1159 -0.3121 +vn 0.9070 -0.3116 -0.2835 +vn 0.5563 -0.2707 0.7856 +vn -0.0152 0.0681 -0.9976 +vn -0.5116 0.1719 -0.8419 +vn 0.8613 -0.1865 0.4725 +vn 0.9010 -0.1097 0.4197 +vn 0.8530 0.1131 0.5095 +vn -0.0309 0.2957 0.9548 +vn 0.7256 0.3806 0.5733 +vn -0.8919 -0.4446 0.0833 +vn 0.7828 0.0201 0.6220 +vn 0.7636 -0.0720 0.6417 +vn 0.6519 -0.3779 0.6574 +vn 0.5019 0.2076 0.8397 +vn 0.7767 0.4955 -0.3889 +vn 0.4890 -0.6843 -0.5409 +vn 0.9583 0.2854 0.0158 +vn 0.3587 0.1317 0.9241 +vn 0.5111 -0.2829 0.8116 +vn 0.9483 0.2394 0.2084 +vn 0.9477 0.2390 0.2116 +vn 0.9469 0.2384 0.2156 +vn 0.2430 -0.0906 0.9658 +vn 0.4058 -0.5950 -0.6938 +vn -0.0931 -0.6067 -0.7894 +vn 0.6459 -0.1002 0.7568 +vn 0.6528 0.2000 0.7307 +vn 0.6850 -0.6643 -0.2992 +vn 0.8936 0.2808 -0.3501 +vn 0.6526 -0.7315 0.1976 +vn 0.3599 0.2577 0.8967 +vn 0.5241 -0.2085 0.8257 +vn 0.7818 -0.3251 -0.5321 +vn -0.1411 0.1857 -0.9724 +vn 0.8429 -0.0054 0.5381 +vn 0.5402 -0.4016 0.7395 +vn 0.7764 0.0371 0.6292 +vn 0.5279 -0.1615 0.8338 +vn 0.3400 0.6529 0.6769 +vn 0.2854 0.5133 0.8093 +vn 0.4629 -0.2232 0.8578 +vn 0.5919 0.0944 0.8004 +vn 0.3248 -0.5837 0.7442 +vn 0.3752 -0.1750 0.9103 +vn 0.2782 0.9272 0.2509 +vn 0.4715 -0.5341 0.7017 +vn 0.4246 0.0212 0.9051 +vn 0.9469 0.2643 0.1830 +vn 0.5856 -0.8072 -0.0745 +vn 0.4097 -0.0419 0.9113 +vn 0.7699 -0.1248 0.6258 +vn 0.7729 -0.3531 -0.5271 +vn 0.4615 -0.5203 0.7186 +vn -0.9762 0.0138 0.2165 +vn -0.9733 0.0150 0.2290 +vn -0.9758 0.0143 0.2184 +vn -0.2194 0.6386 -0.7376 +vn 0.3182 -0.1574 0.9348 +vn 0.9077 -0.0317 0.4183 +vn 0.8382 0.2944 0.4590 +vn 0.3766 0.2072 0.9029 +vn 0.3729 0.2034 0.9053 +vn 0.3739 0.2040 0.9048 +vn -0.2458 0.4420 0.8627 +vn 0.1415 0.8669 0.4780 +vn 0.3711 -0.1060 0.9225 +vn 0.7473 0.0730 0.6604 +vn 0.8099 -0.0494 0.5845 +vn 0.2565 -0.2187 0.9415 +vn 0.8681 0.1665 0.4676 +vn 0.6087 0.2289 0.7597 +vn 0.5742 0.1410 0.8065 +vn 0.2118 -0.7107 0.6709 +vn 0.7978 -0.1957 0.5703 +vn 0.9572 0.0213 0.2885 +vn 0.5777 -0.4505 0.6807 +vn 0.3010 0.3423 0.8901 +vn 0.3605 0.7340 0.5756 +vn -0.1043 -0.1229 -0.9869 +vn 0.8844 0.3113 -0.3478 +vn 0.3292 0.0202 0.9440 +vn 0.7651 -0.2180 0.6059 +vn 0.4527 0.4482 0.7708 +vn 0.6201 -0.0550 0.7826 +vn 0.7342 -0.2705 0.6227 +vn 0.5637 0.3239 0.7598 +vn 0.7196 -0.2061 0.6631 +vn 0.7197 -0.2061 0.6630 +vn 0.7196 -0.2056 0.6632 +vn 0.0218 -0.9996 -0.0171 +vn 0.0186 -0.9996 -0.0211 +vn 0.0188 -0.9996 -0.0219 +vn 0.9284 0.2427 -0.2814 +vn -0.2405 -0.4664 -0.8512 +vn 0.5026 -0.1352 0.8539 +vn 0.3087 0.3115 0.8987 +vn 0.5314 -0.4029 0.7451 +vn 0.2666 0.1957 0.9437 +vn 0.9683 0.0505 0.2447 +vn -0.1954 0.7655 -0.6131 +vn -0.1921 0.7656 -0.6139 +vn -0.1961 0.7652 -0.6132 +vn 0.7538 0.0310 0.6564 +vn 0.7612 0.0346 0.6476 +vn 0.7543 0.0318 0.6558 +vn 0.7802 0.3572 0.5135 +vn 0.3593 0.2286 0.9048 +vn 0.6887 -0.6169 -0.3810 +vn 0.6275 -0.7571 0.1816 +vn 0.4695 -0.8493 -0.2412 +vn 0.3126 0.0070 0.9498 +vn 0.6154 -0.1456 0.7746 +vn 0.4064 -0.1468 0.9018 +vn 0.6791 -0.4548 0.5762 +vn 0.3780 -0.1357 0.9158 +vn 0.5836 0.0805 0.8081 +vn 0.6755 -0.0464 0.7359 +vn 0.8325 0.1491 0.5336 +vn 0.8985 0.4361 0.0496 +vn 0.5794 -0.1572 0.7997 +vn 0.7540 -0.1604 0.6370 +vn 0.5809 0.2461 0.7759 +vn 0.3593 0.1123 0.9264 +vn 0.8301 -0.0992 -0.5487 +vn 0.8633 0.1084 0.4929 +vn 0.4249 -0.1810 0.8870 +vn 0.5058 -0.0224 0.8623 +vn 0.4682 -0.2475 0.8482 +vn 0.3569 0.5037 0.7867 +vn 0.7457 0.3125 0.5885 +vn 0.5528 -0.4421 0.7064 +vn 0.4547 -0.0645 0.8883 +vn 0.3593 -0.6296 0.6888 +vn 0.8715 -0.0048 -0.4903 +vn -0.4958 0.7457 -0.4451 +vn 0.4201 0.2261 0.8789 +vn 0.5094 -0.1476 0.8478 +vn 0.4713 -0.7204 -0.5088 +vn 0.6671 -0.7214 0.1858 +vn 0.9283 -0.0801 -0.3631 +vn 0.5995 -0.3980 0.6943 +vn 0.9313 -0.0373 -0.3624 +vn -0.0312 0.0910 -0.9954 +vn 0.4665 -0.3711 0.8029 +vn 0.5006 -0.6755 0.5413 +vn -0.0493 -0.0576 0.9971 +vn 0.5478 -0.5523 0.6285 +vn 0.0421 0.6683 0.7427 +vn 0.3533 0.3982 0.8465 +vn -0.0077 0.8131 0.5821 +vn -0.0033 0.8138 0.5812 +vn -0.0025 0.8131 0.5821 +vn 0.4813 -0.3682 0.7955 +vn 0.3178 0.0980 0.9431 +vn 0.2870 -0.0518 0.9565 +vn 0.3989 0.1600 0.9029 +vn 0.2287 0.7509 0.6195 +vn 0.5234 -0.0324 0.8515 +vn 0.6856 -0.2965 0.6649 +vn 0.5468 -0.5865 0.5975 +vn 0.6666 -0.2280 0.7097 +vn 0.6638 -0.2295 0.7119 +vn 0.6085 0.3647 0.7047 +vn 0.8790 0.0109 -0.4767 +vn 0.5347 -0.0840 0.8408 +vn 0.5479 -0.0479 0.8352 +vn 0.8818 -0.0776 0.4653 +vn 0.8819 -0.0781 0.4649 +vn 0.8826 -0.0793 0.4635 +vn 0.3370 -0.0867 0.9375 +vn 0.0271 -0.8411 -0.5402 +vn 0.5315 -0.3480 0.7723 +vn 0.4495 -0.1190 0.8853 +vn 0.8828 -0.0795 0.4629 +vn 0.7473 -0.0568 -0.6620 +vn 0.7980 -0.2364 0.5543 +vn 0.3026 -0.0778 0.9499 +vn 0.3025 -0.0783 0.9499 +vn 0.3100 -0.0780 0.9475 +vn 0.4264 0.5104 0.7467 +vn 0.9872 0.0210 -0.1582 +vn 0.7314 -0.2933 0.6157 +vn 0.3601 -0.9219 -0.1427 +vn 0.2976 -0.2068 0.9320 +vn 0.6583 0.4061 0.6339 +vn 0.2411 0.4050 0.8819 +vn 0.5638 -0.7661 0.3085 +vn 0.3067 0.5921 0.7452 +vn 0.7050 -0.1544 0.6922 +vn 0.7208 -0.1206 0.6826 +vn 0.9915 0.0495 0.1203 +vn 0.9915 0.0489 0.1210 +vn 0.9905 0.0467 0.1294 +vn -0.5402 -0.0699 0.8386 +vn 0.3566 0.4923 0.7940 +vn 0.0328 0.4376 0.8986 +vn 0.2359 0.5104 0.8270 +vn 0.5130 0.0094 0.8583 +vn 0.5121 0.1232 0.8501 +vn 0.3030 0.8154 0.4932 +vn 0.6593 0.1347 0.7397 +vn 0.7691 -0.3100 0.5590 +vn 0.5895 -0.5649 0.5773 +vn -0.3959 -0.8879 -0.2343 +vn 0.2732 0.1769 -0.9456 +vn 0.7108 -0.3131 0.6298 +vn 0.5829 -0.4188 0.6963 +vn 0.6666 -0.0907 0.7398 +vn 0.6001 0.1176 0.7912 +vn -0.1682 0.8300 0.5318 +vn -0.8464 0.4618 0.2653 +vn 0.6873 -0.0120 0.7263 +vn 0.6939 0.1942 0.6934 +vn 0.6334 0.3904 0.6682 +vn -0.1168 0.1260 -0.9851 +vn 0.4766 -0.1171 0.8713 +vn 0.7158 -0.3383 0.6109 +vn 0.5114 0.4052 0.7579 +vn 0.4570 0.2859 0.8423 +vn 0.3060 0.3218 0.8960 +vn 0.5900 0.7445 0.3125 +vn 0.7341 -0.0399 0.6779 +vn 0.0594 0.7992 0.5981 +vn 0.7098 -0.4261 0.5610 +vn -0.0082 0.8128 0.5825 +vn 0.8013 -0.1559 0.5775 +vn -0.7086 -0.7031 0.0596 +vn 0.8916 0.4390 -0.1113 +vn 0.6667 -0.2264 0.7101 +vn 0.7528 -0.2256 0.6184 +vn 0.6037 0.0734 0.7938 +vn 0.7617 0.0339 0.6471 +vn 0.6949 0.2086 0.6881 +vn 0.3302 0.1830 0.9260 +vn 0.3640 -0.3783 0.8511 +vn 0.5929 -0.1853 0.7837 +vn 0.3771 0.2083 0.9024 +vn 0.0582 -0.0582 -0.9966 +vn -0.0908 0.2561 0.9624 +vn 0.4617 0.5268 0.7137 +vn 0.4621 0.5265 0.7136 +vn 0.4624 0.5262 0.7137 +vn 0.4697 0.5194 0.7139 +vn 0.4931 -0.0132 0.8699 +vn 0.7434 0.1883 0.6419 +vn 0.3372 -0.1861 0.9228 +vn 0.2577 0.2960 0.9198 +vn 0.4797 0.1032 0.8713 +vn -0.0058 0.3129 0.9498 +vn -0.8915 0.3435 0.2952 +vn 0.3423 0.5946 0.7275 +vn 0.4718 0.3678 0.8013 +vn 0.3432 0.4138 0.8432 +vn 0.8950 -0.4359 -0.0943 +vn 0.7196 -0.2063 0.6630 +vn 0.9515 0.1548 -0.2660 +vn -0.8715 -0.4160 0.2596 +vn -0.9606 0.2774 0.0199 +vn -0.9990 0.0427 -0.0106 +vn 0.9855 -0.1577 -0.0621 +vn 0.9839 -0.1739 -0.0421 +vn 0.9450 0.3248 0.0394 +vn 0.3717 -0.9137 -0.1641 +vn -0.9701 -0.2203 -0.1021 +vn -0.8798 0.4491 -0.1560 +vn -0.6826 0.0935 0.7248 +vn -0.7814 -0.5367 0.3184 +vn -0.4640 -0.0000 0.8858 +vn -0.9935 0.0213 -0.1121 +vn 0.0244 -0.9990 0.0375 +vn 0.0404 -0.9983 0.0412 +vn 0.0413 -0.9983 0.0417 +vn -0.9281 0.2285 0.2938 +vn -0.9809 0.0631 0.1840 +vn -0.9469 0.3014 0.1121 +vn -0.3269 0.8924 -0.3112 +vn -0.4891 0.8484 -0.2026 +vn 0.4192 -0.8186 -0.3927 +vn -0.8966 0.4246 0.1256 +vn 0.9457 0.3178 0.0682 +vn -0.9628 0.2644 0.0552 +vn 0.6985 0.0527 -0.7137 +vn -0.9285 -0.3612 -0.0862 +vn -0.9489 -0.1606 0.2718 +vn 0.7663 -0.1873 -0.6146 +vn 0.2714 -0.8453 0.4602 +vn 0.0731 -0.9781 -0.1949 +vn 0.5108 0.1246 -0.8506 +vn 0.9637 0.1901 0.1876 +vn -0.9724 0.0436 -0.2291 +vn -0.9726 -0.2032 -0.1129 +vn -0.6170 0.7400 0.2678 +vn -0.7092 0.6584 0.2521 +vn 0.9880 -0.0257 -0.1522 +vn -0.8850 0.3796 0.2696 +vn 0.8409 -0.4293 -0.3295 +vn -0.5316 0.7227 -0.4416 +vn -0.9165 -0.3732 0.1437 +vn 0.9179 -0.3254 -0.2271 +vn 0.9856 0.1408 0.0940 +vn 0.8295 -0.5178 -0.2093 +vn -0.7702 0.4066 -0.4914 +vn -0.0145 -0.6441 -0.7648 +vn -0.9028 0.2167 -0.3715 +vn 0.7805 0.3516 0.5169 +vn -0.7462 -0.3718 -0.5522 +vn 0.6289 -0.6647 -0.4034 +vn 0.9484 0.2397 0.2074 +vn 0.1880 0.8870 -0.4218 +vn 0.8462 -0.2055 -0.4916 +vn 0.8232 -0.2117 -0.5267 +vn 0.1031 -0.2209 -0.9698 +vn 0.7070 -0.5171 -0.4825 +vn -0.2746 -0.8093 -0.5192 +vn 0.7569 -0.6256 0.1890 +vn 0.7569 -0.6256 0.1891 +vn 0.7572 -0.6253 0.1887 +vn 0.5309 -0.6425 -0.5526 +vn 0.9944 0.0791 0.0696 +vn 0.9947 0.0772 0.0679 +vn 0.9937 0.0845 0.0742 +vn 0.8852 0.4170 0.2063 +vn -0.9142 0.2756 -0.2972 +vn 0.7486 0.0416 -0.6618 +vn 0.4751 -0.8739 -0.1028 +vn 0.8394 -0.5305 -0.1181 +vn 0.9713 0.1376 0.1940 +vn -0.0138 0.5649 -0.8250 +vn -0.8498 -0.4090 0.3325 +vn -0.7164 -0.6075 -0.3431 +vn 0.9920 -0.1256 0.0130 +vn 0.7579 -0.2556 -0.6002 +vn -0.7115 0.6917 0.1239 +vn -0.8629 -0.4927 0.1125 +vn 0.8582 0.0071 -0.5133 +vn 0.1869 -0.9319 -0.3108 +vn 0.8970 -0.4009 -0.1863 +vn 0.7884 0.2735 -0.5510 +vn 0.0810 0.2790 -0.9569 +vn 0.9317 0.3584 0.0594 +vn 0.7084 -0.6935 -0.1311 +vn -0.4740 0.2296 -0.8501 +vn 0.7724 -0.5244 -0.3584 +vn 0.6074 0.0762 -0.7907 +vn -0.5281 0.8487 -0.0301 +vn 0.7681 0.3739 0.5198 +vn 0.6344 -0.0613 -0.7706 +vn 0.7724 0.1280 -0.6221 +vn 0.7099 -0.6498 -0.2717 +vn -0.8654 -0.4822 -0.1364 +vn -0.8654 -0.4823 -0.1363 +vn -0.8654 -0.4822 -0.1363 +vn 0.0662 -0.4753 0.8773 +vn -0.8913 -0.1860 -0.4136 +vn -0.7786 -0.5018 -0.3768 +vn 0.7848 -0.3254 -0.5275 +vn 0.9879 -0.0881 -0.1276 +vn 0.9875 -0.0946 -0.1263 +vn 0.9880 -0.0864 -0.1278 +vn -0.9490 -0.0799 -0.3050 +vn 0.7555 -0.1856 -0.6283 +vn 0.7488 -0.1875 -0.6357 +vn 0.7486 -0.1866 -0.6362 +vn 0.6288 -0.1215 -0.7680 +vn -0.9102 -0.0364 -0.4125 +vn -0.9090 -0.0422 -0.4147 +vn -0.9091 -0.0413 -0.4144 +vn -0.8640 -0.3918 -0.3162 +vn -0.9763 -0.1434 -0.1619 +vn -0.8837 -0.3794 0.2740 +vn 0.1620 0.9574 -0.2389 +vn 0.1727 0.9559 -0.2377 +vn 0.1737 0.9557 -0.2376 +vn 0.0997 0.7249 -0.6816 +vn -0.2124 -0.4568 -0.8638 +vn 0.7348 -0.3392 -0.5873 +vn -0.1617 0.7318 0.6621 +vn 0.7132 -0.5434 0.4428 +vn 0.7471 0.0620 -0.6618 +vn 0.9757 -0.2170 0.0293 +vn -0.9988 0.0494 0.0062 +vn 0.7529 0.0701 -0.6544 +vn 0.7530 0.0694 -0.6543 +vn 0.7575 0.0632 -0.6498 +vn 0.7695 0.2475 -0.5888 +vn 0.9874 -0.0962 -0.1258 +vn 0.1456 -0.7312 -0.6665 +vn 0.7862 0.2984 0.5411 +vn 0.9773 -0.1110 -0.1804 +vn 0.8598 -0.1660 -0.4830 +vn -0.9392 0.3269 0.1052 +vn 0.7614 -0.4604 -0.4564 +vn -0.9665 0.0680 0.2476 +vn 0.6236 -0.6348 -0.4563 +vn 0.9000 0.3479 0.2626 +vn -0.3813 -0.4251 0.8209 +vn -0.3343 0.8885 -0.3144 +vn -0.9950 0.0592 -0.0803 +vn -0.2928 0.8405 -0.4559 +vn 0.7572 0.0324 -0.6524 +vn 0.7792 -0.0254 -0.6263 +vn 0.2186 0.3119 0.9246 +vn 0.7547 -0.4706 0.4572 +vn -0.9246 0.3391 -0.1736 +vn -0.6128 0.3173 -0.7237 +vn 0.8648 -0.2739 -0.4208 +vn 0.8667 -0.2669 -0.4214 +vn 0.8665 -0.2678 -0.4213 +vn -0.8745 0.0628 -0.4810 +vn -0.8746 0.0630 -0.4807 +vn -0.8771 0.0635 -0.4761 +vn -0.9264 0.2158 -0.3086 +vn 0.7025 -0.4586 -0.5442 +vn 0.7024 -0.4592 -0.5439 +vn 0.7519 -0.5836 -0.3067 +vn 0.8273 -0.5265 -0.1957 +vn 0.9943 0.0400 0.0991 +vn 0.9916 0.0488 0.1197 +vn 0.6574 -0.7522 -0.0456 +vn -0.9624 -0.2693 0.0359 +vn 0.9363 0.1778 0.3029 +vn 0.9880 -0.1537 -0.0136 +vn -0.9505 0.1389 -0.2778 +vn -0.7280 0.6022 0.3277 +vn -0.9106 -0.3825 -0.1563 +vn -0.8020 0.1516 -0.5778 +vn -0.8025 0.1512 -0.5771 +vn -0.8032 0.1534 -0.5757 +vn 0.8646 -0.2745 -0.4209 +vn 0.5393 -0.3209 0.7786 +vn 0.7963 -0.5641 -0.2184 +vn 0.5635 -0.8057 0.1822 +vn 0.7069 -0.3649 -0.6059 +vn 0.7956 -0.1896 -0.5754 +vn -0.3324 0.8230 0.4607 +vn -0.9353 0.2743 -0.2236 +vn -0.9777 -0.0503 -0.2037 +vn 0.6368 -0.7401 -0.2162 +vn 0.6370 -0.7401 -0.2158 +vn 0.6327 -0.7408 -0.2255 +vn 0.1062 0.6209 0.7767 +vn 0.3988 -0.9158 -0.0481 +vn -0.9889 -0.0033 -0.1486 +vn 0.9933 0.0867 0.0760 +vn -0.8124 -0.5740 0.1030 +vn 0.0923 -0.9200 -0.3809 +vn -0.9871 0.1229 0.1026 +vn 0.7440 -0.2397 -0.6237 +vn 0.7504 -0.2335 -0.6184 +vn 0.7446 -0.2394 -0.6231 +vn 0.7336 0.1192 -0.6691 +vn -0.1468 -0.3740 -0.9157 +vn -0.4258 0.8784 0.2169 +vn -0.9596 0.0115 -0.2810 +vn 0.3751 -0.8161 0.4397 +vn 0.7566 -0.6258 0.1894 +vn -0.2188 -0.7126 -0.6665 +vn -0.7042 0.4485 -0.5504 +vn -0.8238 -0.2643 -0.5015 +vn 0.7432 -0.2732 -0.6108 +vn -0.8754 -0.0302 -0.4825 +vn 0.7609 -0.4794 0.4372 +vn -0.2174 0.5505 -0.8060 +vn 0.6870 0.3286 -0.6481 +vn 0.5107 -0.4965 -0.7019 +vn 0.8380 0.2354 -0.4922 +vn -0.1592 0.1888 -0.9690 +vn -0.8413 -0.4503 0.2991 +vn 0.8911 0.1440 0.4303 +vn -0.5756 -0.3481 0.7400 +vn -0.0775 0.0763 -0.9941 +vn 0.0680 -0.8483 -0.5251 +vn 0.7766 -0.1271 -0.6171 +vn 0.2779 0.0566 0.9589 +vn 0.2781 0.0563 0.9589 +vn 0.2782 0.0559 0.9589 +vn -0.9291 -0.0502 -0.3665 +vn 0.6621 -0.0149 -0.7493 +vn 0.1624 -0.3787 -0.9112 +vn 0.7108 -0.6533 0.2607 +vn 0.8242 0.3960 0.4048 +vn -0.0312 0.4225 -0.9058 +vn 0.9145 0.3552 0.1938 +vn -0.8654 -0.4821 -0.1364 +vn 0.6529 -0.6791 -0.3353 +vn -0.6693 0.7376 -0.0893 +vn 0.8843 -0.0443 -0.4647 +vn 0.8842 -0.0438 -0.4650 +vn 0.8842 -0.0438 -0.4651 +vn 0.8687 0.0254 -0.4947 +vn 0.9717 0.1696 -0.1644 +vn -0.9105 -0.0356 -0.4121 +vn -0.1537 -0.3907 -0.9076 +vn 0.7329 0.0693 -0.6768 +vn 0.9228 0.3536 0.1529 +vn 0.9095 0.1552 -0.3856 +vn 0.8386 0.3071 -0.4499 +vn 0.8907 -0.2302 -0.3921 +vn -0.0023 0.9038 -0.4279 +vn -0.7647 0.4983 0.4086 +vn -0.4903 0.7335 0.4707 +vn 0.7183 -0.0436 -0.6944 +vn 0.9740 0.0780 -0.2128 +vn -0.3484 0.7415 0.5735 +vn -0.7476 -0.5999 -0.2849 +vn 0.7096 -0.5311 -0.4630 +vn 0.4339 0.3346 -0.8365 +vn 0.5156 -0.1894 -0.8357 +vn 0.9517 0.3057 -0.0271 +vn 0.9882 -0.1525 -0.0116 +vn 0.7534 -0.1046 -0.6491 +vn 0.7489 -0.1117 -0.6532 +vn 0.7529 -0.1046 -0.6498 +vn 0.8433 -0.1058 -0.5269 +vn -0.9874 -0.1400 0.0735 +vn -0.9371 0.1977 0.2878 +vn 0.9000 0.3939 0.1865 +vn -0.7868 0.5210 0.3308 +vn 0.6959 -0.4209 0.5818 +vn 0.8162 0.5266 -0.2377 +vn 0.5421 -0.2530 0.8013 +vn 0.8843 0.3305 0.3298 +vn 0.5235 -0.4327 -0.7340 +vn -0.0070 -0.9613 0.2755 +vn 0.1043 -0.9504 0.2930 +vn 0.7494 -0.1126 -0.6524 +vn 0.6909 -0.6296 -0.3553 +vn 0.8546 -0.4547 -0.2509 +vn 0.7738 -0.5862 -0.2401 +vn 0.9839 -0.1572 -0.0850 +vn -0.5103 0.8291 -0.2283 +vn 0.9143 0.1804 -0.3628 +vn -0.3096 0.3930 -0.8659 +vn 0.8163 -0.3807 -0.4344 +vn 0.6344 -0.0212 -0.7727 +vn 0.1980 -0.8816 -0.4285 +vn 0.8480 -0.1242 -0.5153 +vn 0.9858 0.1025 -0.1332 +vn -0.6987 -0.4603 -0.5477 +vn -0.4398 0.0822 -0.8943 +vn -0.9647 0.1656 -0.2045 +vn 0.5175 -0.0827 -0.8517 +vn 0.7557 -0.2367 -0.6107 +vn -0.8782 0.4501 -0.1617 +vn 0.9805 -0.1409 0.1370 +vn -0.9778 0.1191 -0.1725 +vn -0.9778 0.1239 -0.1687 +vn -0.9778 0.1168 -0.1739 +vn 0.6611 0.0833 -0.7456 +vn 0.9415 0.3008 0.1520 +vn 0.9948 -0.1010 -0.0119 +vn -0.8827 -0.2860 -0.3729 +vn -0.8832 -0.2859 -0.3717 +vn -0.8781 -0.2908 -0.3799 +vn -0.9099 0.2925 -0.2942 +vn -0.8369 -0.1218 -0.5337 +vn -0.9041 -0.1187 -0.4104 +vn -0.8225 -0.0549 -0.5660 +vn 0.6325 -0.7409 -0.2259 +vn 0.8851 -0.0426 -0.4634 +vn 0.7401 0.0918 -0.6662 +vn 0.9744 0.0156 0.2241 +vn -0.8031 0.1538 -0.5756 +vn 0.9177 0.0377 -0.3955 +vn 0.6848 -0.6509 -0.3277 +vn 0.8143 -0.1708 -0.5547 +vn 0.9947 -0.0822 -0.0611 +vn 0.8783 0.0090 0.4781 +vn 0.9578 -0.2702 -0.0980 +vn 0.9578 -0.2699 -0.0987 +vn 0.9579 -0.2704 -0.0969 +vn 0.7687 -0.4654 -0.4387 +vn -0.5407 0.1559 -0.8266 +vn -0.9467 -0.3120 0.0805 +vn 0.8339 -0.4682 -0.2922 +vn 0.8443 -0.3806 -0.3773 +vn 0.5098 -0.8387 -0.1915 +vn 0.8757 0.2905 0.3856 +vn 0.7510 -0.2327 -0.6180 +vn 0.2384 -0.7228 -0.6487 +vn 0.8455 0.3324 -0.4178 +vn 0.6341 0.0654 -0.7705 +vn 0.9491 0.0846 0.3036 +vn 0.7582 0.0625 -0.6491 +vn -0.3436 -0.5202 0.7819 +vn -0.9511 -0.0613 -0.3029 +vn 0.8876 0.1583 0.4325 +vn 0.8972 0.2594 0.3573 +vn 0.8693 0.3485 0.3505 +vn 0.8428 0.5243 -0.1215 +vn 0.1415 -0.7860 -0.6018 +vn -0.4405 0.7186 0.5381 +vn -0.4456 0.7184 0.5341 +vn -0.4454 0.7182 0.5346 +vn 0.9633 0.1653 0.2115 +vn 0.7827 -0.5660 -0.2589 +vn 0.0824 -0.6380 -0.7656 +vn 0.1645 0.5699 -0.8051 +vn 0.8777 -0.1970 -0.4368 +vn 0.8464 -0.2588 -0.4655 +vn 0.8467 -0.2613 -0.4635 +vn 0.8465 -0.2592 -0.4650 +vn 0.9777 0.1637 0.1318 +vn -0.8692 -0.3268 -0.3711 +vn 0.8271 0.4592 0.3241 +vn 0.9423 0.0333 0.3331 +vn -0.0205 -0.5891 -0.8078 +vn 0.8466 -0.2619 -0.4633 +vn 0.2883 -0.1889 -0.9387 +vn 0.8420 -0.3024 -0.4469 +vn 0.8519 -0.4345 -0.2925 +vn 0.7559 -0.1850 -0.6280 +vn -0.9460 0.1010 -0.3080 +vn 0.9352 0.1054 0.3382 +vn 0.9453 0.0788 0.3166 +vn 0.9354 0.2657 0.2331 +vn 0.8890 0.3884 0.2424 +vn 0.6967 -0.7173 -0.0042 +vn -0.4838 -0.2510 -0.8384 +vn 0.8506 0.4093 0.3299 +vn 0.9618 0.1714 0.2133 +vn 0.5620 -0.6624 0.4954 +vn 0.7013 -0.4589 -0.5455 +vn 0.7416 -0.2258 -0.6317 +vn -0.9850 -0.1638 -0.0541 +vn -0.8210 -0.5286 0.2160 +vn -0.9975 -0.0582 0.0408 +vn 0.9377 0.2702 0.2184 +vn 0.9193 0.3567 0.1664 +vn 0.9769 0.0537 0.2069 +vn 0.9759 0.0367 0.2150 +vn 0.9404 -0.2252 -0.2549 +vn -0.8403 -0.5097 0.1846 +vn 0.8104 0.5067 0.2942 +vn 0.3194 -0.9235 -0.2122 +vn -0.9349 -0.3049 0.1815 +vn 0.9670 0.0795 0.2421 +vn 0.9084 0.3793 0.1760 +vn 0.9492 0.3090 0.0589 +vn -0.2851 -0.3604 -0.8882 +vn -0.2555 -0.3108 -0.9155 +vn -0.2571 -0.3098 -0.9154 +vn -0.2579 -0.3100 -0.9151 +vn 0.8798 0.3415 0.3307 +vn 0.3238 0.5578 -0.7642 +vn 0.2769 0.3263 0.9038 +vn 0.8651 -0.3385 0.3701 +vn 0.8483 -0.5144 -0.1255 +vn 0.3399 -0.4681 0.8157 +vn 0.7658 0.3627 0.5311 +vn 0.8988 -0.4345 -0.0585 +vn 0.9519 0.2460 0.1829 +vn -0.2827 -0.0379 -0.9585 +vn 0.9419 -0.1093 -0.3177 +vn 0.8626 0.3974 0.3131 +vn 0.9458 0.2753 -0.1721 +vn 0.6128 -0.7593 0.2190 +vn 0.6947 -0.6732 0.2533 +vn 0.9645 -0.0689 0.2551 +vn 0.9649 -0.0662 0.2542 +vn 0.4504 -0.8773 -0.1659 +vn 0.9847 0.1194 0.1266 +vn 0.7117 -0.7020 -0.0258 +vn -0.8883 -0.4034 0.2194 +vn -0.7570 0.2157 -0.6168 +vn -0.0121 -0.9999 -0.0096 +vn -0.5070 -0.5854 -0.6327 +vn 0.4756 -0.7179 0.5084 +vn 0.8368 0.4374 0.3293 +vn 0.9626 0.1398 0.2321 +vn 0.9687 0.0973 0.2284 +vn 0.9087 0.2460 0.3373 +vn 0.8900 -0.4259 0.1630 +vn 0.9648 -0.0660 0.2544 +vn 0.8542 0.0568 -0.5168 +vn 0.6532 -0.7571 0.0108 +vn 0.9956 0.0805 0.0489 +vn 0.5164 -0.8086 -0.2820 +vn 0.8836 0.4472 0.1386 +vn -0.1406 0.7055 0.6946 +vn 0.7506 -0.6422 0.1555 +vn 0.8538 -0.5059 0.1228 +vn 0.9900 0.1368 0.0347 +vn -0.0557 0.9880 0.1440 +vn 0.9832 -0.1789 0.0363 +vn 0.9958 0.0890 0.0207 +vn 0.8854 0.3326 0.3249 +vn -0.7518 -0.2768 -0.5984 +vn 0.9370 -0.3384 0.0865 +vn 0.9677 -0.2035 0.1491 +vn 0.9720 0.1887 0.1401 +vn 0.9894 0.1128 0.0910 +vn 0.9661 0.2396 0.0965 +vn 0.8987 0.4312 0.0806 +vn 0.8682 0.4874 0.0934 +vn 0.9599 -0.2595 -0.1061 +vn 0.8455 0.5073 0.1669 +vn 0.9685 -0.2167 0.1229 +vn 0.5188 0.7193 0.4621 +vn 0.7735 0.5505 0.3141 +vn 0.0446 0.9307 0.3630 +vn 0.5954 0.7227 0.3511 +vn 0.2091 -0.7660 0.6079 +vn -0.3664 -0.8144 -0.4500 +vn -0.4171 0.7862 0.4559 +vn -0.4207 0.7823 0.4593 +vn -0.4179 0.7854 0.4565 +vn 0.8723 0.4000 0.2811 +vn 0.7799 0.6103 0.1387 +vn -0.1174 0.8984 0.4231 +vn 0.8919 0.4050 0.2015 +vn -0.2148 -0.0641 0.9746 +vn 0.7810 0.4915 0.3853 +vn 0.5403 0.6133 0.5761 +vn 0.6133 0.6104 0.5012 +vn 0.8742 0.4443 0.1958 +vn 0.8153 0.5571 -0.1578 +vn 0.7880 0.5666 -0.2407 +vn 0.4189 0.3727 0.8280 +vn 0.7218 0.6794 0.1322 +vn 0.5388 0.7713 0.3389 +vn 0.5946 0.6753 0.4364 +vn 0.4917 0.6765 0.5483 +vn -0.0913 0.9754 0.2005 +vn -0.3882 0.8840 0.2605 +vn -0.5049 0.5142 0.6933 +vn 0.8464 0.4901 -0.2082 +vn 0.1288 -0.4486 0.8844 +vn 0.0366 0.9229 0.3832 +vn 0.0358 0.9230 0.3832 +vn 0.0331 0.9222 0.3853 +vn 0.7048 0.6220 0.3412 +vn 0.7015 0.6267 0.3392 +vn 0.7055 0.6208 0.3418 +vn 0.5911 0.7920 -0.1524 +vn 0.4933 0.8698 -0.0064 +vn 0.5018 0.8649 0.0117 +vn 0.3721 0.9124 0.1707 +vn 0.4497 0.8133 0.3693 +vn 0.8043 0.5837 0.1110 +vn 0.6187 -0.0646 -0.7830 +vn 0.0815 0.8869 0.4546 +vn 0.0252 0.9064 0.4217 +vn -0.0961 0.6881 0.7192 +vn 0.0542 0.8369 0.5447 +vn 0.3492 0.8807 -0.3200 +vn 0.1650 0.9821 -0.0906 +vn 0.0746 0.9923 0.0994 +vn -0.0510 0.9621 0.2679 +vn -0.1143 0.9218 0.3703 +vn 0.1346 0.9789 -0.1536 +vn 0.0636 0.9969 0.0471 +vn -0.1881 0.9441 0.2708 +vn -0.1802 0.8587 0.4798 +vn -0.2677 0.9477 0.1738 +vn -0.3897 0.9080 -0.1539 +vn -0.2853 0.8991 0.3321 +vn 0.6760 0.5607 0.4782 +vn 0.6326 0.5732 0.5209 +vn -0.3090 0.9489 -0.0633 +vn 0.7208 0.4457 0.5309 +vn 0.2296 0.6497 0.7246 +vn 0.8876 0.2194 0.4051 +vn -0.3859 0.8966 0.2171 +vn -0.9572 -0.0691 0.2812 +vn -0.5847 0.2586 -0.7690 +vn -0.5305 -0.8462 0.0507 +vn 0.0572 0.9855 -0.1594 +vn -0.0503 0.9558 -0.2898 +vn 0.0328 0.9778 0.2070 +vn 0.6260 0.7772 0.0647 +vn -0.9909 0.1041 0.0849 +vn 0.6613 0.0084 0.7501 +vn -0.8394 -0.5426 -0.0311 +vn -0.9473 0.1691 -0.2719 +vn 0.1320 0.8973 0.4212 +vn -0.9333 0.3532 0.0646 +vn -0.9353 0.3474 0.0678 +vn -0.9336 0.3525 0.0645 +vn -0.9353 0.3472 0.0681 +vn 0.0449 0.4668 -0.8832 +vn 0.9405 0.2967 -0.1655 +vn 0.9744 0.1466 0.1705 +vn 0.8223 0.2166 0.5262 +vn -0.3596 0.8101 0.4630 +vn -0.3496 0.8113 0.4685 +vn -0.3566 0.8105 0.4647 +vn 0.1714 0.9824 0.0746 +vn 0.4963 0.8592 0.1245 +vn 0.5619 0.5969 0.5727 +vn -0.0151 -0.6817 -0.7314 +vn 0.2582 0.9654 -0.0360 +vn 0.8445 0.5241 0.1107 +vn -0.0802 0.8815 0.4654 +vn -0.2030 0.8249 0.5276 +vn -0.3535 0.0087 -0.9354 +vn -0.9158 0.2103 -0.3422 +vn -0.6793 0.3218 -0.6595 +vn -0.3323 0.7513 0.5701 +vn -0.3211 0.9258 -0.1994 +vn -0.2884 0.9483 -0.1324 +vn 0.1844 0.9825 0.0272 +vn 0.1355 0.9722 0.1910 +vn -0.0163 0.9804 0.1962 +vn -0.2998 0.9524 -0.0561 +vn -0.3251 0.9448 -0.0420 +vn -0.3303 0.9438 -0.0132 +vn -0.0550 0.8800 0.4718 +vn 0.5946 0.7408 0.3126 +vn 0.5945 0.7409 0.3126 +vn 0.5944 0.7408 0.3128 +vn 0.1332 0.9669 0.2176 +vn -0.4380 0.8767 0.1990 +vn -0.2418 0.9702 0.0133 +vn -0.1710 0.9838 0.0542 +vn 0.3482 0.9060 -0.2407 +vn -0.0488 0.9982 -0.0350 +vn -0.3506 0.8681 0.3514 +vn -0.7004 0.6824 -0.2093 +vn -0.1653 0.9862 0.0071 +vn -0.0075 0.9932 -0.1162 +vn 0.4493 0.8487 0.2791 +vn 0.5407 0.7802 0.3144 +vn 0.2091 0.9717 0.1096 +vn 0.0508 0.9594 0.2774 +vn 0.7171 0.6490 0.2540 +vn 0.7321 0.6362 0.2436 +vn 0.7007 0.6279 0.3389 +vn 0.4810 0.7856 0.3891 +vn 0.4576 0.7901 0.4078 +vn 0.0841 0.9285 0.3617 +vn -0.9289 -0.2707 0.2525 +vn -0.9286 -0.2758 0.2482 +vn -0.9289 -0.2702 0.2533 +vn 0.3784 0.9189 -0.1116 +vn 0.9666 0.1799 0.1825 +vn 0.6588 0.6242 0.4199 +vn -0.6760 0.7070 0.2078 +vn -0.6866 -0.4321 0.5847 +vn -0.3511 0.9099 -0.2210 +vn -0.6626 0.7380 0.1277 +vn -0.1191 0.9874 -0.1043 +vn 0.3099 0.9463 -0.0922 +vn 0.3022 0.9485 -0.0946 +vn 0.3029 0.9483 -0.0949 +vn 0.8061 0.5245 0.2739 +vn 0.8516 0.3869 0.3537 +vn 0.1591 0.6610 0.7333 +vn 0.1645 0.9234 0.3469 +vn 0.8737 0.2984 0.3842 +vn 0.4871 0.5654 0.6656 +vn 0.4783 0.5649 0.6724 +vn 0.4790 0.5676 0.6696 +vn -0.1533 0.9552 0.2532 +vn 0.0804 0.9968 0.0050 +vn -0.3273 0.9437 0.0483 +vn 0.3984 -0.1200 0.9093 +vn 0.8675 0.3966 0.3003 +vn 0.9020 0.2370 0.3607 +vn 0.9001 0.3406 -0.2716 +vn -0.9619 0.1661 0.2170 +vn 0.0330 0.9219 0.3860 +vn -0.2340 0.8287 0.5084 +vn -0.2226 0.9689 0.1079 +vn 0.8639 0.2984 0.4057 +vn -0.4476 0.8521 0.2714 +vn -0.0622 0.9723 0.2251 +vn -0.9767 -0.2139 -0.0190 +vn 0.4016 0.9148 0.0443 +vn -0.0871 0.9189 0.3848 +vn -0.0180 0.9903 0.1376 +vn -0.0034 0.9983 -0.0589 +vn 0.1240 0.9746 0.1863 +vn -0.9506 0.2373 0.2003 +vn 0.2354 0.9650 0.1154 +vn 0.3746 0.9111 -0.1719 +vn 0.3750 0.9113 -0.1700 +vn 0.3768 0.9120 -0.1621 +vn 0.0620 0.9978 -0.0228 +vn 0.2979 0.9526 0.0611 +vn 0.3323 0.4680 0.8189 +vn 0.2751 0.9165 0.2904 +vn -0.0330 0.9498 0.3112 +vn 0.0390 0.9989 -0.0246 +vn 0.0369 0.9991 -0.0192 +vn 0.0385 0.9990 -0.0217 +vn 0.2675 0.8555 0.4433 +vn -0.8776 0.4693 0.0982 +vn 0.2067 0.9481 0.2414 +vn 0.1669 0.9742 -0.1521 +vn -0.0553 0.8232 0.5651 +vn -0.1331 0.6717 0.7288 +vn -0.2649 0.9524 0.1511 +vn 0.6491 0.7156 0.2580 +vn 0.2804 0.9500 0.1374 +vn -0.1873 0.9599 -0.2086 +vn -0.4872 0.7528 0.4426 +vn 0.0693 0.9772 -0.2009 +vn -0.4262 -0.0856 -0.9006 +vn 0.6046 0.7411 0.2919 +vn 0.8366 0.5472 0.0272 +vn 0.7309 0.6685 0.1376 +vn -0.9481 -0.0183 0.3173 +vn -0.3860 0.8166 0.4290 +vn 0.1359 0.2277 0.9642 +vn 0.1646 0.9411 0.2953 +vn 0.1058 0.9423 0.3175 +vn -0.9397 -0.3324 0.0809 +vn -0.9405 -0.3315 0.0748 +vn -0.9394 -0.3331 0.0809 +vn -0.0264 0.7937 0.6078 +vn -0.4365 0.8949 -0.0932 +vn -0.9421 0.1925 0.2746 +vn 0.8953 -0.4384 -0.0789 +vn 0.4345 0.7619 0.4803 +vn -0.1365 0.9903 0.0249 +vn -0.0111 0.9934 -0.1144 +vn 0.1387 0.9842 -0.1103 +vn -0.0563 0.9982 0.0182 +vn -0.7737 0.6042 -0.1906 +vn -0.9646 0.2628 0.0214 +vn -0.0163 0.8623 0.5061 +vn 0.3338 -0.1094 0.9363 +vn 0.6780 0.4886 0.5492 +vn -0.6587 0.3659 -0.6574 +vn -0.3377 0.8287 0.4463 +vn -0.0718 0.8708 0.4865 +vn -0.0915 0.8490 0.5205 +vn -0.3004 0.9368 0.1795 +vn 0.7309 0.6810 -0.0457 +vn 0.8652 0.4323 0.2540 +vn 0.8998 0.0021 0.4363 +vn -0.2895 0.9497 0.1193 +vn -0.1011 0.9949 -0.0001 +vn 0.0154 0.8640 0.5033 +vn 0.8314 0.5550 -0.0279 +vn 0.2959 0.4736 0.8295 +vn 0.1519 0.9567 0.2481 +vn 0.8299 0.4004 0.3885 +vn -0.0080 0.9923 0.1237 +vn -0.8400 0.3734 0.3936 +vn 0.8268 0.5604 -0.0479 +vn 0.3415 -0.3983 0.8514 +vn 0.8131 0.5810 0.0358 +vn 0.8155 0.5778 0.0347 +vn 0.8135 0.5805 0.0359 +vn 0.8278 0.5292 0.1863 +vn -0.1493 0.8748 0.4610 +vn 0.6185 0.7535 0.2229 +vn -0.9235 0.3245 0.2046 +vn 0.0704 0.9961 0.0537 +vn 0.4688 0.7516 0.4641 +vn -0.0027 0.9997 -0.0237 +vn 0.2419 0.8448 0.4773 +vn 0.0403 0.9989 -0.0243 +vn -0.5532 0.7907 -0.2623 +vn 0.8179 0.5744 0.0336 +vn 0.8087 0.5828 0.0800 +vn 0.9277 0.3715 -0.0375 +vn 0.0616 0.9937 0.0938 +vn -0.5442 0.7930 -0.2739 +vn -0.5251 0.8220 -0.2205 +vn -0.1260 0.7555 0.6429 +vn -0.8059 -0.3614 0.4691 +vn 0.3145 0.9454 -0.0851 +vn 0.3105 0.9462 -0.0916 +vn -0.2313 0.9416 0.2448 +vn 0.4132 0.8529 0.3192 +vn 0.0683 0.9018 0.4266 +vn -0.0389 0.9335 0.3565 +vn 0.7289 -0.5398 -0.4212 +vn 0.7236 0.5790 0.3758 +vn 0.1300 -0.2678 -0.9547 +vn 0.3663 0.8977 -0.2450 +vn 0.6674 0.6825 0.2978 +vn 0.7995 0.2429 0.5493 +vn -0.2851 0.9152 0.2848 +vn -0.0675 0.8016 0.5941 +vn -0.3007 0.9511 -0.0712 +vn -0.7185 0.6916 0.0737 +vn 0.8047 0.5389 -0.2492 +vn 0.5732 0.5703 0.5884 +vn 0.5601 0.6552 0.5069 +vn 0.5635 0.6537 0.5051 +vn 0.5596 0.6554 0.5072 +vn -0.5149 0.6441 0.5657 +vn -0.8180 0.1570 -0.5533 +vn 0.0562 0.3559 -0.9328 +vn -0.2561 0.7593 0.5983 +vn -0.3069 0.8627 0.4020 +vn 0.0853 0.9919 -0.0941 +vn 0.7954 0.6060 0.0108 +vn 0.7430 0.6636 0.0877 +vn 0.6838 0.6679 0.2940 +vn 0.7304 0.6467 0.2198 +vn 0.7046 0.6248 0.3364 +vn 0.6075 0.6730 0.4218 +vn -0.6886 0.4680 -0.5539 +vn -0.5542 0.8307 0.0535 +vn 0.2222 0.9744 -0.0343 +vn 0.5951 0.7406 0.3122 +vn 0.7844 0.5960 0.1719 +vn 0.8051 0.5904 -0.0567 +vn 0.8030 0.5936 -0.0536 +vn 0.8030 0.5935 -0.0537 +vn 0.3771 0.9121 -0.1609 +vn 0.8029 0.5937 -0.0534 +vn 0.7229 0.6903 0.0305 +vn 0.7189 0.6941 0.0383 +vn 0.7224 0.6907 0.0317 +vn 0.7182 0.6948 0.0392 +vn 0.4539 0.8121 0.3666 +vn 0.6385 0.7538 0.1551 +vn -0.3784 0.8525 0.3607 +vn -0.6431 0.5676 -0.5141 +vn 0.8360 0.4717 -0.2803 +vn 0.7635 0.5837 -0.2763 +vn 0.6836 0.7272 -0.0619 +vn 0.6510 0.7566 0.0610 +vn 0.7297 0.6522 -0.2055 +vn 0.1236 0.9398 0.3186 +vn 0.2809 0.8429 0.4589 +vn 0.0559 0.6812 0.7300 +vn -0.9171 0.2253 -0.3290 +vn 0.4879 0.8262 0.2818 +vn 0.1897 0.9706 -0.1480 +vn 0.7648 0.5713 0.2979 +vn -0.2283 0.9514 -0.2068 +vn -0.4620 0.7302 -0.5034 +vn 0.2995 0.2096 0.9308 +vn -0.4322 0.6522 -0.6228 +vn -0.2659 0.7662 0.5851 +vn 0.6717 0.7280 -0.1372 +vn 0.6980 0.7144 -0.0488 +vn 0.5639 0.6535 0.5050 +vn -0.2659 -0.1592 0.9508 +vn 0.2673 0.9543 0.1335 +vn 0.6452 0.7197 0.2563 +vn 0.5208 0.7392 0.4270 +vn 0.5999 0.7367 -0.3121 +vn 0.1979 0.6287 0.7521 +vn -0.9186 -0.3802 0.1078 +vn -0.2772 -0.1053 -0.9550 +vn 0.3963 0.8107 0.4309 +vn 0.4054 0.8091 0.4254 +vn 0.4060 0.8095 0.4242 +vn -0.2135 0.9549 -0.2065 +vn -0.4439 0.8361 0.3223 +vn -0.9216 0.3881 -0.0077 +vn 0.1352 0.8901 0.4352 +vn 0.6468 0.7610 -0.0500 +vn 0.6353 0.7705 0.0527 +vn 0.5684 0.8030 0.1793 +vn 0.3949 0.8123 0.4291 +vn 0.3025 0.7738 0.5565 +vn 0.0501 0.9270 0.3716 +vn 0.1008 0.7604 0.6415 +vn 0.5999 0.7256 -0.3372 +vn 0.5960 0.7751 -0.2099 +vn 0.5963 0.7747 -0.2104 +vn 0.6040 0.7672 -0.2157 +vn 0.6047 0.7666 -0.2161 +vn 0.6232 0.7819 0.0184 +vn 0.5660 0.8170 0.1107 +vn 0.0486 0.7796 0.6245 +vn 0.1854 0.9771 -0.1048 +vn 0.2030 -0.0647 0.9770 +vn 0.0825 0.9916 0.0997 +vn 0.0631 0.9401 0.3349 +vn 0.0916 0.7491 0.6561 +vn 0.5703 0.7754 0.2710 +vn 0.5990 0.7911 -0.1239 +vn 0.3855 0.8691 0.3099 +vn 0.1594 0.7584 0.6320 +vn -0.9689 -0.2234 -0.1068 +vn -0.0106 0.9425 0.3340 +vn -0.5010 0.8412 0.2035 +vn -0.4039 0.8960 0.1843 +vn 0.1113 0.8950 0.4319 +vn 0.9126 -0.3808 -0.1486 +vn 0.6388 -0.5635 -0.5238 +vn 0.4967 0.8649 0.0726 +vn -0.9522 0.2763 -0.1299 +vn 0.6400 0.0315 0.7677 +vn -0.0891 0.8659 0.4923 +vn -0.5286 0.8309 0.1736 +vn -0.8746 0.0620 -0.4808 +vn 0.5167 0.8496 -0.1059 +vn 0.3554 0.8599 0.3665 +vn 0.4534 0.6577 0.6016 +vn 0.5520 0.8066 -0.2113 +vn -0.5338 0.8430 0.0669 +vn -0.0466 0.7025 0.7101 +vn 0.5026 0.8610 -0.0783 +vn 0.5134 0.8579 -0.0210 +vn 0.4815 0.8761 0.0260 +vn 0.4032 0.8601 0.3124 +vn -0.0964 0.8608 0.4997 +vn -0.0977 0.8605 0.4999 +vn -0.0963 0.8608 0.4997 +vn -0.0949 0.8612 0.4994 +vn 0.8343 0.0160 0.5510 +vn 0.5746 0.7842 -0.2342 +vn 0.3722 0.9097 0.1843 +vn 0.4515 0.8197 0.3524 +vn 0.3238 0.7693 0.5508 +vn 0.1928 0.7334 0.6519 +vn -0.6636 -0.7302 -0.1626 +vn 0.9143 0.3267 0.2395 +vn -0.9836 -0.1776 0.0310 +vn -0.2112 -0.2262 -0.9509 +vn 0.0945 0.1374 -0.9860 +vn 0.4309 0.9021 0.0234 +vn 0.3179 0.8220 0.4725 +vn -0.2484 0.8739 0.4179 +vn -0.3102 0.8637 0.3972 +vn 0.5079 0.8468 -0.1582 +vn 0.4069 0.8919 0.1973 +vn 0.3824 0.8953 0.2284 +vn -0.0940 0.7320 0.6748 +vn -0.2125 0.8898 0.4038 +vn 0.0900 0.9941 0.0613 +vn -0.1342 0.9834 -0.1220 +vn 0.2595 0.8561 0.4469 +vn 0.8617 -0.4401 -0.2526 +vn 0.8369 0.4991 0.2246 +vn -0.7099 0.6382 0.2978 +vn -0.7290 0.5344 -0.4278 +vn 0.3770 0.9236 0.0692 +vn 0.8483 0.4949 0.1882 +vn 0.3841 0.8839 0.2668 +vn -0.0937 0.6592 0.7461 +vn -0.7911 -0.4017 -0.4613 +vn -0.7911 -0.3973 -0.4651 +vn -0.7904 -0.4014 -0.4628 +vn -0.8433 -0.5340 0.0611 +vn -0.8867 0.0313 0.4613 +vn -0.8071 0.4352 -0.3990 +vn 0.4292 0.8798 -0.2043 +vn 0.7306 0.4369 0.5248 +vn -0.6790 0.5105 0.5276 +vn 0.1299 -0.0544 -0.9900 +vn -0.8680 0.1838 0.4613 +vn -0.8044 0.5006 0.3199 +vn -0.8184 0.5520 0.1598 +vn -0.2482 -0.7681 0.5902 +vn -0.7004 0.4024 0.5895 +vn -0.8028 0.3755 0.4631 +vn 0.3725 -0.6628 0.6495 +vn -0.3700 0.8447 0.3868 +vn -0.5918 0.6459 0.4823 +vn -0.3368 0.8719 0.3554 +vn -0.3358 0.8724 0.3551 +vn -0.3277 0.8759 0.3541 +vn -0.0537 0.3710 0.9271 +vn -0.2260 0.0027 0.9741 +vn -0.9664 0.1745 0.1888 +vn -0.2071 0.1292 0.9698 +vn -0.4050 0.0766 -0.9111 +vn -0.5371 0.1094 -0.8364 +vn -0.5408 0.1077 -0.8342 +vn -0.5366 0.1089 -0.8368 +vn -0.3431 0.6377 0.6897 +vn -0.3488 0.4697 0.8110 +vn -0.3324 0.0039 0.9431 +vn -0.8328 -0.3254 0.4478 +vn -0.6351 0.4340 0.6390 +vn -0.1375 -0.8063 -0.5754 +vn -0.8746 -0.0420 0.4830 +vn -0.7657 -0.3119 0.5625 +vn -0.7655 -0.3116 0.5629 +vn -0.7656 -0.3118 0.5627 +vn -0.6432 0.7031 0.3033 +vn -0.6385 0.7080 0.3017 +vn -0.6418 0.7045 0.3029 +vn -0.8308 -0.2925 0.4736 +vn -0.8251 -0.0090 0.5649 +vn -0.6375 0.7091 0.3012 +vn -0.9039 -0.4212 0.0747 +vn -0.4919 0.4232 0.7609 +vn -0.5639 0.7221 0.4006 +vn -0.7993 0.3651 0.4773 +vn 0.2359 0.1451 -0.9609 +vn -0.0641 -0.3630 -0.9296 +vn -0.0415 0.1786 0.9830 +vn 0.0123 -0.9992 -0.0374 +vn -0.7654 0.4537 -0.4565 +vn 0.5820 -0.3515 -0.7333 +vn -0.6610 -0.0026 0.7504 +vn -0.5051 0.4138 0.7574 +vn -0.4518 0.2675 0.8510 +vn -0.6944 -0.2646 0.6691 +vn 0.0880 0.1231 -0.9885 +vn 0.9109 0.3528 0.2140 +vn -0.6994 0.5340 0.4751 +vn -0.4607 0.3695 -0.8069 +vn -0.7972 -0.0393 0.6024 +vn -0.6379 0.6937 0.3344 +vn -0.7739 0.3249 0.5436 +vn -0.8135 -0.3725 0.4466 +vn -0.6045 0.7822 0.1511 +vn -0.7593 -0.4719 0.4480 +vn -0.6417 0.5846 0.4964 +vn -0.6437 0.5833 0.4955 +vn -0.6436 0.5833 0.4955 +vn 0.0724 -0.8616 -0.5025 +vn -0.9055 0.3375 0.2571 +vn -0.8807 0.4344 0.1886 +vn -0.4726 0.3860 0.7923 +vn -0.6649 0.3446 0.6627 +vn -0.3452 -0.4314 0.8335 +vn -0.9010 -0.0772 0.4268 +vn -0.2200 0.1322 -0.9665 +vn -0.3716 -0.0426 -0.9274 +vn -0.8409 -0.3360 0.4242 +vn -0.3233 0.1030 -0.9407 +vn -0.7106 -0.2231 -0.6672 +vn -0.8240 -0.0677 0.5625 +vn -0.8251 -0.2811 0.4902 +vn -0.4354 -0.3933 0.8098 +vn -0.0638 0.5823 0.8105 +vn -0.6360 0.2998 0.7111 +vn -0.9660 -0.2376 0.1015 +vn -0.4518 -0.8064 0.3816 +vn -0.2436 -0.8814 0.4047 +vn -0.4222 -0.8320 0.3599 +vn -0.6726 0.0143 0.7398 +vn -0.6317 0.2878 0.7198 +vn -0.5445 0.3668 0.7543 +vn -0.9322 0.2669 0.2444 +vn -0.5240 -0.1345 0.8410 +vn -0.3475 0.8117 0.4695 +vn -0.2193 -0.2275 0.9488 +vn 0.4010 0.1320 0.9065 +vn 0.8689 -0.4736 -0.1442 +vn -0.2063 0.8024 0.5599 +vn -0.4914 0.6571 0.5716 +vn 0.8903 0.4507 0.0646 +vn -0.3855 0.7306 0.5635 +vn -0.9170 0.1662 0.3626 +vn -0.6456 0.5819 0.4945 +vn -0.5560 -0.1821 0.8110 +vn 0.6397 -0.7221 0.2634 +vn 0.0220 0.2499 0.9680 +vn 0.8378 -0.4593 -0.2951 +vn -0.5943 0.5767 0.5605 +vn -0.3657 0.0678 0.9282 +vn 0.1829 -0.8853 -0.4276 +vn -0.2072 -0.8253 0.5253 +vn -0.9166 0.3897 -0.0898 +vn -0.5129 0.3084 0.8012 +vn -0.5759 -0.1701 0.7996 +vn -0.5187 0.2612 0.8141 +vn -0.5469 -0.2749 0.7908 +vn -0.1424 0.2758 0.9506 +vn 0.3101 -0.0784 0.9475 +vn -0.9234 -0.1940 0.3314 +vn -0.6965 0.6530 0.2974 +vn -0.6277 0.1390 0.7660 +vn -0.4896 0.5990 0.6337 +vn -0.3924 0.6642 0.6362 +vn -0.4223 -0.2639 0.8672 +vn -0.1762 -0.9612 -0.2121 +vn -0.4025 0.8243 0.3981 +vn 0.5837 0.7259 -0.3639 +vn -0.8537 0.4415 0.2763 +vn -0.3264 0.5979 0.7321 +vn -0.2041 -0.3401 0.9180 +vn -0.4434 0.2238 0.8679 +vn -0.8267 0.0099 0.5625 +vn -0.4617 0.3092 0.8314 +vn -0.4457 0.8857 0.1303 +vn -0.9816 0.1523 0.1152 +vn -0.7020 0.3283 0.6320 +vn -0.7020 0.3288 0.6317 +vn -0.7018 0.3283 0.6322 +vn -0.3400 0.0822 -0.9368 +vn -0.9151 0.3977 -0.0665 +vn -0.7303 -0.3238 0.6015 +vn -0.3810 -0.1321 0.9151 +vn -0.2349 0.0702 0.9695 +vn -0.8421 -0.2758 0.4634 +vn -0.5398 0.3215 0.7780 +vn -0.6521 -0.0657 0.7553 +vn -0.2842 0.9546 -0.0895 +vn -0.3799 -0.4815 0.7898 +vn -0.6808 -0.2929 0.6713 +vn -0.9274 -0.2170 -0.3047 +vn -0.9225 -0.2260 -0.3128 +vn -0.9263 -0.2268 -0.3007 +vn -0.5811 -0.4455 0.6811 +vn -0.6798 -0.0366 0.7324 +vn -0.7493 0.2275 0.6219 +vn -0.7493 0.2274 0.6220 +vn -0.8884 0.4525 -0.0779 +vn -0.4270 -0.0360 -0.9035 +vn 0.1134 -0.6644 -0.7387 +vn -0.5208 -0.2341 0.8210 +vn -0.3126 -0.1377 0.9399 +vn -0.5132 -0.2354 0.8253 +vn -0.6797 0.1939 0.7074 +vn -0.7999 0.2547 0.5434 +vn -0.5704 0.0806 0.8174 +vn 0.0860 0.7610 0.6430 +vn -0.8041 -0.2799 0.5245 +vn -0.5691 0.6316 0.5264 +vn -0.4517 0.3671 -0.8132 +vn -0.5429 -0.3065 0.7819 +vn -0.7084 -0.0052 0.7058 +vn -0.4942 -0.1802 0.8504 +vn 0.0210 -0.1567 0.9874 +vn -0.3889 -0.3858 0.8366 +vn -0.6529 -0.2362 0.7197 +vn -0.5008 -0.2348 -0.8331 +vn 0.0606 -0.8251 0.5618 +vn -0.1019 0.0763 -0.9919 +vn -0.9562 -0.1403 0.2567 +vn -0.8646 0.4292 -0.2612 +vn -0.7630 -0.3639 0.5343 +vn -0.4929 0.3131 -0.8118 +vn -0.6598 0.4374 0.6111 +vn -0.8737 0.3557 -0.3317 +vn 0.3495 0.2442 -0.9046 +vn -0.9441 -0.1508 -0.2930 +vn -0.9426 -0.1549 -0.2959 +vn -0.9429 -0.1542 -0.2951 +vn -0.0633 -0.4933 -0.8675 +vn -0.0937 -0.0448 -0.9946 +vn -0.7520 0.0122 0.6590 +vn -0.6436 0.3129 -0.6985 +vn -0.6490 0.3118 -0.6939 +vn -0.6444 0.3128 -0.6978 +vn -0.9931 0.0928 0.0710 +vn 0.6653 -0.0513 0.7448 +vn -0.5372 -0.3433 0.7704 +vn -0.6219 0.0048 0.7831 +vn -0.5065 -0.0976 0.8567 +vn -0.3538 0.9031 0.2433 +vn -0.3131 0.7447 0.5895 +vn -0.9315 0.2676 0.2464 +vn -0.8418 0.4865 0.2338 +vn -0.8192 0.5619 -0.1149 +vn 0.3642 0.2353 0.9011 +vn -0.6535 0.0858 0.7521 +vn -0.6623 0.0870 0.7442 +vn -0.6617 0.0867 0.7447 +vn -0.6167 0.7872 0.0038 +vn -0.0043 -0.3682 -0.9297 +vn 0.1928 -0.8164 -0.5444 +vn 0.0206 -0.1562 0.9875 +vn -0.4325 -0.2967 0.8514 +vn -0.5851 -0.1355 -0.7996 +vn -0.7601 0.1587 0.6301 +vn -0.6784 0.4168 0.6050 +vn 0.8054 0.3862 0.4497 +vn -0.9146 0.1791 0.3626 +vn -0.3804 0.1857 -0.9060 +vn -0.4915 -0.3781 0.7845 +vn -0.8640 0.1412 0.4833 +vn -0.9882 -0.0960 -0.1195 +vn -0.6543 0.2260 0.7217 +vn -0.5994 -0.7830 0.1664 +vn -0.3978 0.8146 0.4220 +vn -0.6418 0.5554 0.5289 +vn -0.6281 0.5800 0.5187 +vn -0.5086 -0.0546 0.8593 +vn -0.5091 -0.0542 0.8590 +vn -0.5090 -0.0546 0.8590 +vn -0.9038 -0.0876 0.4190 +vn -0.8957 -0.1308 0.4250 +vn -0.8842 0.2318 0.4056 +vn -0.9029 0.1165 0.4139 +vn -0.3872 0.7180 0.5784 +vn -0.7656 -0.3117 0.5627 +vn -0.5419 0.4882 0.6841 +vn 0.5129 -0.8543 0.0838 +vn -0.7571 0.0139 0.6531 +vn -0.9335 0.2297 0.2753 +vn -0.3267 0.8763 0.3542 +vn -0.6846 0.3054 0.6618 +vn -0.6246 0.4269 0.6539 +vn -0.6143 0.5547 0.5611 +vn -0.4773 0.6406 0.6015 +vn -0.6875 0.6388 -0.3453 +vn -0.2310 0.0278 0.9726 +vn -0.8185 0.4829 0.3111 +vn -0.8886 0.4315 -0.1557 +vn -0.6870 0.3227 0.6510 +vn -0.9222 0.2276 0.3127 +vn -0.3996 0.6414 0.6549 +vn -0.5547 0.7247 0.4089 +vn 0.5089 -0.5210 -0.6853 +vn -0.8477 0.0181 0.5301 +vn 0.1556 -0.3174 -0.9354 +vn -0.8846 0.3475 0.3110 +vn -0.8919 -0.0959 0.4420 +vn -0.3428 -0.8118 0.4727 +vn -0.6603 0.1174 0.7418 +vn -0.8211 -0.3536 0.4480 +vn -0.8526 0.0745 0.5172 +vn -0.2692 -0.0800 -0.9598 +vn -0.8455 -0.3326 0.4177 +vn -0.8418 -0.1663 0.5136 +vn -0.7835 0.2121 0.5841 +vn -0.2869 -0.8870 -0.3619 +vn -0.7399 -0.1005 0.6652 +vn -0.4773 0.2735 0.8351 +vn -0.7257 0.4588 0.5126 +vn -0.6073 0.3078 0.7324 +vn -0.8154 0.0096 0.5788 +vn -0.7926 0.3962 0.4635 +vn -0.8410 0.1482 0.5204 +vn 0.3324 -0.1429 0.9323 +vn -0.5296 0.7595 0.3777 +vn -0.8126 -0.0526 0.5804 +vn -0.6778 0.4545 0.5780 +vn -0.5407 0.1062 -0.8345 +vn 0.1985 0.3766 -0.9049 +vn 0.1986 0.3763 -0.9050 +vn 0.1984 0.3767 -0.9048 +vn -0.7085 0.0542 0.7037 +vn -0.7045 0.0523 0.7078 +vn -0.7084 0.0542 0.7037 +vn -0.3644 0.5249 0.7693 +vn -0.7833 -0.1180 0.6103 +vn 0.3586 -0.8840 -0.3000 +vn -0.0761 0.0211 -0.9969 +vn -0.6181 0.1580 0.7701 +vn -0.6194 0.1788 0.7644 +vn -0.5645 0.5431 0.6216 +vn -0.5657 0.5456 0.6183 +vn -0.5631 0.5414 0.6244 +vn -0.8415 0.1623 0.5154 +vn -0.3351 -0.5939 0.7315 +vn -0.1561 0.0768 -0.9848 +vn -0.2988 -0.2721 -0.9147 +vn -0.8921 -0.2165 0.3966 +vn -0.7816 -0.0916 0.6171 +vn -0.7815 -0.0955 0.6165 +vn -0.7815 -0.0954 0.6165 +vn -0.7816 -0.0957 0.6164 +vn -0.8290 -0.0783 0.5538 +vn 0.7843 0.5324 0.3185 +vn -0.1082 0.2280 -0.9676 +vn 0.5240 0.7643 -0.3760 +vn 0.5239 0.7641 -0.3764 +vn 0.5251 0.7616 -0.3798 +vn -0.4471 0.8029 0.3941 +vn -0.7373 0.5433 0.4015 +vn -0.7364 0.5447 0.4012 +vn -0.7395 0.5398 0.4023 +vn -0.7404 0.1788 0.6480 +vn -0.8255 0.4871 0.2853 +vn -0.3905 0.7955 0.4633 +vn -0.8556 -0.2409 0.4582 +vn -0.7521 0.1412 0.6437 +vn -0.7486 0.1947 0.6338 +vn -0.7611 0.1759 0.6243 +vn -0.6781 0.1090 0.7268 +vn -0.8105 -0.3066 0.4991 +vn -0.5817 0.7304 0.3580 +vn -0.1936 0.2495 -0.9488 +vn -0.0956 0.9858 0.1380 +vn -0.5080 -0.0550 0.8596 +vn -0.7633 0.2176 0.6083 +vn -0.7660 0.2167 0.6052 +vn -0.7637 0.2171 0.6079 +vn -0.5258 0.5921 0.6107 +vn -0.6545 0.4765 0.5870 +vn -0.9182 0.2542 0.3038 +vn -0.7404 0.5383 0.4027 +vn -0.5837 0.6970 0.4164 +vn 0.9286 -0.3167 -0.1936 +vn -0.6049 0.4197 0.6767 +vn -0.5633 0.5406 0.6248 +vn -0.3552 0.8334 0.4234 +vn -0.3550 0.8335 0.4234 +vn -0.3548 0.8335 0.4235 +vn -0.7434 0.3571 0.5655 +vn -0.4375 0.3597 -0.8241 +vn -0.8350 -0.2120 0.5078 +vn -0.8157 -0.0125 0.5783 +vn -0.7278 0.2584 0.6353 +vn -0.7936 0.2924 0.5336 +vn -0.7920 -0.1022 0.6019 +vn -0.4615 0.7983 0.3869 +vn 0.2426 0.2542 -0.9362 +vn -0.4189 0.0292 -0.9076 +vn -0.4188 0.0291 -0.9076 +vn -0.4193 0.0303 -0.9073 +vn -0.9446 0.0706 0.3206 +vn -0.8166 -0.2805 0.5044 +vn -0.5339 -0.1488 0.8324 +vn -0.5167 0.5272 0.6746 +vn -0.7542 -0.5272 0.3915 +vn 0.1743 -0.6360 -0.7518 +vn -0.2542 0.1826 -0.9497 +vn 0.0726 0.2127 -0.9744 +vn 0.0744 0.2121 -0.9744 +vn 0.0740 0.2128 -0.9743 +vn -0.7493 0.2273 0.6220 +vn -0.8959 0.1771 0.4075 +vn -0.0479 0.1877 -0.9811 +vn -0.0466 0.1940 -0.9799 +vn -0.0494 0.1949 -0.9796 +vn -0.8065 -0.2590 0.5315 +vn -0.2222 0.1900 0.9563 +vn -0.5504 0.7657 0.3327 +vn -0.5219 0.7590 0.3893 +vn -0.5924 0.7002 0.3985 +vn -0.7715 0.2554 0.5827 +vn -0.7662 0.2174 0.6048 +vn -0.8531 -0.0817 0.5152 +vn -0.6504 -0.1899 -0.7355 +vn -0.7125 0.0561 0.6994 +vn -0.7129 0.0676 0.6980 +vn -0.4435 -0.0588 -0.8944 +vn 0.9492 -0.2508 -0.1900 +vn -0.8537 0.2651 0.4482 +vn 0.0688 -0.9961 -0.0550 +vn 0.0673 -0.9963 -0.0542 +vn 0.0728 -0.9957 -0.0572 +vn -0.8323 0.3731 0.4099 +vn -0.7172 0.5365 0.4448 +vn -0.6451 0.7564 -0.1076 +vn 0.6506 -0.2499 -0.7171 +vn 0.6506 -0.2505 -0.7169 +vn 0.6502 -0.2506 -0.7172 +vn -0.6682 0.4059 0.6235 +vn -0.6044 0.5365 0.5890 +vn -0.4547 0.3410 -0.8228 +vn -0.6459 -0.4379 0.6254 +vn -0.7152 -0.2836 0.6388 +vn -0.7953 -0.2141 0.5672 +vn -0.7959 -0.1302 0.5913 +vn -0.8599 0.2958 0.4160 +vn -0.7803 0.4325 0.4518 +vn -0.5191 0.6767 0.5221 +vn -0.4147 0.8104 0.4140 +vn -0.5322 0.5118 0.6744 +vn -0.0171 0.3923 0.9197 +vn -0.5118 0.7754 0.3699 +vn -0.5871 0.6089 0.5335 +vn -0.5234 -0.5182 0.6764 +vn -0.7631 0.0597 0.6435 +vn 0.8351 -0.5288 -0.1516 +vn -0.5550 0.5623 0.6130 +vn -0.4746 0.4717 0.7431 +vn -0.1941 0.5089 -0.8387 +vn -0.6746 0.2537 0.6932 +vn -0.6739 0.2098 0.7084 +vn -0.7818 -0.2562 0.5685 +vn -0.7808 0.2695 0.5637 +vn -0.5468 0.6466 0.5319 +vn 0.7299 -0.6815 -0.0533 +vn -0.4187 -0.5771 0.7011 +vn -0.3228 0.7421 0.5874 +vn 0.4847 0.5703 0.6632 +vn 0.4873 0.5651 0.6658 +vn -0.2241 0.3770 -0.8987 +vn -0.5294 -0.3698 -0.7635 +vn -0.2730 -0.0309 -0.9615 +vn -0.7147 0.0943 -0.6931 +vn -0.7038 -0.2329 0.6711 +vn -0.7432 -0.0469 0.6674 +vn 0.4440 -0.5981 -0.6672 +vn -0.1671 0.0046 0.9859 +vn -0.7000 0.3265 0.6352 +vn -0.9552 0.2952 -0.0188 +vn -0.4462 0.8365 0.3180 +vn -0.4666 0.7059 0.5329 +vn -0.6531 0.0869 0.7523 +vn -0.8252 0.1906 0.5317 +vn -0.8401 0.2929 0.4566 +vn -0.2406 -0.1926 -0.9513 +vn 0.3610 0.3505 -0.8642 +vn -0.0550 0.6250 -0.7787 +vn -0.1533 0.3425 -0.9269 +vn -0.0323 0.5900 -0.8067 +vn -0.0221 0.9053 -0.4241 +vn 0.0232 0.9102 -0.4135 +vn 0.0352 0.6937 -0.7194 +vn -0.1922 -0.4395 0.8774 +vn 0.3051 0.6760 -0.6708 +vn 0.2002 0.8247 -0.5290 +vn 0.5305 0.3708 -0.7623 +vn 0.5302 0.3714 -0.7622 +vn 0.5298 0.3731 -0.7616 +vn -0.3368 -0.0161 0.9414 +vn -0.9944 -0.0095 0.1054 +vn -0.9069 -0.1489 -0.3941 +vn -0.3113 0.5174 -0.7971 +vn -0.6649 0.2008 -0.7195 +vn -0.6330 -0.5683 -0.5257 +vn -0.5140 -0.3516 -0.7824 +vn 0.4518 -0.8104 -0.3729 +vn -0.6744 -0.4143 -0.6112 +vn -0.7221 0.0338 -0.6909 +vn -0.9602 0.0106 -0.2793 +vn -0.6025 -0.5544 -0.5742 +vn -0.9459 0.0036 -0.3244 +vn -0.9597 0.0588 -0.2749 +vn -0.9132 -0.2027 -0.3535 +vn -0.9121 -0.2048 -0.3552 +vn -0.9092 -0.2100 -0.3596 +vn -0.5339 -0.5270 -0.6612 +vn -0.3326 -0.6719 -0.6618 +vn -0.8073 -0.3995 -0.4344 +vn -0.5142 -0.6237 -0.5887 +vn -0.9696 0.2397 0.0501 +vn -0.9759 0.1336 -0.1727 +vn -0.6872 -0.4714 -0.5528 +vn -0.8101 0.5526 0.1959 +vn -0.9670 -0.0930 -0.2370 +vn -0.9081 -0.2118 -0.3612 +vn -0.7642 -0.4952 -0.4132 +vn -0.3551 0.9105 -0.2117 +vn -0.3751 -0.7246 -0.5781 +vn -0.6700 -0.5584 -0.4891 +vn -0.6711 -0.5579 -0.4882 +vn -0.6736 -0.5567 -0.4861 +vn -0.6749 -0.5562 -0.4850 +vn -0.9815 -0.0685 -0.1786 +vn -0.9817 -0.0641 -0.1793 +vn -0.9818 -0.0625 -0.1795 +vn -0.4785 -0.6307 -0.6110 +vn -0.9936 0.0364 -0.1072 +vn -0.9716 0.1495 -0.1834 +vn -0.6184 -0.6576 -0.4304 +vn -0.4682 -0.7390 -0.4844 +vn -0.8953 -0.3107 0.3193 +vn -0.9740 0.1517 -0.1683 +vn -0.9032 -0.3228 -0.2831 +vn -0.8388 -0.4567 -0.2963 +vn -0.7931 -0.3954 -0.4633 +vn -0.5494 -0.6668 -0.5035 +vn 0.0102 0.7614 -0.6482 +vn -0.8377 0.5387 0.0904 +vn -0.8984 -0.3553 -0.2582 +vn -0.9783 0.1863 0.0908 +vn -0.7614 -0.5717 -0.3055 +vn -0.9312 0.3187 0.1770 +vn 0.1173 0.5447 -0.8304 +vn -0.4212 0.6870 -0.5922 +vn -0.9779 -0.1680 -0.1249 +vn -0.5778 -0.8029 -0.1469 +vn -0.5777 -0.8030 -0.1466 +vn -0.5779 -0.8028 -0.1470 +vn -0.9686 0.2214 -0.1134 +vn -0.9814 -0.0703 -0.1784 +vn -0.1144 0.6633 -0.7396 +vn -0.1138 0.6636 -0.7394 +vn -0.1140 0.6635 -0.7394 +vn -0.4351 -0.8502 0.2963 +vn -0.9779 0.1259 -0.1669 +vn -0.1014 -0.9937 -0.0474 +vn -0.0999 -0.9940 -0.0453 +vn -0.1012 -0.9937 -0.0472 +vn -0.0469 0.6087 -0.7920 +vn -0.0032 0.3869 -0.9221 +vn -0.6704 -0.3578 -0.6500 +vn -0.6233 -0.1882 -0.7590 +vn -0.7664 0.0637 -0.6392 +vn -0.7516 0.1175 -0.6491 +vn -0.7513 0.1177 -0.6494 +vn -0.7502 0.1180 -0.6506 +vn -0.9393 0.3095 -0.1482 +vn -0.7683 -0.5380 -0.3467 +vn 0.4936 0.6633 -0.5625 +vn -0.7886 -0.3617 -0.4972 +vn -0.7837 -0.3572 -0.5082 +vn -0.7808 -0.3717 -0.5023 +vn -0.8283 -0.3197 -0.4601 +vn -0.8277 -0.3201 -0.4608 +vn -0.8268 -0.3213 -0.4617 +vn -0.5149 0.6542 -0.5539 +vn -0.8705 0.2306 -0.4348 +vn -0.5421 -0.7399 -0.3984 +vn -0.8260 -0.4690 -0.3128 +vn -0.9334 0.1908 0.3038 +vn 0.2448 0.5615 -0.7905 +vn 0.2444 0.5613 -0.7907 +vn 0.2448 0.5616 -0.7904 +vn -0.0742 0.4927 -0.8671 +vn 0.8427 0.5355 0.0562 +vn -0.8281 -0.3117 -0.4660 +vn -0.7797 -0.3679 -0.5068 +vn -0.8817 -0.2613 -0.3928 +vn -0.9161 0.0083 -0.4009 +vn -0.9142 0.0006 -0.4052 +vn -0.9140 0.0013 -0.4057 +vn -0.9164 0.0081 -0.4002 +vn -0.8212 0.4056 -0.4014 +vn -0.8106 0.4209 -0.4071 +vn -0.9971 0.0752 -0.0110 +vn -0.0252 0.3207 -0.9469 +vn -0.0300 0.3192 -0.9472 +vn -0.0309 0.3193 -0.9472 +vn -0.0443 0.7109 -0.7019 +vn -0.7600 -0.2675 -0.5924 +vn -0.7600 -0.2657 -0.5930 +vn -0.7602 -0.2677 -0.5919 +vn -0.9592 0.0408 -0.2797 +vn -0.8350 0.2463 -0.4921 +vn 0.2874 0.6753 0.6793 +vn -0.5706 -0.7263 -0.3832 +vn -0.5292 0.8077 -0.2601 +vn -0.9313 -0.3642 -0.0080 +vn 0.1626 0.7665 -0.6214 +vn 0.2476 0.5678 -0.7850 +vn -0.7790 -0.2394 -0.5795 +vn -0.8840 0.3426 -0.3180 +vn -0.9730 0.0144 0.2302 +vn -0.7493 -0.5804 -0.3190 +vn -0.9343 -0.2955 -0.1996 +vn -0.1340 0.7545 -0.6425 +vn -0.9155 -0.2761 -0.2927 +vn -0.7598 -0.2636 -0.5943 +vn -0.9043 -0.2658 -0.3339 +vn -0.7282 0.6321 -0.2650 +vn -0.6836 -0.6787 -0.2683 +vn -0.9814 -0.1886 -0.0363 +vn -0.9531 -0.0339 -0.3008 +vn -0.7612 0.6266 -0.1670 +vn -0.9957 -0.0924 -0.0010 +vn 0.0880 0.7819 0.6171 +vn 0.3312 -0.2736 0.9030 +vn 0.1840 0.6839 -0.7060 +vn -0.7400 -0.1368 -0.6586 +vn -0.9071 -0.2973 -0.2980 +vn -0.9055 -0.2945 -0.3056 +vn -0.9070 -0.2978 -0.2976 +vn -0.8865 -0.3083 -0.3451 +vn -0.9867 -0.0449 -0.1563 +vn -0.8628 -0.3532 0.3617 +vn -0.0733 0.2762 0.9583 +vn -0.8866 -0.0988 -0.4519 +vn -0.7477 0.4865 -0.4519 +vn -0.7491 0.4562 -0.4803 +vn -0.6767 0.5205 -0.5206 +vn -0.7369 0.3198 0.5956 +vn -0.9320 -0.1891 -0.3092 +vn -0.9072 -0.2965 -0.2985 +vn -0.9223 -0.0564 -0.3823 +vn -0.7935 0.3558 -0.4937 +vn -0.7843 0.3618 -0.5039 +vn -0.9083 0.1771 0.3789 +vn -0.8362 -0.1636 0.5234 +vn -0.9349 0.2936 0.1995 +vn -0.7954 -0.3206 0.5143 +vn -0.9088 -0.2936 -0.2965 +vn -0.9280 -0.2652 -0.2617 +vn -0.9034 0.0707 -0.4228 +vn -0.9099 -0.0322 -0.4135 +vn -0.6386 0.3042 -0.7069 +vn -0.6321 0.3030 -0.7132 +vn -0.6333 0.3032 -0.7120 +vn -0.7243 -0.5976 -0.3439 +vn -0.9785 0.1082 0.1758 +vn -0.0748 0.0705 -0.9947 +vn -0.7801 -0.2177 -0.5865 +vn -0.9405 -0.2207 -0.2585 +vn 0.9917 0.0699 -0.1075 +vn -0.8624 -0.5061 -0.0120 +vn -0.0182 -0.9931 0.1156 +vn -0.0180 -0.9935 0.1126 +vn -0.0179 -0.9934 0.1131 +vn -0.6610 -0.7478 -0.0614 +vn -0.9894 0.1084 -0.0970 +vn 0.2402 0.8116 -0.5325 +vn 0.2421 0.8139 -0.5281 +vn 0.2376 0.8090 -0.5376 +vn 0.0758 0.5395 -0.8386 +vn -0.7014 0.4313 -0.5675 +vn -0.7000 0.4040 -0.5888 +vn -0.5867 0.8091 0.0346 +vn -0.8875 -0.0245 -0.4601 +vn -0.8967 -0.2576 -0.3600 +vn -0.9211 -0.2315 -0.3130 +vn -0.9256 -0.2278 -0.3022 +vn -0.1911 0.7655 -0.6144 +vn -0.9285 -0.2765 0.2479 +vn -0.9567 -0.0454 0.2875 +vn -0.6873 -0.7198 -0.0977 +vn -0.7575 -0.6456 -0.0971 +vn -0.9610 -0.2371 -0.1425 +vn -0.9392 0.3214 -0.1206 +vn -0.9868 -0.0686 -0.1469 +vn -0.9247 0.1386 -0.3546 +vn -0.9048 -0.2947 -0.3074 +vn -0.8399 0.5422 -0.0245 +vn -0.9896 0.0022 -0.1439 +vn -0.7356 -0.5864 -0.3392 +vn -0.6354 0.0089 -0.7721 +vn -0.6388 0.0094 -0.7693 +vn -0.6341 0.0073 -0.7732 +vn -0.3554 0.8333 0.4234 +vn -0.9364 0.1381 -0.3225 +vn 0.1251 -0.7750 -0.6195 +vn -0.3668 0.8936 -0.2587 +vn -0.9047 -0.2946 -0.3077 +vn -0.9815 -0.1314 0.1389 +vn -0.7175 -0.6136 -0.3298 +vn -0.6926 -0.6084 -0.3875 +vn -0.7172 0.3010 -0.6285 +vn -0.6136 0.4093 -0.6753 +vn -0.6179 0.4098 -0.6710 +vn -0.6130 0.4095 -0.6757 +vn -0.8225 0.5181 -0.2345 +vn -0.8058 0.4989 -0.3190 +vn -0.9429 -0.0461 -0.3299 +vn -0.2759 0.2771 -0.9204 +vn -0.2149 -0.7028 -0.6782 +vn -0.5201 0.7364 -0.4326 +vn -0.9693 0.2438 -0.0319 +vn -0.9949 0.0361 0.0942 +vn -0.9159 -0.3753 -0.1425 +vn -0.9750 0.1754 0.1361 +vn -0.8998 0.4201 -0.1179 +vn -0.7862 0.5890 -0.1870 +vn -0.9619 -0.1138 -0.2486 +vn -0.8013 -0.3510 -0.4845 +vn -0.6683 -0.6402 -0.3789 +vn -0.9362 0.3440 0.0717 +vn -0.9137 -0.1820 -0.3633 +vn -0.9116 -0.2532 -0.3239 +vn -0.9117 -0.2529 -0.3237 +vn -0.9118 -0.2528 -0.3237 +vn -0.9119 -0.2524 -0.3235 +vn 0.5582 0.2545 -0.7897 +vn -0.1936 0.1516 -0.9693 +vn -0.9672 0.2512 -0.0372 +vn -0.9812 -0.1896 -0.0352 +vn -0.8490 0.4331 0.3027 +vn -0.8049 -0.5661 -0.1779 +vn -0.8048 -0.5661 -0.1783 +vn -0.8041 -0.5668 -0.1794 +vn -0.9883 0.0224 0.1508 +vn -0.5660 0.7443 -0.3546 +vn -0.8632 0.3946 -0.3149 +vn -0.9742 -0.1135 -0.1948 +vn 0.4998 0.5897 -0.6343 +vn -0.0124 -0.9878 0.1555 +vn -0.8502 0.5241 -0.0486 +vn -0.5071 -0.6620 -0.5519 +vn -0.6958 -0.6527 0.2996 +vn -0.9823 0.1819 0.0454 +vn -0.8425 0.5386 -0.0076 +vn -0.8786 0.4725 -0.0690 +vn -0.9929 0.0956 0.0701 +vn -0.8033 -0.5049 0.3158 +vn -0.9568 0.1753 -0.2318 +vn -0.8436 0.4102 -0.3465 +vn -0.7610 0.5719 -0.3063 +vn -0.7612 0.5716 -0.3064 +vn -0.7609 0.5715 -0.3073 +vn -0.7776 0.6236 0.0801 +vn -0.8667 0.4493 -0.2170 +vn -0.9591 -0.0153 -0.2827 +vn 0.3348 0.3308 -0.8823 +vn -0.0033 0.6031 -0.7977 +vn -0.7747 0.4361 -0.4579 +vn -0.9182 0.2975 -0.2614 +vn -0.8623 0.5036 0.0526 +vn -0.6170 0.7043 -0.3509 +vn -0.5513 0.7391 -0.3871 +vn -0.6745 -0.6462 -0.3572 +vn -0.9948 -0.0112 -0.1016 +vn -0.8014 -0.0634 0.5947 +vn -0.2164 0.7572 0.6162 +vn -0.9875 0.1507 0.0470 +vn -0.6181 0.4102 -0.6706 +vn -0.9330 -0.2496 -0.2591 +vn -0.9295 -0.2500 -0.2713 +vn -0.9333 -0.2484 -0.2592 +vn 0.3881 0.5312 -0.7532 +vn 0.1617 0.9604 -0.2270 +vn 0.4823 0.3863 -0.7863 +vn -0.8421 -0.5374 0.0454 +vn -0.6313 0.7110 -0.3097 +vn -0.3296 0.2793 -0.9019 +vn -0.8518 -0.5019 -0.1500 +vn -0.8769 -0.4633 -0.1285 +vn -0.9406 0.0058 0.3395 +vn -0.9809 -0.1477 0.1269 +vn -0.5282 0.7811 -0.3330 +vn -0.8940 -0.0362 -0.4466 +vn -0.8980 -0.0386 -0.4383 +vn -0.8973 -0.0390 -0.4397 +vn -0.9293 -0.2498 -0.2719 +vn 0.3615 0.5012 -0.7862 +vn -0.6692 -0.3187 -0.6712 +vn -0.1130 -0.9904 0.0794 +vn -0.1773 0.9208 -0.3473 +vn -0.9476 0.0137 -0.3192 +vn -0.9129 0.0879 -0.3987 +vn -0.5543 -0.7296 0.4006 +vn -0.8178 0.5508 0.1669 +vn 0.1408 -0.6707 0.7282 +vn -0.6254 0.7248 -0.2889 +vn -0.8343 0.4040 -0.3750 +vn -0.7589 0.5793 -0.2974 +vn -0.8782 0.0647 -0.4738 +vn -0.8795 0.4543 0.1414 +vn 0.2426 0.8142 -0.5275 +vn -0.7092 -0.5460 -0.4460 +vn -0.9586 0.2507 -0.1349 +vn -0.8039 -0.5671 -0.1794 +vn -0.9747 -0.1451 0.1701 +vn 0.8881 -0.0069 0.4596 +vn -0.9405 -0.3317 0.0742 +vn -0.9957 -0.0847 0.0377 +vn 0.2127 0.6152 0.7592 +vn -0.4400 0.7189 0.5382 +vn -0.3800 0.7485 0.5435 +vn -0.5074 0.2686 -0.8188 +vn -0.7290 -0.0238 -0.6841 +vn -0.7213 0.0364 -0.6917 +vn 0.4754 -0.7139 -0.5142 +vn 0.0448 0.5244 -0.8503 +vn -0.6526 -0.6718 -0.3505 +vn -0.9705 -0.2221 -0.0940 +vn -0.5988 0.6812 -0.4213 +vn -0.2178 0.8308 0.5122 +vn -0.9939 -0.1045 -0.0349 +vn 0.1816 0.9017 -0.3924 +vn 0.1817 0.9016 -0.3925 +vn 0.1817 0.9017 -0.3924 +vn -0.7270 -0.1510 -0.6698 +vn -0.7268 -0.1510 -0.6700 +vn -0.7269 -0.1509 -0.6699 +vn -0.6943 0.3085 -0.6502 +vn 0.5173 0.4492 -0.7284 +vn 0.5226 0.4534 -0.7220 +vn 0.5169 0.4490 -0.7288 +vn -0.9356 -0.3518 -0.0294 +vn -0.9691 0.2463 -0.0165 +vn -0.9677 0.2515 -0.0170 +vn -0.9672 0.2534 -0.0170 +vn -0.8613 -0.4736 -0.1842 +vn -0.9444 -0.3072 0.1177 +vn -0.8854 -0.4495 0.1184 +vn -0.1048 0.5586 -0.8228 +vn -0.7966 -0.1080 -0.5948 +vn -0.6901 0.2014 -0.6951 +vn 0.0418 0.9652 -0.2580 +vn -0.9783 0.0348 -0.2042 +vn -0.8950 0.3012 0.3292 +vn -0.7902 -0.5886 -0.1705 +vn -0.9693 0.2454 -0.0164 +vn -0.9311 -0.3542 -0.0878 +vn -0.6237 0.7559 -0.1993 +vn -0.6184 0.3657 -0.6956 +vn -0.6306 0.5630 -0.5342 +vn 0.2197 -0.1405 -0.9654 +vn 0.2184 -0.1422 -0.9654 +vn 0.2249 -0.1335 -0.9652 +vn -0.9738 0.1767 0.1434 +vn -0.9883 -0.0882 0.1241 +vn 0.2681 0.7765 -0.5703 +vn 0.5439 0.3128 -0.7787 +vn 0.2791 -0.1838 -0.9425 +vn -0.7348 0.0476 -0.6766 +vn 0.4388 0.5377 -0.7200 +vn -0.7851 -0.4933 -0.3745 +vn -0.9137 0.2648 0.3082 +vn -0.6211 0.5835 -0.5233 +vn -0.9741 0.1241 0.1891 +vn -0.8620 0.4371 0.2568 +vn 0.6207 0.1768 -0.7639 +vn 0.5001 0.3474 -0.7932 +vn 0.0340 0.3323 -0.9426 +vn -0.7977 -0.0563 -0.6004 +vn -0.7524 0.1877 -0.6314 +vn 0.0769 0.6273 -0.7750 +vn 0.0045 -0.9998 -0.0211 +vn 0.0024 -0.9997 -0.0226 +vn 0.0042 -0.9998 -0.0211 +vn 0.1403 0.3533 -0.9249 +vn 0.1390 0.3488 -0.9268 +vn 0.1388 0.3486 -0.9270 +vn -0.9030 -0.3470 -0.2534 +vn -0.9515 0.2160 0.2188 +vn -0.8665 -0.4783 -0.1429 +vn 0.1232 0.8416 -0.5258 +vn 0.1593 0.0332 0.9867 +vn -0.1736 0.6281 -0.7585 +vn -0.9580 -0.1902 -0.2146 +vn -0.6850 -0.1748 -0.7073 +vn -0.7495 -0.0281 -0.6614 +vn 0.0265 -0.9993 -0.0275 +vn 0.0196 -0.9996 -0.0214 +vn 0.0171 -0.9996 -0.0233 +vn -0.1769 0.6459 -0.7426 +vn -0.1764 0.6453 -0.7432 +vn -0.1726 0.6474 -0.7424 +vn -0.1893 0.7919 -0.5805 +vn -0.1893 0.7920 -0.5805 +vn -0.1902 0.7913 -0.5810 +vn 0.1042 0.3627 -0.9261 +vn 0.1418 0.3577 -0.9230 +vn -0.0837 0.8168 -0.5709 +vn 0.2997 0.4172 -0.8580 +vn -0.0012 0.8945 -0.4470 +vn -0.4857 0.6145 0.6216 +vn -0.3144 0.7184 -0.6206 +vn -0.8635 -0.0577 -0.5010 +vn -0.5412 -0.5787 -0.6101 +vn -0.5003 -0.7489 -0.4345 +vn -0.7034 -0.1905 -0.6848 +vn -0.2497 0.9093 -0.3330 +vn 0.0420 0.5493 -0.8346 +vn 0.0410 0.5488 -0.8350 +vn 0.0465 0.5450 -0.8371 +vn -0.1330 0.7346 -0.6654 +vn -0.4708 -0.3439 -0.8125 +vn -0.8039 -0.4874 -0.3409 +vn -0.8987 0.2147 -0.3823 +vn -0.7373 -0.1876 -0.6490 +vn -0.8590 -0.5120 0.0007 +vn -0.5002 0.6472 -0.5753 +vn -0.7532 -0.3609 -0.5499 +vn -0.7747 -0.4609 -0.4330 +vn -0.6893 -0.2040 -0.6952 +vn -0.8424 -0.0028 -0.5388 +vn -0.7619 0.1939 -0.6180 +vn -0.7564 0.2152 -0.6177 +vn -0.6813 0.3682 -0.6327 +vn 0.7916 0.3766 -0.4813 +vn 0.2705 -0.1726 -0.9471 +vn 0.0682 0.9363 -0.3445 +vn -0.7280 -0.0337 -0.6847 +vn -0.9941 0.1058 -0.0255 +vn -0.9916 0.1284 0.0134 +vn -0.6532 0.7119 -0.2577 +vn -0.7999 0.5937 -0.0873 +vn 0.0933 0.6313 -0.7699 +vn -0.4932 -0.7257 -0.4798 +vn -0.5623 -0.6900 -0.4557 +vn -0.8225 -0.2745 -0.4982 +vn -0.8434 -0.1768 -0.5074 +vn -0.8744 0.0730 -0.4797 +vn -0.7201 0.1532 -0.6768 +vn -0.6831 0.2231 -0.6954 +vn 0.0728 0.1762 -0.9817 +vn -0.0900 0.4129 -0.9063 +vn 0.0454 0.6283 -0.7767 +vn -0.4732 0.1288 -0.8715 +vn -0.9642 -0.1209 -0.2359 +vn -0.9554 0.0963 -0.2791 +vn -0.7286 0.5289 -0.4352 +vn -0.6774 0.5668 -0.4689 +vn -0.4273 0.8029 -0.4157 +vn -0.8479 0.1006 -0.5205 +vn -0.8772 -0.2755 -0.3932 +vn -0.5730 -0.6202 -0.5358 +vn -0.6543 -0.7121 -0.2545 +vn -0.6546 -0.7119 -0.2543 +vn -0.6540 -0.7125 -0.2542 +vn -0.7497 -0.6005 -0.2781 +vn -0.8123 -0.4339 -0.3898 +vn -0.8737 -0.2004 -0.4433 +vn -0.8898 0.0756 -0.4500 +vn -0.7080 0.3485 -0.6142 +vn 0.3190 0.8612 -0.3958 +vn -0.1106 0.2454 -0.9631 +vn -0.7535 0.1311 -0.6442 +vn -0.7311 0.1707 -0.6606 +vn -0.9432 0.2947 -0.1533 +vn -0.2879 -0.8165 -0.5005 +vn 0.5854 0.5921 0.5538 +vn 0.8108 0.4632 -0.3577 +vn 0.8088 0.4681 -0.3560 +vn 0.8099 0.4653 -0.3571 +vn -0.4605 0.6558 -0.5982 +vn 0.0284 -0.9993 -0.0256 +vn -0.8413 -0.2240 -0.4920 +vn -0.9645 -0.0011 -0.2641 +vn -0.8912 0.1909 -0.4116 +vn -0.8704 0.2830 -0.4028 +vn -0.8050 0.3535 -0.4765 +vn -0.2192 0.7966 -0.5634 +vn 0.2534 -0.9629 0.0929 +vn -0.8290 0.0855 -0.5527 +vn -0.7389 0.1892 -0.6467 +vn -0.7216 0.2856 -0.6307 +vn -0.6902 0.3699 -0.6219 +vn -0.5947 0.6795 -0.4297 +vn -0.4135 0.8037 -0.4280 +vn -0.4025 0.8220 -0.4029 +vn -0.7764 -0.0266 -0.6296 +vn -0.8948 -0.3319 -0.2987 +vn -0.9039 0.1779 -0.3891 +vn -0.9008 0.1759 -0.3970 +vn -0.9001 0.1764 -0.3985 +vn -0.8071 -0.0418 -0.5889 +vn -0.8037 0.0293 -0.5943 +vn 0.5601 0.1620 -0.8125 +vn 0.5597 0.1618 -0.8128 +vn 0.5598 0.1619 -0.8127 +vn -0.6082 0.1605 -0.7774 +vn -0.8103 0.2327 -0.5379 +vn -0.6688 0.2620 -0.6958 +vn -0.7136 0.3692 -0.5953 +vn -0.9753 0.1175 -0.1868 +vn -0.9751 0.1245 -0.1833 +vn -0.9755 0.1166 -0.1867 +vn -0.7280 -0.6150 -0.3031 +vn -0.7290 -0.6117 -0.3072 +vn -0.7291 -0.6115 -0.3074 +vn -0.8965 -0.3059 -0.3204 +vn -0.8080 -0.5217 -0.2738 +vn -0.9498 0.0735 -0.3040 +vn -0.6254 -0.4264 -0.6535 +vn -0.6244 -0.4167 -0.6606 +vn -0.6242 -0.4160 -0.6613 +vn -0.6117 -0.4382 -0.6586 +vn -0.8518 -0.0588 -0.5205 +vn -0.7013 0.2289 -0.6751 +vn 0.5240 0.4545 -0.7203 +vn -0.7651 0.2451 -0.5954 +vn -0.7976 0.2698 -0.5395 +vn -0.7611 0.4841 -0.4317 +vn -0.7345 0.6057 -0.3058 +vn -0.6827 0.7306 -0.0097 +vn -0.8277 0.5310 -0.1816 +vn -0.9802 0.1356 0.1443 +vn -0.7084 0.6589 0.2529 +vn -0.7342 0.6530 -0.1859 +vn -0.9751 0.1255 -0.1826 +vn -0.8656 -0.4742 -0.1607 +vn -0.5858 -0.7500 -0.3072 +vn -0.6542 -0.7105 -0.2592 +vn -0.7279 -0.6152 -0.3028 +vn -0.8773 -0.2919 -0.3810 +vn -0.9399 0.0658 -0.3350 +vn -0.9319 -0.0153 -0.3624 +vn -0.9317 -0.0174 -0.3628 +vn -0.9312 -0.0243 -0.3638 +vn -0.9051 0.1728 -0.3885 +vn -0.8049 0.3358 -0.4893 +vn -0.8524 0.1309 -0.5062 +vn -0.8673 0.1615 -0.4708 +vn -0.8556 0.2126 -0.4719 +vn -0.6932 0.2782 -0.6649 +vn -0.6502 0.3115 -0.6929 +vn -0.8326 0.1310 -0.5382 +vn -0.8024 0.5543 -0.2214 +vn -0.8240 0.5415 -0.1667 +vn -0.9896 0.0678 -0.1272 +vn -0.9440 -0.0621 -0.3241 +vn -0.6251 -0.4271 -0.6534 +vn -0.7337 0.1777 -0.6558 +vn -0.4852 0.7253 -0.4884 +vn 0.4866 0.1246 -0.8647 +vn -0.1129 -0.4265 -0.8974 +vn -0.5572 0.8098 -0.1837 +vn -0.6724 0.7399 0.0198 +vn -0.3933 0.8896 -0.2324 +vn -0.4178 0.8747 -0.2455 +vn -0.0779 0.4740 -0.8771 +vn -0.7754 -0.6025 -0.1889 +vn -0.8991 -0.3077 -0.3113 +vn -0.9090 0.1128 -0.4012 +vn -0.9310 -0.0268 -0.3640 +vn -0.9011 0.1815 -0.3937 +vn -0.8870 0.2962 -0.3543 +vn -0.9176 0.0542 -0.3938 +vn -0.8204 0.3248 -0.4706 +vn -0.4848 -0.1899 0.8538 +vn -0.9339 0.3187 0.1618 +vn -0.6800 0.7317 -0.0463 +vn -0.9746 0.1728 0.1425 +vn -0.3404 0.9358 -0.0920 +vn -0.9800 0.1795 0.0863 +vn -0.9659 -0.2093 0.1525 +vn -0.0232 -0.4122 -0.9108 +vn 0.0148 -0.2884 -0.9574 +vn -0.2451 -0.0867 -0.9656 +vn -0.7513 -0.5976 -0.2801 +vn -0.8275 -0.5057 -0.2440 +vn -0.8878 -0.3966 -0.2335 +vn -0.7163 -0.4306 -0.5491 +vn -0.7029 -0.4172 -0.5761 +vn -0.8554 -0.1301 -0.5013 +vn 0.3749 0.5458 -0.7493 +vn 0.4011 0.2704 -0.8752 +vn 0.4821 0.5374 -0.6919 +vn 0.6512 -0.2490 -0.7169 +vn 0.4192 0.2921 -0.8596 +vn -0.0670 0.7588 -0.6478 +vn 0.6232 0.7479 -0.2285 +vn -0.0131 0.7377 -0.6750 +vn -0.2523 0.6048 -0.7553 +vn 0.6693 -0.6932 -0.2675 +vn -0.1007 0.6905 -0.7163 +vn 0.1502 0.8865 -0.4376 +vn -0.3306 0.8904 -0.3128 +vn 0.5769 0.6190 -0.5329 +vn 0.5393 0.6355 -0.5525 +vn -0.1320 0.0189 -0.9911 +vn 0.7278 0.1531 -0.6685 +vn -0.3471 0.9048 -0.2467 +vn -0.1726 0.9095 -0.3781 +vn -0.1721 0.9104 -0.3763 +vn -0.1744 0.9072 -0.3828 +vn 0.4016 0.3222 -0.8573 +vn 0.1625 0.3493 -0.9228 +vn 0.8173 0.5426 0.1939 +vn 0.9926 0.1040 0.0627 +vn 0.1591 -0.9721 -0.1722 +vn 0.4547 0.7309 -0.5090 +vn 0.5316 0.5456 -0.6478 +vn 0.4483 0.3748 -0.8115 +vn 0.4483 0.3736 -0.8121 +vn 0.4497 0.3796 -0.8085 +vn -0.0336 0.4724 -0.8807 +vn 0.9229 -0.1019 -0.3713 +vn 0.3238 -0.4389 0.8381 +vn 0.6935 0.4297 -0.5783 +vn 0.6992 0.4310 -0.5704 +vn 0.6996 0.4303 -0.5705 +vn 0.9149 -0.1262 -0.3833 +vn 0.6870 0.2881 -0.6671 +vn 0.6934 0.4295 -0.5786 +vn -0.2744 -0.9465 -0.1700 +vn 0.6213 0.1600 -0.7671 +vn 0.1901 0.4729 -0.8603 +vn 0.3035 0.6468 -0.6997 +vn 0.3035 0.6476 -0.6989 +vn -0.1073 0.8345 -0.5405 +vn -0.1129 0.9075 -0.4045 +vn 0.3467 0.7628 -0.5458 +vn 0.4949 0.3321 -0.8030 +vn 0.4258 0.4626 -0.7776 +vn 0.4023 0.7191 -0.5667 +vn 0.5358 0.6876 -0.4900 +vn 0.4503 0.3803 -0.8078 +vn 0.3874 0.4142 -0.8236 +vn 0.3648 0.2902 -0.8847 +vn 0.2345 0.7689 -0.5949 +vn 0.3405 0.5338 -0.7740 +vn 0.4299 0.6439 -0.6329 +vn 0.1864 0.4235 -0.8865 +vn 0.2157 0.3557 -0.9094 +vn -0.0889 0.2314 -0.9688 +vn 0.6790 0.2281 -0.6978 +vn -0.3063 0.8568 -0.4148 +vn -0.6105 0.5819 0.5373 +vn -0.5862 0.5193 -0.6218 +vn 0.0347 -0.9975 0.0619 +vn 0.0346 -0.9975 0.0618 +vn 0.3912 0.6181 -0.6818 +vn 0.3414 0.2631 -0.9023 +vn 0.6475 0.2058 -0.7337 +vn -0.5484 0.0537 -0.8345 +vn -0.7296 -0.1314 0.6711 +vn 0.7397 0.4737 -0.4780 +vn 0.4487 0.2113 -0.8683 +vn 0.5971 -0.1440 -0.7891 +vn -0.1243 0.2561 -0.9586 +vn 0.6781 0.5922 -0.4353 +vn -0.1127 0.7184 -0.6865 +vn -0.0863 0.8796 -0.4678 +vn 0.3083 0.4808 -0.8209 +vn 0.5084 0.5323 -0.6769 +vn 0.7123 0.4247 -0.5588 +vn -0.0032 0.8984 -0.4391 +vn -0.0757 0.5488 -0.8325 +vn 0.5163 0.5113 -0.6870 +vn 0.2779 0.8113 -0.5144 +vn 0.0345 -0.9984 0.0443 +vn 0.4662 0.5962 -0.6536 +vn 0.1217 0.7858 -0.6064 +vn -0.0116 0.4727 -0.8811 +vn 0.6761 -0.5809 0.4532 +vn -0.0104 0.9251 -0.3795 +vn -0.1753 0.9064 -0.3844 +vn 0.6095 0.2482 -0.7530 +vn 0.2984 0.5601 -0.7728 +vn 0.4540 0.2841 -0.8445 +vn 0.3859 0.4928 -0.7799 +vn 0.7927 0.0104 -0.6096 +vn 0.3830 0.7997 -0.4623 +vn 0.3829 0.8000 -0.4620 +vn 0.3855 0.7942 -0.4696 +vn 0.1797 0.1106 -0.9775 +vn 0.7583 -0.1162 -0.6415 +vn 0.0468 0.9752 -0.2163 +vn 0.0739 0.9670 -0.2439 +vn 0.1176 0.5573 -0.8220 +vn -0.0572 0.6327 -0.7723 +vn -0.1552 0.7233 -0.6729 +vn 0.0679 0.7178 -0.6929 +vn 0.6999 0.4909 -0.5188 +vn 0.0998 0.9899 0.1003 +vn -0.8215 0.4818 -0.3051 +vn 0.6914 0.6217 -0.3680 +vn -0.2329 0.7074 -0.6674 +vn 0.6396 0.5464 -0.5408 +vn 0.4065 0.6077 -0.6823 +vn 0.2875 0.7644 -0.5771 +vn 0.2915 0.7179 -0.6321 +vn 0.0201 -0.9992 0.0353 +vn -0.0183 0.4016 -0.9156 +vn -0.2898 0.1706 -0.9418 +vn -0.0779 0.5198 -0.8507 +vn 0.0302 -0.9994 0.0148 +vn -0.1446 0.5526 -0.8208 +vn -0.1351 0.5527 -0.8223 +vn -0.1330 0.5532 -0.8224 +vn -0.9429 -0.1120 -0.3138 +vn -0.1175 0.7906 -0.6010 +vn 0.4991 0.5079 -0.7021 +vn 0.5880 0.5749 -0.5689 +vn 0.2721 0.5611 -0.7818 +vn 0.0404 0.5828 -0.8116 +vn -0.6949 0.6228 -0.3596 +vn -0.3944 0.2927 -0.8711 +vn -0.3585 0.3420 -0.8687 +vn 0.6875 0.1949 -0.6995 +vn 0.0429 0.2002 -0.9788 +vn 0.2754 0.3541 -0.8937 +vn -0.3800 0.8722 -0.3079 +vn -0.2554 0.5147 -0.8184 +vn -0.6469 0.3259 -0.6894 +vn 0.4204 0.4640 -0.7797 +vn -0.1071 0.9429 -0.3154 +vn -0.1418 0.8938 -0.4254 +vn -0.2084 0.8908 -0.4038 +vn 0.0448 0.5228 -0.8513 +vn 0.6810 0.0276 -0.7318 +vn 0.0048 0.4383 -0.8988 +vn 0.0655 0.7805 -0.6217 +vn -0.0510 0.4780 -0.8769 +vn -0.0483 0.6952 -0.7172 +vn -0.0233 0.6170 -0.7866 +vn 0.3752 -0.6243 -0.6852 +vn 0.4289 0.3145 -0.8469 +vn 0.4145 0.4452 -0.7937 +vn 0.1338 0.1473 -0.9800 +vn 0.0213 0.6564 -0.7541 +vn -0.3083 0.8077 -0.5025 +vn -0.5135 -0.1561 -0.8438 +vn -0.0970 -0.5214 -0.8478 +vn 0.9577 -0.2701 -0.0989 +vn 0.7632 0.0051 -0.6462 +vn -0.3740 0.7284 -0.5741 +vn 0.0467 0.5445 -0.8375 +vn 0.2146 -0.7531 -0.6219 +vn 0.0055 0.6974 -0.7167 +vn -0.4833 0.7936 -0.3697 +vn -0.1682 0.6489 -0.7421 +vn 0.6520 -0.5936 -0.4716 +vn -0.0195 0.4372 -0.8992 +vn -0.4154 0.1587 0.8957 +vn -0.0068 0.6769 -0.7361 +vn 0.0493 0.5654 -0.8234 +vn 0.0407 0.5455 -0.8372 +vn 0.4834 0.2909 -0.8256 +vn 0.4742 0.2589 -0.8415 +vn 0.0745 0.4364 -0.8967 +vn 0.5784 0.0078 -0.8157 +vn 0.2507 0.6055 -0.7554 +vn 0.5665 0.2680 -0.7793 +vn -0.6739 -0.6813 -0.2859 +vn 0.2237 0.9689 -0.1061 +vn -0.0658 0.5935 -0.8021 +vn 0.0124 0.9370 -0.3492 +vn -0.0489 0.5836 -0.8106 +vn 0.3540 -0.8899 0.2877 +vn -0.0497 0.5509 -0.8331 +vn 0.8898 -0.1202 -0.4402 +vn 0.3001 0.4729 -0.8284 +vn 0.2323 0.8025 -0.5496 +vn -0.2657 -0.6564 -0.7061 +vn -0.2496 0.8279 -0.5023 +vn 0.1620 0.3324 -0.9291 +vn 0.3619 0.8085 -0.4640 +vn -0.1418 0.8963 -0.4202 +vn 0.2289 0.2083 -0.9509 +vn 0.7950 -0.2991 -0.5277 +vn 0.6594 0.3057 -0.6869 +vn -0.0350 0.8017 -0.5967 +vn -0.0080 0.7952 -0.6063 +vn -0.0105 0.7975 -0.6033 +vn -0.0111 0.7979 -0.6027 +vn 0.1404 0.6375 -0.7576 +vn 0.7981 -0.0622 0.5993 +vn 0.1701 0.0073 -0.9854 +vn 0.0748 0.7942 -0.6031 +vn 0.7499 0.3737 -0.5458 +vn 0.0150 0.4367 -0.8995 +vn -0.2282 0.7154 -0.6604 +vn -0.2583 0.6226 -0.7386 +vn -0.2295 0.5714 -0.7879 +vn 0.7813 0.1595 -0.6034 +vn -0.3115 0.9375 0.1551 +vn -0.3603 0.4830 -0.7980 +vn 0.0083 0.9233 -0.3840 +vn 0.3828 0.8003 -0.4616 +vn 0.1433 -0.2033 -0.9686 +vn 0.3034 0.6459 -0.7005 +vn -0.3789 0.6562 -0.6526 +vn -0.1209 0.7934 -0.5965 +vn 0.3967 0.4800 -0.7825 +vn -0.1746 0.7742 -0.6084 +vn 0.9066 0.4015 0.1299 +vn 0.4358 0.8286 -0.3515 +vn 0.1553 0.7792 -0.6072 +vn 0.5211 0.2700 -0.8096 +vn 0.2805 0.2448 -0.9281 +vn 0.2791 0.2424 -0.9292 +vn 0.2753 0.2408 -0.9307 +vn 0.3082 0.4644 -0.8303 +vn 0.0516 0.6418 -0.7651 +vn -0.4575 0.6546 -0.6018 +vn -0.3922 0.6520 -0.6488 +vn 0.8022 0.5955 -0.0423 +vn 0.3667 0.6729 -0.6425 +vn 0.0970 0.7894 -0.6062 +vn 0.6024 0.3552 -0.7148 +vn 0.6068 0.3137 -0.7303 +vn 0.6068 0.3134 -0.7304 +vn 0.6068 0.3135 -0.7304 +vn 0.6043 0.3072 -0.7351 +vn -0.2110 0.6072 -0.7660 +vn -0.2045 0.6103 -0.7653 +vn -0.2112 0.6072 -0.7659 +vn -0.5251 0.8193 -0.2303 +vn 0.8110 0.4626 -0.3581 +vn 0.4948 0.1890 -0.8482 +vn 0.5299 0.3736 -0.7614 +vn -0.1957 0.7590 -0.6210 +vn -0.1995 0.7259 -0.6583 +vn -0.1246 0.4198 -0.8990 +vn 0.0939 0.6649 -0.7410 +vn 0.0457 0.8409 -0.5393 +vn 0.0062 0.5161 -0.8565 +vn -0.2115 0.6067 -0.7663 +vn -0.1884 0.7926 -0.5799 +vn 0.7686 0.3784 -0.5158 +vn 0.7685 0.3780 -0.5163 +vn 0.7679 0.3716 -0.5218 +vn 0.7677 0.3703 -0.5229 +vn -0.1302 0.7494 -0.6492 +vn 0.0636 0.4477 -0.8919 +vn -0.0647 0.8261 -0.5597 +vn -0.0654 0.8267 -0.5588 +vn -0.0650 0.8264 -0.5593 +vn -0.6541 0.5888 -0.4749 +vn 0.8762 0.4175 -0.2406 +vn -0.0230 0.8033 -0.5951 +vn 0.5101 0.5382 -0.6710 +vn -0.0228 0.8409 -0.5408 +vn -0.1321 0.6831 -0.7183 +vn -0.2642 0.8979 -0.3521 +vn -0.2548 0.9013 -0.3503 +vn -0.2645 0.8978 -0.3520 +vn 0.0279 0.5152 -0.8566 +vn -0.0559 0.5305 -0.8458 +vn 0.5583 0.3129 -0.7683 +vn -0.2649 0.8976 -0.3523 +vn 0.0080 0.9136 -0.4066 +vn 0.5385 0.2726 -0.7973 +vn 0.7461 0.1751 -0.6425 +vn -0.2551 0.6805 -0.6869 +vn 0.8908 0.3996 -0.2162 +vn 0.4426 0.8464 -0.2963 +vn -0.0583 0.4382 -0.8970 +vn 0.5483 0.6863 -0.4778 +vn 0.0148 0.8362 -0.5483 +vn 0.0101 0.8347 -0.5506 +vn 0.0102 0.8341 -0.5515 +vn -0.0256 0.7426 -0.6693 +vn 0.0301 0.5961 -0.8024 +vn 0.0157 0.3518 -0.9360 +vn -0.0639 0.8257 -0.5605 +vn -0.1969 0.9024 -0.3832 +vn 0.1806 0.9022 -0.3917 +vn 0.6284 0.1093 -0.7702 +vn -0.6645 0.5582 -0.4969 +vn 0.1140 0.9567 -0.2677 +vn 0.1257 0.9234 -0.3627 +vn 0.0159 0.8365 -0.5477 +vn 0.0287 0.4384 -0.8983 +vn 0.0405 0.4164 -0.9083 +vn -0.4562 -0.5430 0.7050 +vn -0.0167 0.5375 -0.8431 +vn 0.7242 0.5741 -0.3821 +vn -0.0175 0.8252 -0.5646 +vn 0.0576 -0.1835 -0.9813 +vn 0.4530 0.7439 -0.4914 +vn 0.0013 0.1995 -0.9799 +vn -0.0096 0.6735 -0.7391 +vn -0.3640 -0.3052 0.8800 +vn -0.0516 0.0855 -0.9950 +vn 0.1602 0.9577 -0.2391 +vn 0.1387 0.5969 -0.7902 +vn 0.3902 -0.9017 -0.1861 +vn 0.3156 -0.2035 0.9268 +vn 0.1983 0.3770 -0.9047 +vn 0.5534 0.4582 -0.6956 +vn -0.1467 0.5530 -0.8202 +vn 0.0786 0.6623 -0.7451 +vn 0.0632 0.5326 -0.8440 +vn 0.1759 0.4242 -0.8883 +vn -0.1127 0.6627 -0.7404 +vn 0.0921 0.8378 -0.5382 +vn 0.5347 0.5216 -0.6649 +vn 0.4360 0.8032 -0.4058 +vn 0.5255 0.7613 -0.3798 +vn 0.1425 0.7343 0.6637 +vn 0.2048 0.8026 -0.5603 +vn -0.0929 0.4486 -0.8889 +vn 0.4003 0.2867 -0.8704 +vn 0.0338 0.7983 -0.6014 +vn 0.1398 0.6173 -0.7742 +vn 0.3615 0.4576 -0.8124 +vn 0.5937 0.5332 -0.6027 +vn -0.2665 0.8884 -0.3737 +vn 0.3223 0.3933 -0.8611 +vn 0.6080 0.2987 -0.7356 +vn -0.6322 -0.7748 -0.0099 +vn -0.0079 0.7949 -0.6067 +vn 0.6421 0.4699 -0.6057 +vn 0.3060 0.2480 -0.9192 +vn 0.3062 0.7362 -0.6036 +vn -0.3026 0.8181 -0.4891 +vn -0.5746 0.7786 -0.2522 +vn 0.6477 0.4185 -0.6367 +vn -0.6820 0.5672 -0.4617 +vn 0.1433 0.7661 -0.6265 +vn 0.1177 0.4154 -0.9020 +vn 0.0773 0.8035 -0.5902 +vn 0.4621 -0.8305 -0.3111 +vn 0.2551 0.7325 -0.6312 +vn -0.0307 0.5118 -0.8586 +vn -0.0606 0.5699 -0.8195 +vn -0.1184 0.4877 -0.8649 +vn -0.0862 0.4072 -0.9092 +vn -0.0754 0.8429 -0.5327 +vn -0.1902 0.9110 -0.3660 +vn 0.3864 0.3831 -0.8390 +vn -0.0252 0.7891 -0.6138 +vn -0.6395 0.3043 -0.7060 +vn 0.5778 0.0788 -0.8124 +vn 0.3314 0.3087 -0.8915 +vn 0.2488 0.9167 -0.3128 +vn 0.2542 0.9011 -0.3514 +vn 0.2541 0.9009 -0.3518 +vn 0.2545 0.9010 -0.3514 +vn 0.3510 0.6879 -0.6353 +vn 0.2619 0.6787 -0.6861 +vn 0.3315 0.4791 -0.8127 +vn 0.1776 0.6675 -0.7231 +vn 0.1739 0.6823 -0.7101 +vn -0.0443 0.6269 -0.7778 +vn 0.3809 0.6880 -0.6176 +vn -0.5197 0.6446 -0.5607 +vn 0.0298 0.5898 -0.8070 +vn 0.7090 0.5821 -0.3981 +vn -0.2923 0.2042 -0.9343 +vn 0.2518 0.9006 -0.3542 +vn 0.0356 0.5679 -0.8223 +vn 0.3528 0.5492 -0.7575 +vn 0.0939 0.8649 -0.4931 +vn 0.0254 0.6199 -0.7842 +vn 0.3094 -0.9441 -0.1140 +vn -0.6581 0.7389 -0.1447 +vn -0.5656 -0.5352 -0.6275 +vn 0.3639 0.8318 -0.4191 +vn 0.3729 0.7402 -0.5595 +vn 0.0402 0.3928 -0.9187 +vn -0.5750 0.4221 -0.7008 +vn -0.0266 0.9560 0.2923 +vn 0.5211 0.1537 -0.8395 +vn 0.2146 0.6490 -0.7299 +vn -0.0944 0.2136 -0.9723 +vn -0.0245 0.3212 -0.9467 +vn -0.5813 0.1796 -0.7936 +vn -0.5787 0.8064 0.1216 +vn -0.6247 0.3438 -0.7011 +vn -0.3630 0.1747 -0.9153 +vn -0.4224 0.1335 -0.8965 +vn -0.5062 0.4332 -0.7458 +vn -0.6977 0.1620 -0.6978 +vn -0.3739 0.5349 -0.7577 +vn -0.4602 0.3984 -0.7934 +vn -0.3808 -0.1242 -0.9163 +vn 0.0324 0.8521 0.5223 +vn 0.0832 -0.5832 -0.8080 +vn -0.3800 -0.0883 -0.9208 +vn -0.3962 -0.1077 -0.9118 +vn 0.6495 -0.2310 -0.7244 +vn -0.4400 0.0674 -0.8955 +vn 0.5160 -0.1606 -0.8414 +vn 0.5157 -0.1602 -0.8417 +vn 0.5159 -0.1604 -0.8415 +vn 0.5161 -0.1607 -0.8413 +vn -0.1250 0.2688 -0.9550 +vn -0.4593 0.1988 -0.8657 +vn 0.3533 -0.0746 -0.9325 +vn 0.1924 0.1253 -0.9733 +vn -0.3200 0.4667 -0.8245 +vn 0.4543 -0.3476 -0.8202 +vn 0.4656 -0.4125 -0.7830 +vn 0.0766 -0.6051 -0.7924 +vn 0.6426 -0.0573 -0.7641 +vn -0.4959 -0.3371 -0.8003 +vn -0.4967 -0.3334 -0.8014 +vn -0.4964 -0.3346 -0.8010 +vn -0.3087 -0.3949 -0.8653 +vn -0.3500 -0.7006 -0.6218 +vn 0.0941 -0.8890 -0.4481 +vn -0.8980 -0.0398 -0.4382 +vn 0.3365 -0.1888 -0.9225 +vn -0.6377 -0.1848 -0.7478 +vn -0.6150 -0.1334 -0.7771 +vn -0.3506 0.0987 -0.9313 +vn -0.4322 -0.6466 -0.6286 +vn -0.5758 0.0546 -0.8158 +vn -0.5239 -0.6081 -0.5964 +vn -0.5302 -0.6637 -0.5277 +vn 0.3370 -0.6760 -0.6553 +vn 0.2068 -0.4618 -0.8625 +vn 0.2895 -0.5166 -0.8058 +vn -0.1605 0.4102 -0.8978 +vn -0.4824 -0.7157 -0.5050 +vn -0.6226 -0.4311 -0.6531 +vn -0.2398 0.2372 -0.9414 +vn -0.2395 0.2384 -0.9412 +vn -0.2441 0.2367 -0.9404 +vn -0.3975 0.2693 -0.8772 +vn -0.1070 0.4962 -0.8616 +vn -0.5606 -0.2951 -0.7737 +vn 0.0872 -0.1678 -0.9820 +vn 0.0978 -0.1346 -0.9861 +vn 0.0012 0.1554 -0.9879 +vn 0.0287 0.1184 -0.9926 +vn 0.1100 -0.9032 -0.4148 +vn 0.1855 -0.8865 -0.4239 +vn 0.0129 -0.5694 -0.8220 +vn -0.0737 -0.3721 -0.9252 +vn 0.0117 -0.9973 -0.0722 +vn -0.7040 0.2884 -0.6490 +vn -0.2525 0.4836 -0.8380 +vn -0.0451 0.4472 -0.8933 +vn 0.2303 0.2705 -0.9348 +vn -0.1502 -0.0089 -0.9886 +vn -0.2607 0.1641 -0.9514 +vn -0.2663 0.1112 -0.9575 +vn -0.4816 -0.3382 -0.8085 +vn -0.5020 -0.2633 -0.8238 +vn -0.1044 0.0413 -0.9937 +vn 0.2278 0.1038 -0.9681 +vn -0.5526 0.7076 -0.4404 +vn -0.3564 -0.0161 -0.9342 +vn -0.1478 -0.0892 -0.9850 +vn 0.3563 -0.6234 -0.6960 +vn -0.5337 0.1254 -0.8363 +vn -0.1549 0.2741 -0.9491 +vn -0.4956 -0.3376 -0.8002 +vn -0.0330 -0.4282 -0.9031 +vn 0.2706 0.2461 -0.9307 +vn 0.2961 0.0689 -0.9527 +vn -0.5284 0.1491 -0.8358 +vn 0.2036 -0.5239 -0.8271 +vn 0.1894 -0.4833 -0.8547 +vn -0.7245 -0.6421 -0.2506 +vn -0.4755 0.4017 -0.7827 +vn 0.1049 0.0240 -0.9942 +vn 0.0635 -0.1512 -0.9865 +vn -0.3270 0.1952 -0.9246 +vn -0.3926 0.2850 -0.8744 +vn -0.2877 0.0879 -0.9537 +vn 0.3478 0.1589 -0.9240 +vn -0.2964 -0.0069 -0.9550 +vn -0.3076 0.0685 -0.9490 +vn -0.0313 -0.3349 -0.9417 +vn -0.6841 -0.0407 -0.7283 +vn -0.7224 -0.2666 -0.6380 +vn -0.4259 0.0186 -0.9046 +vn 0.0259 -0.1438 -0.9893 +vn 0.0789 0.1596 -0.9840 +vn 0.1337 -0.3208 -0.9377 +vn -0.2606 0.3690 -0.8922 +vn 0.0673 -0.5165 -0.8536 +vn -0.2772 0.2529 -0.9269 +vn 0.6607 0.0202 -0.7503 +vn 0.0657 0.2886 -0.9552 +vn 0.0586 0.0562 -0.9967 +vn 0.0447 -0.0382 -0.9983 +vn -0.3604 -0.1140 -0.9258 +vn 0.0764 0.1881 -0.9792 +vn 0.0960 -0.4282 -0.8986 +vn 0.2787 -0.8878 -0.3661 +vn -0.0934 0.4410 -0.8926 +vn 0.0062 -0.1078 -0.9942 +vn 0.0060 -0.1079 -0.9941 +vn -0.4445 0.0486 -0.8945 +vn 0.1544 -0.4652 -0.8716 +vn 0.1623 -0.4579 -0.8741 +vn 0.1626 -0.4576 -0.8742 +vn 0.0441 -0.1013 -0.9939 +vn -0.3749 0.0083 -0.9270 +vn 0.0275 -0.3816 -0.9239 +vn 0.4316 -0.0183 -0.9019 +vn -0.0022 0.2010 -0.9796 +vn 0.2204 -0.3013 -0.9277 +vn -0.8766 -0.1684 -0.4508 +vn -0.3543 0.1031 -0.9294 +vn 0.5594 0.1618 -0.8130 +vn -0.3160 -0.4183 -0.8515 +vn -0.1139 -0.1065 -0.9878 +vn -0.2437 -0.4754 -0.8453 +vn -0.1845 -0.6904 -0.6995 +vn -0.5310 0.2759 -0.8012 +vn 0.0869 0.3497 -0.9328 +vn -0.6981 -0.0584 -0.7136 +vn -0.5735 -0.7833 -0.2400 +vn 0.1143 -0.4355 -0.8929 +vn -0.0401 -0.4728 -0.8803 +vn 0.8202 0.4984 0.2808 +vn -0.6902 -0.3839 -0.6134 +vn -0.6886 -0.3891 -0.6119 +vn -0.4667 -0.6697 -0.5777 +vn -0.0359 -0.6097 -0.7918 +vn -0.0779 -0.1506 0.9855 +vn -0.2209 -0.1854 -0.9575 +vn -0.2019 -0.7169 -0.6673 +vn -0.2455 -0.7199 -0.6492 +vn -0.2380 -0.7239 -0.6475 +vn -0.2452 -0.7193 -0.6500 +vn -0.1071 -0.1234 -0.9866 +vn 0.6588 0.2521 -0.7088 +vn 0.5828 0.0098 -0.8126 +vn 0.0835 -0.9481 0.3068 +vn -0.2540 -0.2605 -0.9315 +vn 0.1033 -0.9938 0.0415 +vn -0.3844 -0.1207 -0.9152 +vn -0.2264 -0.8631 -0.4513 +vn -0.1819 -0.3688 -0.9116 +vn -0.1824 -0.3689 -0.9114 +vn -0.1819 -0.3688 -0.9115 +vn 0.6018 0.0522 -0.7969 +vn -0.0799 -0.0759 -0.9939 +vn -0.4315 -0.2978 -0.8515 +vn -0.1364 -0.0286 -0.9902 +vn 0.2942 -0.6847 -0.6668 +vn 0.1540 -0.4656 -0.8715 +vn -0.5371 -0.2250 -0.8130 +vn 0.9809 -0.1761 -0.0829 +vn -0.3856 -0.2291 -0.8938 +vn 0.1176 0.2467 -0.9619 +vn 0.0827 0.0811 -0.9933 +vn -0.5209 -0.2326 -0.8213 +vn -0.5248 -0.2379 -0.8173 +vn -0.5202 -0.2317 -0.8220 +vn 0.4541 -0.4453 -0.7717 +vn 0.1464 0.3354 -0.9306 +vn -0.1103 -0.0967 -0.9892 +vn 0.6335 -0.5578 -0.5362 +vn 0.0108 -0.9919 0.1268 +vn 0.5814 0.1000 -0.8075 +vn 0.5425 0.1270 -0.8304 +vn -0.1815 -0.3687 -0.9117 +vn 0.0269 0.1035 -0.9943 +vn -0.2260 -0.1231 -0.9663 +vn 0.6984 -0.2617 -0.6662 +vn 0.4814 0.0657 -0.8740 +vn -0.0139 0.2742 -0.9616 +vn -0.4768 0.3512 -0.8058 +vn -0.4954 -0.3378 -0.8003 +vn -0.9876 0.1547 0.0249 +vn 0.5095 -0.4982 -0.7016 +vn 0.5772 -0.1576 -0.8013 +vn -0.6933 0.4314 -0.5773 +vn 0.7540 -0.1155 -0.6467 +vn 0.6156 -0.0800 -0.7840 +vn 0.2087 0.3955 -0.8944 +vn -0.0486 0.1868 -0.9812 +vn 0.0368 0.1372 -0.9899 +vn -0.8320 -0.0208 -0.5544 +vn -0.2286 -0.3424 -0.9113 +vn -0.3614 -0.3065 -0.8806 +vn 0.6228 -0.3996 -0.6726 +vn 0.5110 -0.0260 -0.8592 +vn 0.4439 0.0773 -0.8927 +vn -0.4291 -0.5570 -0.7111 +vn 0.0204 -0.0352 -0.9992 +vn -0.0800 -0.2330 -0.9692 +vn 0.4368 -0.5792 -0.6883 +vn 0.6335 -0.4099 -0.6563 +vn 0.5924 -0.1306 -0.7950 +vn 0.5013 0.0877 -0.8608 +vn 0.5333 -0.1884 -0.8247 +vn 0.5331 -0.1883 -0.8249 +vn 0.5332 -0.1884 -0.8247 +vn 0.5334 -0.1886 -0.8246 +vn 0.5398 -0.0204 -0.8416 +vn 0.4970 0.0047 -0.8678 +vn 0.4238 0.1542 -0.8925 +vn 0.4153 0.0627 -0.9075 +vn 0.0770 -0.2528 -0.9644 +vn -0.0294 -0.9991 0.0320 +vn -0.3120 -0.3659 -0.8768 +vn -0.2371 -0.7243 -0.6474 +vn -0.2009 0.2197 -0.9546 +vn -0.2977 0.4287 -0.8530 +vn 0.2723 -0.5842 -0.7646 +vn 0.3285 -0.0775 -0.9413 +vn 0.4525 0.0426 -0.8908 +vn -0.3720 0.9249 -0.0789 +vn -0.5776 -0.8031 -0.1465 +vn -0.2942 0.3193 -0.9009 +vn -0.0647 -0.5915 -0.8037 +vn -0.7717 0.5613 -0.2989 +vn -0.5307 0.0629 -0.8452 +vn 0.0938 -0.5770 -0.8113 +vn 0.3640 0.0383 -0.9306 +vn 0.3517 0.0638 -0.9339 +vn -0.2883 -0.1331 -0.9482 +vn -0.0375 -0.2569 -0.9657 +vn 0.1133 0.2043 -0.9723 +vn -0.2229 0.3947 -0.8914 +vn -0.5505 0.2605 -0.7931 +vn 0.3634 -0.2030 -0.9092 +vn 0.4038 0.0722 -0.9120 +vn 0.6127 0.0927 -0.7849 +vn 0.6159 0.0885 -0.7828 +vn 0.6163 0.0880 -0.7826 +vn -0.2262 0.0602 -0.9722 +vn -0.1444 -0.4358 -0.8884 +vn -0.0425 -0.3220 -0.9458 +vn -0.4356 -0.3081 -0.8458 +vn -0.6269 -0.7459 0.2251 +vn -0.1854 -0.7984 -0.5729 +vn 0.2938 -0.4424 -0.8473 +vn -0.1512 -0.3946 -0.9063 +vn 0.0444 -0.2604 -0.9645 +vn 0.0436 -0.2604 -0.9645 +vn 0.0426 -0.2608 -0.9644 +vn 0.0156 -0.3146 -0.9491 +vn 0.3107 -0.3459 -0.8853 +vn 0.4478 0.0053 -0.8941 +vn 0.5066 -0.3882 -0.7698 +vn 0.3730 -0.1842 -0.9094 +vn 0.3308 -0.1171 -0.9364 +vn 0.3992 0.0250 -0.9165 +vn 0.3990 0.0273 -0.9166 +vn 0.4046 0.0191 -0.9143 +vn -0.6392 0.4974 -0.5866 +vn 0.4478 0.2425 -0.8606 +vn 0.1243 0.2814 -0.9515 +vn -0.0347 0.3618 -0.9316 +vn -0.6885 -0.3895 -0.6118 +vn -0.6552 -0.7546 -0.0362 +vn -0.5566 0.1183 -0.8223 +vn -0.1947 -0.5637 -0.8027 +vn -0.1575 0.1182 -0.9804 +vn 0.4778 -0.3854 -0.7894 +vn 0.2695 -0.4400 -0.8566 +vn 0.2334 0.0125 -0.9723 +vn 0.3825 0.0713 -0.9212 +vn -0.1775 -0.0602 -0.9823 +vn -0.1788 0.3259 -0.9283 +vn -0.1536 0.0454 -0.9871 +vn -0.4945 -0.4122 -0.7652 +vn 0.4933 -0.3703 -0.7871 +vn 0.0513 -0.2829 -0.9578 +vn 0.3657 -0.1388 -0.9203 +vn 0.3587 0.1142 -0.9264 +vn 0.4438 -0.0021 -0.8961 +vn 0.4502 0.1108 -0.8860 +vn 0.3964 0.0281 -0.9176 +vn -0.4667 -0.1078 -0.8778 +vn -0.3931 0.7446 -0.5394 +vn -0.2523 0.3294 -0.9098 +vn 0.0325 -0.9993 -0.0199 +vn 0.0305 -0.9993 -0.0194 +vn 0.2081 -0.3463 -0.9148 +vn 0.1152 -0.4975 -0.8598 +vn 0.3025 -0.2184 -0.9278 +vn 0.2860 -0.0359 -0.9575 +vn 0.2511 -0.2084 -0.9453 +vn 0.4157 -0.7753 -0.4755 +vn -0.9627 0.1859 -0.1965 +vn 0.6124 0.0930 -0.7851 +vn 0.0853 -0.0458 -0.9953 +vn 0.1846 -0.5745 -0.7974 +vn 0.3369 -0.3583 -0.8707 +vn 0.2975 -0.0638 -0.9526 +vn 0.3708 -0.7264 -0.5787 +vn 0.2746 -0.0556 -0.9599 +vn 0.3855 0.0864 -0.9187 +vn 0.4233 -0.0388 -0.9052 +vn -0.0795 0.4399 -0.8945 +vn -0.1307 0.1207 -0.9840 +vn -0.2586 0.3146 -0.9133 +vn 0.5336 -0.8413 0.0862 +vn 0.0616 -0.4239 -0.9036 +vn 0.3346 -0.0804 -0.9389 +vn 0.0444 -0.3485 -0.9362 +vn -0.0521 0.3735 -0.9262 +vn -0.6667 0.2225 -0.7113 +vn 0.1930 -0.1542 -0.9690 +vn -0.0090 -0.2949 -0.9555 +vn 0.2929 0.0324 -0.9556 +vn 0.2472 -0.3820 -0.8905 +vn 0.2391 -0.3343 -0.9116 +vn 0.5887 -0.3514 -0.7280 +vn 0.3326 0.0796 -0.9397 +vn 0.5806 0.0000 -0.8142 +vn 0.4221 0.1272 -0.8976 +vn 0.3942 0.0278 -0.9186 +vn -0.1783 0.0674 -0.9817 +vn -0.0514 -0.0809 -0.9954 +vn -0.2690 0.0603 -0.9613 +vn -0.3500 -0.3648 0.8628 +vn -0.4348 0.2572 -0.8630 +vn 0.1697 0.1946 -0.9661 +vn 0.4180 -0.6886 -0.5926 +vn -0.6066 0.2662 -0.7491 +vn 0.3747 0.2356 -0.8967 +vn 0.1533 -0.3580 -0.9210 +vn 0.1577 -0.3622 -0.9187 +vn 0.1590 -0.3605 -0.9191 +vn 0.1555 -0.1543 -0.9757 +vn 0.4758 0.0526 -0.8780 +vn 0.4595 0.1540 -0.8747 +vn 0.3807 0.0531 -0.9232 +vn 0.0034 -0.9996 0.0269 +vn -0.0052 -0.9998 0.0207 +vn 0.0022 -0.9997 0.0263 +vn -0.4700 -0.1218 -0.8742 +vn -0.3994 0.0088 -0.9167 +vn -0.2536 -0.3058 -0.9177 +vn 0.1808 0.1078 -0.9776 +vn 0.0937 -0.8803 -0.4650 +vn -0.2935 0.1427 -0.9453 +vn -0.4948 0.3311 -0.8034 +vn -0.2856 -0.2932 -0.9124 +vn -0.4636 0.3143 -0.8285 +vn 0.1846 -0.0153 -0.9827 +vn 0.0532 -0.5391 -0.8406 +vn 0.1577 -0.3631 -0.9183 +vn 0.1962 -0.0497 -0.9793 +vn 0.2981 -0.1572 -0.9415 +vn 0.2788 0.0235 -0.9601 +vn 0.2549 -0.0027 -0.9670 +vn -0.3426 0.3280 -0.8804 +vn -0.3120 0.2323 -0.9212 +vn -0.4293 0.3260 -0.8422 +vn -0.4286 0.3291 -0.8414 +vn -0.4287 0.3297 -0.8411 +vn 0.0805 0.2846 -0.9553 +vn -0.0873 0.4739 -0.8762 +vn -0.2860 0.2130 -0.9343 +vn 0.2677 -0.4619 -0.8456 +vn 0.1677 -0.3316 -0.9284 +vn -0.1775 -0.3058 -0.9354 +vn 0.1223 0.1251 -0.9846 +vn 0.1210 0.0798 -0.9894 +vn -0.5833 0.0320 -0.8116 +vn -0.5817 0.0307 -0.8128 +vn -0.5823 0.0311 -0.8124 +vn -0.1141 -0.9752 -0.1895 +vn 0.5819 -0.4736 -0.6612 +vn -0.3568 -0.2437 -0.9018 +vn 0.1777 -0.0239 -0.9838 +vn 0.3824 -0.2851 -0.8789 +vn 0.3771 -0.2930 -0.8786 +vn 0.3820 -0.2842 -0.8794 +vn 0.2309 0.0448 -0.9719 +vn 0.3255 0.1566 -0.9325 +vn -0.3054 -0.2024 -0.9305 +vn 0.3009 0.2751 -0.9131 +vn 0.2980 0.2651 -0.9170 +vn 0.3006 0.2740 -0.9136 +vn -0.2944 -0.1956 -0.9355 +vn -0.3201 -0.2798 -0.9051 +vn 0.3704 -0.2369 -0.8982 +vn 0.1723 -0.3588 -0.9174 +vn 0.1710 -0.2342 -0.9570 +vn 0.1713 -0.2353 -0.9567 +vn 0.1741 -0.2387 -0.9554 +vn 0.1614 -0.0017 -0.9869 +vn 0.3223 0.1778 -0.9298 +vn -0.6984 0.1877 -0.6907 +vn 0.1233 0.2460 -0.9614 +vn -0.2407 -0.2749 -0.9309 +vn -0.1716 -0.0695 -0.9827 +vn -0.7935 -0.2555 -0.5524 +vn 0.2782 -0.2464 -0.9284 +vn 0.2557 0.0108 -0.9667 +vn 0.1257 -0.3623 -0.9235 +vn 0.1167 -0.3580 -0.9264 +vn 0.1157 -0.3565 -0.9271 +vn 0.3020 -0.2022 -0.9316 +vn 0.3747 -0.2921 -0.8800 +vn 0.0244 0.1197 -0.9925 +vn 0.0242 0.1190 -0.9926 +vn 0.0261 0.1140 -0.9931 +vn 0.0710 0.1512 -0.9860 +vn -0.1010 0.5698 -0.8155 +vn -0.6242 -0.0539 -0.7794 +vn -0.8881 -0.0603 -0.4556 +vn 0.0628 -0.3492 -0.9349 +vn 0.1396 -0.7293 -0.6698 +vn 0.2609 0.0242 -0.9651 +vn 0.2668 0.0621 -0.9618 +vn 0.1242 -0.7135 -0.6896 +vn 0.1248 -0.6701 -0.7317 +vn 0.2410 -0.2725 -0.9315 +vn 0.2786 -0.2256 -0.9335 +vn 0.2207 -0.1485 -0.9640 +vn 0.2578 0.0211 -0.9660 +vn 0.1376 -0.4477 -0.8835 +vn -0.3928 0.0528 -0.9181 +vn 0.1398 -0.1436 -0.9797 +vn 0.1556 -0.7006 -0.6964 +vn 0.1729 -0.3548 -0.9188 +vn 0.1279 -0.3625 -0.9232 +vn 0.1749 -0.2390 -0.9551 +vn 0.6020 -0.0858 -0.7939 +vn -0.5838 0.0325 -0.8112 +vn 0.4392 -0.5814 -0.6849 +vn 0.1705 0.1635 -0.9717 +vn -0.1902 -0.3967 -0.8980 +vn -0.2412 0.1867 -0.9524 +vn 0.0863 -0.5367 -0.8394 +vn 0.1101 -0.2428 -0.9638 +vn 0.1875 0.1437 -0.9717 +vn 0.2429 -0.2283 -0.9428 +vn 0.2421 -0.2270 -0.9433 +vn 0.2396 -0.2234 -0.9448 +vn 0.1840 -0.0544 -0.9814 +vn 0.3568 0.1709 -0.9184 +vn 0.2090 0.3395 -0.9171 +vn 0.4052 0.1210 -0.9062 +vn 0.1258 0.3582 -0.9251 +vn 0.1374 -0.0105 -0.9905 +vn 0.1389 -0.0035 -0.9903 +vn 0.1377 -0.0087 -0.9904 +vn 0.1392 -0.0024 -0.9903 +vn 0.1211 -0.2991 -0.9465 +vn 0.2765 -0.3160 -0.9076 +vn 0.2654 -0.1284 -0.9555 +vn 0.3889 0.2701 -0.8808 +vn -0.2875 -0.2370 -0.9280 +vn -0.3127 -0.3475 -0.8840 +vn -0.7499 0.1179 -0.6510 +vn 0.1162 -0.4445 -0.8882 +vn 0.1380 -0.1551 -0.9782 +vn 0.2175 -0.0009 -0.9761 +vn 0.1440 -0.2833 -0.9482 +vn 0.3249 -0.1126 -0.9390 +vn 0.3204 -0.0639 -0.9451 +vn 0.2533 0.1685 -0.9526 +vn -0.6227 0.1481 -0.7683 +vn 0.1346 -0.2482 -0.9593 +vn -0.5739 0.1926 -0.7959 +vn 0.2354 -0.1863 -0.9539 +vn -0.2774 0.3492 -0.8951 +vn -0.2258 0.4764 -0.8497 +vn -0.5129 -0.0798 -0.8547 +vn -0.4984 -0.0419 -0.8660 +vn -0.1578 0.1496 -0.9761 +vn 0.1266 -0.1054 -0.9863 +vn 0.0843 -0.7234 -0.6852 +vn 0.0303 -0.3403 -0.9398 +vn 0.1965 -0.3355 -0.9213 +vn 0.2210 -0.2254 -0.9489 +vn 0.2389 -0.2222 -0.9453 +vn 0.2156 -0.1968 -0.9565 +vn 0.8239 -0.5349 -0.1871 +vn 0.1675 0.3385 -0.9259 +vn 0.1700 0.3452 -0.9230 +vn 0.1676 0.3385 -0.9259 +vn -0.6228 -0.1900 -0.7590 +vn -0.0158 -0.9732 0.2296 +vn -0.3812 -0.3201 -0.8673 +vn 0.1177 -0.7936 -0.5970 +vn 0.0582 -0.5910 -0.8045 +vn 0.1303 -0.7069 -0.6952 +vn 0.1054 -0.4096 -0.9062 +vn 0.1845 -0.1799 -0.9662 +vn 0.1663 0.1055 -0.9804 +vn 0.2978 0.2640 -0.9174 +vn -0.1820 0.2400 -0.9536 +vn -0.0193 0.2541 -0.9670 +vn 0.1993 -0.2617 -0.9444 +vn 0.2009 -0.2592 -0.9447 +vn 0.2013 -0.2583 -0.9449 +vn 0.2204 -0.1737 -0.9598 +vn 0.2198 0.1778 -0.9592 +vn 0.1672 0.3387 -0.9259 +vn -0.4352 0.0240 -0.9000 +vn -0.5822 -0.1103 -0.8055 +vn 0.1307 -0.4606 -0.8779 +vn 0.1986 -0.2624 -0.9443 +vn 0.0128 -0.3742 -0.9273 +vn 0.0888 -0.1245 -0.9882 +vn 0.1228 -0.0231 -0.9922 +vn -0.5254 -0.2385 -0.8167 +vn -0.0521 0.1436 -0.9883 +vn -0.6805 -0.3647 -0.6355 +vn -0.4309 -0.2648 -0.8627 +vn -0.3512 0.4513 -0.8203 +vn -0.8907 0.1676 -0.4225 +vn -0.3273 0.5254 -0.7854 +vn -0.0078 -0.2990 -0.9542 +vn 0.1529 -0.0871 -0.9844 +vn 0.3285 -0.1690 -0.9293 +vn 0.3613 -0.2607 -0.8952 +vn 0.1831 -0.1853 -0.9655 +vn 0.1951 -0.8054 -0.5597 +vn -0.5938 0.1655 -0.7874 +vn -0.2231 0.1764 -0.9587 +vn 0.1291 -0.2634 -0.9560 +vn 0.1146 -0.0358 -0.9928 +vn 0.1999 -0.1938 -0.9605 +vn 0.1682 -0.0046 -0.9857 +vn 0.1258 -0.1142 -0.9855 +vn 0.1493 -0.0559 -0.9872 +vn 0.1484 0.0363 -0.9883 +vn -0.4790 -0.6905 -0.5421 +vn -0.0314 -0.0212 -0.9993 +vn -0.4915 -0.4365 -0.7536 +vn 0.3030 0.2768 -0.9119 +vn -0.0161 -0.5348 -0.8448 +vn 0.2551 -0.3249 -0.9107 +vn 0.1169 -0.0809 -0.9898 +vn -0.2400 0.2402 -0.9406 +vn 0.3918 0.8644 -0.3151 +vn -0.9285 0.3107 -0.2035 +vn -0.9210 0.1828 -0.3440 +vn -0.3741 0.1653 -0.9125 +vn 0.1731 -0.2763 -0.9454 +vn 0.1457 0.2280 -0.9627 +vn 0.2597 -0.1943 -0.9460 +vn 0.3435 -0.2604 -0.9023 +vn 0.9203 -0.3578 -0.1582 +vn -0.3621 0.0938 -0.9274 +vn 0.6177 -0.1476 -0.7724 +vn 0.0065 -0.1077 -0.9942 +vn 0.4433 -0.8567 -0.2636 +vn -0.1299 -0.5764 0.8068 +vn -0.1285 -0.5788 0.8053 +vn -0.1267 -0.5797 0.8049 +vn -0.8422 0.0695 -0.5347 +vn -0.4914 -0.3772 -0.7850 +vn -0.5590 -0.2536 -0.7895 +vn 0.0027 -0.2180 -0.9759 +vn 0.2146 -0.1801 -0.9600 +vn 0.1639 -0.1017 -0.9812 +vn -0.0334 -0.8032 -0.5948 +vn 0.1626 -0.2575 -0.9525 +vn -0.0508 -0.6111 -0.7899 +vn 0.0473 -0.4005 -0.9151 +vn 0.1820 -0.2523 -0.9504 +vn 0.2017 -0.2843 -0.9373 +vn 0.0683 0.0916 -0.9934 +vn 0.7822 0.5254 -0.3349 +vn -0.3756 0.5613 -0.7375 +vn 0.0685 -0.1048 0.9921 +vn -0.0191 0.3324 -0.9429 +vn -0.4297 0.3255 -0.8422 +vn -0.0929 0.4647 -0.8806 +vn 0.7718 -0.5966 0.2198 +vn 0.5262 0.2385 -0.8162 +vn 0.1834 0.0012 -0.9830 +vn 0.1876 0.0068 -0.9822 +vn 0.1835 0.0019 -0.9830 +vn 0.3609 -0.2266 -0.9047 +vn 0.1786 -0.0738 -0.9812 +vn 0.1719 -0.0902 -0.9810 +vn 0.2039 0.0306 -0.9785 +vn 0.1892 -0.1314 -0.9731 +vn -0.9499 0.0166 -0.3120 +vn -0.1422 -0.0169 -0.9897 +vn -0.5430 0.2769 -0.7928 +vn -0.3838 -0.7367 -0.5567 +vn -0.0661 -0.9940 -0.0867 +vn -0.4785 -0.1055 -0.8717 +vn 0.7197 -0.6572 0.2237 +vn -0.5420 -0.4808 -0.6892 +vn -0.4380 -0.0816 -0.8953 +vn -0.7351 -0.1519 -0.6607 +vn -0.6555 -0.1785 0.7338 +vn -0.0876 -0.5345 -0.8406 +vn -0.0842 -0.5078 -0.8573 +vn -0.1520 -0.3432 -0.9269 +vn -0.0179 -0.3696 -0.9290 +vn -0.0380 -0.4108 -0.9109 +vn 0.1070 0.1220 -0.9867 +vn -0.3666 -0.0943 -0.9256 +vn -0.3089 0.1832 -0.9333 +vn -0.0563 0.2666 -0.9622 +vn -0.5873 0.0655 -0.8067 +vn -0.3427 0.1559 -0.9264 +vn -0.7872 0.1175 -0.6053 +vn 0.3021 -0.7726 0.5584 +vn 0.4969 0.1511 -0.8546 +vn -0.7792 -0.2537 -0.5732 +vn 0.0703 -0.1743 -0.9822 +vn 0.0698 -0.1745 -0.9822 +vn 0.0592 -0.1795 -0.9820 +vn 0.0681 -0.1490 -0.9865 +vn -0.2271 0.3128 -0.9223 +vn -0.4549 -0.2929 -0.8410 +vn -0.1115 0.3714 -0.9217 +vn -0.7252 -0.0836 -0.6835 +vn 0.3092 -0.7950 0.5218 +vn -0.5990 -0.2337 -0.7659 +vn 0.1859 -0.2271 -0.9560 +vn -0.2061 -0.4136 -0.8868 +vn -0.2064 -0.4137 -0.8867 +vn -0.2071 -0.4143 -0.8863 +vn -0.2073 -0.4145 -0.8861 +vn 0.0716 -0.1737 -0.9822 +vn 0.0441 0.1331 -0.9901 +vn -0.4388 -0.7199 -0.5377 +vn -0.7969 0.2460 -0.5517 +vn -0.2767 0.0207 -0.9607 +vn 0.2804 -0.9098 -0.3061 +vn -0.5241 -0.1265 -0.8422 +vn -0.6390 0.0122 -0.7691 +vn -0.5205 0.4260 -0.7400 +vn -0.1014 -0.3425 -0.9340 +vn -0.1009 0.2629 -0.9595 +vn -0.1063 0.3240 -0.9401 +vn -0.2828 -0.6903 -0.6660 +vn -0.4256 -0.0874 -0.9007 +vn -0.7363 0.3334 -0.5889 +vn -0.2709 -0.7428 -0.6123 +vn -0.5146 -0.5313 -0.6730 +vn -0.4053 -0.4237 -0.8101 +vn -0.0245 -0.1006 -0.9946 +vn -0.2851 -0.2723 -0.9190 +vn -0.2096 -0.5200 -0.8281 +vn -0.2719 -0.0272 -0.9619 +vn 0.0267 0.1131 -0.9932 +vn 0.0582 -0.4357 -0.8982 +vn 0.0063 -0.9977 0.0682 +vn -0.3901 0.1339 -0.9110 +vn -0.3929 0.1234 -0.9113 +vn -0.3898 0.1328 -0.9113 +vn -0.0169 -0.1021 -0.9946 +vn -0.1522 -0.5517 -0.8201 +vn -0.3129 -0.3626 -0.8778 +vn -0.2915 -0.1855 -0.9384 +vn 0.0925 0.0750 -0.9929 +vn 0.1024 -0.0230 -0.9945 +vn 0.0368 0.3025 -0.9524 +vn -0.6208 -0.6621 0.4198 +vn 0.6441 -0.5224 -0.5587 +vn 0.6589 -0.5584 -0.5041 +vn -0.6640 -0.5389 0.5184 +vn -0.1712 -0.5199 -0.8369 +vn -0.5014 -0.3659 -0.7841 +vn 0.1874 0.0034 -0.9823 +vn -0.2805 -0.3184 -0.9055 +vn -0.2935 -0.3471 -0.8907 +vn -0.7814 -0.3321 -0.5284 +vn 0.0982 -0.4430 -0.8911 +vn -0.1976 -0.6303 -0.7508 +vn -0.7914 0.4841 -0.3733 +vn -0.6559 0.3694 -0.6583 +vn -0.6355 0.0058 -0.7720 +vn -0.4211 0.0369 -0.9062 +vn 0.1886 0.0095 -0.9820 +vn 0.1075 0.3206 -0.9411 +vn 0.0570 -0.0195 -0.9982 +vn -0.1944 -0.2942 -0.9358 +vn -0.1872 -0.1548 -0.9701 +vn -0.1098 -0.0868 -0.9902 +vn -0.2179 0.0117 -0.9759 +vn -0.1613 0.0497 -0.9857 +vn -0.2038 0.1810 -0.9621 +vn -0.3935 0.1229 -0.9111 +vn -0.4425 -0.6300 -0.6382 +vn -0.6599 0.2734 -0.6998 +vn -0.7507 0.6458 -0.1396 +vn 0.1230 0.2804 -0.9520 +vn 0.2255 -0.1328 -0.9652 +vn -0.4741 -0.3726 -0.7977 +vn -0.0804 0.8584 0.5067 +vn 0.2646 0.2738 -0.9247 +vn 0.0422 0.2886 -0.9565 +vn -0.6464 0.1708 -0.7437 +vn 0.3508 0.1199 -0.9287 +vn -0.1767 0.5696 -0.8027 +vn -0.5391 -0.3111 -0.7826 +vn -0.5300 -0.3583 -0.7686 +vn -0.6415 -0.2625 -0.7208 +vn -0.5714 -0.4045 -0.7141 +vn -0.5117 -0.3198 -0.7974 +vn 0.0173 0.2419 -0.9701 +vn -0.0348 0.3174 -0.9477 +vn 0.0300 0.3010 -0.9532 +vn -0.2782 -0.3695 -0.8866 +vn -0.2893 -0.3099 -0.9057 +vn -0.0308 -0.5582 0.8291 +vn -0.2267 -0.8880 0.4001 +vn -0.3695 -0.1283 -0.9203 +vn -0.2750 0.7943 -0.5418 +vn -0.7981 0.5568 -0.2303 +vn -0.5692 -0.2065 -0.7959 +vn -0.4753 -0.0930 -0.8749 +vn -0.4753 -0.0929 -0.8749 +vn -0.4754 -0.0928 -0.8749 +vn -0.3134 0.2235 -0.9230 +vn -0.3350 0.3089 -0.8902 +vn -0.8161 -0.5498 -0.1781 +vn -0.3771 0.5560 -0.7408 +vn -0.1303 0.2093 -0.9691 +vn 0.2845 0.1499 0.9469 +vn -0.7351 -0.3258 -0.5946 +vn -0.0165 -0.6581 -0.7527 +vn -0.1191 -0.4735 -0.8727 +vn -0.2493 -0.2747 -0.9287 +vn -0.4956 -0.0229 -0.8683 +vn -0.6631 0.2334 -0.7112 +vn -0.5037 0.0173 -0.8637 +vn -0.5743 0.2042 -0.7928 +vn -0.3337 -0.1107 -0.9362 +vn -0.4753 -0.0931 -0.8749 +vn -0.2108 -0.4690 -0.8577 +vn -0.0816 -0.0356 -0.9960 +vn 0.0347 -0.2635 -0.9640 +vn -0.0928 -0.9013 0.4231 +vn -0.5212 -0.1504 -0.8400 +vn 0.0723 0.2123 -0.9745 +vn -0.1489 0.3218 -0.9350 +vn -0.3911 0.0117 -0.9203 +vn -0.4073 0.0875 -0.9091 +vn -0.3979 0.3526 -0.8470 +vn -0.4314 0.0679 -0.8996 +vn -0.1441 0.1507 -0.9780 +vn -0.0710 -0.9969 0.0329 +vn -0.0058 -1.0000 0.0054 +vn 0.0141 -0.9992 0.0373 +vn -0.0106 -0.9986 0.0515 +vn 0.1711 -0.0780 0.9822 +vn -0.1070 -0.9940 -0.0239 +vn 0.0058 -0.9760 0.2175 +vn 0.1310 -0.9787 -0.1578 +vn 0.4837 -0.8752 0.0077 +vn -0.5785 -0.7566 0.3047 +vn -0.1870 -0.9803 0.0638 +vn 0.4068 -0.8939 0.1882 +vn -0.6306 -0.7611 0.1520 +vn -0.0301 -0.9962 0.0813 +vn 0.0120 -0.9998 -0.0157 +vn -0.1308 -0.5756 0.8072 +vn -0.4020 -0.8846 -0.2361 +vn -0.4430 -0.7826 -0.4374 +vn 0.1655 -0.8316 0.5301 +vn 0.1680 -0.8336 0.5263 +vn 0.1672 -0.8356 0.5233 +vn -0.3893 -0.6902 -0.6100 +vn -0.9243 -0.1279 -0.3596 +vn 0.0660 -0.9961 0.0592 +vn 0.0616 -0.9962 0.0609 +vn 0.0654 -0.9961 0.0587 +vn 0.0367 -0.9983 0.0450 +vn -0.2619 -0.2305 0.9371 +vn -0.1879 -0.9118 -0.3653 +vn -0.6737 -0.7222 0.1565 +vn -0.3059 -0.4619 0.8325 +vn 0.8272 -0.5218 -0.2087 +vn 0.4464 -0.8281 0.3390 +vn 0.0071 -0.9730 -0.2309 +vn -0.0143 -0.9984 0.0553 +vn -0.4259 -0.8974 -0.1153 +vn -0.1484 -0.9768 -0.1544 +vn -0.4515 -0.7701 0.4506 +vn 0.1935 -0.9695 -0.1504 +vn 0.0828 -0.9960 -0.0338 +vn -0.6302 -0.7721 -0.0814 +vn 0.5347 -0.7093 0.4593 +vn -0.0570 -0.5836 -0.8100 +vn 0.1659 -0.8303 0.5321 +vn 0.1071 -0.9941 0.0197 +vn 0.1748 -0.9158 -0.3617 +vn 0.0266 -0.9994 -0.0222 +vn 0.0299 -0.9992 -0.0278 +vn -0.9416 -0.1168 -0.3159 +vn 0.0153 -0.8422 0.5389 +vn 0.0352 -0.9967 0.0731 +vn -0.0516 -0.9977 0.0443 +vn 0.3148 -0.1059 0.9432 +vn -0.5989 -0.7001 0.3887 +vn -0.0028 -0.9984 0.0571 +vn -0.7616 -0.5909 0.2661 +vn -0.4981 -0.8658 0.0475 +vn -0.6464 -0.7565 0.0996 +vn 0.0328 -0.9993 0.0197 +vn 0.1639 -0.0488 0.9853 +vn -0.3085 -0.1873 0.9326 +vn -0.6640 -0.6934 0.2798 +vn 0.0023 -0.7209 -0.6930 +vn 0.1277 0.7104 0.6922 +vn 0.7696 0.1467 -0.6214 +vn -0.6395 -0.7368 0.2195 +vn 0.1518 -0.9780 0.1433 +vn 0.2654 -0.7784 0.5689 +vn 0.2782 -0.8017 0.5291 +vn 0.1109 -0.8969 0.4281 +vn 0.1155 -0.8956 0.4297 +vn 0.1143 -0.8957 0.4297 +vn 0.0992 -0.8687 0.4854 +vn -0.1823 -0.9814 0.0608 +vn 0.1682 -0.8289 0.5334 +vn 0.0608 -0.9963 0.0615 +vn 0.3233 -0.9414 0.0962 +vn -0.6395 -0.7627 0.0961 +vn 0.1602 -0.9760 -0.1473 +vn 0.1002 -0.9943 0.0367 +vn 0.0740 -0.9958 0.0532 +vn -0.7312 -0.5683 0.3773 +vn 0.1096 -0.9835 0.1439 +vn 0.3047 -0.9411 0.1467 +vn -0.3438 -0.8821 0.3220 +vn -0.6602 -0.7240 0.1998 +vn -0.6689 -0.7328 0.1249 +vn -0.7673 -0.5971 -0.2337 +vn 0.2159 -0.9734 0.0767 +vn 0.2192 -0.9675 0.1258 +vn 0.0515 -0.9967 -0.0624 +vn 0.3349 -0.7661 0.5486 +vn -0.9547 -0.2618 -0.1413 +vn -0.7790 -0.5879 -0.2183 +vn 0.3989 -0.7696 0.4986 +vn 0.2409 -0.0056 0.9705 +vn -0.0055 -0.9985 -0.0551 +vn -0.6270 -0.7676 0.1332 +vn -0.8262 -0.5618 0.0429 +vn -0.3868 -0.9092 -0.1542 +vn -0.5807 -0.6663 -0.4677 +vn -0.6144 -0.6829 -0.3952 +vn -0.5420 -0.7550 0.3690 +vn -0.6328 -0.6961 -0.3391 +vn -0.5362 -0.8046 0.2552 +vn -0.5521 -0.8338 -0.0083 +vn -0.4659 -0.8605 -0.2061 +vn -0.4571 -0.8647 -0.2080 +vn -0.4647 -0.8611 -0.2064 +vn -0.4573 -0.8635 -0.2128 +vn 0.1102 -0.8973 0.4275 +vn -0.6612 -0.7428 -0.1054 +vn -0.0258 -0.9985 -0.0483 +vn 0.0280 -0.9996 -0.0095 +vn 0.0252 -0.9997 -0.0063 +vn 0.0286 -0.9995 -0.0103 +vn -0.4646 -0.8644 -0.1922 +vn -0.6083 -0.7889 -0.0876 +vn 0.3371 -0.9211 0.1946 +vn 0.4982 -0.8611 0.1018 +vn 0.0936 -0.8789 0.4678 +vn -0.0150 -0.9993 -0.0343 +vn -0.1416 -0.9601 0.2413 +vn -0.1412 -0.9601 0.2415 +vn -0.1399 -0.9596 0.2440 +vn -0.0555 -0.9968 -0.0568 +vn 0.1073 -0.9894 -0.0981 +vn 0.0735 -0.9956 -0.0578 +vn -0.5664 -0.8088 0.1582 +vn -0.6287 -0.7469 0.2166 +vn -0.3884 -0.6800 0.6219 +vn 0.8493 0.4027 0.3415 +vn -0.0581 -0.9741 0.2185 +vn -0.5649 -0.6120 0.5535 +vn -0.6410 -0.7108 0.2894 +vn 0.0254 -0.9997 -0.0064 +vn 0.0242 -0.9997 -0.0057 +vn 0.3472 -0.8918 0.2900 +vn 0.2556 -0.8466 0.4668 +vn 0.0283 -0.9993 -0.0230 +vn -0.1369 -0.5762 0.8057 +vn -0.1366 -0.5761 0.8059 +vn -0.1744 -0.2066 0.9627 +vn -0.2931 -0.9550 -0.0448 +vn -0.2894 -0.9560 -0.0474 +vn -0.2887 -0.9562 -0.0478 +vn -0.4255 -0.8912 0.1573 +vn 0.0365 -0.9962 0.0791 +vn 0.0318 -0.9991 -0.0270 +vn 0.0283 -0.9994 0.0188 +vn -0.5080 -0.6571 0.5569 +vn -0.5074 -0.6574 0.5571 +vn -0.5079 -0.6571 0.5570 +vn -0.5499 -0.3159 0.7732 +vn -0.0325 -0.7952 0.6055 +vn -0.5339 0.8451 0.0272 +vn -0.5942 -0.3768 0.7106 +vn -0.3489 -0.9149 -0.2033 +vn 0.0870 -0.7127 -0.6961 +vn 0.3455 -0.9078 0.2376 +vn 0.3398 -0.9074 0.2474 +vn 0.3458 -0.9081 0.2363 +vn 0.2709 -0.8852 -0.3781 +vn -0.0617 0.7135 0.6979 +vn 0.1190 0.4601 0.8798 +vn -0.7127 -0.6797 0.1732 +vn -0.1941 -0.1986 0.9607 +vn -0.8339 -0.4795 0.2732 +vn -0.0219 -0.9839 0.1771 +vn -0.3441 -0.8338 0.4318 +vn 0.0137 -0.9999 -0.0065 +vn 0.0120 -0.9999 -0.0067 +vn 0.0113 -0.9999 -0.0067 +vn -0.3518 -0.9354 0.0360 +vn -0.2944 -0.9545 -0.0467 +vn -0.3063 -0.9069 0.2894 +vn -0.5139 -0.6558 0.5529 +vn -0.4711 -0.4956 0.7297 +vn -0.4594 -0.7186 0.5220 +vn 0.2877 -0.9193 -0.2685 +vn -0.0369 -0.9924 0.1177 +vn -0.9735 -0.1718 -0.1510 +vn 0.7117 0.3257 -0.6225 +vn -0.3861 -0.4104 0.8261 +vn -0.1220 -0.6438 0.7554 +vn 0.0303 -0.9988 0.0381 +vn -0.3819 -0.7764 0.5014 +vn 0.3462 -0.9079 0.2363 +vn 0.5236 0.3733 0.7658 +vn 0.2401 -0.5406 0.8063 +vn 0.2555 -0.6398 0.7248 +vn -0.0393 -0.9517 0.3046 +vn -0.5530 -0.6099 0.5677 +vn 0.0268 -0.9994 -0.0207 +vn -0.0210 -0.9783 0.2060 +vn -0.6097 -0.7574 0.2336 +vn 0.3998 -0.7082 0.5819 +vn -0.8152 -0.4351 0.3822 +vn -0.7718 -0.6287 -0.0952 +vn -0.1135 -0.6669 0.7365 +vn -0.1131 -0.6659 0.7374 +vn -0.1118 -0.6634 0.7398 +vn 0.0052 -0.9980 0.0634 +vn -0.2132 -0.9641 0.1583 +vn -0.2636 -0.9247 0.2747 +vn -0.2440 -0.4906 0.8365 +vn -0.8038 -0.5729 -0.1604 +vn 0.2289 -0.9526 0.2006 +vn 0.3532 -0.8681 0.3488 +vn 0.4653 -0.8727 -0.1476 +vn 0.3358 -0.1581 0.9286 +vn -0.7965 -0.0020 0.6047 +vn -0.7484 -0.5028 0.4325 +vn -0.0796 -0.7371 0.6710 +vn -0.0722 -0.5788 0.8122 +vn 0.7017 -0.6925 -0.1676 +vn -0.0051 -0.9975 0.0710 +vn 0.0113 -0.9998 -0.0157 +vn 0.5951 -0.7743 0.2153 +vn 0.3441 -0.2089 0.9154 +vn -0.7834 -0.6214 -0.0042 +vn -0.7833 -0.6216 -0.0115 +vn -0.7828 -0.6221 -0.0105 +vn -0.6950 -0.6996 -0.1660 +vn -0.6740 -0.7131 0.1928 +vn -0.6863 -0.6805 0.2567 +vn 0.0432 -0.9990 -0.0144 +vn -0.2543 -0.8370 0.4846 +vn -0.3149 -0.9479 0.0473 +vn -0.2881 -0.9372 0.1968 +vn -0.6084 -0.7264 -0.3198 +vn -0.6010 -0.7294 -0.3268 +vn -0.6005 -0.7299 -0.3265 +vn 0.0796 -0.9950 0.0595 +vn -0.6383 -0.7646 0.0890 +vn -0.8088 -0.5663 0.1586 +vn 0.0210 -0.9989 0.0413 +vn -0.5752 -0.6170 0.5371 +vn -0.0761 -0.9113 0.4046 +vn 0.4465 -0.8569 0.2577 +vn 0.5089 -0.7129 0.4825 +vn -0.7733 -0.5783 0.2600 +vn -0.7760 -0.5496 0.3094 +vn -0.6637 -0.0226 0.7476 +vn -0.6670 -0.0195 0.7448 +vn 0.0777 -0.9254 0.3708 +vn -0.4317 -0.4568 0.7778 +vn -0.4310 -0.4590 0.7769 +vn -0.4295 -0.4653 0.7740 +vn -0.4293 -0.4669 0.7732 +vn 0.0173 -0.9998 0.0133 +vn 0.0163 -0.9998 0.0130 +vn 0.0164 -0.9998 0.0130 +vn -0.5415 -0.7887 0.2911 +vn 0.6898 -0.6885 0.2240 +vn -0.7030 -0.7055 -0.0897 +vn -0.6880 -0.7257 0.0066 +vn -0.6880 -0.7257 0.0068 +vn -0.6876 -0.7260 0.0069 +vn -0.7426 -0.6672 0.0579 +vn -0.0541 -0.9918 -0.1162 +vn -0.9111 -0.2391 0.3358 +vn -0.8345 -0.1455 0.5315 +vn -0.1631 -0.8672 0.4705 +vn -0.2174 -0.7363 0.6408 +vn 0.0155 -0.9998 0.0127 +vn -0.5174 -0.8555 -0.0216 +vn -0.3170 -0.9472 -0.0487 +vn -0.6033 -0.7639 -0.2291 +vn -0.6880 -0.7257 0.0065 +vn 0.4350 -0.9000 0.0269 +vn 0.2358 -0.9706 -0.0488 +vn -0.5863 -0.2098 -0.7825 +vn 0.0484 -0.9413 0.3340 +vn -0.6435 -0.7506 0.1499 +vn -0.1652 -0.8785 0.4483 +vn -0.7233 -0.6833 0.0997 +vn -0.0368 -0.9966 -0.0732 +vn -0.4378 -0.5697 0.6955 +vn -0.4004 -0.8878 -0.2268 +vn -0.3974 -0.8904 -0.2221 +vn -0.3997 -0.8881 -0.2270 +vn -0.6172 -0.7438 0.2567 +vn -0.6078 -0.7631 0.2194 +vn -0.6535 -0.7102 0.2620 +vn 0.1326 0.3097 -0.9415 +vn 0.4480 -0.8657 0.2235 +vn 0.5114 -0.8457 0.1526 +vn -0.4257 -0.8936 0.1421 +vn 0.0003 -0.9452 0.3265 +vn -0.2680 -0.7628 0.5885 +vn -0.7958 0.2817 0.5360 +vn -0.8253 -0.5595 -0.0767 +vn -0.3977 -0.8903 -0.2218 +vn -0.4024 -0.8941 -0.1966 +vn -0.4399 -0.8783 -0.1870 +vn -0.5763 -0.8072 0.1275 +vn -0.6450 -0.6485 0.4043 +vn -0.6914 -0.5856 0.4231 +vn -0.6794 -0.5164 0.5213 +vn -0.5743 -0.7633 -0.2960 +vn -0.4212 0.7817 0.4600 +vn -0.2808 -0.9531 -0.1130 +vn -0.6814 -0.5876 -0.4363 +vn -0.5711 -0.8186 0.0612 +vn -0.5975 -0.8015 0.0250 +vn -0.5943 -0.7919 0.1406 +vn -0.0399 -0.9979 0.0518 +vn -0.4547 -0.8629 -0.2206 +vn 0.2514 -0.9348 0.2510 +vn 0.0664 -0.8856 0.4597 +vn -0.0731 -0.7962 0.6006 +vn 0.8558 -0.0750 -0.5118 +vn -0.3108 -0.9504 -0.0130 +vn 0.4283 -0.8208 0.3780 +vn -0.6700 -0.6790 0.3002 +vn -0.5300 -0.3487 0.7730 +vn 0.0341 -0.9988 0.0342 +vn -0.4818 -0.8639 -0.1465 +vn -0.8166 -0.1905 0.5449 +vn 0.3042 -0.9123 0.2742 +vn -0.0127 -0.7232 0.6905 +vn -0.0349 -0.9977 0.0585 +vn -0.0806 -0.9956 -0.0472 +vn -0.3142 -0.9395 -0.1367 +vn -0.3882 -0.9212 0.0267 +vn -0.4442 -0.8641 0.2367 +vn -0.4817 -0.7898 0.3797 +vn -0.5328 -0.7132 0.4555 +vn -0.3519 -0.7988 0.4879 +vn 0.2906 -0.8652 0.4086 +vn -0.4224 -0.8242 0.3773 +vn -0.4918 -0.6839 0.5389 +vn -0.4871 -0.6805 0.5474 +vn -0.4926 -0.6844 0.5375 +vn -0.0427 -0.9990 -0.0102 +vn 0.8689 -0.4931 -0.0426 +vn -0.1548 -0.9465 -0.2830 +vn -0.3083 -0.9443 -0.1152 +vn -0.4304 -0.8629 0.2647 +vn -0.5239 -0.7039 0.4797 +vn -0.6204 -0.5216 0.5857 +vn -0.5604 -0.6003 0.5706 +vn -0.5910 -0.4144 0.6921 +vn -0.9515 0.1762 0.2522 +vn -0.9169 0.3821 0.1148 +vn 0.5120 -0.8204 0.2546 +vn 0.1910 -0.0693 0.9791 +vn -0.2134 -0.9456 0.2457 +vn 0.4313 -0.8302 0.3531 +vn -0.2000 -0.9784 0.0529 +vn -0.0697 -0.9972 0.0278 +vn -0.2254 -0.9712 0.0774 +vn 0.6011 -0.5557 0.5743 +vn -0.5010 -0.7763 0.3824 +vn -0.0814 -0.9966 -0.0120 +vn -0.6423 0.7017 0.3084 +vn -0.2474 -0.9385 -0.2409 +vn -0.3237 -0.9345 0.1481 +vn -0.3262 -0.9340 0.1458 +vn -0.3233 -0.9345 0.1486 +vn -0.4709 -0.7890 0.3947 +vn -0.5060 -0.7622 0.4037 +vn 0.5981 -0.6019 0.5291 +vn 0.0036 -0.9996 0.0279 +vn -0.4432 -0.8358 -0.3240 +vn -0.2996 -0.9335 -0.1971 +vn -0.4034 -0.8445 -0.3524 +vn -0.2907 -0.9437 -0.1581 +vn -0.3967 -0.4643 0.7918 +vn -0.2579 0.4673 -0.8456 +vn -0.2100 0.6440 -0.7356 +vn 0.2595 -0.9628 0.0746 +vn 0.2547 -0.9640 0.0766 +vn 0.2552 -0.9638 0.0766 +vn 0.2454 -0.9499 0.1934 +vn -0.0523 -0.9881 -0.1446 +vn -0.0628 -0.9881 -0.1403 +vn -0.0634 -0.9881 -0.1403 +vn 0.0320 -0.9978 -0.0575 +vn -0.0682 -0.9973 -0.0278 +vn -0.0110 -0.9999 -0.0079 +vn -0.1847 -0.9686 0.1665 +vn -0.4989 -0.7509 0.4327 +vn -0.7756 -0.5886 -0.2279 +vn -0.5939 -0.7563 -0.2743 +vn -0.3273 -0.9335 0.1466 +vn -0.4021 -0.6420 0.6528 +vn -0.3531 -0.5818 0.7327 +vn -0.4073 -0.2407 0.8810 +vn -0.0331 -0.9985 0.0435 +vn -0.3464 -0.9265 0.1470 +vn -0.2750 -0.9571 0.0909 +vn -0.2911 -0.9215 0.2571 +vn -0.3049 -0.9080 0.2873 +vn -0.3929 -0.7291 0.5604 +vn -0.3937 -0.7287 0.5604 +vn -0.3938 -0.7283 0.5609 +vn -0.1201 -0.9621 0.2446 +vn -0.5861 -0.7437 0.3215 +vn -0.0044 -0.9042 -0.4270 +vn -0.4054 -0.8882 0.2162 +vn -0.2470 -0.9506 0.1878 +vn -0.4865 -0.6800 0.5486 +vn -0.6962 -0.6725 0.2511 +vn -0.0514 0.9443 -0.3250 +vn -0.2651 -0.9605 -0.0848 +vn -0.2759 -0.8870 0.3703 +vn -0.3474 -0.8366 0.4236 +vn -0.3473 -0.8365 0.4238 +vn -0.3472 -0.8365 0.4239 +vn -0.3920 -0.7299 0.5600 +vn -0.4310 -0.8977 -0.0912 +vn -0.4023 -0.9142 0.0481 +vn 0.5920 -0.7913 0.1533 +vn -0.3471 -0.8364 0.4242 +vn -0.4069 -0.7896 0.4592 +vn 0.0883 -0.6659 0.7408 +vn -0.0520 -0.9881 -0.1450 +vn -0.3200 -0.9459 -0.0542 +vn -0.6601 -0.7296 -0.1788 +vn 0.3365 -0.9412 -0.0308 +vn 0.3511 -0.9202 -0.1728 +vn 0.2594 -0.9642 -0.0552 +vn -0.7432 0.1678 0.6477 +vn 0.0044 -1.0000 -0.0063 +vn -0.0029 -0.9999 0.0114 +vn -0.0015 -0.9999 0.0114 +vn -0.0068 -0.9999 0.0116 +vn -0.0616 -0.9969 0.0495 +vn -0.0616 -0.9969 0.0494 +vn -0.0615 -0.9969 0.0496 +vn 0.2595 -0.9629 0.0737 +vn 0.2234 -0.6444 0.7314 +vn -0.5272 -0.0714 -0.8467 +vn -0.2149 -0.9348 0.2829 +vn -0.2607 -0.8897 0.3749 +vn 0.3369 -0.0776 0.9383 +vn 0.2220 0.3342 0.9160 +vn -0.2474 -0.8854 0.3936 +vn -0.2871 -0.8530 0.4358 +vn -0.2672 -0.6793 0.6835 +vn -0.3142 -0.5937 0.7408 +vn 0.4921 -0.6560 0.5723 +vn 0.0322 -0.9993 -0.0186 +vn 0.2928 0.9555 -0.0353 +vn -0.2931 -0.7270 0.6209 +vn 0.0159 -0.9970 0.0760 +vn -0.5082 -0.7232 0.4676 +vn 0.1925 -0.6305 -0.7520 +vn -0.0596 -0.9810 -0.1846 +vn -0.0314 -0.9992 -0.0262 +vn -0.3846 -0.7254 0.5709 +vn -0.6252 -0.7800 -0.0277 +vn -0.9443 -0.1498 -0.2929 +vn 0.1137 -0.3087 0.9443 +vn -0.3504 0.5279 0.7736 +vn -0.0184 -0.9931 0.1162 +vn -0.6890 -0.6611 -0.2969 +vn -0.6864 -0.6835 -0.2484 +vn -0.1755 -0.9702 -0.1670 +vn -0.1922 -0.9809 -0.0296 +vn -0.6134 -0.7889 0.0386 +vn -0.2161 -0.8331 0.5093 +vn -0.2965 -0.5707 0.7658 +vn -0.0996 -0.9940 -0.0446 +vn -0.7040 -0.6862 -0.1833 +vn -0.1386 -0.9895 -0.0415 +vn -0.0501 -0.9922 -0.1143 +vn -0.0124 -0.9999 -0.0079 +vn -0.0115 -0.9999 -0.0076 +vn -0.0093 -0.9999 -0.0075 +vn -0.0055 -1.0000 -0.0035 +vn 0.0077 -1.0000 0.0057 +vn -0.0084 -0.9999 0.0118 +vn -0.4325 -0.9016 0.0126 +vn 0.0249 -0.9749 -0.2212 +vn -0.1400 -0.9595 0.2444 +vn 0.0173 -0.9998 -0.0032 +vn 0.0161 -0.9996 -0.0214 +vn 0.0193 -0.9996 -0.0206 +vn 0.0197 -0.9996 -0.0201 +vn -0.0102 -0.9886 -0.1505 +vn -0.0617 -0.9969 0.0493 +vn -0.0165 -0.9996 0.0214 +vn -0.1413 -0.9898 -0.0170 +vn -0.2079 -0.8682 0.4506 +vn -0.2454 -0.8237 0.5111 +vn -0.1233 -0.6553 0.7453 +vn -0.0089 -1.0000 -0.0006 +vn -0.2122 -0.6717 0.7097 +vn -0.1101 -0.5536 0.8255 +vn 0.0065 -0.9998 -0.0189 +vn 0.1079 -0.9342 -0.3401 +vn -0.0210 -0.9993 -0.0296 +vn 0.0956 -0.9943 0.0465 +vn 0.0558 -0.9984 0.0072 +vn -0.0999 -0.9934 0.0567 +vn 0.5393 -0.6731 0.5061 +vn -0.1921 -0.6769 0.7105 +vn -0.3898 -0.9207 -0.0184 +vn -0.1199 -0.9846 0.1273 +vn 0.0139 -0.9998 0.0131 +vn 0.4054 -0.9066 0.1174 +vn -0.2078 -0.9436 0.2576 +vn -0.0340 -0.9984 0.0451 +vn -0.0110 -0.9995 0.0280 +vn -0.0138 -0.9995 0.0295 +vn -0.0183 -0.9992 0.0344 +vn -0.5244 -0.7027 0.4809 +vn 0.2337 -0.5411 0.8078 +vn -0.1402 -0.9891 0.0445 +vn -0.6568 -0.7473 0.1009 +vn -0.2163 -0.8167 0.5349 +vn -0.1112 -0.6625 0.7408 +vn 0.0174 -0.9988 0.0461 +vn 0.0240 -0.9990 0.0367 +vn 0.0204 -0.9989 0.0416 +vn 0.1003 -0.9949 0.0118 +vn 0.0462 -0.9988 -0.0141 +vn -0.4917 -0.7306 0.4738 +vn 0.3012 -0.9495 0.0877 +vn -0.1752 -0.7355 0.6545 +vn 0.0036 -0.9898 0.1426 +vn -0.0106 -0.9989 0.0467 +vn 0.0584 -0.9674 0.2466 +vn 0.5881 -0.6905 0.4211 +vn 0.5066 -0.8304 0.2318 +vn 0.8256 -0.5642 0.0018 +vn 0.8258 -0.5640 0.0024 +vn 0.8298 -0.5580 0.0064 +vn -0.0199 -0.9992 0.0359 +vn -0.5579 -0.7100 0.4297 +vn -0.4127 0.3843 -0.8259 +vn -0.7840 -0.6207 -0.0033 +vn 0.0023 -0.5383 0.8427 +vn -0.0326 -0.5788 0.8148 +vn -0.0328 -0.5785 0.8150 +vn -0.0329 -0.5778 0.8155 +vn 0.0964 -0.8488 0.5199 +vn 0.1870 -0.9053 0.3813 +vn 0.0169 -0.9988 0.0465 +vn -0.0201 -0.9992 0.0352 +vn -0.6951 -0.1729 -0.6978 +vn -0.6083 -0.7267 -0.3191 +vn 0.0371 -0.6348 0.7718 +vn -0.0326 -0.5791 0.8146 +vn -0.0703 -0.4987 0.8639 +vn 0.2871 -0.8765 0.3865 +vn 0.5073 -0.5517 0.6621 +vn 0.5262 -0.7708 0.3591 +vn 0.7828 -0.5394 0.3103 +vn 0.0156 -0.9997 -0.0207 +vn -0.7791 -0.3347 0.5300 +vn 0.2772 0.0564 0.9592 +vn -0.3961 -0.5787 0.7129 +vn -0.4241 -0.4248 0.7998 +vn 0.0174 -0.9981 -0.0589 +vn -0.4821 -0.8501 0.2120 +vn -0.0086 -0.9992 0.0385 +vn -0.0881 -0.9454 0.3139 +vn 0.0621 -0.9981 -0.0021 +vn 0.0004 -0.9994 0.0342 +vn 0.3323 -0.9343 -0.1292 +vn -0.3622 -0.9240 -0.1226 +vn 0.0316 -0.9776 0.2082 +vn 0.0830 -0.6982 0.7111 +vn 0.0071 -0.9976 0.0695 +vn 0.0087 -0.9970 0.0768 +vn 0.0065 -0.9977 0.0672 +vn -0.1595 -0.7238 0.6713 +vn -0.0359 -0.9858 0.1641 +vn 0.0216 -0.9992 0.0324 +vn 0.0195 -0.9993 0.0334 +vn 0.0196 -0.9993 0.0333 +vn 0.0175 -0.9993 0.0343 +vn -0.0358 -0.9805 0.1931 +vn -0.0817 -0.8869 0.4547 +vn -0.2894 -0.3151 0.9039 +vn 0.1093 -0.9938 -0.0227 +vn 0.1075 -0.9941 -0.0151 +vn 0.1098 -0.9937 -0.0231 +vn 0.0220 -0.9996 -0.0201 +vn -0.3708 -0.3639 0.8544 +vn -0.0117 -0.8997 0.4363 +vn 0.1642 -0.8945 0.4158 +vn -0.0158 -0.9982 0.0580 +vn 0.0678 -0.7160 0.6948 +vn 0.2126 -0.9535 0.2135 +vn -0.0165 -0.9992 -0.0358 +vn 0.0377 -0.9976 -0.0575 +vn 0.0167 -0.9998 0.0138 +vn 0.0125 -0.9998 0.0127 +vn 0.0119 -0.9998 0.0133 +vn 0.4183 -0.8978 -0.1378 +vn -0.4366 -0.8967 -0.0731 +vn 0.0277 -0.9978 0.0606 +vn 0.2359 -0.2991 -0.9246 +vn 0.2293 -0.7472 0.6237 +vn 0.1878 -0.9515 0.2437 +vn 0.1178 -0.9930 -0.0117 +vn 0.0091 -0.9968 0.0792 +vn -0.1861 -0.6957 0.6938 +vn -0.2411 -0.4052 0.8819 +vn 0.3017 -0.9196 0.2515 +vn 0.1075 -0.9941 -0.0140 +vn 0.0655 -0.6336 0.7709 +vn -0.3301 -0.9235 -0.1955 +vn -0.4572 -0.7286 0.5101 +vn -0.5628 -0.7740 0.2902 +vn -0.9217 -0.3081 0.2356 +vn -0.8058 -0.5082 -0.3039 +vn -0.0283 -0.9984 0.0486 +vn 0.0112 -0.9997 0.0199 +vn -0.0284 -0.6731 0.7390 +vn 0.0020 -0.9997 -0.0231 +vn 0.0170 -0.9998 0.0143 +vn -0.4977 -0.7304 0.4677 +vn 0.0050 -0.9958 0.0912 +vn 0.1728 -0.6194 0.7658 +vn -0.0422 -0.9709 0.2355 +vn 0.0406 -0.9992 0.0022 +vn -0.0769 -0.9958 0.0505 +vn -0.5485 -0.6391 0.5391 +vn -0.0062 -0.9998 0.0198 +vn 0.0058 -0.9991 0.0421 +vn -0.1079 -0.5452 0.8314 +vn 0.0709 -0.9890 0.1301 +vn 0.1181 -0.2083 0.9709 +vn -0.0473 -0.9979 0.0443 +vn 0.2320 -0.9676 -0.0992 +vn 0.0143 -0.9999 -0.0063 +vn 0.0055 -0.9873 0.1586 +vn -0.1004 -0.6306 0.7696 +vn -0.1031 -0.6590 0.7450 +vn -0.5455 -0.7680 0.3355 +vn -0.0637 -0.9899 0.1263 +vn -0.2517 -0.9207 0.2984 +vn -0.2484 -0.9619 0.1144 +vn -0.1303 -0.9914 -0.0071 +vn -0.6604 -0.7341 0.1581 +vn -0.2945 -0.9237 0.2449 +vn -0.3376 -0.9339 0.1175 +vn -0.4391 -0.8812 0.1752 +vn 0.1748 -0.9816 -0.0769 +vn 0.0592 -0.9976 -0.0357 +vn 0.0260 -0.7500 -0.6609 +vn 0.7205 -0.6791 -0.1403 +vn -0.1568 -0.9829 -0.0966 +vn 0.2821 -0.9288 -0.2405 +vn 0.1168 -0.9885 -0.0957 +vn 0.1530 -0.9742 -0.1657 +vn -0.0385 -0.9973 -0.0631 +vn 0.0076 -0.9186 -0.3952 +vn 0.2957 -0.8791 -0.3739 +vn 0.3718 -0.9272 -0.0447 +vn 0.0546 -0.9734 -0.2226 +vn 0.0938 -0.9792 -0.1799 +vn 0.1460 -0.9857 0.0845 +vn -0.0841 -0.9919 -0.0947 +vn 0.0752 -0.9772 -0.1987 +vn -0.2364 -0.6411 -0.7301 +vn -0.1836 -0.6231 -0.7603 +vn 0.1535 -0.6496 -0.7446 +vn 0.4936 -0.7843 -0.3757 +vn -0.2870 -0.5142 -0.8083 +vn 0.4351 -0.7962 -0.4204 +vn -0.2252 -0.6038 -0.7647 +vn 0.4329 -0.7831 -0.4464 +vn -0.0374 -0.6955 -0.7176 +vn 0.4887 -0.8160 -0.3088 +vn 0.8253 -0.5647 0.0021 +vn 0.1496 -0.7942 -0.5890 +vn 0.4845 -0.7841 -0.3878 +vn 0.8166 -0.5571 -0.1512 +vn 0.4879 -0.8093 -0.3271 +vn 0.4835 -0.8315 -0.2736 +vn 0.7111 -0.7029 -0.0163 +usemtl None +s 1 +f 1//1 2//1 3//1 +f 4//2 5//2 6//2 +f 7//3 8//3 9//3 +f 10//4 11//4 12//4 +f 9//5 13//5 14//5 +f 15//6 16//6 17//6 +f 18//7 19//8 20//9 +f 21//10 22//10 23//10 +f 24//11 25//11 26//11 +f 27//12 28//12 29//12 +f 30//13 31//13 32//13 +f 33//14 34//14 35//14 +f 36//15 37//15 38//15 +f 19//8 39//16 20//9 +f 40//17 24//17 41//17 +f 42//18 43//18 44//18 +f 45//19 46//19 47//19 +f 48//20 49//20 50//20 +f 51//21 52//21 53//21 +f 54//22 55//23 42//24 +f 56//25 57//25 54//25 +f 58//26 59//26 60//26 +f 44//27 43//27 61//27 +f 62//28 63//29 64//30 +f 55//31 43//32 42//33 +f 65//34 66//34 67//34 +f 68//35 69//35 70//35 +f 71//36 72//37 73//38 +f 74//39 75//39 76//39 +f 77//40 78//41 79//42 +f 80//43 81//44 25//45 +f 82//46 83//46 73//46 +f 72//47 82//47 73//47 +f 84//48 85//48 86//48 +f 8//49 13//49 9//49 +f 87//50 88//50 89//50 +f 90//51 91//51 92//51 +f 93//52 94//52 6//52 +f 71//53 73//54 95//55 +f 96//56 97//56 98//56 +f 99//57 100//57 101//57 +f 49//58 57//58 56//58 +f 88//59 102//60 103//61 +f 104//62 68//62 105//62 +f 83//63 106//63 73//63 +f 106//64 83//64 18//64 +f 10//65 107//65 11//65 +f 108//66 7//66 66//66 +f 109//67 98//67 110//67 +f 111//68 73//68 112//68 +f 113//69 24//69 114//69 +f 115//70 60//70 46//70 +f 116//71 50//72 56//73 +f 46//74 60//74 47//74 +f 117//75 118//75 119//75 +f 111//76 112//77 120//78 +f 121//79 122//79 123//79 +f 124//80 59//80 125//80 +f 114//81 24//81 40//81 +f 39//82 65//82 126//82 +f 125//83 127//83 128//83 +f 129//84 130//84 131//84 +f 132//85 133//85 134//85 +f 43//86 135//86 61//86 +f 136//87 137//87 138//87 +f 131//88 139//88 140//88 +f 141//89 142//89 143//89 +f 115//90 58//90 60//90 +f 144//91 145//91 146//91 +f 147//92 148//92 149//92 +f 148//93 150//93 149//93 +f 150//94 151//94 149//94 +f 152//95 153//95 154//95 +f 97//96 155//96 156//96 +f 142//97 157//97 158//97 +f 23//98 159//98 21//98 +f 138//99 137//99 160//99 +f 59//100 124//100 60//100 +f 147//101 161//101 148//101 +f 162//102 163//102 164//102 +f 22//103 165//104 166//105 +f 61//106 135//106 167//106 +f 168//107 169//107 170//107 +f 171//108 118//108 117//108 +f 172//109 173//109 174//109 +f 175//110 176//110 177//110 +f 178//111 179//111 180//111 +f 181//112 148//112 161//112 +f 181//113 150//113 148//113 +f 182//114 162//114 151//114 +f 183//115 184//115 185//115 +f 186//116 26//117 187//118 +f 188//119 189//120 72//121 +f 50//72 49//122 56//73 +f 31//123 133//123 190//123 +f 104//124 105//124 191//124 +f 60//125 192//125 47//125 +f 193//126 106//126 194//126 +f 150//127 182//127 151//127 +f 195//128 163//128 162//128 +f 182//129 195//129 162//129 +f 196//130 197//130 198//130 +f 126//131 65//131 67//131 +f 154//132 10//132 12//132 +f 21//133 165//104 22//103 +f 199//134 112//134 193//134 +f 131//135 130//135 139//135 +f 200//136 201//136 161//136 +f 181//137 202//137 150//137 +f 150//138 203//138 182//138 +f 204//139 205//139 206//139 +f 207//140 208//140 209//140 +f 41//141 26//141 186//141 +f 68//142 70//142 105//142 +f 171//143 117//144 210//145 +f 211//146 1//146 212//146 +f 213//147 214//147 215//147 +f 216//148 217//149 63//150 +f 200//151 218//151 201//151 +f 150//152 202//152 203//152 +f 219//153 163//153 220//153 +f 221//154 222//154 117//154 +f 223//155 32//155 190//155 +f 224//156 225//157 226//158 +f 201//159 227//159 181//159 +f 227//160 202//160 181//160 +f 203//161 228//161 182//161 +f 195//162 220//162 163//162 +f 229//163 230//163 218//163 +f 231//164 232//164 233//164 +f 20//165 39//165 130//165 +f 234//166 190//166 132//166 +f 235//167 236//167 237//167 +f 182//168 228//168 195//168 +f 238//169 239//169 240//169 +f 241//170 242//170 243//170 +f 244//171 235//171 237//171 +f 39//172 126//172 130//172 +f 245//173 246//174 247//175 +f 218//176 227//177 201//178 +f 248//179 249//179 250//179 +f 251//180 241//180 243//180 +f 240//181 252//182 253//183 +f 241//184 254//184 242//184 +f 255//185 256//185 257//185 +f 82//186 258//186 19//186 +f 18//187 20//187 259//187 +f 260//188 261//188 262//188 +f 263//189 218//189 230//189 +f 263//190 227//177 218//176 +f 264//191 265//191 266//191 +f 228//192 267//192 195//192 +f 268//193 269//193 270//193 +f 254//194 271//194 272//194 +f 273//195 274//195 275//195 +f 276//196 277//196 278//196 +f 279//197 280//197 281//197 +f 4//198 136//198 5//198 +f 282//199 283//199 284//199 +f 285//200 261//200 260//200 +f 261//201 286//201 287//201 +f 286//202 288//202 287//202 +f 289//203 290//203 291//203 +f 292//204 293//204 294//204 +f 295//205 296//205 297//205 +f 298//206 227//206 299//206 +f 300//207 275//207 301//207 +f 302//208 303//209 304//210 +f 1//211 305//211 306//211 +f 307//212 95//212 111//212 +f 129//213 131//213 308//213 +f 309//214 286//214 261//214 +f 310//215 311//215 312//215 +f 313//216 314//216 315//216 +f 316//217 317//217 318//217 +f 319//218 320//218 321//218 +f 322//219 104//220 191//221 +f 323//222 324//223 325//224 +f 326//225 327//225 253//225 +f 145//226 322//219 191//221 +f 327//227 326//228 328//229 +f 113//230 25//230 24//230 +f 66//231 7//231 9//231 +f 188//232 72//233 329//234 +f 187//235 330//235 186//235 +f 120//236 199//236 331//236 +f 285//237 309//237 261//237 +f 332//238 333//239 334//240 +f 335//241 266//241 265//241 +f 336//242 337//242 313//242 +f 337//243 314//243 313//243 +f 336//244 313//244 338//244 +f 339//245 340//245 341//245 +f 254//246 272//246 342//246 +f 343//247 344//247 345//247 +f 242//248 342//248 243//248 +f 106//249 18//249 194//249 +f 346//250 347//250 348//250 +f 260//251 346//251 285//251 +f 349//252 350//252 351//252 +f 352//253 292//254 353//255 +f 354//256 355//256 266//256 +f 267//257 356//257 357//257 +f 358//258 359//258 273//258 +f 360//259 358//260 273//261 +f 189//262 108//262 258//262 +f 82//263 72//121 189//120 +f 7//264 361//265 8//266 +f 73//54 111//267 95//55 +f 362//268 363//268 364//268 +f 365//269 366//269 367//269 +f 368//270 366//270 347//270 +f 347//271 366//271 348//271 +f 369//272 346//272 348//272 +f 369//273 285//273 346//273 +f 369//274 309//275 285//276 +f 353//277 294//277 100//277 +f 292//278 294//278 353//278 +f 370//279 273//279 371//279 +f 372//280 373//280 374//280 +f 375//281 376//281 377//281 +f 335//282 354//282 266//282 +f 378//283 379//283 380//283 +f 381//284 382//285 383//286 +f 361//265 13//287 8//266 +f 372//288 384//288 385//288 +f 295//289 297//289 355//289 +f 386//290 387//290 388//290 +f 198//291 389//292 390//293 +f 391//294 392//294 393//294 +f 190//295 133//295 132//295 +f 394//296 395//296 396//296 +f 365//297 397//297 366//297 +f 366//298 398//298 348//298 +f 399//299 309//275 369//274 +f 400//300 401//300 402//300 +f 403//301 404//301 405//301 +f 406//302 372//302 385//302 +f 344//303 407//303 345//303 +f 408//304 409//304 410//304 +f 411//305 369//305 348//305 +f 398//306 411//306 348//306 +f 412//307 309//307 399//307 +f 412//308 413//308 309//308 +f 414//309 415//309 416//309 +f 335//310 265//310 337//310 +f 417//311 418//311 255//311 +f 69//312 419//312 420//312 +f 70//313 69//313 421//313 +f 9//314 14//314 422//314 +f 423//315 424//315 425//315 +f 426//316 427//316 428//316 +f 429//317 430//317 365//317 +f 430//318 397//318 365//318 +f 397//319 431//319 366//319 +f 366//320 431//320 398//320 +f 431//321 432//321 398//321 +f 411//322 399//322 369//322 +f 100//323 294//323 101//323 +f 433//324 376//325 375//326 +f 371//327 273//327 275//327 +f 434//328 413//328 412//328 +f 352//253 435//329 292//254 +f 66//330 9//330 67//330 +f 436//331 437//331 438//331 +f 439//332 397//332 430//332 +f 439//333 431//333 397//333 +f 398//334 432//334 411//334 +f 411//335 440//335 399//335 +f 413//336 434//336 441//336 +f 264//337 442//337 265//337 +f 352//338 290//338 443//338 +f 444//339 445//339 446//339 +f 447//340 448//340 449//340 +f 433//341 450//341 376//341 +f 451//342 452//342 453//342 +f 439//343 454//343 431//343 +f 455//344 337//344 336//344 +f 456//345 457//345 458//345 +f 124//346 125//346 459//346 +f 361//347 460//347 13//347 +f 461//348 462//348 463//348 +f 464//349 465//349 429//349 +f 432//350 466//351 411//352 +f 467//353 412//353 399//353 +f 467//354 434//354 412//354 +f 468//355 379//355 378//355 +f 450//356 469//356 470//356 +f 471//357 472//358 473//359 +f 474//360 349//360 351//360 +f 475//361 442//361 385//361 +f 101//362 376//362 476//362 +f 477//363 478//363 28//363 +f 479//364 175//364 480//364 +f 429//365 481//365 430//365 +f 430//366 481//366 439//366 +f 466//351 440//367 411//352 +f 482//368 434//368 467//368 +f 373//369 296//369 374//369 +f 483//370 484//370 485//370 +f 486//371 487//371 488//371 +f 442//372 406//372 385//372 +f 489//373 16//373 490//373 +f 491//374 492//374 13//374 +f 225//375 224//375 493//375 +f 494//376 495//376 245//376 +f 464//377 496//377 465//377 +f 465//378 497//378 429//378 +f 429//379 497//379 481//379 +f 481//380 498//380 439//380 +f 439//381 498//381 454//381 +f 454//382 466//383 431//384 +f 466//385 432//385 431//385 +f 440//386 499//387 399//388 +f 399//389 499//389 467//389 +f 434//390 500//390 441//390 +f 372//391 297//391 373//391 +f 501//392 447//392 502//392 +f 503//393 504//394 505//395 +f 489//396 506//396 16//396 +f 269//397 507//398 508//399 +f 17//400 16//400 509//400 +f 510//401 451//401 462//401 +f 511//402 497//402 465//402 +f 512//403 466//383 454//382 +f 466//404 512//404 440//404 +f 513//405 475//405 385//405 +f 514//406 505//406 515//406 +f 515//407 349//407 474//407 +f 516//408 517//408 447//408 +f 518//409 503//409 519//409 +f 517//410 520//410 521//410 +f 517//411 522//411 520//411 +f 523//412 524//412 525//412 +f 526//413 350//413 349//413 +f 527//414 528//414 529//414 +f 393//415 530//415 531//415 +f 532//416 533//416 534//416 +f 535//417 169//418 536//419 +f 497//420 537//421 481//422 +f 537//421 498//423 481//422 +f 512//424 454//424 498//424 +f 512//425 538//425 440//425 +f 440//386 538//426 499//387 +f 538//427 539//427 499//427 +f 539//428 467//428 499//428 +f 482//429 540//429 434//429 +f 540//430 541//430 500//430 +f 434//431 540//431 500//431 +f 414//432 400//432 415//432 +f 542//433 543//433 544//433 +f 545//434 546//434 547//434 +f 513//435 314//435 475//435 +f 519//436 503//393 505//395 +f 548//437 549//437 408//437 +f 465//438 550//438 511//438 +f 467//439 551//439 482//439 +f 551//440 540//441 482//442 +f 375//443 515//443 474//443 +f 378//444 380//444 552//444 +f 351//445 553//446 433//447 +f 352//448 353//448 290//448 +f 554//449 555//449 556//449 +f 550//450 537//450 511//450 +f 537//451 497//451 511//451 +f 557//452 498//452 537//452 +f 558//453 512//453 498//453 +f 559//454 538//454 512//454 +f 551//455 467//455 539//455 +f 351//456 547//456 560//456 +f 342//457 272//457 524//457 +f 290//458 353//458 561//458 +f 470//459 248//459 562//459 +f 563//460 564//460 565//460 +f 566//461 555//461 506//461 +f 567//462 488//462 35//462 +f 568//463 569//463 570//463 +f 557//464 558//464 498//464 +f 512//465 558//465 559//465 +f 551//440 571//466 540//441 +f 562//467 248//467 250//467 +f 502//468 449//468 416//468 +f 415//469 502//469 416//469 +f 572//470 501//470 400//470 +f 402//471 572//471 400//471 +f 501//472 516//472 447//472 +f 573//473 156//473 574//473 +f 73//474 106//474 112//474 +f 575//475 323//475 576//475 +f 577//476 578//476 579//476 +f 538//477 580//477 539//477 +f 580//478 581//478 539//478 +f 581//479 571//479 551//479 +f 539//480 581//480 551//480 +f 314//481 337//482 265//483 +f 582//484 414//484 583//484 +f 291//485 561//485 99//485 +f 544//486 584//486 585//486 +f 474//487 433//324 375//326 +f 586//488 587//488 588//488 +f 589//489 556//489 555//489 +f 590//490 591//490 556//490 +f 120//78 112//77 199//491 +f 592//492 550//492 593//492 +f 592//493 537//493 550//493 +f 557//494 559//494 558//494 +f 580//495 538//495 559//495 +f 594//496 540//496 571//496 +f 595//497 541//497 540//497 +f 473//498 596//498 597//498 +f 250//499 249//499 318//499 +f 589//500 598//500 556//500 +f 598//501 590//501 556//501 +f 83//502 19//502 18//502 +f 599//503 537//503 592//503 +f 600//504 557//504 537//504 +f 601//505 559//505 602//505 +f 601//506 580//506 559//506 +f 603//507 604//507 605//507 +f 455//508 606//508 337//508 +f 607//509 158//509 157//509 +f 566//510 608//510 555//510 +f 130//511 126//511 139//511 +f 599//512 600//512 537//512 +f 600//513 609//513 557//513 +f 557//514 609//515 559//516 +f 609//515 602//517 559//516 +f 580//518 601//518 581//518 +f 581//519 594//519 571//519 +f 541//520 610//520 611//520 +f 612//521 613//521 614//521 +f 615//522 450//522 470//522 +f 561//523 353//523 100//523 +f 28//524 616//524 617//524 +f 561//525 100//525 99//525 +f 142//526 618//527 157//528 +f 619//529 620//530 305//531 +f 608//532 621//532 589//532 +f 555//533 608//533 589//533 +f 621//534 598//534 589//534 +f 622//535 42//535 44//535 +f 623//536 624//536 625//536 +f 626//537 627//537 592//537 +f 627//538 599//538 592//538 +f 601//539 628//539 581//539 +f 629//540 594//540 581//540 +f 629//541 595//541 594//541 +f 594//542 595//542 540//542 +f 630//543 610//544 541//545 +f 631//546 405//546 632//546 +f 633//547 634//547 635//547 +f 636//548 637//549 618//550 +f 351//551 545//551 547//551 +f 118//552 212//552 119//552 +f 626//553 638//553 627//553 +f 628//554 629//554 581//554 +f 595//555 639//555 541//555 +f 639//556 640//556 541//556 +f 640//557 630//558 541//559 +f 641//560 321//560 642//560 +f 523//561 643//561 270//561 +f 501//562 644//562 516//562 +f 373//563 297//563 296//563 +f 604//564 619//564 305//564 +f 193//565 112//565 106//565 +f 194//566 18//566 259//566 +f 456//567 645//567 626//567 +f 645//568 638//568 626//568 +f 638//569 646//569 627//569 +f 646//570 599//570 627//570 +f 629//571 647//571 595//571 +f 595//572 647//572 639//572 +f 245//573 568//573 648//573 +f 649//574 468//574 650//574 +f 637//575 651//575 157//575 +f 618//527 637//576 157//528 +f 651//577 607//577 157//577 +f 198//578 197//578 652//578 +f 653//579 645//579 458//579 +f 654//580 599//580 646//580 +f 654//581 600//581 599//581 +f 654//582 609//582 600//582 +f 609//583 654//583 602//583 +f 628//584 655//584 629//584 +f 629//585 655//585 647//585 +f 79//586 78//586 656//586 +f 343//587 345//587 657//587 +f 658//588 450//588 615//588 +f 376//589 658//589 476//589 +f 542//590 650//590 543//590 +f 608//591 659//591 621//591 +f 660//592 661//592 653//592 +f 653//593 661//593 645//593 +f 645//594 662//594 638//594 +f 654//595 655//595 601//595 +f 602//596 654//596 601//596 +f 601//597 655//597 628//597 +f 657//598 345//598 663//598 +f 664//599 17//599 665//599 +f 666//600 667//600 668//600 +f 351//601 560//601 553//601 +f 659//602 669//602 621//602 +f 621//603 669//603 598//603 +f 670//604 653//604 598//604 +f 661//605 671//605 645//605 +f 646//606 672//606 654//606 +f 672//607 673//607 654//607 +f 673//608 655//608 654//608 +f 655//609 674//609 647//609 +f 675//610 641//610 676//610 +f 414//611 416//611 583//611 +f 376//612 450//612 658//612 +f 677//613 678//613 679//613 +f 208//614 680//614 681//614 +f 669//615 670//615 598//615 +f 645//616 682//616 662//616 +f 662//617 646//617 638//617 +f 662//618 672//618 646//618 +f 683//619 655//619 673//619 +f 683//620 674//620 655//620 +f 674//621 684//621 647//621 +f 684//622 685//622 647//622 +f 647//623 685//623 639//623 +f 639//624 686//624 640//624 +f 687//625 688//625 630//625 +f 689//626 690//626 691//626 +f 544//627 543//627 584//627 +f 692//628 693//628 651//628 +f 694//629 607//629 693//629 +f 695//630 696//630 697//630 +f 31//631 190//631 32//631 +f 698//632 669//633 659//634 +f 670//635 660//635 653//635 +f 671//636 682//636 645//636 +f 699//637 339//637 700//637 +f 692//638 701//638 693//638 +f 661//639 702//639 671//639 +f 662//640 703//640 672//640 +f 703//641 704//641 672//641 +f 672//642 704//642 673//642 +f 704//643 705//643 673//643 +f 705//644 706//644 673//644 +f 706//645 683//645 673//645 +f 707//646 674//647 683//648 +f 707//649 708//649 674//649 +f 708//650 684//650 674//650 +f 708//651 685//651 684//651 +f 685//652 686//652 639//652 +f 543//653 709//653 584//653 +f 253//654 710//654 711//654 +f 425//655 712//655 713//655 +f 211//656 212//656 118//656 +f 714//657 715//657 670//657 +f 716//658 660//658 670//658 +f 717//659 661//660 660//661 +f 717//662 702//662 661//662 +f 703//663 662//663 682//663 +f 718//664 703//664 682//664 +f 719//665 685//665 708//665 +f 687//666 640//666 686//666 +f 442//667 372//667 406//667 +f 720//668 560//668 721//668 +f 709//669 722//670 584//671 +f 723//672 701//672 692//672 +f 670//673 669//674 714//675 +f 715//676 716//676 670//676 +f 702//677 682//677 671//677 +f 724//678 704//678 703//678 +f 704//679 725//679 705//679 +f 705//680 726//680 706//680 +f 727//681 708//681 707//681 +f 686//682 685//682 687//682 +f 585//683 584//683 722//683 +f 606//684 335//684 337//684 +f 701//685 728//685 694//685 +f 693//686 701//686 694//686 +f 201//687 181//687 161//687 +f 728//688 387//688 729//688 +f 730//689 731//689 23//689 +f 716//690 717//659 660//661 +f 717//691 732//691 702//691 +f 733//692 703//692 718//692 +f 733//693 724//693 703//693 +f 724//694 725//694 704//694 +f 725//695 726//695 705//695 +f 734//696 99//696 735//696 +f 514//697 515//697 375//697 +f 733//698 725//698 724//698 +f 726//699 736//699 706//699 +f 727//700 719//700 708//700 +f 492//701 687//701 685//701 +f 317//702 696//703 318//704 +f 101//705 377//705 376//705 +f 587//706 313//706 315//706 +f 562//707 737//707 738//707 +f 28//708 617//708 29//708 +f 294//709 514//709 377//709 +f 24//710 26//710 41//710 +f 259//711 20//711 129//711 +f 20//712 130//712 129//712 +f 716//713 715//713 739//713 +f 740//714 717//714 716//714 +f 732//715 718//715 702//715 +f 718//716 682//716 702//716 +f 736//717 741//717 706//717 +f 706//718 741//718 683//718 +f 742//719 707//646 683//648 +f 743//720 744//720 477//720 +f 745//721 302//721 78//721 +f 740//722 732//722 717//722 +f 746//723 733//723 718//723 +f 746//724 725//724 733//724 +f 741//725 742//725 683//725 +f 742//726 747//726 707//726 +f 747//727 727//727 707//727 +f 748//728 749//728 644//728 +f 290//729 561//729 291//729 +f 713//730 750//730 425//730 +f 330//731 32//731 223//731 +f 739//732 740//732 716//732 +f 740//733 751//733 732//733 +f 751//734 718//734 732//734 +f 751//735 752//735 718//735 +f 718//736 752//736 746//736 +f 746//737 753//737 725//737 +f 753//738 754//738 726//738 +f 725//739 753//739 726//739 +f 726//740 754//740 736//740 +f 742//741 755//741 747//741 +f 747//742 719//742 727//742 +f 492//743 685//743 719//743 +f 756//744 326//744 757//744 +f 416//745 758//745 583//745 +f 709//746 552//746 483//746 +f 443//747 289//747 759//747 +f 760//748 729//748 761//748 +f 762//749 763//749 753//749 +f 736//750 754//750 741//750 +f 699//751 764//751 765//751 +f 483//752 552//752 484//752 +f 474//753 351//445 433//447 +f 377//754 514//754 375//754 +f 560//755 720//755 553//755 +f 2//756 1//756 211//756 +f 5//757 136//757 138//757 +f 766//758 193//758 194//758 +f 767//759 740//759 739//759 +f 768//760 767//760 739//760 +f 767//761 751//761 740//761 +f 331//762 362//763 364//764 +f 102//765 689//765 109//765 +f 741//766 755//766 742//766 +f 239//767 769//767 770//767 +f 771//768 317//768 772//768 +f 468//769 378//769 543//769 +f 666//770 562//770 738//770 +f 631//771 403//771 405//771 +f 65//772 108//772 66//772 +f 773//773 301//774 774//775 +f 570//776 775//776 776//776 +f 777//777 778//777 779//777 +f 767//778 780//778 751//778 +f 751//779 780//779 752//779 +f 781//780 747//780 755//780 +f 782//781 719//781 747//781 +f 783//782 782//782 747//782 +f 782//783 492//783 719//783 +f 784//784 785//784 786//784 +f 552//785 787//785 484//785 +f 225//786 493//786 788//786 +f 293//787 514//787 294//787 +f 475//788 265//788 442//788 +f 789//789 247//790 246//791 +f 790//792 767//792 768//792 +f 791//793 792//793 780//793 +f 793//794 794//794 795//794 +f 317//795 131//795 696//795 +f 449//796 448//796 796//796 +f 797//797 741//797 754//797 +f 741//798 797//798 755//798 +f 798//799 782//799 783//799 +f 799//800 492//800 782//800 +f 799//801 14//801 492//801 +f 515//802 504//802 526//802 +f 470//803 469//803 248//803 +f 266//804 355//804 264//804 +f 667//805 666//805 738//805 +f 505//806 504//806 515//806 +f 800//807 777//807 779//807 +f 801//808 802//808 323//808 +f 802//809 324//810 323//811 +f 522//812 517//812 803//812 +f 804//813 129//813 308//813 +f 362//814 766//814 805//814 +f 806//815 755//815 797//815 +f 755//816 806//817 781//818 +f 783//819 747//819 781//819 +f 799//820 422//820 14//820 +f 720//821 469//821 553//821 +f 355//822 372//822 442//822 +f 250//823 318//704 695//824 +f 468//825 543//825 650//825 +f 542//826 296//826 650//826 +f 553//827 469//827 450//827 +f 807//828 779//828 170//828 +f 800//829 808//829 777//829 +f 808//830 809//830 777//830 +f 42//831 622//831 54//831 +f 356//832 810//832 357//832 +f 811//833 783//833 781//833 +f 339//834 699//834 340//834 +f 812//835 632//835 813//835 +f 729//836 386//837 814//838 +f 815//839 814//839 816//839 +f 433//840 553//840 450//840 +f 807//841 170//841 817//841 +f 818//842 807//842 817//842 +f 819//843 779//843 807//843 +f 819//844 800//844 779//844 +f 820//845 821//845 822//845 +f 199//846 193//846 362//846 +f 132//847 134//847 823//847 +f 94//848 4//848 6//848 +f 13//849 824//849 491//849 +f 825//850 826//850 827//850 +f 781//851 828//851 811//851 +f 829//852 379//852 468//852 +f 722//853 483//853 485//853 +f 378//854 552//854 709//854 +f 154//855 12//856 830//857 +f 247//858 789//859 563//860 +f 317//861 308//861 131//861 +f 831//862 832//862 833//862 +f 811//863 798//863 783//863 +f 834//864 782//864 798//864 +f 835//865 226//865 473//865 +f 562//866 250//866 695//866 +f 519//867 836//867 837//867 +f 447//868 521//868 448//868 +f 472//869 835//869 473//869 +f 838//870 809//870 808//870 +f 809//871 838//871 839//871 +f 199//872 362//872 331//872 +f 193//873 766//873 362//873 +f 840//874 841//874 842//874 +f 54//875 622//875 56//875 +f 843//876 844//877 845//878 +f 846//879 811//880 828//881 +f 847//882 848//882 644//882 +f 641//883 319//883 321//883 +f 807//884 849//884 819//884 +f 819//885 849//885 800//885 +f 838//886 808//886 800//886 +f 850//887 851//887 852//887 +f 131//888 140//888 696//888 +f 331//762 364//764 853//889 +f 665//890 854//890 855//890 +f 856//891 325//891 208//891 +f 846//892 857//892 811//892 +f 857//893 798//893 811//893 +f 422//894 799//894 782//894 +f 834//895 422//895 782//895 +f 858//896 859//896 860//896 +f 695//824 318//704 696//703 +f 483//897 722//670 709//669 +f 380//898 861//898 862//898 +f 294//899 377//899 101//899 +f 807//900 863//900 849//900 +f 849//901 864//901 800//901 +f 864//902 838//902 800//902 +f 838//903 865//903 839//903 +f 189//904 866//904 108//904 +f 766//905 194//905 867//905 +f 868//906 494//906 596//906 +f 869//907 870//907 871//907 +f 749//908 517//908 516//908 +f 562//909 695//909 737//909 +f 585//910 722//910 872//910 +f 505//911 514//911 873//911 +f 179//912 159//912 731//912 +f 871//913 874//914 875//915 +f 804//916 308//916 771//916 +f 876//917 857//917 846//917 +f 877//918 834//918 798//918 +f 877//919 422//919 834//919 +f 878//920 879//920 880//920 +f 291//921 99//921 734//921 +f 862//922 881//922 552//922 +f 37//923 882//923 38//923 +f 864//924 865//924 838//924 +f 194//925 259//925 867//925 +f 259//926 129//927 804//928 +f 883//929 884//929 871//929 +f 870//930 883//930 871//930 +f 884//931 874//931 871//931 +f 362//932 805//932 363//932 +f 370//933 360//933 273//933 +f 351//934 350//934 545//934 +f 435//935 352//935 881//935 +f 862//936 552//936 380//936 +f 865//937 885//937 886//937 +f 887//938 888//939 883//940 +f 889//941 875//915 874//914 +f 889//942 890//942 875//942 +f 891//943 867//943 804//943 +f 892//944 893//945 894//946 +f 895//947 857//947 820//947 +f 895//948 798//948 857//948 +f 896//949 422//949 877//949 +f 896//950 67//950 422//950 +f 355//951 297//951 372//951 +f 400//952 502//952 415//952 +f 649//953 650//953 296//953 +f 338//954 313//954 587//954 +f 897//955 865//955 864//955 +f 849//956 897//956 864//956 +f 898//957 886//957 885//957 +f 885//958 899//958 898//958 +f 900//959 888//939 887//938 +f 888//960 901//960 883//960 +f 901//961 902//961 883//961 +f 902//962 884//962 883//962 +f 902//963 874//963 884//963 +f 903//964 889//964 874//964 +f 889//965 904//965 890//965 +f 1//966 905//966 906//966 +f 766//967 907//967 805//967 +f 908//968 877//968 798//968 +f 909//969 67//969 896//969 +f 910//970 523//970 270//970 +f 370//971 371//971 911//971 +f 517//972 521//972 447//972 +f 865//973 899//973 885//973 +f 912//974 901//974 888//974 +f 902//975 913//975 874//975 +f 821//976 820//976 857//976 +f 908//977 896//977 877//977 +f 378//978 709//978 543//978 +f 586//979 338//979 587//979 +f 400//980 501//980 502//980 +f 863//981 897//981 849//981 +f 897//982 914//982 865//982 +f 865//983 914//983 899//983 +f 616//984 343//984 311//984 +f 900//985 912//985 888//985 +f 912//986 915//987 901//988 +f 901//989 916//989 902//989 +f 916//990 913//990 902//990 +f 903//991 874//991 913//991 +f 771//992 308//992 317//992 +f 917//993 895//993 820//993 +f 917//994 918//994 895//994 +f 908//995 798//995 895//995 +f 918//996 908//996 895//996 +f 126//997 67//997 909//997 +f 545//998 919//998 546//998 +f 644//999 749//999 516//999 +f 447//1000 449//1000 502//1000 +f 914//1001 920//1001 899//1001 +f 920//1002 534//1002 899//1002 +f 900//1003 921//1003 912//1003 +f 921//1004 915//987 912//986 +f 915//1005 922//1005 901//1005 +f 901//1006 922//1006 916//1006 +f 923//1007 889//1007 903//1007 +f 923//1008 904//1008 889//1008 +f 328//1009 274//1009 327//1009 +f 484//1010 443//1010 485//1010 +f 126//1011 909//1011 139//1011 +f 355//1012 442//1012 264//1012 +f 374//1013 296//1013 542//1013 +f 787//1014 443//1014 484//1014 +f 249//1015 316//1015 318//1015 +f 648//1016 570//1016 776//1016 +f 914//1017 513//1018 920//1019 +f 867//1020 259//926 804//928 +f 867//1021 907//1021 766//1021 +f 913//1022 924//1022 903//1022 +f 924//1023 923//1023 903//1023 +f 925//1024 240//1025 327//1026 +f 926//1027 917//1027 822//1027 +f 926//1028 667//1028 917//1028 +f 667//1029 918//1029 917//1029 +f 697//1030 909//1030 896//1030 +f 604//1031 603//1031 850//1031 +f 863//1032 587//1032 897//1032 +f 840//1033 927//1033 841//1033 +f 734//1034 904//1034 923//1034 +f 738//1035 908//1036 918//1037 +f 737//1038 896//1038 908//1038 +f 737//1039 697//1039 896//1040 +f 384//1041 372//1041 374//1041 +f 314//481 265//483 475//1042 +f 787//1043 352//1043 443//1043 +f 316//1044 772//1044 317//1044 +f 587//1045 315//1045 897//1045 +f 897//1046 315//1046 914//1046 +f 854//1047 928//1047 509//1047 +f 533//1048 532//1048 929//1048 +f 542//1049 921//1049 929//1049 +f 915//1050 872//1050 922//1050 +f 922//1051 485//1051 916//1051 +f 916//1052 930//1052 913//1052 +f 930//1053 924//1053 913//1053 +f 668//1054 667//1054 926//1054 +f 738//1035 737//1055 908//1036 +f 271//1056 700//1056 272//1056 +f 881//1057 352//1057 787//1057 +f 881//1058 787//1058 552//1058 +f 315//1059 513//1059 914//1059 +f 920//1060 532//1060 534//1060 +f 921//1004 585//1061 915//987 +f 915//1062 585//1062 872//1062 +f 485//1063 930//1063 916//1063 +f 289//1064 924//1065 930//1066 +f 289//1064 923//1067 924//1065 +f 291//1068 734//1068 923//1068 +f 931//1069 822//1069 932//1069 +f 738//1070 918//1070 667//1070 +f 140//1071 909//1071 697//1071 +f 140//1072 139//1072 909//1072 +f 848//1073 748//1073 644//1073 +f 588//1074 587//1074 863//1074 +f 532//1075 542//1075 929//1075 +f 759//1076 289//1076 930//1076 +f 923//1077 289//1077 291//1077 +f 575//1078 418//1078 417//1078 +f 933//1079 822//1080 931//1081 +f 737//1039 695//1082 697//1039 +f 699//1083 765//1083 340//1083 +f 829//1084 468//1084 649//1084 +f 315//1085 314//1085 513//1085 +f 513//1018 385//1086 920//1019 +f 920//1087 384//1087 532//1087 +f 532//1088 374//1088 542//1088 +f 921//1089 544//1089 585//1089 +f 485//1090 759//1090 930//1090 +f 743//1091 28//1091 27//1091 +f 443//1092 290//1092 289//1092 +f 920//1093 385//1093 384//1093 +f 384//1094 374//1094 532//1094 +f 542//1095 544//1095 921//1095 +f 872//1096 722//1096 922//1096 +f 722//1097 485//1097 922//1097 +f 485//1098 443//1098 759//1098 +f 93//1099 934//1100 94//1101 +f 935//1102 336//1102 936//1102 +f 615//1103 470//1103 562//1103 +f 862//1104 937//1105 881//1106 +f 938//1107 814//838 386//837 +f 881//1106 937//1105 435//1108 +f 607//1109 694//1109 939//1109 +f 940//1110 941//1110 942//1110 +f 943//1111 944//1111 945//1111 +f 946//1112 947//1112 295//1112 +f 948//1113 949//1113 950//1113 +f 951//1114 526//1114 952//1114 +f 226//1115 225//1115 473//1115 +f 953//1116 748//1116 954//1116 +f 955//1117 956//1117 957//1117 +f 958//1118 954//1118 847//1118 +f 448//1119 959//1119 960//1119 +f 961//1120 274//1120 358//1120 +f 962//1121 659//1121 963//1121 +f 964//1122 954//1122 958//1122 +f 958//1123 847//1124 965//1125 +f 966//1126 244//1127 967//1128 +f 968//1129 969//1129 970//1129 +f 692//1130 637//549 636//548 +f 952//1131 526//1131 504//1131 +f 971//1132 972//1132 973//1132 +f 974//1133 975//1133 976//1133 +f 273//1134 359//1134 274//1134 +f 977//1135 978//1135 945//1135 +f 979//1136 980//1136 981//1136 +f 641//1137 982//1137 676//1137 +f 52//1138 51//1138 983//1138 +f 202//1139 984//1139 203//1139 +f 249//1140 721//1140 560//1140 +f 968//1141 985//1141 986//1141 +f 321//1142 987//1142 642//1142 +f 988//1143 989//1143 990//1143 +f 202//1144 298//1144 991//1144 +f 991//1145 984//1145 202//1145 +f 992//1146 993//1146 994//1146 +f 299//1147 995//1147 298//1147 +f 996//1148 997//1148 998//1148 +f 999//1149 845//1150 546//1151 +f 1000//1152 1001//1152 1002//1152 +f 970//1153 1003//1154 985//1155 +f 978//1156 383//1156 1004//1156 +f 413//1157 1005//1158 288//1159 +f 1006//1160 631//1160 632//1160 +f 1007//1161 965//1161 1008//1161 +f 40//1162 283//1162 1009//1162 +f 1010//1163 995//1163 299//1163 +f 298//1164 1011//1164 991//1164 +f 448//1165 521//1165 520//1165 +f 986//1166 985//1166 979//1166 +f 383//1167 382//1167 1012//1167 +f 1013//1168 1014//1168 1015//1168 +f 1013//1169 1010//1169 1014//1169 +f 991//1170 356//1170 984//1170 +f 978//1171 1004//1171 1016//1171 +f 1017//1172 995//1172 1010//1172 +f 991//1173 1011//1173 356//1173 +f 773//1174 774//1174 1018//1174 +f 1008//1175 1019//1175 1020//1175 +f 1021//1176 1010//1176 1013//1176 +f 1021//1177 1017//1177 1010//1177 +f 1017//1178 1022//1178 995//1178 +f 995//1179 1022//1179 298//1179 +f 298//1180 1022//1180 1011//1180 +f 1023//1181 958//1181 1024//1181 +f 1023//1182 964//1182 958//1182 +f 1025//1183 1026//1183 1027//1183 +f 1028//1184 1029//1184 1030//1184 +f 546//1151 845//1150 547//1185 +f 1031//1186 1032//1186 63//1186 +f 1033//1187 1015//1187 1034//1187 +f 1035//1188 1013//1188 1015//1188 +f 1011//1189 1036//1189 356//1189 +f 700//1190 339//1190 1037//1190 +f 964//1191 1038//1191 953//1191 +f 1039//1192 1040//1192 1041//1192 +f 1042//1193 1043//1193 1044//1193 +f 954//1194 748//1194 848//1194 +f 953//1195 1038//1195 1045//1195 +f 1033//1196 1035//1196 1015//1196 +f 1021//1197 1013//1197 1035//1197 +f 1022//1198 1046//1198 1011//1198 +f 1047//1199 1048//1199 1049//1199 +f 1050//1200 1051//1200 1052//1200 +f 1017//1201 1053//1201 1022//1201 +f 1036//1202 810//1202 356//1202 +f 1054//1203 1055//1204 1056//1205 +f 402//1206 965//1125 847//1124 +f 956//1207 1057//1207 957//1207 +f 826//1208 1058//1208 1059//1208 +f 847//1209 954//1209 848//1209 +f 1017//1210 1021//1210 1053//1210 +f 1046//1211 1060//1211 1011//1211 +f 1011//1212 1060//1212 1036//1212 +f 1061//1213 292//1213 435//1213 +f 979//1214 1062//1214 980//1214 +f 1008//1215 965//1215 1063//1215 +f 1064//1216 1065//1216 1066//1216 +f 1067//1217 1033//1217 1005//1217 +f 413//1218 1067//1218 1005//1218 +f 1053//1219 1046//1219 1022//1219 +f 1068//1220 1051//1221 1039//1221 +f 1035//1222 1033//1222 1067//1222 +f 1060//1223 1069//1223 1036//1223 +f 1032//1224 1070//1224 1071//1224 +f 959//1225 1072//1225 1025//1225 +f 1073//1226 1074//1226 1075//1226 +f 1076//1227 1077//1227 1078//1227 +f 1078//1228 1079//1228 1080//1228 +f 1079//1229 1081//1229 1080//1229 +f 1082//1230 1074//1230 1079//1230 +f 1083//1231 971//1231 973//1231 +f 1084//1232 1021//1232 1035//1232 +f 1084//1233 1085//1233 1021//1233 +f 1085//1234 1053//1234 1021//1234 +f 1053//1235 1086//1235 1046//1235 +f 1086//1236 1087//1236 1046//1236 +f 1046//1237 1087//1237 1060//1237 +f 1087//1238 1088//1238 1060//1238 +f 1060//1239 1088//1239 1069//1239 +f 1069//1240 1089//1240 1036//1240 +f 1089//1241 810//1241 1036//1241 +f 1073//1242 1075//1242 1090//1242 +f 959//1243 1025//1243 960//1243 +f 910//1244 243//1244 523//1244 +f 1074//1245 1073//1245 1079//1245 +f 1067//1246 1084//1246 1035//1246 +f 1091//1247 810//1247 1089//1247 +f 1071//1248 1070//1248 1092//1248 +f 350//1249 941//1249 545//1249 +f 504//1250 503//1250 952//1250 +f 1085//1251 1093//1251 1053//1251 +f 1093//1252 1086//1252 1053//1252 +f 155//1253 163//1253 219//1253 +f 1094//1254 489//1254 490//1254 +f 1095//1255 489//1255 1094//1255 +f 251//1256 243//1256 910//1256 +f 842//1257 841//1257 1096//1257 +f 951//1258 941//1258 350//1258 +f 1097//1259 1062//1259 1003//1259 +f 1062//1260 979//1260 1003//1260 +f 1098//1261 1099//1261 1100//1261 +f 1101//1262 1102//1262 1065//1262 +f 1103//1263 1104//1263 616//1263 +f 441//1264 1105//1265 1084//1266 +f 1067//1267 441//1267 1084//1267 +f 1084//1266 1105//1265 1085//1268 +f 1106//1269 1107//1269 386//1269 +f 969//1270 968//1270 1108//1270 +f 844//1271 772//1271 845//1271 +f 845//1272 772//1272 547//1272 +f 836//1273 873//1273 1061//1273 +f 1109//1274 999//1274 546//1274 +f 1110//1275 1086//1275 1093//1275 +f 1111//1276 1089//1276 1069//1276 +f 1111//1277 1112//1277 1089//1277 +f 1112//1278 1091//1278 1089//1278 +f 1091//1279 1113//1279 810//1279 +f 576//1280 325//1280 856//1280 +f 856//1281 207//1281 1114//1281 +f 1115//1282 1116//1282 1117//1282 +f 1105//1283 1118//1283 1085//1283 +f 1118//1284 1119//1285 1085//1286 +f 1085//1286 1119//1285 1093//1287 +f 1110//1288 1120//1288 1086//1288 +f 1121//1289 1087//1289 1086//1289 +f 1120//1290 1121//1290 1086//1290 +f 1122//1291 1087//1291 1121//1291 +f 1122//1292 1088//1292 1087//1292 +f 1123//1293 1069//1293 1088//1293 +f 1122//1294 1123//1294 1088//1294 +f 1069//1295 1123//1295 1111//1295 +f 1124//1296 1091//1296 1112//1296 +f 1091//1297 1124//1297 1113//1297 +f 764//1298 1125//1298 765//1298 +f 1126//1299 967//1299 634//1299 +f 1127//1300 1093//1300 1119//1300 +f 1093//1301 1127//1301 1110//1301 +f 1111//1302 1124//1302 1112//1302 +f 1128//1303 593//1303 465//1303 +f 566//1304 489//1304 1095//1304 +f 566//1305 506//1305 489//1305 +f 608//1306 566//1307 1129//1308 +f 1100//1309 1099//1309 1130//1309 +f 1115//1310 1131//1311 1116//1312 +f 23//1313 1132//1313 730//1313 +f 1127//1314 1120//1314 1110//1314 +f 1120//1315 1122//1315 1121//1315 +f 1133//1316 713//1316 712//1316 +f 357//1317 1113//1317 166//1317 +f 1042//1318 1134//1318 1135//1318 +f 524//1319 1037//1320 525//1321 +f 518//1322 1134//1323 503//1324 +f 1136//1325 1076//1325 1080//1325 +f 1098//1326 1117//1326 1099//1326 +f 1120//1327 1137//1327 1122//1327 +f 1111//1328 1138//1328 1124//1328 +f 1139//1329 1140//1329 1141//1329 +f 342//1330 524//1330 523//1330 +f 227//1331 298//1331 202//1331 +f 1101//1332 1064//1332 1131//1332 +f 1061//1333 873//1333 293//1333 +f 240//181 239//1334 252//182 +f 1142//1335 1047//1335 970//1335 +f 463//1336 1143//1337 1144//1338 +f 1049//1339 1062//1339 1097//1339 +f 1127//1340 1145//1340 1120//1340 +f 1138//1341 1146//1341 1124//1341 +f 1147//1342 1129//1343 1095//1344 +f 1057//1345 1148//1345 957//1345 +f 836//1346 519//1347 873//1348 +f 1149//1349 758//1349 1082//1349 +f 1150//1350 409//1350 1151//1350 +f 1152//1351 1041//1351 1153//1351 +f 1154//1352 1155//1352 956//1352 +f 1062//1353 1156//1354 1154//1355 +f 1157//1356 1118//1356 1105//1356 +f 500//1357 1157//1357 1105//1357 +f 1157//1358 1119//1358 1118//1358 +f 1123//1359 1122//1359 1111//1359 +f 1158//1360 1138//1360 1111//1360 +f 1147//1342 963//1361 1129//1343 +f 263//1362 1014//1362 1010//1362 +f 1159//1363 1051//1363 1068//1363 +f 1160//1364 1161//1364 446//1364 +f 1047//1365 1049//1365 1097//1365 +f 970//1366 1047//1366 1097//1366 +f 1134//1323 518//1322 1162//1367 +f 1163//1368 1127//1368 1119//1368 +f 1127//1369 1163//1369 1145//1369 +f 1158//1370 1164//1370 1138//1370 +f 1138//1371 1164//1371 1146//1371 +f 681//1372 1165//1372 209//1372 +f 1166//1373 1153//1373 1167//1373 +f 382//1374 388//1374 1012//1374 +f 697//1375 696//1375 140//1375 +f 873//1376 514//1376 293//1376 +f 386//1377 729//1377 387//1377 +f 935//1378 1081//1378 1108//1378 +f 1162//1379 518//1379 837//1379 +f 349//1380 515//1380 526//1380 +f 1064//1381 1066//1382 381//284 +f 938//1383 825//1383 1168//1383 +f 70//1384 421//1384 171//1384 +f 1163//1385 1119//1385 1157//1385 +f 1145//1386 1137//1387 1120//1388 +f 1122//1389 1158//1389 1111//1389 +f 1169//1390 172//1390 174//1390 +f 1027//1391 1026//1391 1153//1391 +f 1153//1392 1170//1392 1171//1392 +f 1167//1393 1153//1393 1171//1393 +f 1172//1394 1173//1394 1174//1394 +f 1175//1395 490//1395 16//1395 +f 519//1347 505//1396 873//1348 +f 1044//1397 952//1397 503//1397 +f 611//1398 1157//1399 500//1400 +f 1137//1401 1176//1401 1122//1401 +f 1177//1402 1102//1402 1178//1402 +f 942//1403 1179//1403 940//1403 +f 1154//1404 955//1404 980//1404 +f 253//1405 1180//1406 710//1407 +f 756//1408 774//775 301//774 +f 1181//1409 1027//1409 1153//1409 +f 955//1410 1154//1410 956//1410 +f 1062//1411 1154//1411 980//1411 +f 1044//1412 503//1412 1134//1412 +f 938//1413 1168//1413 814//1413 +f 325//1414 1126//1414 633//1414 +f 1182//1415 1107//1415 1106//1415 +f 1183//1416 1184//1416 1185//1416 +f 1163//1417 1186//1417 1145//1417 +f 1186//1418 1187//1418 1145//1418 +f 1145//1386 1187//1419 1137//1387 +f 1137//1420 530//1420 1176//1420 +f 1122//1421 1176//1421 1158//1421 +f 1165//1422 681//1422 943//1422 +f 1188//1423 1061//1423 937//1423 +f 1171//1424 1170//1424 1189//1424 +f 1179//1425 942//1425 1190//1425 +f 1182//1426 1066//1426 1107//1426 +f 1191//1427 1135//1427 1192//1427 +f 611//1398 1163//1428 1157//1399 +f 1187//1429 530//1429 1137//1429 +f 1117//1430 977//1430 1099//1430 +f 1027//1431 1181//1431 1193//1431 +f 1194//1432 1179//1432 1190//1432 +f 1042//1433 1195//1433 1043//1433 +f 951//1434 350//1434 526//1434 +f 968//1435 970//1435 985//1435 +f 1196//1436 1146//1436 1164//1436 +f 160//1437 1197//1437 144//1437 +f 227//1438 263//1438 1010//1438 +f 1186//1439 1198//1439 1187//1439 +f 422//1440 67//1440 9//1440 +f 1001//1441 1199//1441 1002//1441 +f 29//1442 617//1442 311//1442 +f 1001//1443 919//1443 1199//1443 +f 1047//1444 1200//1445 1048//1446 +f 1201//1447 605//1447 1202//1447 +f 1190//1448 952//1448 1044//1448 +f 1191//1449 1042//1449 1135//1449 +f 1203//1450 1171//1450 1204//1450 +f 1167//1451 1171//1452 1203//1453 +f 611//1454 1205//1454 1163//1454 +f 1163//1455 1205//1455 1186//1455 +f 1187//1456 531//1456 530//1456 +f 586//1457 1206//1458 338//1459 +f 1081//1460 1073//1460 1207//1460 +f 1150//1461 410//1461 409//1461 +f 1207//1462 1073//1462 1090//1462 +f 836//1463 1061//1463 1188//1463 +f 1195//1464 1190//1464 1043//1464 +f 1179//1465 1000//1465 940//1465 +f 960//1466 1027//1466 796//1466 +f 826//1467 825//1467 1107//1467 +f 1042//1468 1044//1468 1134//1468 +f 1208//1469 1209//1469 1210//1469 +f 775//1470 310//1470 776//1470 +f 1205//1471 1198//1471 1186//1471 +f 855//1472 1211//1472 1212//1472 +f 966//1473 1213//1473 244//1473 +f 606//1474 968//1474 335//1474 +f 381//1475 388//1476 382//1477 +f 141//1478 618//1478 142//1478 +f 758//1479 1074//1479 1082//1480 +f 946//1481 979//1481 981//1481 +f 1051//1482 1214//1482 1028//1482 +f 1204//1483 1189//1483 1192//1483 +f 1204//1484 1171//1484 1189//1484 +f 1215//1485 1216//1485 1217//1485 +f 1198//1486 531//1486 1187//1486 +f 1218//1487 424//1487 1219//1487 +f 936//1488 336//1488 338//1488 +f 203//1489 984//1489 228//1489 +f 1136//1490 936//1490 338//1490 +f 1039//1491 1051//1491 1040//1491 +f 1152//1492 1039//1492 1041//1492 +f 1218//1493 712//1493 425//1493 +f 935//1494 1108//1494 455//1494 +f 1064//1381 381//284 383//286 +f 1220//1495 1030//1495 1000//1495 +f 984//1496 267//1496 228//1496 +f 1221//1497 1037//1320 1222//1498 +f 861//1499 380//1499 379//1499 +f 1130//1500 944//1500 681//1500 +f 1223//1501 1195//1501 1191//1501 +f 1155//1502 1162//1502 956//1502 +f 1213//1503 1224//1503 244//1503 +f 1225//1504 1226//1504 1227//1504 +f 1063//1505 401//1505 1019//1505 +f 1205//1506 611//1506 610//1506 +f 26//117 1228//1507 187//118 +f 1229//1508 1068//1508 1072//1508 +f 1206//1458 1230//1509 338//1459 +f 1195//1510 1223//1510 1190//1510 +f 957//1511 1148//1511 861//1511 +f 964//1512 35//1512 1038//1512 +f 1001//1513 1150//1513 1151//1513 +f 1075//1514 1166//1514 1200//1514 +f 1231//1515 172//1515 1232//1515 +f 1075//1516 1200//1516 1047//1516 +f 1079//1517 1073//1517 1081//1517 +f 448//1518 960//1518 796//1518 +f 486//1519 339//1519 487//1519 +f 339//1520 341//1520 487//1520 +f 274//1521 328//1521 275//1521 +f 681//1522 944//1522 943//1522 +f 1030//1523 410//1523 1150//1523 +f 1100//1524 635//1524 812//1524 +f 796//1525 758//1525 449//1525 +f 1220//1526 1000//1526 1179//1526 +f 1233//1527 463//1527 1234//1527 +f 1131//1528 383//1529 978//1530 +f 1166//1531 1167//1531 1200//1531 +f 495//1532 1235//1532 245//1532 +f 1000//1533 1002//1533 940//1533 +f 1066//1534 1182//1534 1106//1534 +f 301//1535 275//1535 328//1535 +f 300//1536 1236//1536 371//1536 +f 1041//1537 1040//1537 1170//1537 +f 582//1538 1237//1538 414//1538 +f 988//1539 1238//1539 1239//1539 +f 1239//1540 1238//1541 817//1542 +f 1238//1541 818//1543 817//1542 +f 1019//1544 401//1544 1240//1544 +f 1241//1545 1242//1546 1243//1547 +f 945//1548 978//1548 1016//1548 +f 1188//1549 862//1549 861//1549 +f 81//1550 1228//1550 1244//1550 +f 1245//1551 1246//1551 612//1551 +f 1247//1552 861//1552 379//1552 +f 1099//1553 977//1553 945//1553 +f 1063//1554 402//1555 401//1556 +f 166//1557 1248//1557 357//1557 +f 1024//1558 1007//1558 1249//1558 +f 547//1559 772//1559 249//1559 +f 1192//1560 1189//1560 1191//1560 +f 1064//1561 383//1561 1131//1561 +f 567//1562 964//1562 1023//1562 +f 942//1563 941//1563 1190//1563 +f 1250//1564 1251//1564 1007//1564 +f 388//1565 723//1565 1012//1565 +f 1252//1566 1253//1566 1254//1566 +f 1255//1567 525//1567 1221//1567 +f 1256//1568 1257//1568 341//1568 +f 231//1569 233//1569 1258//1569 +f 749//1570 748//1570 1045//1570 +f 141//1571 1132//1571 987//1571 +f 987//1572 1132//1572 642//1572 +f 143//1573 1132//1573 141//1573 +f 1259//1574 1260//1574 232//1574 +f 1261//1575 588//1575 1238//1575 +f 892//1576 894//1577 1262//1578 +f 1263//1579 1264//1579 107//1579 +f 293//1580 292//1580 1061//1580 +f 238//1581 769//1581 239//1581 +f 986//1582 354//1582 335//1582 +f 825//1583 1265//1583 1168//1583 +f 388//1584 387//1584 723//1584 +f 1040//1585 1223//1585 1191//1585 +f 1065//1586 1064//1586 1101//1586 +f 1178//1587 1102//1587 1101//1587 +f 772//1588 316//1588 249//1588 +f 988//1589 1261//1589 1238//1589 +f 1148//1590 1188//1590 861//1590 +f 1018//1591 1068//1591 1229//1591 +f 1170//1592 1266//1592 1189//1592 +f 1170//1593 1191//1593 1266//1593 +f 272//1594 700//1595 1037//1594 +f 520//1596 1229//1596 448//1596 +f 1267//1597 141//1597 987//1597 +f 588//1598 863//1598 818//1598 +f 1116//1599 1131//1528 978//1530 +f 1051//1600 1220//1600 1052//1600 +f 862//1601 1188//1601 937//1601 +f 1040//1602 1191//1602 1170//1602 +f 1194//1603 1220//1603 1179//1603 +f 1008//1604 1250//1605 1007//1606 +f 675//1607 256//1607 319//1607 +f 272//1594 1037//1594 524//1608 +f 946//1609 981//1609 947//1609 +f 63//1610 217//1610 1031//1610 +f 1268//1611 1269//1611 1270//1611 +f 1249//1612 1023//1612 1024//1612 +f 1023//1613 1249//1613 567//1613 +f 964//1614 567//1614 35//1614 +f 933//1615 926//1615 822//1615 +f 1000//1616 1030//1616 1150//1616 +f 114//1617 1271//1617 113//1617 +f 1072//1618 1026//1618 1025//1618 +f 1072//1619 1039//1619 1152//1619 +f 1272//1620 987//1620 321//1620 +f 1267//1621 618//1621 141//1621 +f 993//1622 770//1622 769//1622 +f 251//1623 910//1623 1173//1623 +f 487//1624 341//1624 1257//1624 +f 572//1625 847//1625 501//1625 +f 1075//1626 1193//1626 1181//1626 +f 1273//1627 1274//1628 1275//1629 +f 354//1630 986//1630 946//1630 +f 423//1631 750//1631 1276//1631 +f 1126//1632 966//1632 967//1632 +f 1272//1633 1267//1633 987//1633 +f 1267//1634 636//1634 618//1634 +f 27//1635 310//1635 775//1635 +f 238//1636 183//1636 185//1636 +f 1277//1637 1278//1637 1279//1637 +f 837//1638 1188//1638 1148//1638 +f 402//1639 847//1639 572//1639 +f 242//1640 254//1640 342//1640 +f 63//1641 1032//1641 1280//1641 +f 1072//1642 1068//1220 1039//1221 +f 1074//1643 1193//1643 1075//1643 +f 1026//1644 1072//1644 1152//1644 +f 981//1645 829//1645 947//1645 +f 999//1646 1281//1646 1282//1646 +f 919//1647 1109//1647 546//1647 +f 981//1648 980//1648 829//1648 +f 1191//1649 1195//1649 1042//1649 +f 336//1650 935//1650 455//1650 +f 413//1651 441//1651 1067//1651 +f 907//1652 867//1652 891//1652 +f 1108//1653 968//1653 455//1653 +f 979//1654 946//1654 986//1654 +f 641//1655 642//1655 982//1655 +f 270//1656 643//1656 268//1656 +f 1247//1657 1283//1657 861//1657 +f 1050//1658 1052//1658 1223//1658 +f 1284//1659 233//1659 407//1659 +f 969//1660 1142//1660 970//1660 +f 1285//1661 1286//1662 1287//1663 +f 1288//1664 1183//1664 1185//1664 +f 985//1665 1003//1665 979//1665 +f 1289//1666 1068//1666 1018//1666 +f 1028//1667 1290//1667 1029//1667 +f 943//1668 945//1669 1016//1670 +f 286//1671 309//1671 413//1671 +f 1116//1672 978//1672 977//1672 +f 1247//1673 379//1673 829//1673 +f 1220//1674 1194//1674 1052//1674 +f 1107//1675 825//1675 938//1675 +f 1283//1676 957//1676 861//1676 +f 1214//1677 1290//1677 1028//1677 +f 610//1678 1198//1678 1205//1678 +f 1066//1679 1106//1679 381//1679 +f 1291//1680 288//1159 1005//1158 +f 960//1681 1025//1681 1027//1681 +f 1018//1682 1292//1682 773//1682 +f 1293//1683 1114//1683 1272//1683 +f 1294//1684 636//1684 1267//1684 +f 1294//1685 1295//1685 636//1685 +f 1296//1686 1297//1686 1298//1686 +f 185//1687 769//1687 238//1687 +f 1261//1688 1299//1688 588//1688 +f 387//1689 728//1689 723//1689 +f 1151//1690 919//1690 1001//1690 +f 1153//1691 1041//1691 1170//1691 +f 1204//1692 1192//1692 1156//1692 +f 1190//1693 951//1693 952//1693 +f 1082//1694 1078//1695 1077//1696 +f 1300//1697 1301//1698 1302//1699 +f 925//1700 183//1700 238//1700 +f 344//1701 1258//1701 1284//1701 +f 1283//1702 955//1702 957//1702 +f 1057//1703 837//1703 1148//1703 +f 1090//1704 1075//1704 1047//1704 +f 1080//1705 935//1705 936//1705 +f 642//1706 1132//1706 1303//1706 +f 1304//1707 1288//1708 1185//1709 +f 1051//1710 1050//1711 1040//1712 +f 1029//1713 410//1713 1030//1713 +f 836//1714 1188//1714 837//1714 +f 243//1715 342//1715 523//1715 +f 1293//1716 320//1716 856//1716 +f 1174//1717 270//1717 1305//1717 +f 1299//1718 1306//1718 588//1718 +f 1099//1719 945//1719 944//1719 +f 1189//1720 1266//1720 1191//1720 +f 1090//1721 1142//1721 1207//1721 +f 1136//1722 1080//1722 936//1722 +f 1135//1723 1134//1723 1162//1723 +f 1052//1724 1194//1724 1223//1724 +f 1051//1725 1028//1725 1220//1725 +f 253//1726 252//1726 1180//1726 +f 1267//1727 1272//1727 1294//1727 +f 1307//1728 692//1728 636//1728 +f 1295//1729 1307//1729 636//1729 +f 644//1730 501//1730 847//1730 +f 1308//1731 360//1731 370//1731 +f 1051//1732 1159//1732 1214//1732 +f 980//1733 1283//1733 1247//1733 +f 1166//1734 1181//1734 1153//1734 +f 1075//1735 1181//1735 1166//1735 +f 941//1736 1199//1736 545//1736 +f 1220//1737 1028//1737 1030//1737 +f 965//1738 402//1555 1063//1554 +f 1309//1739 1294//1739 1272//1739 +f 1237//1740 1240//1740 401//1740 +f 271//1741 764//1741 700//1741 +f 1310//1742 1311//1742 1312//1742 +f 692//1743 651//1743 637//1743 +f 980//1744 955//1744 1283//1744 +f 1173//1745 910//1745 1174//1745 +f 856//1746 1114//1746 1293//1746 +f 360//259 1313//1747 358//260 +f 1309//1748 1272//1748 1114//1748 +f 1313//1749 961//1749 358//1749 +f 479//1750 1314//1750 175//1750 +f 1081//1751 1207//1751 1108//1751 +f 1207//1752 969//1752 1108//1752 +f 926//1753 666//1753 668//1753 +f 455//1754 968//1754 606//1754 +f 1315//1755 1295//1755 1294//1755 +f 1004//1756 1307//1756 1295//1756 +f 1315//1757 1004//1758 1295//1759 +f 335//1760 968//1760 986//1760 +f 1206//1761 586//1761 588//1761 +f 1306//1762 1206//1762 588//1762 +f 937//1763 1061//1763 435//1763 +f 1101//1764 1131//1311 1115//1310 +f 956//1765 1162//1765 1057//1765 +f 1090//1766 1047//1766 1142//1766 +f 1207//1767 1142//1767 969//1767 +f 1192//1768 1155//1769 1156//1354 +f 1190//1770 941//1770 951//1770 +f 764//1771 699//1771 700//1771 +f 1155//1772 1135//1772 1162//1772 +f 1200//1445 1167//1773 1048//1446 +f 448//1774 1229//1775 959//1776 +f 1223//1777 1194//1777 1190//1777 +f 1006//1778 632//1778 812//1778 +f 1114//1779 1165//1779 1309//1779 +f 1309//1780 1315//1780 1294//1780 +f 959//1776 1229//1775 1072//1781 +f 1316//1782 1317//1782 613//1782 +f 701//1783 723//1783 728//1783 +f 1261//1784 988//1785 950//1786 +f 1151//1787 1109//1787 919//1787 +f 275//1788 300//1788 371//1788 +f 1204//1789 1156//1789 1062//1789 +f 812//1790 813//1790 1098//1790 +f 295//1791 649//1791 296//1791 +f 1000//1792 1150//1792 1001//1792 +f 721//1793 249//1793 248//1793 +f 321//1794 320//1794 1293//1794 +f 1318//1795 1307//1795 1004//1795 +f 1318//1796 692//1796 1307//1796 +f 1318//1797 723//1797 692//1797 +f 1319//1798 1273//1799 663//1800 +f 598//1801 458//1801 590//1801 +f 953//1802 1045//1802 748//1802 +f 815//1803 1320//1803 729//1803 +f 818//1804 863//1804 807//1804 +f 1048//1805 1204//1805 1062//1805 +f 1048//1806 1062//1806 1049//1806 +f 1117//1807 1116//1807 977//1807 +f 1156//1354 1155//1769 1154//1355 +f 954//1808 964//1808 953//1808 +f 796//1809 1027//1809 1193//1809 +f 209//1810 1165//1810 1114//1810 +f 1161//1811 1235//1811 1321//1811 +f 213//1812 1322//1812 85//1812 +f 1007//1813 1024//1813 965//1813 +f 583//1814 758//1814 1149//1814 +f 1106//1815 386//1815 388//1815 +f 381//1475 1106//1816 388//1476 +f 1323//1817 610//1817 688//1817 +f 1324//1818 1325//1818 1326//1818 +f 1044//1819 1043//1819 1190//1819 +f 758//1479 796//1479 1074//1479 +f 1066//1820 1058//1820 1107//1820 +f 1115//1821 1327//1821 1101//1821 +f 1328//1822 213//1822 85//1822 +f 829//1823 980//1823 1247//1823 +f 1024//1824 958//1824 965//1824 +f 1065//1825 1058//1825 1066//1825 +f 1162//1826 837//1826 1057//1826 +f 1080//1827 1081//1827 935//1827 +f 1246//1828 1329//1828 826//1828 +f 1048//1829 1203//1829 1204//1829 +f 555//1830 554//1830 16//1830 +f 796//1831 1193//1831 1074//1831 +f 1016//1832 1004//1758 1315//1757 +f 1318//1833 1012//1833 723//1833 +f 1330//1834 136//1834 4//1834 +f 1331//1835 675//1835 676//1835 +f 1192//1768 1135//1836 1155//1769 +f 1107//1837 938//1837 386//1837 +f 1153//1838 1026//1838 1152//1838 +f 1040//1712 1050//1711 1223//1839 +f 1107//1840 1058//1840 826//1840 +f 469//1841 720//1841 721//1841 +f 1165//1842 943//1842 1315//1842 +f 1309//1843 1165//1843 1315//1843 +f 943//1668 1016//1670 1315//1844 +f 1332//1845 1333//1845 1334//1845 +f 288//1846 286//1846 413//1846 +f 940//1847 1002//1848 941//1849 +f 1002//1848 1199//1850 941//1849 +f 1076//1851 1078//1851 1080//1851 +f 729//1852 1320//1852 761//1852 +f 1003//1154 970//1153 1097//1853 +f 566//1307 1095//1854 1129//1308 +f 1167//1451 1203//1453 1048//1855 +f 658//1856 926//1856 933//1856 +f 1335//1857 1336//1857 1337//1857 +f 383//1858 1318//1858 1004//1858 +f 383//1859 1012//1859 1318//1859 +f 545//1860 1199//1860 919//1860 +f 1338//1861 312//1861 311//1861 +f 1082//1694 1079//1862 1078//1695 +f 961//1863 183//1863 925//1863 +f 80//43 1339//1864 81//44 +f 1340//1865 934//1100 93//1099 +f 1340//1866 93//1866 133//1866 +f 1341//1867 1342//1867 1343//1867 +f 1341//1868 1343//1868 789//1868 +f 1344//1869 116//1869 1345//1869 +f 1098//1870 1100//1870 812//1870 +f 77//40 1346//1871 78//41 +f 421//1872 118//1872 171//1872 +f 1347//1873 1348//1873 1349//1873 +f 1350//1874 1330//1874 1351//1874 +f 1349//1875 1352//1875 1094//1875 +f 133//1876 93//1876 134//1876 +f 1353//1877 334//1878 1354//1879 +f 1355//1880 1356//1880 1351//1880 +f 145//1881 1357//1881 322//1881 +f 322//1882 1358//1882 68//1882 +f 85//1883 84//1883 527//1883 +f 1359//1884 85//1884 527//1884 +f 1305//1885 1172//1885 1174//1885 +f 68//1886 1358//1886 1360//1886 +f 1361//1887 116//1887 1344//1887 +f 304//1888 303//1888 1362//1888 +f 1363//1889 764//1889 271//1889 +f 160//1890 146//1890 1364//1890 +f 419//1891 1201//1891 420//1891 +f 1365//1892 974//1892 976//1892 +f 1366//1893 1367//1893 1368//1893 +f 1369//1894 1370//1894 1278//1894 +f 625//1895 1371//1895 1372//1895 +f 1316//1896 1373//1896 1374//1896 +f 210//1897 1375//1897 105//1897 +f 1364//1898 146//1898 191//1898 +f 96//1899 98//1899 691//1899 +f 851//1900 96//1900 691//1900 +f 576//1901 319//1901 256//1901 +f 303//1902 1376//1902 1377//1902 +f 1374//1903 677//1903 679//1903 +f 1211//1904 1378//1904 276//1904 +f 1339//1905 1287//1905 30//1905 +f 310//1906 1342//1906 776//1906 +f 565//1907 1379//1907 471//1907 +f 1380//1908 1242//1546 1241//1545 +f 1378//1909 831//1909 1381//1909 +f 237//1910 1006//1910 634//1910 +f 5//1911 280//1911 279//1911 +f 1065//1912 1373//1912 1059//1912 +f 842//1913 1096//1913 1382//1913 +f 1383//1914 1380//1914 1384//1914 +f 232//1915 1274//1628 1273//1627 +f 1385//1916 1386//1916 1387//1916 +f 1388//1917 1389//1917 360//1917 +f 1390//1918 1389//1918 1388//1918 +f 225//1919 788//1919 868//1919 +f 1391//1920 1392//1920 1393//1920 +f 616//1921 28//1921 478//1921 +f 813//1922 1327//1923 1098//1924 +f 1394//1925 1383//1925 1384//1925 +f 1345//1926 564//1927 563//1928 +f 1345//1929 45//1929 564//1929 +f 134//1930 1395//1930 823//1930 +f 1396//1931 1397//1931 1398//1931 +f 320//1932 576//1932 856//1932 +f 1177//1933 678//1933 677//1933 +f 1374//1934 1373//1934 677//1934 +f 1399//1935 1304//1935 1185//1935 +f 1400//1936 1339//1936 80//1936 +f 5//1937 138//1937 1401//1937 +f 247//1938 563//1938 565//1938 +f 1365//1939 976//1939 1208//1939 +f 854//1940 591//1940 1402//1940 +f 1339//1941 30//1941 1403//1941 +f 1313//1942 1389//1942 1404//1942 +f 495//1943 494//1943 868//1943 +f 312//1944 1342//1944 310//1944 +f 1404//1945 1405//1945 184//1945 +f 1406//1946 1407//1946 1408//1946 +f 1361//1947 50//1947 116//1947 +f 523//1948 525//1948 643//1948 +f 510//1949 1409//1949 1410//1949 +f 973//1950 972//1950 1242//1950 +f 880//1951 1411//1951 1412//1951 +f 690//1952 852//1952 691//1952 +f 1373//1953 1065//1953 1177//1953 +f 1412//1954 878//1954 880//1954 +f 1413//1955 1414//1955 1415//1955 +f 1242//1956 972//1956 1243//1956 +f 652//1957 833//1958 1416//1959 +f 1367//1960 582//1960 583//1960 +f 1364//1961 1375//1961 1417//1961 +f 1401//1962 138//1962 1418//1962 +f 1419//1963 1388//1963 1308//1963 +f 312//1964 1344//1965 1342//1966 +f 132//1967 823//1967 1420//1967 +f 1421//1968 1397//1969 1422//1970 +f 1423//1971 1424//1971 1425//1971 +f 1375//1972 210//1973 1426//1974 +f 138//1975 1364//1975 1418//1975 +f 1364//1976 191//1976 1375//1976 +f 1356//1977 1350//1977 1351//1977 +f 1427//1978 1428//1979 1429//1980 +f 1430//1981 1431//1981 1432//1981 +f 1433//1982 1434//1982 1317//1982 +f 623//1983 1390//1983 1388//1983 +f 904//1984 734//1984 1435//1984 +f 1436//1985 1437//1985 1077//1985 +f 1396//1986 1398//1986 1419//1986 +f 407//1987 1319//1987 345//1987 +f 1438//1988 1439//1988 1336//1988 +f 1419//1989 1308//1990 1396//1991 +f 1413//1992 1440//1992 1414//1992 +f 1361//1993 1344//1965 312//1964 +f 634//1994 1006//1994 812//1994 +f 1178//1995 1101//1995 1327//1995 +f 358//1996 274//1996 359//1996 +f 1389//1997 1313//1997 360//1997 +f 1376//1998 303//1998 302//1998 +f 971//1999 1441//1999 1442//1999 +f 1443//2000 1336//2000 603//2000 +f 1444//2001 1384//2001 1380//2001 +f 564//2002 47//2002 1379//2002 +f 365//2003 1445//2003 1446//2003 +f 1447//2004 827//2004 1329//2004 +f 78//2005 794//2005 745//2005 +f 1448//2006 1449//2006 1450//2006 +f 1397//2007 1396//2007 1451//2007 +f 1452//2008 1397//2008 1451//2008 +f 659//2009 608//2009 1129//2009 +f 1077//2010 1437//2010 1082//2010 +f 421//2011 211//2011 118//2011 +f 1216//2012 1453//2012 1454//2012 +f 1422//2013 1452//2014 1455//2015 +f 210//2016 117//2017 222//2018 +f 134//2019 279//2019 1395//2019 +f 1391//2020 1456//2020 1392//2021 +f 971//2022 1442//2022 1457//2022 +f 1442//2023 1391//2023 1458//2023 +f 565//2024 564//2024 1379//2024 +f 1273//1799 1319//1798 233//2025 +f 1459//2026 1178//2026 813//2026 +f 81//2027 1339//2027 187//2027 +f 677//2028 1373//2028 1177//2028 +f 789//859 1343//2029 563//860 +f 190//2030 234//2030 223//2030 +f 1460//2031 1461//2031 1263//2031 +f 186//2032 330//2032 223//2032 +f 620//2033 1312//2034 306//2035 +f 1422//2013 1455//2015 1462//2036 +f 1076//2037 1463//2037 1077//2037 +f 1457//2038 1442//2038 1458//2038 +f 1464//2039 1436//2039 1465//2039 +f 975//2040 1456//2040 976//2040 +f 1209//2041 976//2041 1441//2041 +f 1466//2042 277//2042 1467//2042 +f 134//2043 6//2043 279//2043 +f 1468//2044 833//2044 652//2044 +f 1457//2045 1458//2046 972//2047 +f 500//2048 541//2048 611//2048 +f 1130//2049 680//2049 635//2049 +f 197//2050 1468//2050 652//2050 +f 1343//2051 1345//1926 563//1928 +f 1339//2052 1403//2052 187//2052 +f 1469//2053 1470//2053 1471//2053 +f 793//2054 1376//2054 745//2054 +f 975//2055 1421//2056 1456//2057 +f 1472//2058 1473//2058 1392//2058 +f 927//2059 1474//2059 1475//2059 +f 1476//2060 1477//2060 1478//2060 +f 605//2061 604//2061 1479//2061 +f 1034//2062 1015//2062 1480//2062 +f 813//1922 1178//2063 1327//1923 +f 405//2064 679//2064 678//2064 +f 1481//2065 1482//2065 1483//2065 +f 1//2066 3//2066 305//2066 +f 623//2067 1388//2067 1419//2067 +f 1479//2068 604//2068 3//2068 +f 1437//2069 1149//2069 1082//2069 +f 1484//2070 1485//2070 1486//2070 +f 1487//2071 1415//2071 1488//2071 +f 1473//2072 1393//2072 1392//2072 +f 1413//2073 1415//2073 185//2073 +f 64//2074 63//2074 1280//2074 +f 1489//2075 113//2075 1271//2075 +f 1159//2076 1490//2076 1214//2076 +f 1491//2077 200//2077 1492//2077 +f 1407//2078 1493//2078 1408//2078 +f 1469//2079 1494//2079 1470//2079 +f 1397//2080 1452//2080 1422//2080 +f 1495//2081 1206//2082 1306//2083 +f 1418//2084 1364//2084 1417//2084 +f 1496//2085 1423//2085 1425//2085 +f 1497//2086 1498//2086 840//2086 +f 1437//2087 1499//2087 1149//2087 +f 1059//2088 612//2088 1246//2088 +f 1407//2089 1500//2089 1493//2089 +f 1501//2090 50//2090 1361//2090 +f 389//2091 652//1957 1416//1959 +f 972//2092 1458//2092 1276//2092 +f 1502//2093 1503//2093 277//2093 +f 1452//2094 1451//2095 1504//2096 +f 1451//2097 1308//2097 370//2097 +f 675//2098 319//2098 641//2098 +f 1375//1972 1426//1974 1417//2099 +f 842//2100 1497//2100 840//2100 +f 975//2101 974//2101 1425//2101 +f 676//2102 982//2102 1505//2102 +f 961//2103 1404//2103 184//2103 +f 1415//2104 994//2104 185//2104 +f 1452//2105 1504//2105 1455//2105 +f 1506//2106 1507//2106 1508//2106 +f 1503//2107 197//2107 196//2107 +f 196//2108 1467//2108 277//2108 +f 1208//2109 976//2109 1209//2109 +f 274//2110 961//2110 925//2110 +f 196//2111 277//2111 1503//2111 +f 280//2112 5//2112 1401//2112 +f 1383//2113 1509//2113 1380//2113 +f 1510//2114 1511//2114 1512//2114 +f 975//2115 1425//2115 1513//2115 +f 327//2116 240//2116 253//2116 +f 657//2117 1361//2117 312//2117 +f 878//2118 1412//2119 1398//2120 +f 1398//2121 623//2121 1419//2121 +f 1201//2122 1443//2122 603//2122 +f 603//2123 1514//2123 851//2123 +f 1501//2124 48//2124 50//2124 +f 1514//2125 96//2125 851//2125 +f 1293//2126 1272//2126 321//2126 +f 239//2127 770//2127 1515//2127 +f 449//2128 758//2128 416//2128 +f 1316//2129 1059//2129 1373//2129 +f 1516//2130 1509//2130 1383//2130 +f 1517//2131 1518//2131 1519//2131 +f 1369//2132 1520//2132 1521//2132 +f 1412//2119 623//2133 1398//2120 +f 1243//2134 1276//2134 750//2134 +f 1241//2135 1243//2135 750//2135 +f 1241//2136 750//2136 1133//2136 +f 565//2137 471//2137 247//2137 +f 664//2138 855//2138 1212//2138 +f 961//2139 184//2139 183//2139 +f 1144//2140 1328//2140 1359//2140 +f 1456//2141 1462//2141 1392//2141 +f 1424//2142 1398//2142 1397//2142 +f 1394//2143 1384//2143 1471//2143 +f 1388//2144 360//2144 1308//2144 +f 274//2145 925//2145 327//2145 +f 1401//2146 1418//2146 1522//2146 +f 1523//2147 858//2147 1524//2147 +f 6//2148 5//2148 279//2148 +f 1425//2149 1424//2149 1513//2149 +f 878//2150 1398//2150 1424//2150 +f 852//2151 619//2151 850//2151 +f 345//2152 1319//2152 663//2152 +f 1525//2153 1526//2154 445//2155 +f 1412//2156 624//2156 623//2156 +f 663//2157 1501//2157 1361//2157 +f 657//2158 663//2158 1361//2158 +f 41//2159 186//2160 1527//2161 +f 1381//2162 1468//2162 1502//2162 +f 2//2163 1479//2163 3//2163 +f 3//2164 604//2164 305//2164 +f 306//2165 905//2165 1//2165 +f 971//2166 1457//2045 972//2047 +f 1451//2095 370//2167 1504//2096 +f 271//2168 1511//2168 1363//2168 +f 774//2169 1289//2169 1018//2169 +f 306//2035 1312//2034 905//2170 +f 1313//2171 1404//2171 961//2171 +f 1243//2172 972//2172 1276//2172 +f 1210//2173 1209//2173 1441//2173 +f 1343//2174 1342//2174 1344//2174 +f 1115//2175 1117//2175 1098//2175 +f 1338//2176 657//2177 312//2178 +f 1210//2179 1441//2179 971//2179 +f 1528//2180 1524//2180 858//2180 +f 795//2181 794//2181 1346//2181 +f 1509//2182 1242//2182 1380//2182 +f 1441//2183 1391//2183 1442//2183 +f 568//2184 570//2184 648//2184 +f 1529//2185 1029//2185 1290//2185 +f 1421//2056 1422//2186 1456//2057 +f 1471//2187 1470//2187 1530//2187 +f 185//2188 994//2188 769//2188 +f 1513//2189 1424//2189 1397//2189 +f 1531//2190 1164//2190 1158//2190 +f 1396//1991 1308//1990 1451//2191 +f 1532//2192 1533//2192 1534//2192 +f 234//2193 132//2193 1420//2193 +f 1490//2194 1290//2194 1214//2194 +f 1490//2195 1529//2195 1290//2195 +f 1529//2196 410//2196 1029//2196 +f 1515//2197 252//2197 239//2197 +f 1471//2198 1530//2198 1394//2198 +f 1535//2199 277//2200 1466//2201 +f 1273//2202 1275//2202 663//2202 +f 1133//2203 750//2203 713//2203 +f 967//2204 237//2204 634//2204 +f 1536//2205 1537//2205 1538//2205 +f 1441//2206 976//2206 1391//2206 +f 1455//2207 1539//2208 1462//2209 +f 1275//2210 1501//2210 663//2210 +f 1202//2211 1479//2211 2//2211 +f 1275//2212 48//2212 1501//2212 +f 1531//2213 1196//2213 1164//2213 +f 1433//2214 1317//2214 679//2214 +f 1462//2209 1539//2208 1472//2215 +f 1434//2216 613//2216 1317//2216 +f 1456//2217 1422//2217 1462//2217 +f 1509//2218 973//2218 1242//2218 +f 1513//2219 1397//1969 1421//1968 +f 421//2220 1202//2220 2//2220 +f 1540//2221 1159//2221 1289//2221 +f 1540//2222 1490//2222 1159//2222 +f 1540//2223 1529//2223 1490//2223 +f 548//2224 410//2224 1529//2224 +f 1541//2225 643//2225 1255//2225 +f 1474//2226 1542//2226 1543//2226 +f 1544//2227 1176//2227 1545//2227 +f 1544//2228 1531//2228 1176//2228 +f 525//1321 1037//1320 1221//1497 +f 209//2229 1114//2229 207//2229 +f 976//2230 1456//2020 1391//2020 +f 975//2231 1513//2231 1421//2231 +f 421//2232 69//2232 1202//2232 +f 1546//2233 1547//2233 1548//2233 +f 69//2234 420//2234 1202//2234 +f 711//2235 1529//2235 1540//2235 +f 710//2236 548//2236 1529//2236 +f 1531//2237 1303//2237 1196//2237 +f 1303//2238 1132//2238 1196//2238 +f 1504//2239 911//2239 1455//2239 +f 1547//2240 80//2240 1548//2240 +f 1545//2241 530//2241 1505//2241 +f 27//2242 570//2242 569//2242 +f 1547//2243 1400//2243 80//2243 +f 774//2244 1540//2244 1289//2244 +f 711//2245 710//2245 1529//2245 +f 253//2246 711//2246 326//2246 +f 1549//2247 217//2247 1550//2247 +f 1542//2248 1549//2249 1550//2250 +f 35//2251 488//2251 1257//2251 +f 614//2252 1245//2252 612//2252 +f 518//2253 519//2253 837//2253 +f 1007//2254 1251//2254 1249//2254 +f 1177//2255 1459//2255 678//2255 +f 295//2256 355//2256 946//2256 +f 1059//2257 1058//2257 1065//2257 +f 311//2258 343//2258 1338//2258 +f 757//2259 711//2259 1540//2259 +f 613//2260 1434//2260 614//2260 +f 1504//2261 370//2261 911//2261 +f 982//2262 1544//2262 1545//2262 +f 925//1024 238//2263 240//1025 +f 1020//2264 1541//2264 1551//2264 +f 1551//2265 1541//2265 1250//2265 +f 1249//2266 486//2267 567//2267 +f 269//2268 1305//2268 270//2268 +f 757//2269 1540//2269 774//2269 +f 643//2270 525//2270 1255//2270 +f 81//2271 1244//2271 25//2271 +f 305//531 620//530 306//2272 +f 1552//2273 1553//2273 1554//2273 +f 1474//2274 1543//2274 1475//2274 +f 944//2275 1130//2275 1099//2275 +f 982//2276 1545//2276 1505//2276 +f 642//2277 1531//2277 1544//2277 +f 1531//2278 642//2278 1303//2278 +f 1531//2279 1158//2279 1176//2279 +f 1250//2280 1221//2280 1251//2280 +f 567//2267 486//2267 488//2281 +f 1555//2282 973//2282 1509//2282 +f 268//2283 643//2283 1541//2283 +f 328//2284 756//2284 301//2284 +f 1174//2285 910//2285 270//2285 +f 116//2286 1556//2286 1345//2286 +f 803//2287 517//2287 749//2287 +f 1541//2288 1255//2288 1250//2288 +f 1250//2289 1255//2289 1221//2289 +f 756//2290 328//229 326//228 +f 554//2291 854//2291 509//2291 +f 1222//2292 339//2292 486//2292 +f 1343//2293 1344//2293 1345//2293 +f 982//2294 642//2294 1544//2294 +f 1550//2295 217//2295 1557//2295 +f 1221//2296 1222//2296 1251//2296 +f 1251//2297 486//2297 1249//2297 +f 487//2298 1257//2298 488//2298 +f 756//2299 757//2299 774//2299 +f 326//2300 711//2300 757//2300 +f 710//1407 1180//1406 548//2301 +f 1180//2302 549//2302 548//2302 +f 1037//2303 339//2303 1222//2303 +f 676//2304 1505//2304 392//2304 +f 1251//2305 1222//2305 486//2305 +f 11//2306 1558//2306 12//2306 +f 1559//2307 1560//2307 1274//2307 +f 11//2308 107//2308 55//2308 +f 60//2309 124//2309 1561//2309 +f 963//2310 1147//2310 1139//2310 +f 1562//2311 495//2311 868//2311 +f 1563//2312 1460//2313 107//2314 +f 23//2315 22//2315 1196//2315 +f 192//2316 60//2316 1561//2316 +f 10//2317 1563//2317 107//2317 +f 1379//2318 192//2318 472//2318 +f 598//2319 653//2319 458//2319 +f 1560//2320 48//2320 1274//2320 +f 1045//2321 1038//2321 34//2321 +f 1560//2322 12//2322 48//2322 +f 1556//2323 45//2323 1345//2323 +f 1564//2324 1331//2324 1565//2324 +f 765//2325 1256//2325 341//2325 +f 810//2326 1113//2326 357//2326 +f 1256//2327 1566//2327 33//2327 +f 1567//2328 34//2328 33//2328 +f 1566//2329 1567//2329 33//2329 +f 1567//2330 1045//2330 34//2330 +f 1568//2331 103//2331 1569//2331 +f 1570//2332 36//2332 38//2332 +f 170//2333 169//2333 817//2333 +f 765//2334 1252//2334 1256//2334 +f 401//2335 414//2335 1237//2335 +f 1571//2336 1572//2337 1248//2338 +f 45//2339 115//2340 46//2341 +f 1252//2342 1573//2342 1256//2342 +f 1573//2343 1574//2343 1256//2343 +f 1256//2344 1574//2344 1566//2344 +f 1574//2345 1575//2345 1566//2345 +f 1566//2346 1575//2346 1567//2346 +f 1257//2347 1256//2347 33//2347 +f 418//2348 576//2348 256//2348 +f 1575//2349 1576//2349 1567//2349 +f 459//2350 125//2350 128//2350 +f 1577//2351 760//2351 761//2351 +f 1567//2352 1576//2352 803//2352 +f 1254//2353 1573//2353 1252//2353 +f 1578//2354 1574//2354 1573//2354 +f 1574//2355 1579//2355 1575//2355 +f 1575//2356 1579//2356 1576//2356 +f 1569//2357 573//2357 574//2357 +f 1580//2358 1578//2358 1573//2358 +f 1579//2359 1574//2359 1578//2359 +f 1579//2360 1581//2360 1576//2360 +f 1576//2361 522//2361 803//2361 +f 39//2362 258//2362 65//2362 +f 1311//2363 87//2363 128//2363 +f 1581//2364 522//2364 1576//2364 +f 1292//2365 1229//2365 522//2365 +f 1292//2366 522//2366 1581//2366 +f 1581//2367 1579//2367 1578//2367 +f 773//2368 1292//2368 1581//2368 +f 845//2369 999//2369 1282//2369 +f 22//2370 1146//2370 1196//2370 +f 689//2371 98//2371 109//2371 +f 1438//2372 1336//2372 1443//2372 +f 1268//2373 1582//2373 1269//2373 +f 137//2374 136//2374 1330//2374 +f 1583//2375 1578//2375 1580//2375 +f 1236//2376 1583//2376 1580//2376 +f 1583//2377 1581//2377 1578//2377 +f 1581//2378 1583//2378 773//2378 +f 133//2379 31//2379 1286//2379 +f 729//2380 760//2380 728//2380 +f 1351//2381 1330//2381 4//2381 +f 105//2382 171//143 210//145 +f 1571//2383 1248//2383 166//2383 +f 934//2384 1351//2385 94//2386 +f 1351//2385 4//2387 94//2386 +f 1092//2388 1584//2388 1071//2388 +f 300//2389 301//2389 1583//2389 +f 1583//2390 301//2390 773//2390 +f 1146//2391 22//2391 1113//2391 +f 1577//2392 38//2393 694//2394 +f 1585//2395 159//2395 179//2395 +f 731//2396 159//2396 23//2396 +f 166//2397 1113//2397 22//2397 +f 868//2398 596//2398 225//2398 +f 866//2399 1586//2399 7//2399 +f 1274//2400 1260//2400 1559//2400 +f 61//2401 125//2401 59//2401 +f 574//2402 156//2402 155//2402 +f 1410//2403 451//2403 510//2403 +f 1381//2404 831//2404 1468//2404 +f 1483//2405 276//2405 1587//2405 +f 158//2406 178//2406 180//2406 +f 1588//2407 87//2407 1311//2407 +f 1588//2408 88//2408 87//2408 +f 159//2409 1585//2409 1589//2409 +f 1589//2410 1590//2410 165//2410 +f 1568//2411 1569//2411 1572//2411 +f 1588//2412 690//2412 102//2412 +f 88//2413 1588//2413 102//2413 +f 690//2414 689//2414 102//2414 +f 1591//2415 1323//2415 688//2415 +f 1558//2416 49//2417 48//2418 +f 165//2419 1590//2419 1571//2419 +f 689//2420 691//2420 98//2420 +f 82//2421 189//2421 258//2421 +f 88//59 103//61 1568//2422 +f 1592//2423 1593//2423 1594//2423 +f 459//2424 128//2424 1595//2424 +f 107//2425 1264//2425 43//2425 +f 882//2426 37//2426 1596//2426 +f 83//2427 82//2427 19//2427 +f 1597//2428 1598//2428 1599//2428 +f 57//2429 11//2429 55//2429 +f 1559//2430 830//2430 1560//2430 +f 1600//2431 1601//2431 1602//2431 +f 1571//2432 1590//2432 1572//2432 +f 1556//2433 56//2433 45//2433 +f 56//2434 1603//2434 45//2434 +f 1603//2435 115//2340 45//2339 +f 1603//2436 44//2436 115//2436 +f 44//2437 58//2437 115//2437 +f 824//2438 1591//2438 1604//2438 +f 1605//2439 145//2440 144//2441 +f 1593//2442 1586//2442 1594//2442 +f 613//2443 612//2443 1059//2443 +f 12//2444 1558//2444 48//2444 +f 1606//2445 17//2445 664//2445 +f 457//2446 1607//2446 1608//2446 +f 1310//2447 1588//2447 1311//2447 +f 1609//2448 1610//2448 1563//2448 +f 87//2449 89//2449 1595//2449 +f 1600//2450 1586//2451 1593//2452 +f 1611//2453 392//2453 391//2453 +f 48//2454 1275//2454 1274//2454 +f 142//2455 158//2455 180//2455 +f 1602//2456 1611//2456 1591//2456 +f 1612//2457 391//2457 1198//2457 +f 1281//2458 999//2459 1109//2460 +f 103//2461 573//2461 1569//2461 +f 459//2462 1595//2462 1597//2462 +f 1609//2463 153//2463 152//2463 +f 829//2464 649//2464 947//2464 +f 391//2465 393//2465 531//2465 +f 531//2466 1198//2466 391//2466 +f 341//2467 340//2467 765//2467 +f 1357//2468 656//2468 322//2468 +f 1572//2337 1613//2469 1248//2338 +f 574//2470 155//2470 219//2470 +f 19//2471 258//2471 39//2471 +f 391//2472 1612//2472 1611//2472 +f 178//2473 1614//2473 179//2473 +f 1590//2474 1568//2474 1572//2474 +f 1244//2475 1228//2475 26//2475 +f 1615//2476 830//2476 1559//2476 +f 1569//2477 574//2477 1613//2477 +f 1616//2478 1568//2478 1590//2478 +f 89//2479 1598//2479 1595//2479 +f 1601//2480 1611//2480 1602//2480 +f 322//2481 656//2481 1358//2481 +f 1600//2482 1602//2482 361//2482 +f 1561//2483 459//2484 1617//2485 +f 1599//2486 1585//2486 179//2486 +f 1600//2487 361//2487 1586//2487 +f 180//2488 143//2488 142//2488 +f 165//2489 1571//2489 166//2489 +f 933//2490 1618//2490 658//2490 +f 1598//2491 1616//2492 1585//2493 +f 44//2494 59//2494 58//2494 +f 68//2495 1360//2495 69//2495 +f 361//2496 1602//2496 460//2496 +f 1594//2497 1586//2497 866//2497 +f 491//2498 1604//2498 688//2498 +f 491//2499 688//2499 687//2499 +f 103//2500 102//2500 109//2500 +f 180//2501 730//2501 143//2501 +f 159//2502 165//2502 21//2502 +f 329//2503 72//37 71//36 +f 167//2504 1619//2504 125//2504 +f 1620//2505 1597//2505 1599//2505 +f 1268//2506 1621//2506 235//2506 +f 180//2507 731//2507 730//2507 +f 1565//2508 392//2508 1611//2508 +f 1601//2509 1565//2509 1611//2509 +f 69//2510 1622//2510 419//2510 +f 110//2511 97//2511 156//2511 +f 615//2512 562//2512 666//2512 +f 460//2513 1602//2513 824//2513 +f 1602//2514 1591//2514 824//2514 +f 419//2515 1443//2516 1201//2517 +f 1623//2518 219//2518 220//2518 +f 1620//2519 1599//2519 1624//2519 +f 1625//2520 1626//2520 1627//2520 +f 789//2521 648//2521 1341//2521 +f 1611//2522 1612//2522 1323//2522 +f 89//2523 88//2523 1568//2523 +f 1594//2524 866//2524 1628//2524 +f 1428//2525 1601//2525 1629//2525 +f 89//2526 1568//2526 1616//2526 +f 664//2527 1212//2527 1630//2527 +f 104//2528 322//2528 68//2528 +f 1591//2529 1611//2529 1323//2529 +f 227//2530 1010//2530 299//2530 +f 409//2531 1631//2531 1151//2531 +f 1632//2532 1633//2532 1634//2532 +f 125//2533 61//2533 167//2533 +f 1613//2534 574//2534 1623//2534 +f 1623//2535 574//2535 219//2535 +f 258//2536 108//2536 65//2536 +f 1565//2537 1331//2537 392//2537 +f 564//2538 45//2538 47//2538 +f 1289//2539 1159//2539 1068//2539 +f 108//2540 866//2540 7//2540 +f 128//2541 87//2541 1595//2541 +f 1613//2542 1623//2542 1248//2542 +f 252//2543 1635//2543 1180//2543 +f 814//2544 1168//2544 816//2544 +f 180//2545 179//2545 731//2545 +f 1246//2546 826//2546 1059//2546 +f 1614//2547 1599//2547 179//2547 +f 1636//2548 1355//2548 1637//2548 +f 1515//2549 1635//2549 252//2549 +f 500//2550 1105//2550 441//2550 +f 1180//2551 1635//2552 549//2553 +f 549//2554 1638//2554 408//2554 +f 1591//2555 688//2555 1604//2555 +f 1561//2556 124//2556 459//2556 +f 1639//2557 1263//2557 1461//2557 +f 1585//2558 1616//2558 1589//2558 +f 830//857 12//856 1560//2559 +f 1598//2560 89//2560 1616//2560 +f 824//2561 1604//2561 491//2561 +f 1599//2562 1598//2491 1585//2493 +f 1310//2563 620//2563 1588//2563 +f 1635//2552 1640//2564 549//2553 +f 549//2565 1640//2565 1638//2565 +f 1331//2566 676//2566 392//2566 +f 1589//2567 1616//2567 1590//2567 +f 852//2568 1588//2568 620//2568 +f 1588//2569 852//2569 690//2569 +f 1435//2570 734//2570 735//2570 +f 652//2571 389//292 198//291 +f 1429//2572 1629//2572 1593//2572 +f 1629//2573 1600//2450 1593//2452 +f 103//2574 109//2574 573//2574 +f 11//2575 57//2575 1558//2575 +f 154//2576 153//2576 10//2576 +f 1572//2577 1569//2577 1613//2577 +f 320//2578 319//2578 576//2578 +f 1631//2579 409//2579 408//2579 +f 214//2580 1641//2580 1642//2580 +f 1593//2581 1592//2581 1429//2581 +f 1612//2582 1198//2582 1323//2582 +f 1198//2583 610//2583 1323//2583 +f 109//2584 110//2584 573//2584 +f 816//2585 1320//2585 815//2585 +f 1624//2586 1599//2586 1614//2586 +f 1643//2587 1624//2587 1614//2587 +f 1644//2588 1515//2588 770//2588 +f 1645//2589 1151//2589 1631//2589 +f 1646//2590 1645//2591 1631//2592 +f 1647//2593 1535//2593 1648//2593 +f 221//2594 117//2594 119//2594 +f 1649//2595 1650//2595 1651//2595 +f 38//2596 761//2596 1320//2596 +f 573//2597 110//2597 156//2597 +f 1595//2598 1598//2598 1597//2598 +f 1635//2599 1652//2599 1640//2599 +f 1640//2600 1653//2600 1638//2600 +f 1638//2601 1653//2601 408//2601 +f 1653//2602 1654//2602 408//2602 +f 1654//2603 1631//2603 408//2603 +f 1654//2604 1646//2604 1631//2604 +f 1482//2605 276//2605 1483//2605 +f 816//2606 1570//2606 1320//2606 +f 1629//2607 1601//2607 1600//2607 +f 1558//2416 57//2608 49//2417 +f 116//71 56//73 1556//2609 +f 1515//2610 1655//2611 1635//2612 +f 459//2484 1597//2613 1617//2485 +f 1655//2611 1652//2614 1635//2612 +f 1652//2615 1656//2616 1640//2617 +f 1640//2617 1656//2616 1653//2618 +f 622//2619 44//2619 1603//2619 +f 1657//2620 1654//2620 1653//2620 +f 43//2621 1264//2621 135//2621 +f 1482//2622 1212//2622 276//2622 +f 1658//2623 1659//2623 1655//2623 +f 1515//2624 1658//2624 1655//2624 +f 1655//2625 1656//2625 1652//2625 +f 1656//2626 1657//2626 1653//2626 +f 1644//2627 1658//2627 1515//2627 +f 107//2628 43//32 55//31 +f 460//2629 824//2629 13//2629 +f 492//2630 491//2630 687//2630 +f 279//2631 1660//2631 1395//2631 +f 1657//2632 1646//2632 1654//2632 +f 1428//2633 1629//2633 1429//2633 +f 1505//2634 530//2634 393//2634 +f 188//232 329//234 1628//2635 +f 1212//2636 1211//2636 276//2636 +f 248//2637 469//2637 721//2637 +f 152//2638 1661//2638 1662//2638 +f 904//2639 1435//2639 932//2639 +f 1659//2640 1663//2640 1655//2640 +f 1655//2641 1663//2641 1656//2641 +f 1281//2642 1645//2591 1646//2590 +f 535//2643 989//2643 1239//2643 +f 159//2644 1589//2644 165//2644 +f 1664//2645 1646//2645 1657//2645 +f 1664//2646 1281//2646 1646//2646 +f 1564//2647 1665//2647 1331//2647 +f 220//2648 195//2648 357//2648 +f 1666//2649 795//2649 1346//2649 +f 1542//2650 1550//2650 1543//2650 +f 1667//2651 1281//2652 1664//2653 +f 866//2654 188//2654 1628//2654 +f 1643//2655 1614//2655 178//2655 +f 1402//2656 831//2656 1378//2656 +f 476//2657 1668//2657 101//2657 +f 1663//2658 1669//2658 1656//2658 +f 1656//2659 1670//2659 1657//2659 +f 1671//2660 1664//2660 1657//2660 +f 1667//2651 1672//2661 1281//2652 +f 1281//2662 1672//2662 1282//2662 +f 1618//2663 476//2663 658//2663 +f 1623//2664 220//2664 357//2664 +f 1658//2665 1673//2665 1659//2665 +f 1659//2666 1673//2667 1663//2668 +f 1673//2667 1674//2669 1663//2668 +f 1656//2670 1669//2670 1670//2670 +f 1670//2671 1671//2671 1657//2671 +f 735//2672 99//2672 1668//2672 +f 1564//2673 1601//2673 1428//2673 +f 355//2674 354//2674 946//2674 +f 7//2675 1586//2675 361//2675 +f 476//2676 1618//2676 1668//2676 +f 1248//2677 1623//2677 357//2677 +f 622//2678 1603//2678 56//2678 +f 1663//2679 1674//2679 1669//2679 +f 1671//2680 1667//2680 1664//2680 +f 1672//2681 843//2681 1282//2681 +f 1346//1871 794//2682 78//41 +f 1618//2683 931//2683 1668//2683 +f 153//2684 1609//2684 1563//2684 +f 1476//2685 1648//2685 1477//2685 +f 44//2686 61//2686 59//2686 +f 789//789 246//791 648//2687 +f 617//2688 616//2688 311//2688 +f 1670//2689 1675//2689 1671//2689 +f 93//2690 6//2690 134//2690 +f 815//2691 729//2691 814//2691 +f 153//2692 1563//2692 10//2692 +f 855//2693 854//2693 1402//2693 +f 210//2016 222//2018 1426//2694 +f 1674//2695 364//2695 1669//2695 +f 1676//2696 1672//2696 1667//2696 +f 1672//2697 844//877 843//876 +f 1601//2698 1564//2698 1565//2698 +f 1570//2699 38//2699 1320//2699 +f 687//2700 630//558 640//557 +f 364//2701 363//2701 1669//2701 +f 1669//2702 363//2702 1670//2702 +f 1670//2703 363//2703 1675//2703 +f 1671//2704 1676//2704 1667//2704 +f 931//2705 1435//2706 735//2707 +f 1668//2708 931//2705 735//2707 +f 1113//2709 1124//2709 1146//2709 +f 1673//2710 1677//2710 1674//2710 +f 1675//2711 1676//2711 1671//2711 +f 891//2712 1672//2712 1676//2712 +f 1672//2713 771//2713 844//2713 +f 844//2714 771//2714 772//2714 +f 25//2715 1244//2715 26//2715 +f 47//2716 192//2716 1379//2716 +f 146//2717 145//2717 191//2717 +f 927//2718 1475//2718 841//2718 +f 1678//2719 1092//2719 1070//2719 +f 363//2720 805//2720 1675//2720 +f 1672//2721 891//2721 771//2721 +f 932//2722 822//2722 821//2722 +f 38//2723 1577//2723 761//2723 +f 1677//2724 364//2724 1674//2724 +f 1675//2725 907//2725 1676//2725 +f 907//2726 891//2726 1676//2726 +f 688//2727 610//544 630//543 +f 931//2728 932//2728 1435//2728 +f 1661//2729 152//2729 830//2729 +f 866//2730 189//2730 188//2730 +f 891//2731 804//2731 771//2731 +f 247//2732 473//2732 597//2732 +f 410//2733 548//2733 408//2733 +f 1563//2734 1461//2734 1460//2734 +f 1//2735 906//2735 1679//2735 +f 805//2736 907//2736 1675//2736 +f 392//2737 1505//2737 393//2737 +f 57//2738 55//23 54//22 +f 607//2739 651//2739 693//2739 +f 1680//2740 1681//2741 1382//2742 +f 1403//2743 30//2743 187//2743 +f 390//2744 1682//2744 997//2744 +f 212//2745 1//2745 1679//2745 +f 853//2746 364//2746 1677//2746 +f 35//2747 34//2747 1038//2747 +f 806//2748 1683//2748 828//2748 +f 1322//2749 213//2749 215//2749 +f 1348//2750 1625//2750 1684//2750 +f 15//2751 17//2751 1625//2751 +f 1685//2752 1461//2752 1563//2752 +f 1416//2753 1686//2753 1687//2753 +f 17//2754 1606//2754 1625//2754 +f 1348//2755 15//2755 1625//2755 +f 592//2756 593//2756 1128//2756 +f 1688//2757 932//2757 821//2757 +f 1689//2758 714//2758 1690//2758 +f 1691//2759 777//2760 1692//2761 +f 768//2762 739//2762 1692//2762 +f 1693//2763 346//2763 260//2763 +f 1377//2764 1337//2764 303//2764 +f 917//2765 820//2765 822//2765 +f 1143//2766 1694//2766 1695//2766 +f 1224//2767 1696//2768 1268//2769 +f 890//2770 904//2770 1697//2770 +f 1175//2771 16//2771 15//2771 +f 900//2772 929//2772 921//2772 +f 1698//2773 1699//2773 762//2773 +f 1700//2774 797//2774 754//2774 +f 1701//2775 1231//2775 1232//2775 +f 762//2776 753//2776 746//2776 +f 780//2777 1702//2778 752//2779 +f 1325//2780 135//2781 1263//2782 +f 792//2783 1703//2783 1702//2783 +f 1704//2784 457//2784 1608//2784 +f 135//2781 1264//2785 1263//2782 +f 446//2786 445//2786 1526//2786 +f 535//2787 817//2787 169//2787 +f 1619//2788 167//2788 1324//2788 +f 1700//2789 1705//2789 797//2789 +f 480//2790 175//2790 1706//2790 +f 214//2791 1497//2791 1681//2791 +f 615//2792 926//2792 658//2792 +f 1707//2793 1708//2793 1709//2793 +f 216//2794 62//2794 1710//2794 +f 596//2795 473//2795 225//2795 +f 590//2796 458//2796 457//2796 +f 1711//2797 875//2797 890//2797 +f 287//2798 1712//2798 261//2798 +f 898//2799 887//2799 1713//2799 +f 493//2800 177//2800 788//2800 +f 1196//2801 1132//2801 23//2801 +f 1690//2802 714//2802 1714//2802 +f 1217//2803 1216//2803 1715//2803 +f 1704//2804 590//2804 457//2804 +f 135//2805 1325//2805 1324//2805 +f 1716//2806 1705//2806 1700//2806 +f 1702//2807 1703//2807 1698//2807 +f 1717//2808 939//2808 882//2808 +f 1718//2809 1699//2809 1698//2809 +f 1697//2810 1683//2811 1711//2812 +f 678//2813 1459//2813 632//2813 +f 1619//2814 1326//2814 1719//2814 +f 1720//2815 1619//2815 1719//2815 +f 149//2816 151//2816 1721//2816 +f 1722//2817 1714//2817 698//2817 +f 1718//2818 883//2818 870//2818 +f 762//2819 1723//2819 763//2819 +f 1724//2820 1725//2820 1726//2820 +f 235//2821 1224//2821 1268//2821 +f 1702//2822 1698//2822 762//2822 +f 1727//2823 1728//2823 1729//2823 +f 1694//2824 1730//2824 1731//2824 +f 790//2825 839//2825 791//2825 +f 1702//2826 780//2826 792//2826 +f 534//2827 533//2827 898//2827 +f 1683//2828 876//2828 828//2828 +f 1348//2829 1175//2829 15//2829 +f 1416//2830 832//2830 1732//2830 +f 1416//2831 1732//2831 1686//2831 +f 1733//2832 1687//2832 1686//2832 +f 1732//2833 1733//2833 1686//2833 +f 1226//2834 169//2834 1734//2834 +f 1347//2835 1175//2835 1348//2835 +f 1716//2836 875//2836 1711//2836 +f 1704//2837 1735//2837 1402//2837 +f 898//2838 533//2838 900//2838 +f 38//2393 939//2839 694//2394 +f 898//2840 900//2840 887//2840 +f 963//2841 659//2841 1129//2841 +f 648//2842 776//2842 1341//2842 +f 1688//2843 821//2843 876//2843 +f 1690//2844 1736//2844 1689//2844 +f 232//2845 1260//2845 1274//2845 +f 1688//2846 876//2846 1683//2846 +f 591//2847 1704//2847 1402//2847 +f 1711//2812 1683//2811 1705//2848 +f 870//2849 869//2849 1699//2849 +f 1464//2850 1499//2850 1437//2850 +f 876//2851 846//879 828//881 +f 597//2852 245//2852 247//2852 +f 1683//2853 797//2853 1705//2853 +f 1094//2854 490//2854 1347//2854 +f 634//2855 812//2855 635//2855 +f 1607//2856 1737//2856 1732//2856 +f 1626//2857 1630//2857 1627//2857 +f 1347//2858 490//2858 1175//2858 +f 1699//2859 869//2859 1723//2859 +f 869//2860 875//2860 1716//2860 +f 887//2861 1718//2861 1738//2861 +f 714//675 669//674 698//2862 +f 950//1786 1299//2863 1261//1784 +f 832//2864 1608//2864 1732//2864 +f 127//2865 1720//2865 1739//2865 +f 347//2866 346//2866 368//2866 +f 1740//2867 164//2867 1741//2867 +f 1741//2868 163//2868 155//2868 +f 366//2869 368//2869 367//2869 +f 1160//2870 569//2870 1161//2870 +f 127//2871 125//2871 1619//2871 +f 1658//2872 1742//2872 1673//2872 +f 1326//2873 1619//2873 1324//2873 +f 1691//2874 715//2874 714//2874 +f 1743//2875 1744//2875 1745//2875 +f 869//2876 871//2876 875//2876 +f 809//2877 839//2877 790//2877 +f 262//2878 261//2878 1712//2878 +f 665//2879 17//2879 928//2879 +f 794//2880 793//2880 745//2880 +f 1690//2881 1714//2882 1722//2883 +f 1729//2884 1728//2884 1725//2884 +f 1630//2885 1746//2885 1627//2885 +f 865//2886 886//2886 839//2886 +f 456//2887 458//2887 645//2887 +f 1747//2888 1743//2888 1745//2888 +f 762//2889 1699//2889 1723//2889 +f 1748//2890 149//2890 1721//2890 +f 1748//2891 1749//2891 1744//2891 +f 928//2892 854//2892 665//2892 +f 887//2893 1738//2893 1713//2893 +f 1227//2894 1226//2894 962//2894 +f 1543//2895 1750//2896 1475//2897 +f 1445//2898 1751//2898 1752//2898 +f 898//2899 1713//2899 886//2899 +f 1226//2900 1722//2901 962//2901 +f 578//2902 1753//2902 1754//2902 +f 1621//2903 1268//2903 1270//2903 +f 424//2904 1755//2904 1756//2904 +f 367//2905 368//2905 1757//2905 +f 1747//2906 1745//2906 1758//2906 +f 887//2907 883//2907 1718//2907 +f 1721//2908 1759//2908 1749//2908 +f 1748//2909 1721//2909 1749//2909 +f 1693//2910 262//2910 1760//2910 +f 1045//2911 1567//2911 749//2911 +f 1703//2912 1738//2912 1718//2912 +f 168//2913 778//2913 1690//2913 +f 1761//2914 1762//2914 1763//2914 +f 367//2915 1757//2915 1751//2915 +f 1760//2916 1764//2916 1757//2916 +f 1758//2917 1745//2917 1765//2917 +f 1743//2918 1747//2918 1766//2918 +f 161//2919 1744//2919 1743//2919 +f 456//2920 1607//2920 457//2920 +f 1767//2921 437//2921 1258//2921 +f 1147//2922 1768//2922 1140//2922 +f 1769//2923 1770//2923 64//2923 +f 579//2924 578//2924 1754//2924 +f 1771//2925 1772//2925 578//2925 +f 1703//2926 1718//2926 1698//2926 +f 1773//2927 1774//2927 1775//2927 +f 1721//2928 1740//2928 1776//2928 +f 1746//2929 1482//2929 1481//2929 +f 1777//2930 1778//2930 1779//2930 +f 1780//2931 1746//2932 1481//2933 +f 1767//2934 1258//2934 344//2934 +f 1297//2935 1296//2935 1334//2935 +f 1781//2936 198//2936 390//2936 +f 1782//2937 1774//2938 906//2939 +f 1783//2940 1771//2940 578//2940 +f 1327//2941 1115//2941 1098//2941 +f 367//2942 1751//2942 1445//2942 +f 1744//2943 1749//2943 1745//2943 +f 368//2944 1693//2944 1760//2944 +f 509//2945 928//2945 17//2945 +f 1697//2946 904//2946 932//2946 +f 1784//2947 1771//2947 1783//2947 +f 1784//2948 1785//2948 1771//2948 +f 1785//2949 1772//2949 1771//2949 +f 962//2950 698//632 659//634 +f 1765//2951 1745//2952 1786//2953 +f 1785//2954 1648//2954 1476//2954 +f 214//2955 1642//2955 1497//2955 +f 1126//2956 634//2956 633//2956 +f 926//2957 615//2957 666//2957 +f 161//2958 1743//2958 1491//2958 +f 1787//2959 1680//2959 1788//2959 +f 1749//2960 1759//2960 1786//2960 +f 1721//2961 1776//2961 1759//2961 +f 1065//2962 1102//2962 1177//2962 +f 1636//2963 1637//2963 1286//2963 +f 1725//2964 1728//2964 1789//2964 +f 870//2965 1699//2965 1718//2965 +f 763//2966 1700//2966 753//2966 +f 1790//2967 1627//2967 1746//2967 +f 1791//2968 262//2968 1712//2968 +f 1792//2969 1684//2969 1790//2969 +f 1689//2970 777//2970 1691//2970 +f 1784//2971 1647//2971 1785//2971 +f 1647//2972 1648//2972 1785//2972 +f 149//2973 1748//2974 1744//2975 +f 1793//2976 1794//2976 1287//2976 +f 1287//2977 1794//2977 1285//2977 +f 1795//2978 1286//2978 1285//2978 +f 1795//2979 1636//2979 1286//2979 +f 1689//2980 1736//2980 777//2980 +f 752//2779 1702//2778 746//2981 +f 1721//2982 164//2982 1740//2982 +f 208//2983 207//2983 856//2983 +f 1745//2984 1749//2984 1786//2984 +f 1336//2985 1514//2985 603//2985 +f 777//2760 809//2986 1692//2761 +f 1783//2987 1796//2987 1784//2987 +f 1796//2988 1647//2988 1784//2988 +f 698//2989 1714//2989 714//2989 +f 168//2990 779//2990 778//2990 +f 1624//2991 1643//2991 1797//2991 +f 346//2992 1693//2992 368//2992 +f 1720//2993 127//2993 1619//2993 +f 1630//2994 1482//2994 1746//2994 +f 1798//2995 1796//2995 1783//2995 +f 1734//2996 1690//2996 1226//2996 +f 164//2997 163//2997 1741//2997 +f 778//2998 1736//2998 1690//2998 +f 1317//2999 1374//2999 679//2999 +f 1794//3000 1795//3000 1285//3000 +f 840//3001 1474//3001 927//3001 +f 1625//3002 1606//3002 1626//3002 +f 1735//3003 1704//3003 1608//3003 +f 1737//3004 1733//3004 1732//3004 +f 262//3005 1791//3005 1760//3005 +f 1702//3006 762//3006 746//3006 +f 754//3007 753//3007 1700//3007 +f 1322//3008 1787//3008 1788//3008 +f 1400//3009 1799//3009 1793//3009 +f 1799//3010 1794//3010 1793//3010 +f 1800//3011 1636//3011 1795//3011 +f 1801//3012 426//3012 428//3012 +f 790//3013 791//3013 767//3013 +f 1712//3014 287//3014 1802//3014 +f 1803//3015 1647//3015 1796//3015 +f 1734//3016 169//3016 168//3016 +f 1794//3017 1804//3017 1795//3017 +f 1800//3018 1355//3018 1636//3018 +f 1716//3019 1700//3019 763//3019 +f 962//3020 963//3020 1520//3020 +f 167//3021 135//3021 1324//3021 +f 1492//3022 161//3022 1491//3022 +f 168//3023 1690//3023 1734//3023 +f 1224//2767 1805//3024 1696//2768 +f 122//3025 1649//3026 1777//3027 +f 1764//3028 1760//3029 1791//3030 +f 168//3031 170//3031 779//3031 +f 839//3032 886//3032 1713//3032 +f 680//3033 325//3033 633//3033 +f 1806//3034 1332//3034 1807//3034 +f 1791//3035 1712//3035 1808//3035 +f 1808//3036 1712//3036 1802//3036 +f 1535//3037 1647//3038 1803//3039 +f 1723//3040 1716//3040 763//3040 +f 1533//3041 1532//3041 1809//3041 +f 1296//3042 1031//3042 217//3042 +f 1224//3043 235//3043 244//3043 +f 1799//3044 1400//3044 1547//3044 +f 1799//3045 1764//3046 1794//3047 +f 1794//3047 1764//3046 1804//3048 +f 839//3049 1713//3049 791//3049 +f 1176//3050 530//3050 1545//3050 +f 1810//3051 1032//3051 1031//3051 +f 1677//3052 1673//3053 1811//3054 +f 1697//3055 1688//3055 1683//3055 +f 1812//3056 96//3057 1514//3058 +f 1813//3059 1803//3059 1798//3059 +f 1263//3060 1326//3060 1325//3060 +f 1477//3061 1467//3061 1478//3061 +f 1547//3062 1814//3062 1799//3062 +f 1804//3063 1808//3063 1795//3063 +f 1808//3064 1800//3064 1795//3064 +f 1808//3065 1815//3065 1800//3065 +f 869//3066 1716//3066 1723//3066 +f 792//3067 1738//3067 1703//3067 +f 1689//3068 1691//3068 714//3068 +f 62//28 64//30 1448//3069 +f 1816//3070 1265//3070 827//3070 +f 147//3071 149//2973 1744//2975 +f 198//3072 1781//3073 1817//3074 +f 1818//3075 1740//3075 1741//3075 +f 1776//3076 1740//3076 1818//3076 +f 1335//3077 1514//3077 1336//3077 +f 1335//3078 1812//3056 1514//3058 +f 97//3079 96//3079 1812//3079 +f 1342//3080 1341//3080 776//3080 +f 1813//3081 1819//3081 1803//3081 +f 1803//3039 1819//3082 1535//3037 +f 1466//3083 1467//3084 1477//3085 +f 1716//3086 1711//3086 1705//3086 +f 451//3087 453//3087 462//3087 +f 1814//3088 1820//3088 1799//3088 +f 1820//3089 1764//3089 1799//3089 +f 1815//3090 1821//3090 1800//3090 +f 196//3091 198//3091 1817//3091 +f 1802//3092 1822//3092 1821//3092 +f 110//3093 98//3093 97//3093 +f 1823//3094 1824//3094 1825//3094 +f 1826//3095 1827//3096 1828//3097 +f 1625//3098 1627//3098 1790//3098 +f 1713//3099 1738//3099 792//3099 +f 368//3100 1760//3100 1757//3100 +f 1711//3101 890//3101 1697//3101 +f 1547//3102 1829//3102 1814//3102 +f 1830//3103 1831//3103 1554//3103 +f 216//148 63//150 62//3104 +f 1406//3105 1408//3106 1832//3107 +f 962//2901 1722//2901 698//3108 +f 1833//3109 1376//3109 793//3109 +f 1032//3110 1834//3111 1678//3112 +f 791//3113 1713//3113 792//3113 +f 1239//3114 817//3114 535//3114 +f 178//3115 1835//3115 1643//3115 +f 778//3116 777//3116 1736//3116 +f 1817//3117 1478//3117 1467//3117 +f 1781//3118 997//3118 1478//3118 +f 1817//3074 1781//3073 1478//3119 +f 390//3120 997//3120 1781//3120 +f 1836//3121 1837//3121 1838//3121 +f 1764//3028 1791//3030 1804//3122 +f 1804//3123 1791//3123 1808//3123 +f 394//3124 1773//3124 1839//3124 +f 233//3125 1319//3125 407//3125 +f 1833//3126 1377//3126 1376//3126 +f 1840//3127 1841//3128 1471//3129 +f 1776//3130 1335//3130 1337//3130 +f 1818//3131 1812//3131 1335//3131 +f 1476//3132 1772//3132 1785//3132 +f 879//3133 1424//3134 1423//3135 +f 1813//3136 278//3136 1819//3136 +f 278//3137 1535//3137 1819//3137 +f 1763//3138 1762//3138 1842//3138 +f 1752//3139 1751//3139 1814//3139 +f 1814//3140 1751//3140 1820//3140 +f 795//3141 1765//3141 793//3141 +f 793//3142 1765//3142 1833//3142 +f 1776//3143 1337//3143 1377//3143 +f 1818//3144 1335//3144 1776//3144 +f 1812//3145 1741//3145 97//3145 +f 1697//3146 932//3146 1688//3146 +f 1692//3147 809//3147 768//3147 +f 715//3148 1692//3148 739//3148 +f 178//3149 939//3149 1835//3149 +f 797//3150 1683//3150 806//3150 +f 1843//3151 200//3151 1491//3151 +f 768//3152 809//3152 790//3152 +f 29//3153 311//3153 310//3153 +f 196//3154 1817//3154 1467//3154 +f 1721//3155 151//3155 164//3155 +f 1844//3156 786//3156 785//3156 +f 1808//3157 1802//3157 1815//3157 +f 1815//3158 1802//3158 1821//3158 +f 1845//3159 1765//3159 795//3159 +f 1786//3160 1377//3160 1833//3160 +f 1741//3161 1812//3161 1818//3161 +f 27//3162 29//3162 310//3162 +f 147//3163 1744//3163 161//3163 +f 178//3164 158//3164 939//3164 +f 1109//2460 1151//3165 1645//3166 +f 1280//3167 1032//3167 1071//3167 +f 1787//3168 1681//3168 1680//3168 +f 216//3169 1557//3169 217//3169 +f 1846//3170 1836//3170 1633//3170 +f 1751//3171 1757//3171 1820//3171 +f 1820//3172 1757//3172 1764//3172 +f 1458//3173 1847//3173 1276//3173 +f 806//817 828//3174 781//818 +f 1226//3175 1690//2881 1722//2883 +f 1587//3176 276//3176 278//3176 +f 38//3177 882//3177 939//3177 +f 97//3178 1741//3178 155//3178 +f 1765//2951 1786//2953 1833//3179 +f 1786//3180 1759//3180 1377//3180 +f 1759//3181 1776//3181 1377//3181 +f 1258//3182 1848//3182 231//3182 +f 1849//3183 1850//3183 1851//3183 +f 1852//3184 1853//3184 1854//3184 +f 1260//3185 1259//3185 1855//3185 +f 1856//3186 1857//3186 1858//3186 +f 95//3187 307//3187 1430//3187 +f 120//3188 1859//3188 1431//3188 +f 1860//3189 1861//3189 1862//3189 +f 200//3190 229//3190 218//3190 +f 1253//3191 1125//3191 1863//3191 +f 123//3192 1864//3192 1386//3192 +f 1865//3193 1866//3194 1778//3195 +f 929//3196 900//3196 533//3196 +f 831//3197 1735//3197 832//3197 +f 438//3198 1867//3198 436//3198 +f 1868//3199 463//3199 462//3199 +f 152//3200 1662//3200 1869//3200 +f 436//3201 1870//3201 1869//3201 +f 1184//3202 1871//3202 1872//3202 +f 423//3203 425//3203 750//3203 +f 436//3204 1867//3204 1870//3204 +f 1610//3205 1609//3205 1869//3205 +f 1873//3206 1874//3206 478//3206 +f 1870//3207 1875//3207 1869//3207 +f 1873//3208 1876//3208 438//3208 +f 1874//3209 1873//3209 438//3209 +f 438//3210 1876//3211 1867//3212 +f 1877//3213 1610//3213 1869//3213 +f 1875//3214 1877//3214 1869//3214 +f 1867//3215 1878//3215 1870//3215 +f 1870//3216 1878//3216 1875//3216 +f 745//3217 1376//3217 302//3217 +f 1879//3218 1873//3218 1880//3218 +f 1877//3219 1685//3219 1610//3219 +f 1563//3220 1610//3220 1685//3220 +f 1873//3221 1879//3221 1876//3221 +f 1876//3211 1881//3222 1867//3212 +f 1867//3223 1881//3223 1878//3223 +f 86//3224 1882//3224 84//3224 +f 1875//3225 1883//3225 1877//3225 +f 1877//3226 1883//3227 1685//3228 +f 1883//3227 1884//3229 1685//3228 +f 1879//3230 1885//3231 1876//3232 +f 1878//3233 1883//3233 1875//3233 +f 303//3234 1439//3234 1362//3234 +f 1879//3235 1880//3235 744//3235 +f 1886//3236 1884//3236 1883//3236 +f 1878//3237 1886//3237 1883//3237 +f 1793//3238 1287//3238 1339//3238 +f 1525//3239 1879//3239 744//3239 +f 1885//3240 1887//3240 1876//3240 +f 1876//3241 1887//3241 1881//3241 +f 1382//2742 1681//2741 842//3242 +f 1881//3243 1886//3243 1878//3243 +f 1888//3244 1860//3244 1862//3244 +f 1626//3245 1606//3245 664//3245 +f 743//3246 1526//3246 744//3246 +f 1639//3247 1461//3247 1884//3247 +f 1886//3248 1639//3248 1884//3248 +f 996//3249 1478//3249 997//3249 +f 1889//3250 1890//3250 1860//3250 +f 1891//3251 1868//3251 1892//3251 +f 1202//3252 605//3252 1479//3252 +f 1893//3253 1526//3254 743//3255 +f 1894//3256 1879//3256 1525//3256 +f 1894//3257 1885//3231 1879//3230 +f 1895//3258 1896//3259 1897//3260 +f 1898//3261 1899//3261 1900//3261 +f 1526//2154 1525//2153 744//3262 +f 1901//3263 1902//3264 1903//3265 +f 1854//3266 1853//3266 1904//3266 +f 1905//3267 1832//3267 1408//3267 +f 1906//3268 1907//3268 1838//3268 +f 1907//3269 1908//3269 1836//3269 +f 1908//3270 1909//3270 1836//3270 +f 1909//3271 1634//3272 1836//3273 +f 445//3274 1894//3274 1525//3274 +f 1886//3275 1910//3275 1639//3275 +f 1440//3276 1911//3276 1912//3276 +f 1906//3277 1913//3278 1907//3279 +f 1907//3280 1914//3281 1908//3282 +f 1915//3283 1632//3283 1916//3283 +f 1917//3284 1634//3284 1909//3284 +f 1918//3285 1886//3285 1881//3285 +f 1887//3286 1918//3286 1881//3286 +f 1910//3287 1263//3287 1639//3287 +f 1890//3288 1919//3289 1861//3290 +f 1920//3291 1921//3291 1922//3291 +f 1316//3292 613//3292 1059//3292 +f 1923//3293 1914//3281 1907//3280 +f 1913//3278 1923//3294 1907//3279 +f 1914//3295 1924//3295 1908//3295 +f 1924//3296 1925//3297 1909//3298 +f 1908//3299 1924//3296 1909//3298 +f 1710//3300 1916//3300 1634//3300 +f 1917//3301 1710//3301 1634//3301 +f 1910//3302 1926//3302 1263//3302 +f 1920//3303 121//3304 1921//3305 +f 1888//3306 784//3306 1432//3306 +f 1871//3307 1927//3308 1906//3309 +f 1924//3310 1928//3310 1925//3310 +f 1925//3311 1917//3311 1909//3311 +f 816//3312 1168//3312 1265//3312 +f 1918//3313 1910//3313 1886//3313 +f 664//3314 665//3314 855//3314 +f 77//3315 1605//3315 1197//3315 +f 1921//3316 121//3316 1386//3316 +f 1860//3317 1890//3288 1861//3290 +f 1927//3318 1923//3318 1906//3318 +f 1906//3277 1923//3294 1913//3278 +f 1710//3319 1917//3319 1925//3319 +f 1287//1663 1286//1662 31//3320 +f 1929//3321 1918//3321 1887//3321 +f 1885//3322 1929//3322 1887//3322 +f 1888//3323 1862//3323 784//3323 +f 1184//3324 1930//3324 1927//3324 +f 1871//3307 1184//3325 1927//3308 +f 1923//3326 1931//3326 1914//3326 +f 1710//3327 1450//3327 1916//3327 +f 1918//3328 1932//3328 1910//3328 +f 1910//3329 1932//3329 1926//3329 +f 1468//3330 831//3330 833//3330 +f 1630//3331 1212//3331 1482//3331 +f 1362//3332 1438//3332 419//3332 +f 99//3333 101//3333 1668//3333 +f 288//3334 1291//3334 287//3334 +f 1921//3335 1385//3335 1933//3335 +f 1934//3336 1930//3336 1184//3336 +f 1927//3337 1935//3338 1923//3339 +f 1914//3340 1931//3340 1924//3340 +f 1894//3341 1929//3341 1885//3341 +f 1793//3342 1339//3342 1400//3342 +f 857//3343 876//3343 821//3343 +f 1936//3344 1523//3344 1937//3344 +f 1936//3345 859//3345 1938//3345 +f 1936//3346 1939//3346 859//3346 +f 1939//3347 1940//3347 859//3347 +f 1800//3348 1821//3348 1356//3348 +f 1934//3349 1941//3349 1930//3349 +f 1927//3337 1930//3350 1935//3338 +f 1928//3351 1557//3351 1925//3351 +f 216//3352 1710//3352 1925//3352 +f 1557//3353 216//3353 1925//3353 +f 1355//3354 1800//3354 1356//3354 +f 1821//3355 1942//3355 1356//3355 +f 1926//3356 1326//3356 1263//3356 +f 1942//3357 1350//3357 1356//3357 +f 1935//3338 1931//3358 1923//3339 +f 1931//3359 1750//3359 1924//3359 +f 1924//3360 1543//3360 1928//3360 +f 1543//3361 1557//3361 1928//3361 +f 1943//3362 1944//3363 1596//3364 +f 1918//3365 1945//3365 1932//3365 +f 1932//3366 1326//3366 1926//3366 +f 1946//3367 858//3367 860//3367 +f 1184//3368 1183//3368 1934//3368 +f 1924//3369 1750//3369 1543//3369 +f 1379//3370 472//3370 471//3370 +f 1469//3371 1947//3371 1494//3371 +f 1948//3372 1949//3373 1950//3374 +f 446//3375 1951//3375 444//3375 +f 444//3376 1951//3376 445//3376 +f 1859//3377 1952//3378 1953//3379 +f 1824//3380 1857//3380 1856//3380 +f 1954//3381 1939//3381 1936//3381 +f 1954//3382 529//3382 1939//3382 +f 1882//3383 1183//3383 1955//3383 +f 1934//3384 1183//3384 1941//3384 +f 1941//3385 1935//3385 1930//3385 +f 1931//3386 1956//3387 1750//2896 +f 1957//3388 1288//1708 1304//1707 +f 79//3389 145//2440 1605//2439 +f 79//3390 1357//3390 145//3390 +f 1161//3391 1958//3391 446//3391 +f 446//3392 1958//3392 1951//3392 +f 1951//3393 1959//3393 445//3393 +f 1959//3394 1894//3394 445//3394 +f 1894//3395 1960//3395 1929//3395 +f 1937//3396 1954//3396 1936//3396 +f 1935//3338 1956//3397 1931//3358 +f 1961//3398 1894//3398 1959//3398 +f 1961//3399 1960//3399 1894//3399 +f 1929//3400 1945//3400 1918//3400 +f 1962//3401 1963//3402 1964//3403 +f 1648//3404 1466//3083 1477//3085 +f 1937//3405 1965//3405 1954//3405 +f 1469//3406 1262//3406 1966//3406 +f 84//3407 1882//3407 1955//3407 +f 1935//3338 1096//3408 1956//3397 +f 1750//2896 1956//3387 1475//2897 +f 77//3409 79//3409 1605//3409 +f 1960//3410 1945//3410 1929//3410 +f 1945//3411 1967//3411 1932//3411 +f 1968//3412 1447//3412 1964//3412 +f 1269//3413 1968//3414 1964//3415 +f 1969//3416 529//3416 1954//3416 +f 1970//3417 1183//3417 1882//3417 +f 1183//3418 1971//3418 1941//3418 +f 51//3419 1972//3419 510//3419 +f 405//3420 678//3420 632//3420 +f 1211//3421 1402//3421 1378//3421 +f 831//3422 1402//3422 1735//3422 +f 1973//3423 1719//3423 1932//3423 +f 1967//3424 1973//3424 1932//3424 +f 1932//3425 1719//3425 1326//3425 +f 1969//3426 1954//3426 1965//3426 +f 1969//3427 527//3427 529//3427 +f 1183//3428 1970//3428 1971//3428 +f 1096//3429 841//3429 1956//3429 +f 1960//3430 1967//3430 1945//3430 +f 656//3431 302//208 304//210 +f 1971//3432 1382//3432 1941//3432 +f 1941//3433 1382//3434 1935//3435 +f 1935//3435 1382//3434 1096//3436 +f 1974//3437 1975//3437 1866//3437 +f 64//3438 1280//3438 1976//3438 +f 304//3439 1362//3439 1622//3439 +f 1622//3440 1362//3440 419//3440 +f 1358//3441 656//3441 1360//3441 +f 1958//3442 1977//3443 1951//3444 +f 1608//3445 832//3445 1735//3445 +f 855//3446 1402//3446 1211//3446 +f 1978//3447 1969//3447 1965//3447 +f 1970//3448 1979//3448 1971//3448 +f 1980//3449 1981//3449 1982//3449 +f 1521//3450 1139//3450 1983//3450 +f 1626//3451 664//3451 1630//3451 +f 1984//3452 1985//3452 1986//3452 +f 1942//3453 1987//3453 1350//3453 +f 1988//3454 1959//3454 1951//3454 +f 1959//3455 1988//3455 1961//3455 +f 578//3456 1772//3456 1753//3456 +f 78//3457 302//3457 656//3457 +f 1197//3458 1605//3458 144//3458 +f 983//3459 1989//3459 1965//3459 +f 1989//3460 1978//3460 1965//3460 +f 1978//3461 527//3462 1969//3463 +f 852//3464 851//3464 691//3464 +f 1990//3465 1970//3465 1882//3465 +f 1990//3466 1979//3466 1970//3466 +f 1991//3467 1922//3467 1921//3467 +f 1992//3468 205//3468 1993//3468 +f 1378//3469 1381//3469 1502//3469 +f 1502//3470 1468//3470 197//3470 +f 1502//3471 197//3471 1503//3471 +f 1378//3472 1502//3472 277//3472 +f 1378//3473 277//3473 276//3473 +f 1988//3474 1967//3474 1960//3474 +f 1961//3475 1988//3475 1960//3475 +f 1821//3476 1822//3476 1942//3476 +f 14//3477 13//3477 492//3477 +f 603//3478 851//3478 850//3478 +f 1269//3413 1582//3479 1968//3414 +f 1979//3480 1382//3481 1971//3482 +f 1981//3483 1994//3483 1995//3483 +f 1573//3484 1254//3484 1580//3484 +f 1982//3485 1981//3485 1850//3485 +f 832//3486 1416//3486 833//3486 +f 852//3487 620//3487 619//3487 +f 510//3488 462//3488 461//3488 +f 1988//3489 1996//3489 1967//3489 +f 1967//3490 1996//3490 1973//3490 +f 79//3491 656//3491 1357//3491 +f 605//3492 1201//3492 603//3492 +f 86//3493 1990//3493 1882//3493 +f 1788//3494 1680//3495 1990//3496 +f 1979//3480 1680//3497 1382//3481 +f 1995//3498 1865//3498 1850//3498 +f 1997//3499 1998//3499 1999//3499 +f 2000//3500 1520//3500 1369//3500 +f 1449//3501 1506//3501 2001//3501 +f 850//3502 619//3502 604//3502 +f 2//3503 211//3503 421//3503 +f 1235//3504 1977//3504 1321//3504 +f 1360//3505 304//3505 69//3505 +f 1139//3506 1520//3506 963//3506 +f 2002//3507 1570//3507 1968//3507 +f 1234//3508 1978//3508 1989//3508 +f 1978//3461 1359//3509 527//3462 +f 1417//3510 1426//2694 222//2018 +f 69//3511 304//3511 1622//3511 +f 2003//3512 1952//3378 1859//3377 +f 2004//3513 2005//3513 2006//3513 +f 70//3514 171//3514 105//3514 +f 1977//3443 2007//3515 1951//3444 +f 1719//3516 1973//3516 1996//3516 +f 1292//3517 1018//3517 1229//3517 +f 1438//3518 1443//2516 419//2515 +f 420//3519 1201//3519 1202//3519 +f 267//3520 357//3520 195//3520 +f 1466//2201 1648//3521 1535//2199 +f 607//3522 939//3522 158//3522 +f 1245//3523 614//3523 1962//3523 +f 2008//3524 2009//3524 2010//3524 +f 2010//3525 2009//3525 2011//3525 +f 1104//3526 344//3526 343//3526 +f 2012//3527 1896//3527 1895//3527 +f 1562//3528 1977//3528 1235//3528 +f 1996//3529 2013//3529 1719//3529 +f 1312//3530 620//3530 1310//3530 +f 1692//3531 715//3531 1691//3531 +f 1362//3532 1439//3532 1438//3532 +f 331//3533 2003//3534 1859//3535 +f 1998//3536 2014//3537 2008//3538 +f 2011//3539 2015//3539 1216//3539 +f 1994//3540 1488//3541 1974//3542 +f 330//3543 30//3543 32//3543 +f 1951//3544 2016//3545 1988//3546 +f 1988//3547 2016//3547 1996//3547 +f 30//3548 1287//3548 31//3548 +f 144//3549 146//3549 160//3549 +f 1852//3550 2017//3550 1853//3550 +f 2018//3551 2009//3551 2008//3551 +f 2015//3552 1453//3552 1216//3552 +f 1594//3553 2019//3553 2020//3553 +f 1375//3554 191//3554 105//3554 +f 934//3555 1355//3555 1351//3555 +f 1562//3556 2007//3556 1977//3556 +f 2016//3545 1951//3544 2007//3557 +f 2016//3558 2013//3558 1996//3558 +f 2002//3559 36//3559 1570//3559 +f 1596//3560 1582//3560 1696//3560 +f 37//3561 2002//3561 1582//3561 +f 2021//3562 1831//3563 2022//3564 +f 81//3565 187//3565 1228//3565 +f 1286//3566 1340//3566 133//3566 +f 1953//3567 1952//3567 1860//3567 +f 2023//3568 2024//3568 2025//3568 +f 1966//3569 2021//3569 2026//3569 +f 2027//3570 2011//3570 2009//3570 +f 2028//3571 1849//3571 1889//3571 +f 1562//3572 2029//3572 2007//3572 +f 1340//3573 1286//3573 934//3573 +f 37//3574 1582//3574 1596//3574 +f 2013//3575 1720//3575 1719//3575 +f 1637//3576 1355//3576 934//3576 +f 1414//3577 1440//3577 1866//3577 +f 2030//3578 2031//3578 2025//3578 +f 2012//3579 1584//3579 1896//3579 +f 2014//3580 2018//3580 2008//3580 +f 2015//3581 2011//3581 2027//3581 +f 1863//3582 1510//3582 2032//3582 +f 1707//3583 1709//3584 2033//3585 +f 205//3586 2034//3587 206//3588 +f 2016//3589 2035//3589 2013//3589 +f 1286//3590 1637//3590 934//3590 +f 138//3591 160//3591 1364//3591 +f 1507//3592 1387//3592 1538//3592 +f 338//3593 1230//3593 1136//3593 +f 2012//3594 2036//3594 2037//3594 +f 2038//3595 2018//3595 2014//3595 +f 2018//3596 2039//3596 2009//3596 +f 2009//3597 2039//3597 2027//3597 +f 2040//3598 1707//3599 2033//3600 +f 2041//3601 2036//3602 2042//3603 +f 2043//3604 1904//3605 2042//3606 +f 1493//3607 1500//3607 1056//3607 +f 205//3586 1537//3608 2034//3587 +f 1431//3609 1888//3609 1432//3609 +f 1919//3610 1890//3610 2044//3610 +f 1407//3611 1507//3611 1506//3611 +f 278//3612 277//3612 1535//3612 +f 1852//3613 1858//3613 2017//3613 +f 1730//3614 2045//3614 1731//3614 +f 1731//3615 2045//3615 2046//3615 +f 1986//3616 2047//3616 1984//3616 +f 2038//3617 2048//3617 2018//3617 +f 1448//3618 1500//3618 1449//3618 +f 1853//3619 2017//3620 2049//3621 +f 784//3622 1862//3622 785//3622 +f 2029//3623 868//3623 1828//3623 +f 2029//3624 2050//3624 2007//3624 +f 2035//3625 2016//3625 2007//3625 +f 1543//3626 1550//3626 1557//3626 +f 187//3627 30//3627 330//3627 +f 1868//3628 1891//3628 2051//3628 +f 1984//3629 2052//3629 2038//3629 +f 2053//3630 2048//3630 2038//3630 +f 2048//3631 2039//3631 2018//3631 +f 2054//3632 2027//3632 2039//3632 +f 2027//3633 2055//3633 2015//3633 +f 2055//3634 1453//3634 2015//3634 +f 2056//3635 2057//3635 1453//3635 +f 185//3636 184//3636 1413//3636 +f 2022//3637 1831//3637 1830//3637 +f 1407//3638 1385//3638 1507//3638 +f 2029//3639 1828//3639 2050//3639 +f 2035//3640 1739//3640 1720//3640 +f 2013//3641 2035//3641 1720//3641 +f 1717//3642 882//3642 1596//3642 +f 2058//3643 2051//3643 1891//3643 +f 1432//3644 1854//3644 2059//3644 +f 2060//3645 2061//3645 1986//3645 +f 1986//3646 2061//3646 2047//3646 +f 2038//3647 2052//3647 2053//3647 +f 2048//3648 2054//3648 2039//3648 +f 2054//3649 2055//3649 2027//3649 +f 2062//3650 1453//3650 2055//3650 +f 2063//3651 2057//3651 2056//3651 +f 1769//3652 1056//3652 1770//3652 +f 1500//3653 1448//3653 1770//3653 +f 1385//3654 1407//3654 1933//3654 +f 1827//3655 2050//3655 1828//3655 +f 2050//3656 2064//3656 2007//3656 +f 2007//3657 2064//3657 2035//3657 +f 1717//3658 1596//3658 1944//3658 +f 2065//3659 1717//3659 1944//3659 +f 2066//3660 1891//3660 1892//3660 +f 2051//3661 1730//3661 2067//3661 +f 2045//3662 2068//3662 2069//3662 +f 1801//3663 2061//3663 2060//3663 +f 2047//3664 2070//3665 1984//3666 +f 1984//3667 2070//3667 2052//3667 +f 2053//3668 2071//3668 2048//3668 +f 2048//3669 2071//3669 2054//3669 +f 2072//3670 2055//3670 2054//3670 +f 2056//3671 1453//3671 2062//3671 +f 853//3672 2003//3672 331//3672 +f 1500//3673 1770//3673 1056//3673 +f 2073//3674 1827//3674 1782//3674 +f 2073//3675 2050//3675 1827//3675 +f 1739//3676 2035//3676 2064//3676 +f 427//3677 2069//3677 2068//3677 +f 825//3678 827//3678 1265//3678 +f 770//3679 993//3680 992//3681 +f 1955//3682 1183//3682 1288//3682 +f 1518//3683 2040//3598 2033//3600 +f 2071//3684 2074//3684 2054//3684 +f 2075//3685 2072//3685 2054//3685 +f 2055//3686 1660//3686 2062//3686 +f 1660//3687 281//3687 2062//3687 +f 281//3688 2056//3688 2062//3688 +f 2076//3689 2059//3689 1904//3689 +f 1279//3690 1278//3690 2077//3690 +f 906//3691 2073//3691 1782//3691 +f 2073//3692 2064//3692 2050//3692 +f 2065//3693 1944//3693 2078//3693 +f 2079//3694 1892//3694 75//3694 +f 2079//3695 2080//3695 1892//3695 +f 2080//3696 2066//3696 1892//3696 +f 1891//3697 2066//3697 2058//3697 +f 2051//3698 2045//3698 1730//3698 +f 2052//3699 1527//3699 2053//3699 +f 2072//3700 1660//3701 2055//3702 +f 2081//3703 2082//3703 2083//3703 +f 2082//3704 2084//3704 2083//3704 +f 2085//3705 2086//3706 1371//3707 +f 1774//3708 1782//3708 1775//3708 +f 2087//3709 2064//3709 2073//3709 +f 1797//3710 2065//3710 2078//3710 +f 1753//3711 2079//3711 75//3711 +f 998//3712 2045//3713 2051//3714 +f 2070//3715 2088//3716 2052//3717 +f 2052//3718 2088//3718 1527//3718 +f 2053//3719 1527//3719 2071//3719 +f 2074//3720 2075//3720 2054//3720 +f 2063//3721 1522//3722 396//3723 +f 2081//3724 396//3724 1522//3724 +f 2081//3725 1417//3725 2082//3725 +f 119//3726 1774//3726 221//3726 +f 2089//3727 1488//3541 1994//3540 +f 905//3728 2087//3728 2073//3728 +f 2087//3729 1739//3729 2064//3729 +f 2090//3730 2065//3730 1797//3730 +f 2090//3731 1717//3731 2065//3731 +f 2090//3732 1835//3732 1717//3732 +f 1772//3733 2079//3733 1753//3733 +f 1439//3734 1337//3734 1336//3734 +f 127//3735 1739//3735 128//3735 +f 1772//3736 2080//3736 2079//3736 +f 998//3712 1682//3737 2045//3713 +f 2045//3738 1682//3738 2068//3738 +f 283//3739 2091//3739 2070//3739 +f 2047//3664 283//3740 2070//3665 +f 2070//3715 2091//3741 2088//3716 +f 2088//3742 41//2159 1527//2161 +f 234//3743 2075//3743 2074//3743 +f 2075//3744 1420//3745 2072//3746 +f 1395//3747 1660//3701 2072//3700 +f 281//3748 280//3748 2056//3748 +f 280//3749 2063//3749 2056//3749 +f 222//3750 2084//3750 2082//3750 +f 222//3751 221//3751 2084//3751 +f 119//3752 1679//3752 1774//3752 +f 1679//3753 906//2939 1774//2938 +f 906//3754 905//3754 2073//3754 +f 1311//3755 1739//3755 2087//3755 +f 996//3756 2051//3756 2058//3756 +f 996//3757 998//3757 2051//3757 +f 2075//3758 234//3758 1420//3758 +f 280//3759 1522//3722 2063//3721 +f 905//3760 1312//3760 2087//3760 +f 1312//3761 1311//3761 2087//3761 +f 2085//3762 2092//3762 2031//3762 +f 1497//3763 842//3763 1681//3763 +f 37//3764 36//3764 2002//3764 +f 1476//3765 2080//3765 1772//3765 +f 1476//3766 2066//3766 2080//3766 +f 1476//3767 2058//3767 2066//3767 +f 1788//3768 85//3768 1322//3768 +f 2091//3769 41//3769 2088//3769 +f 2071//3770 223//3770 2074//3770 +f 223//3771 234//3771 2074//3771 +f 1420//3745 823//3772 2072//3746 +f 823//3773 1395//3747 2072//3700 +f 279//3774 281//3774 1660//3774 +f 1417//3775 222//3775 2082//3775 +f 212//3776 1679//3776 119//3776 +f 200//3777 161//3777 1492//3777 +f 656//3778 304//3778 1360//3778 +f 1643//3779 1835//3779 2090//3779 +f 303//3780 1337//3780 1439//3780 +f 1478//3781 2058//3781 1476//3781 +f 2058//3782 1478//3782 996//3782 +f 997//3783 1682//3783 998//3783 +f 214//3784 1681//3784 1787//3784 +f 214//3785 1787//3785 215//3785 +f 215//3786 1787//3786 1322//3786 +f 283//3787 2047//3787 284//3787 +f 1527//3788 186//3788 2071//3788 +f 2071//3789 186//3789 223//3789 +f 280//3790 1401//3790 1522//3790 +f 1522//3791 1418//3791 2081//3791 +f 1418//3792 1417//3792 2081//3792 +f 1864//3793 2024//3793 2093//3793 +f 2024//3794 2094//3794 2093//3794 +f 1981//3795 2095//3795 1994//3795 +f 879//3133 878//3796 1424//3134 +f 1779//3797 2031//3797 2030//3797 +f 2096//3798 1430//3798 2059//3798 +f 1260//3799 1615//3799 1559//3799 +f 2097//3800 2043//3800 1897//3800 +f 2012//3801 2037//3801 1071//3801 +f 570//3802 27//3802 775//3802 +f 1432//3803 784//3803 786//3803 +f 1507//3804 1385//3804 1387//3804 +f 1450//3805 1449//3805 1915//3805 +f 1658//3806 1980//3806 1742//3806 +f 1980//3807 2098//3807 1742//3807 +f 231//3808 1848//3808 1259//3808 +f 232//3809 231//3809 1259//3809 +f 84//3810 1955//3810 527//3810 +f 1500//3811 1407//3812 1506//3813 +f 1777//3814 1779//3814 2030//3814 +f 2099//3815 1472//3815 1539//3815 +f 827//3816 826//3816 1329//3816 +f 1273//3817 233//3817 232//3817 +f 1235//3818 568//3818 245//3818 +f 1742//3819 2098//3819 2100//3819 +f 2025//3820 2024//3820 2101//3820 +f 2086//3821 2085//3822 1779//3823 +f 1905//3824 1055//3824 2049//3824 +f 911//3825 371//3825 2102//3825 +f 2103//3826 2104//3826 2105//3826 +f 1405//3827 1440//3828 184//3829 +f 2102//3830 1539//3830 911//3830 +f 1911//3831 1405//3831 1372//3831 +f 1440//3828 1405//3827 1911//3832 +f 2106//3833 2004//3833 2107//3833 +f 1425//3834 974//3834 1496//3834 +f 1865//3835 2108//3835 1850//3835 +f 2109//3836 1865//3836 2110//3837 +f 2111//3838 2097//3838 1897//3838 +f 95//3839 1430//3839 71//3839 +f 2100//3840 2028//3840 1952//3840 +f 2025//3841 2031//3841 2023//3841 +f 1994//3842 1974//3842 1865//3842 +f 2098//3843 2028//3843 2100//3843 +f 1658//3844 2095//3844 1980//3844 +f 1912//3845 2086//3821 1779//3823 +f 1865//3846 1778//3846 1651//3846 +f 1851//3847 1850//3847 2108//3847 +f 1387//3848 1864//3848 1538//3848 +f 2030//3849 2025//3849 122//3849 +f 2020//3850 2112//3850 2113//3850 +f 2102//3851 2114//3851 1539//3851 +f 2114//3852 2099//3852 1539//3852 +f 1855//3853 1615//3853 1260//3853 +f 1415//3854 1414//3854 1488//3854 +f 1288//3855 528//3855 1955//3855 +f 854//3856 556//3856 591//3856 +f 528//3857 1939//3857 529//3857 +f 1949//3858 2115//3859 1950//3859 +f 2028//3860 2098//3860 1982//3860 +f 1651//3861 1778//3861 1777//3861 +f 1488//3862 1414//3862 1975//3862 +f 1694//3863 1143//3863 2067//3863 +f 780//3864 767//3864 791//3864 +f 994//3865 1487//3865 992//3865 +f 1778//3866 1912//3866 1779//3866 +f 623//3867 625//3867 1390//3867 +f 1359//3868 1328//3868 85//3868 +f 992//3869 2095//3869 1658//3869 +f 1852//3870 1856//3870 1858//3870 +f 1506//3871 1508//3871 2001//3871 +f 1824//3872 2116//3872 1825//3872 +f 122//3873 2025//3873 2101//3873 +f 2117//3874 2114//3874 2102//3874 +f 307//3875 1431//3875 1430//3875 +f 2114//3876 2118//3876 2099//3876 +f 2095//3877 2089//3877 1994//3877 +f 1387//3878 1386//3878 1864//3878 +f 2077//3879 1278//3879 2119//3879 +f 2095//3880 1981//3880 1980//3880 +f 2120//3881 2043//3881 2097//3881 +f 2049//3882 1055//3882 2036//3882 +f 1250//1605 1008//1604 1551//3883 +f 111//3884 120//3884 307//3884 +f 1500//3811 1506//3813 1449//3885 +f 1125//3886 764//3886 1363//3886 +f 1982//3887 1849//3887 2028//3887 +f 1865//3888 1974//3888 1866//3888 +f 1995//3889 1994//3889 1865//3889 +f 371//3890 2117//3890 2102//3890 +f 1811//3891 1952//3892 853//3893 +f 1946//3894 2022//3894 1830//3894 +f 254//3895 1511//3895 271//3895 +f 1597//3896 1620//3896 1617//3896 +f 1620//3897 1561//3897 1617//3897 +f 2116//3898 1824//3898 1856//3898 +f 2032//3899 2114//3899 2117//3899 +f 1904//3900 2041//3900 2042//3900 +f 1430//3901 1432//3901 2059//3901 +f 1253//3902 765//3902 1125//3902 +f 154//3903 830//3903 152//3903 +f 1643//3904 2090//3904 1797//3904 +f 2121//3905 1561//3905 1620//3905 +f 2122//3906 2121//3906 1620//3906 +f 2121//3907 472//3907 1561//3907 +f 2101//3908 2024//3908 1864//3908 +f 2028//3909 1860//3909 1952//3909 +f 2028//3910 1889//3910 1860//3910 +f 2077//3911 2119//3911 2123//3911 +f 1399//3912 860//3912 1304//3912 +f 1233//3913 51//3913 510//3913 +f 2036//3914 1054//3914 2037//3914 +f 2077//3915 2123//3915 2124//3915 +f 786//3916 2116//3917 1854//3918 +f 477//3919 1880//3919 478//3919 +f 1620//3920 1624//3920 2122//3920 +f 2122//3921 2125//3921 2121//3921 +f 2121//3922 2125//3922 472//3922 +f 1864//3923 2093//3923 1538//3923 +f 1537//3924 205//3924 1992//3924 +f 1624//3925 1797//3925 2122//3925 +f 1797//3926 2126//3926 2122//3926 +f 2126//3927 2125//3927 2122//3927 +f 2125//3928 835//3928 472//3928 +f 860//3929 2127//3929 1946//3929 +f 1890//3930 1849//3930 1851//3930 +f 527//3931 1955//3931 528//3931 +f 1304//3932 860//3932 1957//3932 +f 2078//3933 2126//3933 1797//3933 +f 417//3934 226//3934 835//3934 +f 1628//3935 2111//3935 2019//3935 +f 2019//3936 2111//3936 2128//3936 +f 2129//3937 71//3937 2096//3937 +f 1054//3938 2036//3938 1055//3938 +f 1372//3939 1389//3939 1390//3939 +f 1830//3940 1528//3940 858//3940 +f 1508//3941 1538//3941 1992//3941 +f 2012//3942 1071//3942 1584//3942 +f 1432//3943 786//3943 1854//3943 +f 1854//3944 2116//3944 1852//3944 +f 1172//3945 2130//3945 1173//3945 +f 2125//3946 2131//3946 835//3946 +f 835//3947 2131//3947 417//3947 +f 1933//3948 1406//3948 1823//3948 +f 1853//3949 2041//3949 1904//3949 +f 2120//3950 2129//3950 2043//3950 +f 1848//3951 1258//3951 437//3951 +f 237//3952 967//1128 244//1127 +f 1338//2176 343//3953 657//2177 +f 371//3954 1236//3954 2117//3954 +f 2129//3955 2096//3955 2076//3955 +f 1853//3619 2049//3621 2041//3956 +f 1172//3957 424//3957 1756//3957 +f 1897//3958 2043//3958 2042//3958 +f 62//3959 1448//3959 1450//3959 +f 2042//3603 2036//3602 2012//3960 +f 344//3961 1284//3961 407//3961 +f 205//3962 204//3962 1485//3962 +f 260//3963 262//3963 1693//3963 +f 1862//3964 1861//3964 785//3964 +f 1919//3965 1844//3965 785//3965 +f 1861//3966 1919//3966 785//3966 +f 417//3967 2132//3967 226//3967 +f 226//3968 2132//3968 2133//3968 +f 2134//3969 2135//3969 2136//3969 +f 418//3970 575//3970 576//3970 +f 1863//3971 1125//3971 1510//3971 +f 1974//3972 1488//3972 1975//3972 +f 2005//3973 2137//3973 2006//3973 +f 1852//3974 2116//3974 1856//3974 +f 1993//3975 1485//3975 1484//3975 +f 1580//3976 1254//3976 1236//3976 +f 205//3977 1485//3977 1993//3977 +f 681//3978 680//3978 1130//3978 +f 1512//3979 2118//3979 2114//3979 +f 911//3980 1539//3980 1455//3980 +f 1849//3981 1890//3981 1889//3981 +f 1253//3982 1863//3982 1254//3982 +f 405//3983 1433//3983 679//3983 +f 1915//3984 2001//3984 1484//3984 +f 1706//3985 2138//3985 480//3985 +f 853//3986 1952//3986 2003//3986 +f 71//3987 1430//3987 2096//3987 +f 575//3988 2131//3988 2125//3988 +f 1462//3989 1472//3989 1392//3989 +f 2132//3990 255//3990 2139//3990 +f 2128//3991 2111//3991 1897//3991 +f 2140//3992 2128//3993 1897//3994 +f 2141//3995 2109//3995 1650//3995 +f 1229//3996 520//3996 522//3996 +f 2022//3997 1946//3997 2127//3997 +f 1859//3998 1953//3998 1888//3998 +f 1487//3999 994//3999 1415//3999 +f 2142//4000 2138//4000 1706//4000 +f 2142//4001 2143//4001 2138//4001 +f 2143//4002 2144//4002 2145//4002 +f 2138//4003 2143//4003 2145//4003 +f 1389//4004 1405//4004 1404//4004 +f 556//4005 854//4005 554//4005 +f 1957//4006 860//4006 1940//4006 +f 1816//4007 827//4007 1447//4007 +f 1811//3891 2100//4008 1952//3892 +f 2146//4009 1947//4009 1966//4009 +f 1865//3836 2109//3836 2108//4010 +f 1484//4011 1486//4011 1915//4011 +f 2001//4012 1993//4012 1484//4012 +f 2147//4013 1536//4013 1538//4013 +f 2129//4014 2076//4014 2043//4014 +f 192//4015 1561//4015 472//4015 +f 1594//4016 2020//4016 1592//4016 +f 1386//4017 121//4017 123//4017 +f 2139//4018 2148//4018 2133//4018 +f 2149//4019 1706//4020 2150//4021 +f 2148//4022 2149//4022 2150//4022 +f 2149//4023 2142//4023 1706//4023 +f 528//4024 1957//4024 1940//4024 +f 1486//4025 1632//4025 1915//4025 +f 1583//4026 1236//4026 300//4026 +f 122//4027 2101//4027 123//4027 +f 2117//4028 1236//4028 2032//4028 +f 255//4029 257//4029 2139//4029 +f 257//4030 2151//4031 2139//4032 +f 2139//4032 2151//4031 2148//4033 +f 2152//4034 2144//4035 2143//4036 +f 1788//4037 1990//4037 86//4037 +f 770//3679 992//3681 1644//4038 +f 1372//4039 1371//4039 1912//4039 +f 1866//3194 1912//4040 1778//3195 +f 2149//4041 2153//4041 2142//4041 +f 2153//4042 2143//4042 2142//4042 +f 2154//4043 2144//4043 2152//4043 +f 1537//4044 1992//4044 1538//4044 +f 1236//4045 1254//4045 1863//4045 +f 2042//4046 2012//4046 1895//4046 +f 2155//4047 2152//4034 2143//4036 +f 2043//3604 2076//4048 1904//3605 +f 256//4049 1665//4050 257//4051 +f 1665//4050 2151//4052 257//4051 +f 2156//4053 2155//4053 2143//4053 +f 2135//4054 2134//4054 2154//4054 +f 1508//4055 1992//4056 1993//4057 +f 1940//4058 1939//4058 528//4058 +f 675//4059 1665//4059 256//4059 +f 2151//4060 2157//4060 2149//4060 +f 2148//4061 2151//4061 2149//4061 +f 2149//4062 2157//4062 2153//4062 +f 2143//4063 2153//4063 2156//4063 +f 329//4064 71//4065 2129//4066 +f 2017//4067 1905//4067 2049//4067 +f 2158//4068 2152//4068 2155//4068 +f 1510//4069 1363//4069 1511//4069 +f 329//4064 2129//4066 2120//4070 +f 307//4071 120//4071 1431//4071 +f 1510//4072 1125//4072 1363//4072 +f 1372//4073 1405//4073 1389//4073 +f 2096//4074 2059//4074 2076//4074 +f 1331//4075 1665//4075 675//4075 +f 1564//4076 2157//4076 2151//4076 +f 2158//4077 2154//4077 2152//4077 +f 1564//4078 2151//4078 1665//4078 +f 2157//4079 2159//4080 2153//4081 +f 2153//4082 2159//4082 2156//4082 +f 2156//4083 2158//4083 2155//4083 +f 2160//4084 2154//4084 2158//4084 +f 2001//4085 1508//4055 1993//4057 +f 329//4086 2120//4086 1628//4086 +f 120//4087 331//3533 1859//3535 +f 1975//4088 1414//4088 1866//4088 +f 2002//4089 1968//4089 1582//4089 +f 1564//4090 1427//4090 2157//4090 +f 1427//4091 2161//4091 2157//4091 +f 2157//4079 2161//4092 2159//4080 +f 2160//4093 2135//4093 2154//4093 +f 2160//4094 2136//4094 2135//4094 +f 2162//4095 287//4095 1291//4095 +f 2041//4096 2049//4096 2036//4096 +f 1252//4097 765//4097 1253//4097 +f 1431//4098 1859//4098 1888//4098 +f 575//4099 2125//4099 801//4099 +f 1811//4100 1742//4100 2100//4100 +f 1825//4101 2116//4101 2163//4101 +f 2042//4102 1895//4102 1897//4102 +f 534//4103 898//4103 899//4103 +f 1844//4104 2163//4104 2116//4104 +f 1564//4105 1428//1979 1427//1978 +f 2164//4106 2158//4106 2156//4106 +f 208//4107 325//4107 680//4107 +f 1136//4108 2165//4108 1463//4108 +f 1777//3027 2030//4109 122//3025 +f 2089//4110 1487//4110 1488//4110 +f 1844//4111 2116//3917 786//3916 +f 2159//4112 2166//4112 2156//4112 +f 2166//4113 2164//4113 2156//4113 +f 2164//4114 2160//4114 2158//4114 +f 1897//3260 1896//3259 2140//4115 +f 1507//4116 1538//4116 1508//4116 +f 2098//4117 1980//4117 1982//4117 +f 1677//4118 1811//4118 853//4118 +f 1673//3053 1742//4119 1811//3054 +f 803//4120 749//4120 1567//4120 +f 2161//4121 2167//4121 2159//4121 +f 1920//4122 1922//4122 1650//4122 +f 1512//4123 1511//4123 2168//4123 +f 2109//4124 2110//4124 1650//4124 +f 2109//4125 2141//4125 2108//4125 +f 1865//4126 1651//4126 2110//4126 +f 992//4127 1487//4127 2089//4127 +f 1449//4128 2001//4128 1915//4128 +f 1890//4129 1851//4129 2044//4129 +f 1911//4130 1372//4130 1912//4130 +f 2123//4131 2119//4131 2169//4131 +f 2020//4132 2128//3993 2140//3992 +f 2095//4133 992//4133 2089//4133 +f 2044//4134 1851//4134 2170//4134 +f 2020//4135 2140//4135 2112//4135 +f 528//4136 1288//4136 1957//4136 +f 1968//4137 1570//4137 1265//4137 +f 1866//4138 1440//4138 1912//4138 +f 1816//4139 1447//4139 1968//4139 +f 1385//4140 1921//4140 1386//4140 +f 2044//4141 1844//4141 1919//4141 +f 1953//4142 1860//4142 1888//4142 +f 596//4143 494//4143 597//4143 +f 2159//4144 2167//4144 2166//4144 +f 2171//4145 2160//4145 2164//4145 +f 2171//4146 2172//4146 2160//4146 +f 2172//4147 2136//4147 2160//4147 +f 2172//4148 1092//4148 2136//4148 +f 2111//4149 2120//4149 2097//4149 +f 1628//4150 2120//4150 2111//4150 +f 1982//4151 1850//4151 1849//4151 +f 1236//4152 1863//4152 2032//4152 +f 1943//3362 1596//3364 1696//4153 +f 1411//4154 2173//4154 2092//4154 +f 1779//4155 2085//4155 2031//4155 +f 1427//4156 1429//4156 1592//4156 +f 1427//4157 2167//4158 2161//4159 +f 2112//4160 2166//4160 2167//4160 +f 2113//4161 2112//4161 2167//4161 +f 2112//4162 2164//4162 2166//4162 +f 2112//4163 2140//4163 2164//4163 +f 2140//4164 2171//4164 2164//4164 +f 2059//4165 1854//4165 1904//4165 +f 123//4166 2101//4166 1864//4166 +f 1868//4167 2051//4167 2067//4167 +f 1510//4168 2114//4168 2032//4168 +f 1644//4169 992//4169 1658//4169 +f 1233//4170 510//4170 461//4170 +f 1427//4157 1592//4171 2167//4158 +f 1896//4172 2172//4172 2171//4172 +f 1981//4173 1995//4173 1850//4173 +f 2019//4174 2128//4174 2020//4174 +f 1510//4175 1512//4175 2114//4175 +f 1130//4176 635//4176 1100//4176 +f 1968//4177 1265//4177 1816//4177 +f 2169//4178 2119//4178 2174//4178 +f 2020//4179 2167//4179 1592//4179 +f 2020//4180 2113//4180 2167//4180 +f 2172//4181 1896//4181 1092//4181 +f 1447//4182 1329//4182 1962//4182 +f 931//1081 1618//4183 933//1079 +f 2023//4184 2031//4184 2173//4184 +f 2140//4185 1896//4185 2171//4185 +f 1946//4186 1830//4186 858//4186 +f 1920//3303 1649//4187 121//3304 +f 2011//4188 1216//4188 1215//4188 +f 1835//4189 939//4189 1717//4189 +f 1453//4190 2057//4190 1454//4190 +f 1728//4191 1715//4191 1789//4191 +f 90//4192 2057//4192 91//4192 +f 1454//4193 2057//4193 90//4193 +f 2175//4194 2057//4194 2063//4194 +f 1842//4195 90//4195 2145//4195 +f 2176//4196 90//4196 1842//4196 +f 395//4197 2177//4197 2178//4197 +f 16//4198 506//4198 555//4198 +f 1830//4199 1554//4199 1528//4199 +f 395//4200 1839//4200 2177//4200 +f 1839//4201 2179//4201 2177//4201 +f 241//4202 1511//4202 254//4202 +f 2179//4203 1839//4203 2180//4203 +f 2181//4204 2168//4205 1511//4206 +f 241//4207 2181//4204 1511//4206 +f 2182//4208 2183//4208 2134//4208 +f 2180//4209 1782//4209 1826//4209 +f 2181//4210 2184//4210 2168//4210 +f 2184//4211 2185//4211 2168//4211 +f 463//4212 1868//4212 2067//4212 +f 251//4213 2186//4213 241//4213 +f 241//4214 2186//4214 2181//4214 +f 172//4215 2187//4215 1232//4215 +f 1365//4216 2188//4216 974//4216 +f 1997//4217 1999//4218 2189//4219 +f 2190//4220 1213//4220 966//4220 +f 1103//4221 616//4221 478//4221 +f 1552//4222 2021//4222 1262//4222 +f 1990//3496 1680//3495 1979//4223 +f 2186//4224 2184//4224 2181//4224 +f 1836//4225 1838//4225 1907//4225 +f 1837//4226 1836//4226 1846//4226 +f 1789//4227 2191//4227 1726//4227 +f 2192//4228 2193//4228 2194//4228 +f 2078//4229 2195//4229 801//4229 +f 1985//4230 2196//4230 2192//4230 +f 1986//4231 1985//4231 2192//4231 +f 1173//4232 2130//4232 251//4232 +f 2130//4233 2197//4233 2186//4233 +f 251//4234 2130//4234 2186//4234 +f 2185//4235 2099//4235 2118//4235 +f 1986//4236 2192//4236 2060//4236 +f 1985//4237 1997//4237 2196//4237 +f 2198//4238 1763//4239 2183//4240 +f 2199//4241 2200//4241 2191//4241 +f 2154//4242 2183//4242 2144//4242 +f 394//4243 396//4243 2081//4243 +f 2197//4244 2201//4244 2186//4244 +f 2186//4245 2201//4245 2184//4245 +f 2201//4246 1473//4246 2185//4246 +f 2184//4247 2201//4247 2185//4247 +f 2021//4248 1552//4248 1831//4248 +f 1554//4249 1831//4249 1552//4249 +f 172//4250 1231//4250 2202//4250 +f 1826//4251 868//4251 788//4251 +f 1410//4252 1409//4252 2203//4252 +f 1962//4253 1964//4253 1447//4253 +f 1857//4254 2017//4254 1858//4254 +f 2185//4255 1473//4255 2099//4255 +f 1473//4256 1472//4256 2099//4256 +f 2179//4257 176//4257 1314//4257 +f 2179//4258 2180//4258 176//4258 +f 176//4259 2180//4259 2204//4259 +f 396//4260 2178//4260 2175//4260 +f 396//4261 395//4261 2178//4261 +f 1724//4262 1726//4262 2205//4262 +f 175//4263 493//4263 224//4263 +f 1450//4264 1915//4264 1916//4264 +f 1789//4265 1761//4265 2191//4265 +f 2177//4266 92//4266 91//4266 +f 1172//4267 1756//4267 2130//4267 +f 1839//4268 1775//4268 2180//4268 +f 1725//4269 1789//4269 1726//4269 +f 1997//4217 2189//4219 2196//4270 +f 2187//4271 172//4271 1169//4271 +f 175//4272 2150//4021 1706//4020 +f 175//4273 224//4273 2150//4273 +f 2180//4274 1775//4274 1782//4274 +f 1756//4275 1755//4275 2130//4275 +f 1755//4276 2197//4276 2130//4276 +f 1958//4277 1161//4277 1321//4277 +f 2176//4278 1454//4278 90//4278 +f 1641//4279 213//4279 1328//4279 +f 213//4280 1641//4280 214//4280 +f 2191//4281 2198//4281 2206//4281 +f 2199//4282 2191//4282 2206//4282 +f 2207//4283 2200//4283 2199//4283 +f 224//156 226//158 2133//4284 +f 2208//4285 2207//4285 1806//4285 +f 2208//4286 2200//4286 2207//4286 +f 840//4287 2209//4287 1474//4287 +f 2069//4288 1731//4288 2046//4288 +f 2069//4289 2210//4289 1731//4289 +f 1782//4290 1827//3096 1826//3095 +f 2197//4291 2211//4291 2201//4291 +f 1393//4292 1473//4292 2201//4292 +f 2211//4293 1393//4293 2201//4293 +f 1493//4294 1905//4294 1408//4294 +f 172//4295 2202//4295 173//4295 +f 1615//4296 1855//4296 1662//4296 +f 1390//4297 625//4297 1372//4297 +f 1493//4298 1056//1205 1055//1204 +f 2207//4299 1297//4299 1334//4299 +f 1333//4300 2207//4300 1334//4300 +f 2189//4301 1727//4301 2212//4301 +f 1857//4302 1823//4302 1832//4302 +f 174//4303 173//4303 2213//4303 +f 424//4304 1172//4304 1219//4304 +f 2214//4305 2182//4305 2136//4305 +f 2215//4306 1807//4307 1332//4306 +f 1727//4308 2010//4308 1215//4308 +f 1755//4309 1847//4310 2197//4311 +f 2197//4312 1847//4312 2211//4312 +f 801//4313 2126//4313 2078//4313 +f 173//4314 1807//4314 2215//4314 +f 624//4315 1371//4315 625//4315 +f 2136//4316 2182//4316 2134//4316 +f 1847//4317 1393//4317 2211//4317 +f 1956//4318 841//4318 1475//4318 +f 1727//4319 1215//4319 1728//4319 +f 1371//3707 2086//3706 1912//4320 +f 2175//4321 2178//4321 91//4321 +f 1806//4322 1333//4322 1332//4322 +f 2216//4323 966//4323 324//4323 +f 1701//4324 1232//4324 2210//4324 +f 2057//4325 2175//4325 91//4325 +f 1584//4326 1092//4326 1896//4326 +f 1999//4327 2008//4327 2010//4327 +f 868//4328 2029//4328 1562//4328 +f 2213//4329 2215//4329 2217//4329 +f 2213//4330 2209//4330 2187//4330 +f 1132//4331 143//4331 730//4331 +f 1985//4332 2038//4333 1997//4333 +f 2218//4334 1801//4334 2060//4334 +f 1126//4335 324//4335 966//4335 +f 1743//4336 1766//4336 1491//4336 +f 2219//4337 1641//4337 1695//4337 +f 1701//4338 2210//4338 2069//4338 +f 426//4339 1701//4340 2069//4341 +f 1806//4342 2207//4342 1333//4342 +f 255//4343 2132//4343 417//4343 +f 624//4344 2092//4344 1371//4344 +f 1520//4345 1139//4345 1521//4345 +f 2220//4346 2221//4346 2222//4346 +f 2119//4347 1278//4347 2223//4347 +f 1999//4348 1727//4348 2189//4348 +f 426//4349 2069//4349 427//4349 +f 2224//4350 173//4351 2202//4352 +f 974//4353 2188//4353 1496//4353 +f 1334//4354 1296//4354 2225//4354 +f 2195//4355 2190//4355 2216//4355 +f 2177//4356 479//4356 92//4356 +f 424//4357 423//4357 1755//4357 +f 423//4358 1847//4310 1755//4309 +f 1731//4359 2210//4359 2221//4359 +f 471//357 473//359 247//4360 +f 2187//4361 2209//4361 2226//4361 +f 1857//4362 1824//4362 1823//4362 +f 177//4363 493//4363 175//4363 +f 1731//4364 2219//4365 1694//4366 +f 2227//4367 1516//4367 1383//4367 +f 1537//4368 1536//4368 2228//4368 +f 2177//4369 1314//4369 479//4369 +f 1210//4370 971//4370 1083//4370 +f 1278//4371 1370//4371 2223//4371 +f 2173//4372 1411//4372 880//4372 +f 2092//4373 2085//4373 1371//4373 +f 2229//4374 2224//4350 2202//4352 +f 2207//4375 2199//4375 1297//4375 +f 2199//4376 1298//4376 1297//4376 +f 1423//4377 2230//4377 879//4377 +f 2231//4378 2173//4378 880//4378 +f 1678//4379 2232//4379 2214//4379 +f 1715//4380 1762//4380 1761//4380 +f 2196//4270 2189//4219 2229//4381 +f 1461//4382 1685//4382 1884//4382 +f 1083//4383 2233//4383 1210//4383 +f 2233//4384 1208//4384 1210//4384 +f 1916//4385 1632//4385 1634//4385 +f 1496//4386 2230//4386 1423//4386 +f 2230//4387 880//4387 879//4387 +f 1538//4388 2093//4388 2147//4388 +f 1810//4389 1834//3111 1032//3110 +f 1834//4390 2232//4390 1678//4390 +f 1874//4391 438//4391 1767//4391 +f 2219//4392 2220//4392 1641//4392 +f 2234//4393 2187//4393 2226//4393 +f 2233//4394 1365//4394 1208//4394 +f 2230//4395 2231//4395 880//4395 +f 2231//4396 2235//4396 2173//4396 +f 2196//4397 2229//4397 2193//4397 +f 1314//4398 176//4398 175//4398 +f 801//4399 323//4399 575//4399 +f 1083//4400 1555//4400 2233//4400 +f 2233//4401 2236//4401 1365//4401 +f 1365//4402 2236//4402 2188//4402 +f 2188//4403 2237//4403 1496//4403 +f 2237//4404 2238//4405 2230//4406 +f 1496//4407 2237//4404 2230//4406 +f 2230//4408 2238//4408 2231//4408 +f 2238//4409 2239//4409 2231//4409 +f 2239//4410 2240//4410 2231//4410 +f 2240//4411 2235//4411 2231//4411 +f 1641//4412 2222//4412 1642//4412 +f 1369//4413 1521//4413 1370//4413 +f 2221//4414 2234//4414 2222//4414 +f 2218//4415 1701//4340 426//4339 +f 2182//4416 2198//4416 2183//4416 +f 1763//4417 1842//4417 2144//4417 +f 1555//4418 2241//4418 2233//4418 +f 2188//4419 2242//4419 2237//4419 +f 2173//4420 2235//4420 2023//4420 +f 128//4421 1739//4421 1311//4421 +f 446//4422 1526//3254 1893//3253 +f 983//4423 51//4423 1234//4423 +f 1169//4424 174//4424 2187//4424 +f 453//4425 75//4425 1892//4425 +f 1726//4426 2200//4426 2208//4426 +f 2233//4427 2243//4427 2236//4427 +f 2236//4428 2243//4428 2188//4428 +f 2243//4429 2242//4429 2188//4429 +f 1695//4430 1641//4430 1328//4430 +f 2217//4431 2225//4431 1474//4431 +f 1649//4432 1651//4432 1777//4432 +f 1486//4433 1485//4433 2244//4433 +f 463//4434 2067//4434 1143//4434 +f 2237//4435 2245//4435 2238//4435 +f 2240//4436 2246//4436 2235//4436 +f 1411//4437 624//4438 1412//4439 +f 1144//4440 1695//4440 1328//4440 +f 1642//4441 2234//4441 1498//4441 +f 2217//4442 1474//4442 2209//4442 +f 1232//4443 2187//4443 2221//4443 +f 1330//4444 1350//4444 2247//4444 +f 2218//4445 1231//4445 1701//4445 +f 2233//4446 2241//4446 2243//4446 +f 2234//4447 2226//4447 1498//4447 +f 2226//4448 2209//4449 1498//4450 +f 2209//4451 2213//4451 2217//4451 +f 2227//4452 2248//4452 1516//4452 +f 1516//4453 2248//4453 1555//4453 +f 1555//4454 2248//4454 2241//4454 +f 2242//4455 2245//4455 2237//4455 +f 2238//4456 2245//4456 2239//4456 +f 2249//4457 2023//4458 2235//4459 +f 1450//4460 1710//4460 62//4460 +f 2094//4461 2024//4461 2023//4461 +f 2118//4462 2168//4462 2185//4462 +f 1649//4463 122//4463 121//4463 +f 1998//4464 1997//4333 2038//4333 +f 2137//4465 2250//4465 2251//4465 +f 1805//4466 1943//4466 1696//4466 +f 2193//4467 2202//4467 1231//4467 +f 177//4468 2204//4468 788//4468 +f 2248//4469 2252//4469 2241//4469 +f 2241//4470 2253//4470 2243//4470 +f 2253//4471 2242//4471 2243//4471 +f 2254//4472 2246//4472 2240//4472 +f 2179//4473 1314//4473 2177//4473 +f 1233//4474 461//4474 463//4474 +f 1031//4475 1296//4475 1810//4475 +f 2063//4476 396//4476 2175//4476 +f 1383//4477 1394//4477 2227//4477 +f 2255//4478 2256//4478 2245//4478 +f 2245//4479 2256//4479 2239//4479 +f 2256//4480 2240//4480 2239//4480 +f 2246//4481 2257//4481 2235//4481 +f 2257//4482 2249//4482 2235//4482 +f 2249//4457 2094//4483 2023//4458 +f 1805//4484 1213//4484 2190//4484 +f 453//4485 1892//4485 1868//4485 +f 2232//4486 2206//4486 2182//4486 +f 1517//4487 1302//4488 1518//3683 +f 2227//4489 2258//4489 2248//4489 +f 2248//4490 2259//4490 2252//4490 +f 2252//4491 2260//4491 2241//4491 +f 2253//4492 2261//4492 2242//4492 +f 2242//4493 2262//4493 2245//4493 +f 343//4494 616//4494 1104//4494 +f 1234//4495 1989//4495 983//4495 +f 2092//4496 624//4438 1411//4437 +f 2248//4497 2258//4497 2259//4497 +f 2259//4498 2260//4498 2252//4498 +f 2241//4499 2260//4499 2253//4499 +f 2242//4500 2261//4500 2262//4500 +f 2262//4501 2263//4501 2245//4501 +f 2245//4502 2263//4502 2255//4502 +f 2254//4503 2240//4503 2256//4503 +f 2254//4504 2257//4504 2246//4504 +f 1092//4505 2214//4505 2136//4505 +f 1298//4506 2199//4506 2232//4506 +f 2199//4507 2206//4507 2232//4507 +f 208//4508 681//4508 209//4508 +f 2227//4509 2264//4509 2258//4509 +f 2263//4510 2265//4510 2255//4510 +f 2222//4511 2234//4511 1642//4511 +f 1770//4512 1448//4512 64//4512 +f 1944//4513 1943//4513 2078//4513 +f 1530//4514 2266//4514 2227//4514 +f 2259//4515 2258//4515 2264//4515 +f 2267//4516 2255//4516 2265//4516 +f 2267//4517 2268//4517 2256//4517 +f 2255//4518 2267//4518 2256//4518 +f 2268//4519 2269//4519 2254//4519 +f 2256//4520 2268//4520 2254//4520 +f 2254//4521 2269//4521 2257//4521 +f 2257//4522 2270//4522 2249//4522 +f 2270//4523 2094//4483 2249//4457 +f 1296//4524 1834//4524 1810//4524 +f 2225//4525 1296//4525 1549//4525 +f 1259//4526 1848//4526 1855//4526 +f 592//4527 456//4527 626//4527 +f 1938//4528 859//4528 858//4528 +f 1991//4529 2170//4529 2141//4529 +f 973//4530 1555//4530 1083//4530 +f 1773//4531 2084//4531 1774//4531 +f 2094//4532 2271//4532 2093//4532 +f 2260//4533 2272//4534 2253//4535 +f 2261//4536 2273//4536 2262//4536 +f 2269//4537 2274//4537 2257//4537 +f 2274//4538 2270//4538 2257//4538 +f 2094//4539 2270//4539 2271//4539 +f 1521//4540 1983//4541 1370//4542 +f 1805//4543 1224//4543 1213//4543 +f 1789//4544 1715//4544 1761//4544 +f 1474//4545 1549//2249 1542//2248 +f 1922//4546 1991//4546 2141//4546 +f 1459//4547 813//4547 632//4547 +f 2204//4548 2180//4548 1826//4548 +f 1216//4549 1454//4549 2176//4549 +f 2189//4550 2212//4550 2224//4550 +f 1715//4551 1216//4551 2176//4551 +f 2227//4552 2266//4552 2264//4552 +f 2259//4553 2272//4553 2260//4553 +f 2272//4534 2275//4554 2253//4535 +f 2253//4555 2275//4555 2261//4555 +f 2268//4556 2276//4556 2269//4556 +f 2276//4557 2277//4557 2269//4557 +f 2269//4558 2277//4558 2274//4558 +f 1359//4559 463//1336 1144//1338 +f 1234//4560 463//4560 1359//4560 +f 1762//4561 2176//4562 1842//4563 +f 1825//4564 2170//4564 1991//4564 +f 2183//4565 2154//4565 2134//4565 +f 1839//4566 1773//4566 1775//4566 +f 2259//4567 2278//4567 2272//4567 +f 2263//4568 2262//4568 2265//4568 +f 1641//4569 2220//4569 2222//4569 +f 2163//4570 2170//4570 1825//4570 +f 2163//4571 2044//4571 2170//4571 +f 2195//4572 2078//4573 1943//4574 +f 569//4575 568//4575 1161//4575 +f 2278//4576 2279//4576 2272//4576 +f 2272//4577 2273//4577 2275//4577 +f 2273//4578 2261//4578 2275//4578 +f 2273//4579 2280//4580 2262//4581 +f 2277//4582 2281//4582 2274//4582 +f 2281//4583 2270//4583 2274//4583 +f 1549//4584 1296//4584 217//4584 +f 1851//4585 2108//4586 2170//4587 +f 2178//4588 2177//4588 91//4588 +f 2219//4589 2221//4589 2220//4589 +f 2280//4590 2265//4590 2262//4590 +f 2267//4591 2282//4591 2268//4591 +f 2268//4592 2282//4593 2276//4594 +f 2147//4595 2271//4595 2270//4595 +f 2281//4596 2147//4596 2270//4596 +f 2067//4597 1730//4597 1694//4597 +f 1933//4598 1991//4598 1921//4598 +f 801//4599 2195//4599 802//4599 +f 53//4600 1972//4600 51//4600 +f 1874//4601 1103//4601 478//4601 +f 2279//4602 2283//4602 2272//4602 +f 2283//4603 2284//4603 2272//4603 +f 2284//4604 2285//4605 2272//4606 +f 2272//4607 2285//4607 2273//4607 +f 2285//4608 2280//4580 2273//4579 +f 1296//4609 1298//4610 1834//4611 +f 1844//4612 2044//4612 2163//4612 +f 1922//4613 2141//4613 1650//4613 +f 1806//4614 1726//4614 2208//4614 +f 437//4615 1767//4615 438//4615 +f 2264//4616 2286//4616 2259//4616 +f 2259//4617 2286//4617 2278//4617 +f 2276//4618 2287//4618 2277//4618 +f 2277//4619 2287//4619 2281//4619 +f 2288//4620 2278//4620 2286//4620 +f 2278//4621 2288//4621 2279//4621 +f 2285//4622 2289//4622 2280//4622 +f 2289//4623 2290//4623 2265//4623 +f 2280//4624 2289//4624 2265//4624 +f 2290//4625 2267//4625 2265//4625 +f 174//4626 2213//4626 2187//4626 +f 1143//4627 1695//4627 1144//4627 +f 1530//4628 2291//4628 2266//4628 +f 2288//4629 2292//4629 2279//4629 +f 2279//4630 2292//4630 2283//4630 +f 2284//4604 2289//4631 2285//4605 +f 2282//4593 2293//4632 2276//4594 +f 2287//4633 2294//4633 2281//4633 +f 2195//4572 1943//4574 1805//4634 +f 1276//4635 1847//4635 423//4635 +f 1823//4636 1991//4636 1933//4636 +f 2224//4637 1807//4637 173//4637 +f 2204//4638 1826//4638 788//4638 +f 1470//4639 1947//4639 1530//4639 +f 1530//4640 1947//4640 2291//4640 +f 2295//4641 2267//4641 2290//4641 +f 2267//4642 2295//4643 2282//4644 +f 2276//4645 2293//4645 2287//4645 +f 2228//4646 2147//4646 2281//4646 +f 1823//4647 1825//4647 1991//4647 +f 2133//4648 2148//4648 2150//4648 +f 2131//4649 575//4649 417//4649 +f 2291//4650 2296//4651 2266//4652 +f 2296//4651 2264//4653 2266//4652 +f 2292//4654 2297//4654 2283//4654 +f 2284//4655 2297//4655 2289//4655 +f 2287//4656 2298//4656 2294//4656 +f 2228//4657 2281//4657 2294//4657 +f 2229//4658 2189//4658 2224//4658 +f 2216//4659 2190//4659 966//4659 +f 1836//3273 1634//3272 1633//4660 +f 1470//4661 1494//4661 1947//4661 +f 2264//4662 2296//4662 2286//4662 +f 2283//4663 2297//4663 2284//4663 +f 2297//4664 2299//4664 2289//4664 +f 2293//4665 2300//4665 2287//4665 +f 2300//4666 2298//4666 2287//4666 +f 2298//4667 2228//4667 2294//4667 +f 2083//4668 2084//4668 1773//4668 +f 2217//4669 2215//4669 2225//4669 +f 2200//4670 1726//4670 2191//4670 +f 2282//4671 2301//4671 2293//4671 +f 1280//4672 1071//4672 1976//4672 +f 1976//4673 1071//4673 2037//4673 +f 2195//4674 1805//4674 2190//4674 +f 2083//4675 1773//4675 394//4675 +f 176//4676 2204//4676 177//4676 +f 2296//4677 2302//4677 2286//4677 +f 2286//4678 2302//4678 2288//4678 +f 2292//4679 2303//4679 2297//4679 +f 2299//4680 2304//4680 2289//4680 +f 2289//4681 2304//4681 2290//4681 +f 2295//4643 2301//4682 2282//4644 +f 2293//4683 2305//4683 2300//4683 +f 1133//4684 1444//4684 1241//4684 +f 2034//4685 1537//4686 2228//4687 +f 2081//4688 2083//4688 394//4688 +f 1519//4689 1518//4689 2306//4689 +f 2221//4690 2187//4690 2234//4690 +f 2302//4691 2307//4691 2288//4691 +f 2307//4692 2303//4692 2292//4692 +f 2288//4693 2307//4693 2292//4693 +f 2303//4694 2308//4694 2297//4694 +f 2304//4695 2309//4695 2290//4695 +f 2309//4696 2295//4696 2290//4696 +f 2108//4586 2141//4697 2170//4587 +f 51//4698 1233//4698 1234//4698 +f 1678//4699 2214//4699 1092//4699 +f 2297//4700 2310//4701 2299//4702 +f 2301//4703 2305//4703 2293//4703 +f 206//4704 2228//4704 2298//4704 +f 206//4705 2034//4685 2228//4687 +f 1826//4706 1828//4706 868//4706 +f 437//4707 1855//4707 1848//4707 +f 2308//4708 2311//4708 2297//4708 +f 2297//4700 2311//4709 2310//4701 +f 2299//4710 2312//4710 2304//4710 +f 2305//4711 2313//4711 2300//4711 +f 2313//4712 2298//4712 2300//4712 +f 1731//4364 2221//4713 2219//4365 +f 1832//4714 1905//4714 1857//4714 +f 1985//4715 1984//4715 2038//4715 +f 2195//4716 2216//4716 802//4716 +f 2183//4717 1763//4717 2144//4717 +f 75//4718 452//4718 76//4718 +f 2144//4719 1842//4719 2145//4719 +f 2312//4720 2309//4720 2304//4720 +f 2309//4721 2314//4721 2301//4721 +f 2295//4722 2309//4722 2301//4722 +f 2314//4723 2315//4723 2305//4723 +f 2301//4724 2314//4724 2305//4724 +f 2021//4725 1966//4725 1262//4725 +f 452//4726 451//4726 76//4726 +f 1761//4727 2198//4727 2191//4727 +f 1947//4728 2146//4728 2291//4728 +f 2291//4729 2146//4729 2296//4729 +f 2299//4730 2310//4730 2312//4730 +f 2315//4731 2316//4731 2305//4731 +f 2305//4732 2316//4732 2313//4732 +f 2313//4733 2317//4733 2298//4733 +f 2298//4734 2317//4734 206//4734 +f 2060//4735 2194//4735 2218//4735 +f 1332//4736 1334//4736 2225//4736 +f 2210//4737 1232//4737 2221//4737 +f 2147//4738 2228//4738 1536//4738 +f 2308//4739 2318//4739 2311//4739 +f 2312//4740 2319//4740 2309//4740 +f 2316//4741 2317//4741 2313//4741 +f 2198//4238 1761//4742 1763//4239 +f 1245//4743 1329//4743 1246//4743 +f 1965//4744 52//4744 983//4744 +f 1965//4745 1937//4745 52//4745 +f 510//4746 1972//4746 1409//4746 +f 233//4747 1284//4747 1258//4747 +f 1407//4748 1406//4748 1933//4748 +f 2310//4749 2319//4749 2312//4749 +f 2314//4750 2320//4750 2315//4750 +f 1354//4751 2321//4751 1708//4751 +f 1806//4752 2205//4752 1726//4752 +f 1555//4753 1509//4753 1516//4753 +f 1332//4306 2225//4754 2215//4306 +f 494//4755 245//4755 597//4755 +f 2322//4756 1519//4757 2306//4758 +f 1938//4759 1523//4759 1936//4759 +f 1434//4760 1433//4760 404//4760 +f 404//4761 2323//4761 1434//4761 +f 1474//4762 2225//4762 1549//4762 +f 2146//4763 2026//4763 2296//4763 +f 2296//4764 2324//4764 2302//4764 +f 2325//4765 2307//4765 2302//4765 +f 2324//4766 2325//4766 2302//4766 +f 2325//4767 2303//4767 2307//4767 +f 2303//4768 2318//4768 2308//4768 +f 2311//4769 2319//4769 2310//4769 +f 2319//4770 2326//4770 2309//4770 +f 2317//4771 204//4771 206//4771 +f 994//4772 993//4772 769//4772 +f 1868//4773 462//4773 453//4773 +f 1095//4774 1768//4774 1147//4774 +f 1650//4775 1649//4775 1920//4775 +f 1715//4776 2176//4562 1762//4561 +f 1054//4777 1976//4777 2037//4777 +f 2321//4778 2327//4778 1277//4778 +f 2133//4779 2132//4779 2139//4779 +f 2296//4780 2026//4781 2324//4782 +f 2326//4783 2320//4783 2314//4783 +f 2309//4784 2326//4784 2314//4784 +f 2320//4785 2328//4785 2315//4785 +f 2315//4786 2328//4786 2316//4786 +f 2316//4787 2329//4787 2317//4787 +f 1873//4788 478//4788 1880//4788 +f 2212//4789 2205//4789 2224//4789 +f 1268//4790 1696//4790 1582//4790 +f 1801//4791 2218//4791 426//4791 +f 2330//4792 1410//4792 2203//4792 +f 1410//4793 2330//4793 451//4793 +f 2327//4794 1278//4794 1277//4794 +f 1433//4795 405//4795 404//4795 +f 1434//4796 2323//4796 614//4796 +f 1999//4797 1998//3536 2008//3538 +f 1227//4798 962//4798 1520//4798 +f 2331//4799 2303//4799 2325//4799 +f 2331//4800 2318//4800 2303//4800 +f 2311//4801 2318//4801 2319//4801 +f 2318//4802 2332//4802 2319//4802 +f 2319//4803 2332//4803 2326//4803 +f 2329//4804 204//4804 2317//4804 +f 2205//4805 1806//4805 2224//4805 +f 1728//4806 1217//4806 1715//4806 +f 1493//4807 1055//4807 1905//4807 +f 614//4808 2323//4808 1962//4808 +f 1215//4809 1217//4809 1728//4809 +f 74//4810 1754//4810 75//4810 +f 2333//4811 1237//4811 1366//4811 +f 2092//4812 2173//4812 2031//4812 +f 1874//4813 1767//4813 1103//4813 +f 2326//4814 2334//4815 2320//4816 +f 2320//4817 2334//4817 2328//4817 +f 2206//4818 2198//4818 2182//4818 +f 1694//4819 2219//4819 1695//4819 +f 2232//4820 2182//4820 2214//4820 +f 436//4821 1855//4821 437//4821 +f 2335//4822 2336//4822 2337//4822 +f 1963//4823 2323//4823 404//4823 +f 2146//4824 1966//4824 2026//4824 +f 2331//4825 2338//4826 2318//4827 +f 2338//4826 2332//4828 2318//4827 +f 2326//4814 2339//4829 2334//4815 +f 2340//4830 204//4830 2329//4830 +f 2192//4831 2194//4831 2060//4831 +f 75//4832 1754//4832 1753//4832 +f 1727//4833 2205//4833 2212//4833 +f 680//4834 633//4834 635//4834 +f 2341//4835 1963//4835 404//4835 +f 1963//3402 1962//3401 2323//4836 +f 1329//4837 1245//4837 1962//4837 +f 2332//4838 2339//4838 2326//4838 +f 2340//4839 2244//4839 204//4839 +f 2244//4840 1485//4840 204//4840 +f 2194//4841 2193//4841 1231//4841 +f 394//4842 1839//4842 395//4842 +f 221//4843 1774//4843 2084//4843 +f 2194//4844 1231//4844 2218//4844 +f 2342//4845 2343//4845 278//4845 +f 1872//4846 2338//4846 2331//4846 +f 2334//4847 2344//4847 2328//4847 +f 2316//4848 2340//4848 2329//4848 +f 2229//4849 2202//4849 2193//4849 +f 1727//4850 1724//4850 2205//4850 +f 1298//4610 2232//4851 1834//4611 +f 1642//4852 1498//4852 1497//4852 +f 1469//4853 892//1576 1262//1578 +f 1727//4854 1729//4855 1724//4856 +f 2345//4857 2325//4857 2324//4857 +f 2345//4858 2331//4858 2325//4858 +f 2332//4859 2346//4859 2339//4859 +f 2346//4860 2334//4860 2339//4860 +f 2328//4861 2344//4861 2316//4861 +f 2316//4862 2344//4862 2340//4862 +f 2127//4863 860//4863 1399//4863 +f 1798//4864 577//4864 2347//4864 +f 1458//4865 1393//4865 1847//4865 +f 1458//4866 1391//4866 1393//4866 +f 1814//4867 1829//4867 1752//4867 +f 236//4868 403//4868 631//4868 +f 2341//4869 404//4869 403//4869 +f 2026//4781 2127//4870 2324//4782 +f 2345//4871 1872//4871 2331//4871 +f 2346//4872 2332//4872 2338//4872 +f 2045//4873 2069//4873 2046//4873 +f 173//4874 2215//4874 2213//4874 +f 1103//4875 1767//4875 1104//4875 +f 452//4876 75//4876 453//4876 +f 1481//4877 1483//4877 1587//4877 +f 1964//3403 1963//3402 2341//4878 +f 1523//4879 1938//4879 858//4879 +f 2026//4781 2022//4880 2127//4870 +f 1399//4881 2324//4881 2127//4881 +f 1399//4882 2345//4882 2324//4882 +f 2346//4883 2348//4883 2334//4883 +f 2349//4884 2344//4884 2334//4884 +f 2348//4885 2349//4885 2334//4885 +f 2349//4886 2350//4886 2344//4886 +f 2350//4887 2340//4887 2344//4887 +f 2340//4888 2350//4888 2244//4888 +f 1724//4856 1729//4855 1725//4889 +f 2192//4890 2196//4890 2193//4890 +f 2343//4891 1481//4891 1587//4891 +f 1587//4892 278//4892 2343//4892 +f 1678//4893 1070//4893 1032//4893 +f 2021//3562 2022//3564 2026//4894 +f 1872//4895 2346//4895 2338//4895 +f 554//4896 509//4896 16//4896 +f 2271//4897 2147//4897 2093//4897 +f 1769//4898 1054//4898 1056//4898 +f 152//4899 1869//4899 1609//4899 +f 224//4900 2133//4900 2150//4900 +f 1399//4901 1185//4901 2345//4901 +f 1184//4902 1872//4902 2345//4902 +f 1871//4903 2346//4903 1872//4903 +f 1871//4904 1906//4904 2346//4904 +f 1838//4905 2346//4905 1906//4905 +f 1838//4906 2348//4906 2346//4906 +f 479//4907 480//4907 2138//4907 +f 1769//4908 1976//4908 1054//4908 +f 1651//4909 1650//4909 2110//4909 +f 1621//4910 403//4910 236//4910 +f 1621//4911 2341//4911 403//4911 +f 2351//4912 1491//4912 1766//4912 +f 2352//4913 1687//4913 1733//4913 +f 1185//4914 1184//4914 2345//4914 +f 86//4915 85//4915 1788//4915 +f 1234//4916 1359//4916 1978//4916 +f 1838//4917 1837//4917 2348//4917 +f 1837//4918 2349//4919 2348//4920 +f 2350//4921 1633//4921 2244//4921 +f 1633//4922 1486//4922 2244//4922 +f 1321//4923 1977//4923 1958//4923 +f 90//4924 2138//4924 2145//4924 +f 90//4925 92//4925 2138//4925 +f 1238//4926 588//4926 818//4926 +f 1998//4927 2038//4927 2014//4927 +f 1302//4488 2040//3598 1518//3683 +f 237//4928 631//4928 1006//4928 +f 237//4929 236//4929 631//4929 +f 235//4930 1621//4930 236//4930 +f 1270//4931 2341//4931 1621//4931 +f 1270//4932 1269//4932 1964//4932 +f 2341//4933 1270//4933 1964//4933 +f 2011//4934 1215//4934 2010//4934 +f 2224//4935 1806//4935 1807//4935 +f 1846//4936 2349//4919 1837//4918 +f 324//810 802//809 2216//4937 +f 92//4938 479//4938 2138//4938 +f 1498//4450 2209//4449 840//4939 +f 1840//4940 1533//4940 1809//4940 +f 2174//4941 2119//4941 2223//4941 +f 1406//3105 1832//3107 1823//4942 +f 801//4943 2125//4943 2126//4943 +f 1846//4944 2350//4944 2349//4944 +f 2350//4945 1846//4945 1633//4945 +f 1633//4946 1632//4946 1486//4946 +f 1999//4947 2010//4947 1727//4947 +f 64//4948 1976//4948 1769//4948 +f 2353//4949 2354//4949 2355//4949 +f 2354//4950 2356//4950 2355//4950 +f 2357//4951 2358//4951 2356//4951 +f 2354//4952 2357//4952 2356//4952 +f 2165//4953 1136//4953 2359//4953 +f 2360//4954 2361//4954 2336//4954 +f 2362//4955 990//4955 2363//4955 +f 2364//4956 2365//4956 2366//4956 +f 268//4957 2367//4957 269//4957 +f 2368//4958 2369//4958 2370//4958 +f 2361//4959 2371//4959 2372//4959 +f 2367//4960 2373//4960 507//4960 +f 2250//4961 2372//4961 2368//4961 +f 2374//4962 2000//4962 1369//4962 +f 2375//4963 1301//1698 1300//1697 +f 2322//4756 2376//4964 1519//4757 +f 2364//4965 2377//4965 2365//4965 +f 2378//4966 2355//4966 2356//4966 +f 1495//4967 2379//4968 2380//4969 +f 2365//4970 2377//4970 2366//4970 +f 744//4971 1880//4971 477//4971 +f 2377//4972 2381//4973 2366//4974 +f 2353//4975 2355//4975 2382//4975 +f 1802//4976 287//4976 2162//4976 +f 477//4977 28//4977 743//4977 +f 1684//4978 1792//4978 2383//4978 +f 365//4979 1446//4979 464//4979 +f 1380//1908 1241//1545 1444//4980 +f 1019//4981 2333//4981 2373//4981 +f 569//4982 1893//4982 27//4982 +f 2362//4983 2363//4983 2374//4983 +f 1160//4984 446//4984 1893//4984 +f 569//4985 1160//4985 1893//4985 +f 1534//4986 1533//4986 2384//4986 +f 2385//4987 1218//4987 1219//4987 +f 2385//4988 1898//4988 1218//4988 +f 1898//4989 2377//4989 2364//4989 +f 1551//4990 1008//4990 1020//4990 +f 1767//4991 344//4991 1104//4991 +f 1495//4967 949//4992 2379//4968 +f 2381//4993 2354//4993 2353//4993 +f 424//4994 1218//4994 425//4994 +f 2386//4995 2387//4996 1517//4487 +f 2378//4997 2356//4997 2388//4997 +f 2105//4998 2335//4998 2337//4998 +f 2360//4999 2371//4999 2361//4999 +f 2355//5000 2389//5000 2382//5000 +f 949//5001 1299//5001 950//5001 +f 2355//5002 2378//5002 2389//5002 +f 2380//5003 2379//5003 2358//5003 +f 2368//5004 2370//5004 2251//5004 +f 1987//5005 2390//5005 2391//5005 +f 390//5006 2392//5006 1682//5006 +f 1218//5007 1900//5007 2103//5007 +f 2359//5008 1136//5008 1230//5008 +f 989//5009 535//5009 536//5009 +f 137//5010 1330//5010 160//5010 +f 324//5011 1126//5011 325//5011 +f 1282//5012 843//5012 845//5012 +f 418//5013 256//5013 255//5013 +f 1330//5014 2247//5014 1197//5014 +f 2393//5015 2357//5015 2354//5015 +f 2393//5016 1463//5016 2357//5016 +f 2357//5017 1463//5017 2165//5017 +f 2394//5018 2165//5019 2359//5020 +f 2357//5021 2165//5021 2394//5021 +f 2370//5022 1950//5022 2251//5022 +f 949//4992 948//5023 2379//4968 +f 2366//4974 2381//4973 2353//5024 +f 2335//5025 2395//5025 2336//5025 +f 2396//5026 77//5026 1197//5026 +f 2397//5027 2385//5027 1219//5027 +f 2385//5028 2398//5028 1898//5028 +f 2398//5029 2377//5029 1898//5029 +f 2389//5030 2378//5030 2399//5030 +f 2398//5031 2400//5031 2377//5031 +f 2400//5032 2381//5032 2377//5032 +f 2104//5033 1900//5033 1899//5033 +f 1330//5034 1197//5034 160//5034 +f 2247//5035 2396//5035 1197//5035 +f 77//5036 2396//5036 2401//5036 +f 1465//5037 2354//5037 2381//5037 +f 1465//5038 2393//5038 2354//5038 +f 1218//5039 2103//5039 712//5039 +f 1240//5040 1237//5040 2333//5040 +f 2123//5041 2169//5041 2402//5041 +f 2006//5042 2137//5042 2251//5042 +f 1019//5043 1240//5043 2333//5043 +f 949//5044 1495//5044 1306//5044 +f 2107//5045 1300//5045 2386//5045 +f 2247//5046 1350//5046 2396//5046 +f 1666//5047 1346//5047 2403//5047 +f 2005//5048 2336//5048 2137//5048 +f 2004//5049 1903//5049 2005//5049 +f 2404//5050 1903//5050 2004//5050 +f 1533//5051 1901//5051 2384//5051 +f 2061//5052 284//5052 2047//5052 +f 1350//5053 1987//5053 2396//5053 +f 2396//5054 1987//5054 2391//5054 +f 2391//5055 2405//5056 2396//5057 +f 2396//5057 2405//5056 2401//5058 +f 2359//5020 2380//5059 2394//5018 +f 1901//5060 2404//5060 2384//5060 +f 2107//5061 2386//5061 2106//5061 +f 2406//5062 1902//5063 2407//5064 +f 2405//5065 2408//5065 2401//5065 +f 2401//5066 2408//5066 2403//5066 +f 1464//5067 2381//5067 2400//5067 +f 1464//5068 1465//5068 2381//5068 +f 1140//5069 1139//5069 1147//5069 +f 2106//5070 2386//5070 2409//5070 +f 2106//5071 2409//5072 1534//5073 +f 2251//5074 2375//5074 2107//5074 +f 1384//5075 2407//5075 1471//5075 +f 2407//5076 1840//3127 1471//3129 +f 2408//5077 2410//5077 2403//5077 +f 2403//5078 2410//5078 1666//5078 +f 1900//5079 2104//5079 2103//5079 +f 35//5080 1257//5080 33//5080 +f 2409//5081 1517//5081 2411//5081 +f 1798//5082 2412//5082 1813//5082 +f 2410//5083 2413//5083 1666//5083 +f 2103//5084 2337//5085 1902//5063 +f 2373//5086 2333//5086 1368//5086 +f 2333//5087 1366//5087 1368//5087 +f 2409//5088 2386//4995 1517//4487 +f 2376//4964 1532//5089 2411//5090 +f 988//5091 1239//5091 989//5091 +f 2405//5092 2414//5093 2408//5094 +f 2408//5095 2414//5095 2410//5095 +f 2415//5096 333//5096 332//5096 +f 2386//4995 1300//5097 2387//4996 +f 1950//5098 1353//5098 2375//5098 +f 1845//5099 2413//5100 2410//5101 +f 1758//5102 1765//5102 1845//5102 +f 2337//5103 2103//5103 2105//5103 +f 1570//5104 816//5104 1265//5104 +f 1520//5105 2000//5105 1227//5105 +f 2391//5106 2390//5106 2405//5106 +f 576//5107 323//222 325//224 +f 2373//5108 1368//5109 2416//5110 +f 1305//5111 1219//5111 1172//5111 +f 760//5112 1577//5112 694//5112 +f 728//5113 760//5113 694//5113 +f 113//5114 1548//5114 25//5114 +f 1758//5115 1766//5115 1747//5115 +f 1548//5116 80//5116 25//5116 +f 1809//5117 893//5117 2417//5117 +f 2363//5118 536//5118 1225//5118 +f 1301//5119 1353//5120 1707//5121 +f 2390//5122 2418//5122 2405//5122 +f 2418//5123 2414//5093 2405//5092 +f 2414//5124 2419//5124 2410//5124 +f 2420//5125 1845//5099 2410//5101 +f 2420//5126 1758//5126 1845//5126 +f 2399//5127 2421//5127 1948//5127 +f 1305//5128 2397//5128 1219//5128 +f 2421//5129 1949//5129 1948//5129 +f 1746//5130 1780//5130 1790//5130 +f 1440//5131 1413//5131 184//5131 +f 1445//5132 365//5132 367//5132 +f 893//5133 2376//5133 2322//5133 +f 332//5134 334//1878 1353//1877 +f 2410//5135 2419//5135 2420//5135 +f 2373//5108 2416//5110 507//5136 +f 984//5137 356//5137 267//5137 +f 1014//5138 263//5138 230//5138 +f 1480//5139 1014//5139 230//5139 +f 2411//5140 1517//5140 1519//5140 +f 2376//4964 2411//5090 1519//4757 +f 2422//5141 2370//5141 2369//5141 +f 1301//5142 1707//3599 1302//4488 +f 2417//5143 893//945 892//944 +f 1822//5144 2390//5144 1942//5144 +f 1480//5145 1015//5145 1014//5145 +f 795//5146 1666//5146 2413//5146 +f 2403//5147 1346//5147 2401//5147 +f 893//5148 1809//5149 2376//5150 +f 2417//5151 892//1576 1469//4853 +f 2423//5152 2414//5152 2418//5152 +f 2423//5153 2419//5153 2414//5153 +f 2420//5154 1766//5154 1758//5154 +f 1346//5155 77//5155 2401//5155 +f 2424//5156 2400//5156 2398//5156 +f 2424//5157 1499//5157 2400//5157 +f 2395//5158 2360//5158 2336//5158 +f 1463//5159 1076//5159 1136//5159 +f 1684//5160 1349//5160 1348//5160 +f 1546//5161 1829//5161 1547//5161 +f 2419//5162 2351//5162 2420//5162 +f 2420//5163 2351//5163 1766//5163 +f 245//173 648//5164 246//174 +f 334//5165 2425//5165 1354//5165 +f 2375//4963 1300//1697 2107//5166 +f 1499//5167 1464//5167 2400//5167 +f 295//5168 947//5168 649//5168 +f 1009//5169 1271//5170 114//5171 +f 283//5172 282//5172 1009//5172 +f 1271//5173 2426//5173 1489//5173 +f 1548//5174 1829//5174 1546//5174 +f 1353//5175 1354//5175 1707//5175 +f 989//5176 536//5176 2363//5176 +f 2162//5177 2418//5177 2390//5177 +f 2162//5178 2423//5178 2418//5178 +f 2061//5179 2427//5180 284//5181 +f 2425//5182 2327//5182 1354//5182 +f 1109//2460 1645//3166 1281//2458 +f 282//5183 2426//5183 1009//5183 +f 113//5184 1489//5184 1548//5184 +f 1950//5185 332//5134 1353//1877 +f 2162//5186 2390//5186 1822//5186 +f 990//5187 989//5187 2363//5187 +f 1436//5188 2393//5188 1465//5188 +f 1436//5189 1463//5189 2393//5189 +f 1489//5190 2428//5190 1548//5190 +f 2428//5191 1829//5191 1548//5191 +f 1226//5192 1225//5193 169//418 +f 1291//5194 2423//5194 2162//5194 +f 2419//5195 1843//5196 2351//5197 +f 1843//5196 1491//5198 2351//5197 +f 2379//5199 2362//5200 2358//5201 +f 2372//5202 2371//5202 2369//5202 +f 1436//5203 1464//5203 1437//5203 +f 284//5204 2429//5204 282//5204 +f 2430//5205 2431//5206 282//5207 +f 282//5208 2431//5208 2426//5208 +f 1235//5209 495//5209 1562//5209 +f 1732//5210 1608//5210 1607//5210 +f 1802//5211 2162//5211 1822//5211 +f 2432//5212 2419//5212 2423//5212 +f 2419//5213 2432//5213 1843//5213 +f 2362//5200 2374//5214 2358//5201 +f 2421//5215 2378//5215 2388//5215 +f 2336//5216 2361//5216 2137//5216 +f 2427//5217 2429//5217 284//5217 +f 2429//5218 2430//5205 282//5207 +f 2367//5219 507//398 269//397 +f 1133//5220 2407//5220 1444//5220 +f 1869//5221 1662//5221 436//5221 +f 2432//5222 2423//5222 1291//5222 +f 2250//5223 2368//5223 2251//5223 +f 2433//5224 2389//5224 2399//5224 +f 2431//5225 2434//5225 2426//5225 +f 2337//5226 2336//5226 1903//5226 +f 229//5227 200//5227 1843//5227 +f 1801//5228 428//5229 2427//5230 +f 2426//5231 2435//5231 1489//5231 +f 2435//5232 2436//5232 1489//5232 +f 1489//5233 2436//5233 2428//5233 +f 1512//5234 2168//5234 2118//5234 +f 1020//5235 2373//5235 2367//5235 +f 268//5236 1020//5236 2367//5236 +f 2347//5237 577//5237 579//5237 +f 2437//5238 2432//5238 1291//5238 +f 2432//5239 229//5239 1843//5239 +f 1803//5240 1796//5240 1798//5240 +f 74//5241 579//5241 1754//5241 +f 428//5229 2438//5242 2427//5230 +f 2438//5243 2439//5243 2427//5243 +f 2427//5244 2439//5244 2429//5244 +f 2429//5218 2431//5206 2430//5205 +f 2431//5245 2440//5245 2434//5245 +f 2436//5246 2441//5246 2428//5246 +f 2441//5247 1829//5247 2428//5247 +f 2441//5248 1752//5248 1829//5248 +f 1682//5249 2442//5249 2068//5249 +f 107//2314 1460//2313 1263//5250 +f 2330//5251 2443//5251 74//5251 +f 76//5252 2330//5252 74//5252 +f 2429//5253 2439//5253 2431//5253 +f 2439//5254 2444//5254 2431//5254 +f 2431//5255 2444//5255 2440//5255 +f 1840//5256 1809//5256 1841//5256 +f 2384//5257 2404//5257 2106//5257 +f 1005//5258 2437//5258 1291//5258 +f 2437//5259 1480//5259 2432//5259 +f 2432//5260 1480//5260 229//5260 +f 1374//5261 1317//5261 1316//5261 +f 74//5262 2443//5262 579//5262 +f 1367//5263 1499//5263 2424//5263 +f 2440//5264 2435//5264 2426//5264 +f 2434//5265 2440//5265 2426//5265 +f 1471//5266 2417//5266 1469//5266 +f 2106//5267 2404//5267 2004//5267 +f 1798//5268 1783//5268 577//5268 +f 1034//5269 2437//5269 1005//5269 +f 1480//5270 230//5270 229//5270 +f 2389//5271 2371//5271 2360//5271 +f 2203//5272 2443//5272 2330//5272 +f 2438//5273 2445//5273 2439//5273 +f 2446//5274 2444//5274 2439//5274 +f 2444//5275 2447//5275 2440//5275 +f 2435//5276 2448//5276 2436//5276 +f 2436//5277 2448//5277 2441//5277 +f 2363//5278 1225//5278 2000//5278 +f 2387//4996 1300//5097 1302//4488 +f 1302//4488 1707//3599 2040//3598 +f 1034//5279 1480//5279 2437//5279 +f 2433//5280 2369//5280 2371//5280 +f 2433//5281 2422//5282 2369//5283 +f 2203//5284 2449//5284 2443//5284 +f 1177//5285 1178//5285 1459//5285 +f 1235//5286 1161//5286 568//5286 +f 2445//5287 2446//5287 2439//5287 +f 2447//5288 2450//5288 2440//5288 +f 2448//5289 2451//5289 2441//5289 +f 2452//5290 1752//5290 2441//5290 +f 2451//5291 2452//5291 2441//5291 +f 1752//5292 2452//5292 1445//5292 +f 1790//5293 1684//5293 1625//5293 +f 578//5294 577//5294 1783//5294 +f 1033//5295 1034//5295 1005//5295 +f 1230//5296 1206//5296 2359//5296 +f 1225//5193 536//419 169//418 +f 2389//5297 2433//5297 2371//5297 +f 1020//5298 1019//5298 2373//5298 +f 2453//5299 579//5299 2443//5299 +f 2449//5300 2453//5300 2443//5300 +f 2453//5301 2347//5301 579//5301 +f 1436//5302 1077//5302 1463//5302 +f 2435//5303 2454//5303 2448//5303 +f 2382//5304 2389//5304 2455//5304 +f 278//5305 1813//5305 2342//5305 +f 427//5306 2438//5306 428//5306 +f 2446//5307 2447//5308 2444//5309 +f 2440//5310 2450//5310 2454//5310 +f 2440//5311 2454//5311 2435//5311 +f 1149//5312 1367//5312 583//5312 +f 1354//5313 2327//5313 2321//5313 +f 2107//5314 2004//5314 2006//5314 +f 2068//5315 2442//5315 2438//5315 +f 427//5316 2068//5316 2438//5316 +f 2438//5317 2442//5317 2445//5317 +f 2452//5318 1446//5318 1445//5318 +f 1905//5319 2017//5319 1857//5319 +f 1662//5320 1661//5320 1615//5320 +f 2416//5321 2398//5322 2385//5323 +f 2416//5324 2424//5324 2398//5324 +f 1972//5325 2456//5326 1409//5327 +f 2457//5328 2203//5328 1409//5328 +f 2456//5329 2457//5329 1409//5329 +f 2457//5330 2449//5330 2203//5330 +f 2412//5331 2347//5331 2453//5331 +f 2347//5332 2412//5332 1798//5332 +f 40//5333 41//5333 2091//5333 +f 2445//5334 2442//5334 1682//5334 +f 2446//5307 2458//5335 2447//5308 +f 2459//5336 2452//5336 2451//5336 +f 2459//5337 1446//5337 2452//5337 +f 1349//5338 1094//5338 1347//5338 +f 2460//5339 2453//5339 2449//5339 +f 1682//5340 2392//5340 2445//5340 +f 2461//5341 2458//5341 2446//5341 +f 2458//5342 2462//5342 2447//5342 +f 2447//5343 2462//5343 2450//5343 +f 2448//5344 2459//5345 2451//5346 +f 1534//5347 2384//5347 2106//5347 +f 2399//5348 2378//5348 2421//5348 +f 2357//5349 2394//5349 2358//5349 +f 1899//5350 1898//5350 2364//5350 +f 2460//5351 2412//5351 2453//5351 +f 2399//5352 2422//5282 2433//5281 +f 1987//5353 1942//5353 2390//5353 +f 1594//5354 1628//5354 2019//5354 +f 2445//5355 2461//5355 2446//5355 +f 2463//5356 2450//5356 2462//5356 +f 2450//5357 2463//5358 2454//5359 +f 2464//5360 2459//5345 2448//5344 +f 2361//5361 2372//5361 2250//5361 +f 2137//5362 2361//5362 2250//5362 +f 1541//5363 1020//5363 268//5363 +f 2463//5358 2464//5364 2454//5359 +f 2454//5365 2464//5365 2448//5365 +f 1366//5366 1237//5366 582//5366 +f 53//5367 2456//5326 1972//5325 +f 2392//5368 2461//5368 2445//5368 +f 2091//5369 283//5369 40//5369 +f 2455//5370 2389//5370 2360//5370 +f 1305//5371 508//5371 2397//5371 +f 508//5372 2385//5372 2397//5372 +f 591//5373 590//5373 1704//5373 +f 2465//5374 2457//5374 2456//5374 +f 2466//5375 2449//5376 2457//5377 +f 2466//5378 2460//5379 2449//5380 +f 508//5381 2416//5321 2385//5323 +f 1366//5382 582//5382 1367//5382 +f 76//5383 451//5383 2330//5383 +f 1687//5384 2462//5384 2458//5384 +f 1687//5385 2463//5385 2462//5385 +f 1306//5386 1299//5386 949//5386 +f 2387//4996 1302//4488 1517//4487 +f 249//5387 560//5387 547//5387 +f 1687//5388 2352//5388 2463//5388 +f 2352//5389 2464//5389 2463//5389 +f 2467//5390 2468//5390 2459//5390 +f 2459//5391 2468//5391 1446//5391 +f 1149//5392 1499//5392 1367//5392 +f 2465//5393 2456//5393 53//5393 +f 830//5394 1615//5394 1661//5394 +f 2464//5395 2467//5395 2459//5395 +f 333//239 2425//5396 334//240 +f 1227//5397 2000//5397 1225//5397 +f 1966//5398 1947//5398 1469//5398 +f 52//5399 2469//5399 53//5399 +f 2469//5400 2465//5400 53//5400 +f 2412//5401 2460//5401 1813//5401 +f 2460//5402 2342//5402 1813//5402 +f 1481//2933 2343//5403 1780//2931 +f 401//5404 400//5404 414//5404 +f 162//5405 164//5405 151//5405 +f 1948//3372 1950//3374 2370//5406 +f 1523//5407 2470//5407 1937//5407 +f 2470//5408 2469//5408 1937//5408 +f 1937//5409 2469//5409 52//5409 +f 2342//5410 1792//5410 1780//5410 +f 1780//5411 1792//5411 1790//5411 +f 2467//5412 2464//5412 2352//5412 +f 2468//5413 464//5413 1446//5413 +f 1902//3264 2337//5414 1903//3265 +f 2107//5415 2006//5415 2251//5415 +f 1524//5416 2471//5416 1523//5416 +f 2471//5417 2470//5417 1523//5417 +f 2471//5418 2472//5419 2470//5420 +f 2472//5419 2469//5421 2470//5420 +f 2473//5422 2457//5422 2465//5422 +f 2473//5423 2466//5375 2457//5377 +f 2460//5424 2474//5424 2342//5424 +f 743//5425 27//5425 1893//5425 +f 1534//5073 2409//5072 2411//5426 +f 2469//5427 2475//5427 2465//5427 +f 2475//5428 2476//5429 2465//5430 +f 2473//5431 2477//5431 2466//5431 +f 2466//5378 2478//5432 2460//5379 +f 2478//5433 2474//5433 2460//5433 +f 2474//5434 1792//5434 2342//5434 +f 1733//5435 1737//5435 2352//5435 +f 1737//5436 2467//5436 2352//5436 +f 496//5437 464//5437 2468//5437 +f 2472//5419 2475//5438 2469//5421 +f 2467//5439 2479//5439 2468//5439 +f 2479//5440 496//5440 2468//5440 +f 1218//5441 1898//5441 1900//5441 +f 1528//5442 1553//5442 1524//5442 +f 1553//5443 2471//5443 1524//5443 +f 2471//5444 2480//5444 2472//5444 +f 2465//5445 2481//5445 2473//5445 +f 2474//5446 2383//5446 1792//5446 +f 1008//5447 1063//5447 1019//5447 +f 1532//5448 1534//5448 2411//5448 +f 1554//5449 1553//5449 1528//5449 +f 2482//5450 2465//5450 2476//5450 +f 2482//5451 2481//5451 2465//5451 +f 2483//5452 2473//5452 2481//5452 +f 2477//5453 2223//5453 2466//5453 +f 2223//5454 2478//5454 2466//5454 +f 2478//5455 2484//5456 2474//5457 +f 2383//5458 1349//5458 1684//5458 +f 2483//5459 2481//5459 2482//5459 +f 2485//5460 2383//5460 2474//5460 +f 2426//5461 1271//5461 1009//5461 +f 1607//5462 2467//5462 1737//5462 +f 1809//5149 1532//5463 2376//5150 +f 2486//5464 2480//5465 2471//5466 +f 2475//5467 2472//5467 2480//5467 +f 2487//5468 2475//5468 2480//5468 +f 2485//5469 1349//5469 2383//5469 +f 507//5470 2416//5470 508//5470 +f 1607//5471 2479//5471 2467//5471 +f 1841//5472 1809//5472 2417//5472 +f 2251//5473 1950//5473 2375//5473 +f 2379//5474 948//5474 2362//5474 +f 2488//5475 2480//5475 2486//5475 +f 2488//5476 2489//5476 2480//5476 +f 2489//5477 2487//5478 2480//5479 +f 2484//5456 2485//5480 2474//5457 +f 2485//5481 1352//5481 1349//5481 +f 859//5482 1940//5482 860//5482 +f 40//5483 1009//5169 114//5171 +f 2479//5484 2490//5484 496//5484 +f 496//5485 1128//5486 465//5487 +f 2380//5488 2359//5488 1495//5488 +f 1368//5489 1367//5489 2424//5489 +f 2486//5464 2471//5466 1553//5490 +f 1141//5491 2485//5480 2484//5456 +f 436//5492 1662//5492 1855//5492 +f 2427//5180 2061//5179 1801//5493 +f 1607//5494 2490//5494 2479//5494 +f 2490//5495 1128//5486 496//5485 +f 465//5496 593//5496 550//5496 +f 2491//5497 2488//5497 2486//5497 +f 2491//5498 2492//5498 2488//5498 +f 2492//5499 2493//5499 2488//5499 +f 2493//5500 2489//5500 2488//5500 +f 2124//5501 2476//5429 2475//5428 +f 2413//5502 1845//5502 795//5502 +f 2359//5503 1206//2082 1495//2081 +f 1607//5504 456//5504 2490//5504 +f 456//5505 1128//5505 2490//5505 +f 1841//5506 2417//5506 1471//5506 +f 1901//5507 1533//5507 1840//5507 +f 894//5508 2486//5508 1553//5508 +f 1140//5509 1352//5509 2485//5509 +f 2407//5510 1902//5510 1840//5510 +f 2394//5511 2380//5511 2358//5511 +f 1133//5512 712//5512 2407//5512 +f 2343//5513 2342//5513 1780//5513 +f 2494//5514 2486//5514 894//5514 +f 2494//5515 2491//5515 2486//5515 +f 2124//5516 2482//5517 2476//5518 +f 2482//5519 2495//5519 2483//5519 +f 2496//5520 2478//5520 2223//5520 +f 2496//5521 2497//5522 2478//5523 +f 2497//5522 2484//5524 2478//5523 +f 1140//5525 2485//5525 1141//5525 +f 1768//5526 1352//5526 1140//5526 +f 1352//5527 1768//5527 1094//5527 +f 712//5528 2406//5529 2407//5530 +f 1707//5531 1354//5531 1708//5531 +f 456//5532 592//5532 1128//5532 +f 948//5533 950//5533 2362//5533 +f 950//5534 990//5534 2362//5534 +f 1552//5535 894//5535 1553//5535 +f 2498//5536 2491//5536 2494//5536 +f 2499//5537 2493//5537 2492//5537 +f 2499//5538 2500//5538 2493//5538 +f 2124//5539 2475//5539 2487//5539 +f 2497//5540 1141//5541 2484//5542 +f 269//5543 508//5543 1305//5543 +f 2388//5544 1949//5544 2421//5544 +f 1950//3859 2115//3859 332//5545 +f 2227//5546 1394//5546 1530//5546 +f 2501//5547 2492//5547 2491//5547 +f 2501//5548 2499//5548 2492//5548 +f 1709//5549 2500//5549 2499//5549 +f 2502//5550 2482//5517 2124//5516 +f 2502//5551 2495//5551 2482//5551 +f 429//5552 365//5552 464//5552 +f 2416//5553 1368//5553 2424//5553 +f 712//5528 2103//5554 2406//5529 +f 2491//5555 2498//5555 2501//5555 +f 1903//5556 2336//5556 2005//5556 +f 2399//5557 1948//5557 2422//5557 +f 2372//5558 2369//5558 2368//5558 +f 1902//5559 1901//5559 1840//5559 +f 1901//5560 1903//5560 2404//5560 +f 2033//5561 2499//5561 2501//5561 +f 1983//5562 2497//5562 2496//5562 +f 2406//5062 2103//5084 1902//5063 +f 2498//5563 2306//5563 2501//5563 +f 2033//3585 1709//3584 2499//5564 +f 1983//5565 1141//5541 2497//5540 +f 2422//5566 1948//5566 2370//5566 +f 2115//5567 2415//5567 332//5567 +f 990//5568 950//5568 988//5568 +f 1518//5569 2501//5569 2306//5569 +f 1518//5570 2033//5570 2501//5570 +f 2124//5571 2123//5571 2502//5571 +f 2502//5572 2123//5572 2495//5572 +f 1370//4542 1983//4541 2496//5573 +f 1262//5574 894//5574 1552//5574 +f 2498//5575 2322//5575 2306//5575 +f 1139//5576 1141//5576 1983//5576 +f 1094//5577 1768//5577 1095//5577 +f 2363//5578 2000//5578 2374//5578 +f 1444//5579 2407//5579 1384//5579 +f 2375//5580 1353//5120 1301//5119 +f 893//5581 2494//5581 894//5581 +f 893//5582 2322//5582 2498//5582 +f 2494//5583 893//5583 2498//5583 +f 2123//5584 2402//5584 2495//5584 +f 1370//5585 2496//5585 2223//5585 +f 1687//5586 2458//5586 2503//5586 +f 2458//5587 2461//5587 2503//5587 +f 2461//5588 2392//5588 2503//5588 +f 2392//5589 390//5589 2503//5589 +f 390//5590 389//5590 2503//5590 +f 389//5591 1416//5591 2503//5591 +f 1416//5592 1687//5592 2503//5592 +f 2473//5593 2495//5593 2174//5593 +f 1899//5594 2455//5594 2105//5594 +f 2374//5595 2425//5595 2358//5595 +f 1708//5596 2321//5596 2077//5596 +f 2402//5597 2169//5597 2174//5597 +f 2174//5598 2223//5598 2473//5598 +f 2477//5599 2473//5599 2223//5599 +f 2483//5600 2495//5600 2473//5600 +f 2402//5601 2174//5601 2495//5601 +f 2360//5602 2395//5602 2335//5602 +f 2105//5603 2104//5603 1899//5603 +f 2360//5604 2335//5604 2455//5604 +f 2382//5605 2455//5605 2364//5605 +f 2366//5606 2353//5606 2364//5606 +f 1899//5607 2364//5607 2455//5607 +f 2335//5608 2105//5608 2455//5608 +f 2353//5609 2382//5609 2364//5609 +f 2115//5610 1949//5610 2356//5610 +f 2388//5611 2356//5611 1949//5611 +f 2358//5612 2425//5612 333//5612 +f 1369//5613 1278//5613 2327//5613 +f 2415//5614 2115//5614 2358//5614 +f 1369//5615 2327//5615 2425//5615 +f 2115//5616 2356//5616 2358//5616 +f 1369//5617 2425//5617 2374//5617 +f 333//5618 2415//5618 2358//5618 +f 2077//5619 2124//5619 1708//5619 +f 2487//5478 2489//5477 2493//5620 +f 2500//5621 1709//5621 2124//5621 +f 2487//5622 2493//5622 2500//5622 +f 1277//5623 1279//5623 2077//5623 +f 2124//5624 2487//5624 2500//5624 +f 1709//5625 1708//5625 2124//5625 +f 2321//5626 1277//5626 2077//5626 diff --git a/data/cube.obj b/data/cube.obj new file mode 100644 index 0000000..a7273c7 --- /dev/null +++ b/data/cube.obj @@ -0,0 +1,38 @@ +# Blender v2.83.4 OBJ File: '' +# www.blender.org +o Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/4/2 4/3/2 8/5/2 7/6/2 +f 7/6/3 8/5/3 6/7/3 5/8/3 +f 5/8/4 6/7/4 2/9/4 1/10/4 +f 3/11/5 7/6/5 5/8/5 1/12/5 +f 8/5/6 4/13/6 2/14/6 6/7/6 diff --git a/fractionnement.pro b/fractionnement.pro new file mode 100644 index 0000000..3ec2b4c --- /dev/null +++ b/fractionnement.pro @@ -0,0 +1,30 @@ +QT += core gui opengl +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +TARGET = fractionnement +TEMPLATE = app +DEFINES += QT_DEPRECATED_WARNINGS +CONFIG += debug + +unix:!macx { + LIBS += -L $$_PRO_FILE_PWD_/libs/OpenMesh/liblinux/ +} +macx { + LIBS += -L $$_PRO_FILE_PWD_/libs/OpenMesh/libosx/ +} +LIBS += -lglut -lGLU -lOpenMeshCore -lm + +INCLUDEPATH += libs/OpenMesh/inc/ src/ + +SOURCES += \ + src/main.cpp \ + src/mainwindow.cpp \ + src/meshviewerwidget.cpp \ + src/mymesh.cpp + +HEADERS += \ + src/mainwindow.h \ + src/meshviewerwidget.h \ + src/mymesh.h + +FORMS += \ + ui/mainwindow.ui diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Config.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Config.hh new file mode 100644 index 0000000..b1f1b08 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Config.hh @@ -0,0 +1,75 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Defines +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_CONFIG_HH +#define OPENMESH_GEOMETRY_CONFIG_HH + + +//== INCLUDES ================================================================= + +// OpenMesh Namespace Defines +#include + + +//== NAMESPACES =============================================================== + +#define BEGIN_NS_GEOMETRY namespace geometry { +#define END_NS_GEOMETRY } + + +//============================================================================= +#endif // OPENMESH_GEOMETRY_CONFIG_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/LoopSchemeMaskT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/LoopSchemeMaskT.hh new file mode 100644 index 0000000..feca771 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/LoopSchemeMaskT.hh @@ -0,0 +1,196 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef LOOPSCHEMEMASKT_HH +#define LOOPSCHEMEMASKT_HH + +#include +#include + +#include +#include + +namespace OpenMesh +{ + +/** implements cache for the weights of the original Loop scheme + supported: + - vertex projection rule on the next level + - vertex projection rule on the limit surface + - vertex projection rule on the k-th (level) step (Barthe, Kobbelt'2003) + - vertex tangents on the limit surface +*/ + +template +class LoopSchemeMaskT +{ +public: + enum { cache_size = cache_size_ }; + typedef T_ Scalar; + +protected: + + Scalar proj_weights_[cache_size]; + Scalar limit_weights_[cache_size]; + Scalar step_weights_[cache_size]; + std::vector tang0_weights_[cache_size]; + std::vector tang1_weights_[cache_size]; + +protected: + + inline static Scalar compute_proj_weight(uint _valence) + { + //return pow(3.0 / 2.0 + cos(2.0 * M_PI / _valence), 2) / 2.0 - 1.0; + double denom = (3.0 + 2.0*cos(2.0*M_PI/(double)_valence)); + double weight = (64.0*_valence)/(40.0 - denom*denom) - _valence; + return (Scalar) weight; + } + + inline static Scalar compute_limit_weight(uint _valence) + { + double proj_weight = compute_proj_weight(_valence); + proj_weight = proj_weight/(proj_weight + _valence);//normalize the proj_weight + double weight = (3.0/8.0)/(1.0 - proj_weight + (3.0/8.0)); + return (Scalar)weight; + } + + inline static Scalar compute_step_weight(uint _valence) + { + double proj_weight = compute_proj_weight(_valence); + proj_weight = proj_weight/(proj_weight + _valence);//normalize the proj_weight + double weight = proj_weight - (3.0/8.0); + return (Scalar)weight; + } + + inline static Scalar compute_tang0_weight(uint _valence, uint _ver_id) + { + return (Scalar)cos(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + inline static Scalar compute_tang1_weight(uint _valence, uint _ver_id) + { + return (Scalar)sin(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + void cache_weights() + { + proj_weights_[0] = 1; + for (uint k = 1; k < cache_size; ++k) + { + proj_weights_[k] = compute_proj_weight(k); + limit_weights_[k] = compute_limit_weight(k); + step_weights_[k] = compute_step_weight(k); + tang0_weights_[k].resize(k); + tang1_weights_[k].resize(k); + for (uint i = 0; i < k; ++i) + { + tang0_weights_[k][i] = compute_tang0_weight(k,i); + tang1_weights_[k][i] = compute_tang1_weight(k,i); + } + } + } + +public: + + LoopSchemeMaskT() + { + cache_weights(); + } + + inline Scalar proj_weight(uint _valence) const + { + assert(_valence < cache_size ); + return proj_weights_[_valence]; + } + + inline Scalar limit_weight(uint _valence) const + { + assert(_valence < cache_size ); + return limit_weights_[_valence]; + } + + inline Scalar step_weight(uint _valence, uint _step) const + { + assert(_valence < cache_size); + return pow(step_weights_[_valence], (int)_step);//can be precomputed + } + + inline Scalar tang0_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang0_weights_[_valence][_ver_id]; + } + + inline Scalar tang1_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang1_weights_[_valence][_ver_id]; + } + + void dump(uint _max_valency = cache_size - 1) const + { + assert(_max_valency <= cache_size - 1); + //CConsole::printf("(k : pw_k, lw_k): "); + for (uint i = 0; i <= _max_valency; ++i) + { + //CConsole::stream() << "(" << i << " : " << proj_weight(i) << ", " << limit_weight(i) << ", " << step_weight(i,1) << "), "; + } + //CConsole::printf("\n"); + } +}; + +typedef LoopSchemeMaskT LoopSchemeMaskDouble; +typedef SingletonT LoopSchemeMaskDoubleSingleton; + +}//namespace OpenMesh + +#endif//LOOPSCHEMEMASKT_HH + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/MathDefs.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/MathDefs.hh new file mode 100644 index 0000000..c61bb7d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/MathDefs.hh @@ -0,0 +1,172 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef MATHDEFS_HH +#define MATHDEFS_HH + +#include +#include + +#ifndef M_PI + #define M_PI 3.14159265359 +#endif + +namespace OpenMesh +{ + +/** comparison operators with user-selected precision control +*/ +template +inline bool is_zero(const T& _a, Real _eps) +{ return fabs(_a) < _eps; } + +template +inline bool is_eq(const T1& a, const T2& b, Real _eps) +{ return is_zero(a-b, _eps); } + +template +inline bool is_gt(const T1& a, const T2& b, Real _eps) +{ return (a > b) && !is_eq(a,b,_eps); } + +template +inline bool is_ge(const T1& a, const T2& b, Real _eps) +{ return (a > b) || is_eq(a,b,_eps); } + +template +inline bool is_lt(const T1& a, const T2& b, Real _eps) +{ return (a < b) && !is_eq(a,b,_eps); } + +template +inline bool is_le(const T1& a, const T2& b, Real _eps) +{ return (a < b) || is_eq(a,b,_eps); } + +/*const float flt_eps__ = 10*FLT_EPSILON; +const double dbl_eps__ = 10*DBL_EPSILON;*/ +const float flt_eps__ = (float)1e-05; +const double dbl_eps__ = 1e-09; + +inline float eps__(float) +{ return flt_eps__; } + +inline double eps__(double) +{ return dbl_eps__; } + +template +inline bool is_zero(const T& a) +{ return is_zero(a, eps__(a)); } + +template +inline bool is_eq(const T1& a, const T2& b) +{ return is_zero(a-b); } + +template +inline bool is_gt(const T1& a, const T2& b) +{ return (a > b) && !is_eq(a,b); } + +template +inline bool is_ge(const T1& a, const T2& b) +{ return (a > b) || is_eq(a,b); } + +template +inline bool is_lt(const T1& a, const T2& b) +{ return (a < b) && !is_eq(a,b); } + +template +inline bool is_le(const T1& a, const T2& b) +{ return (a < b) || is_eq(a,b); } + +/// Trigonometry/angles - related + +template +inline T sane_aarg(T _aarg) +{ + if (_aarg < -1) + { + _aarg = -1; + } + else if (_aarg > 1) + { + _aarg = 1; + } + return _aarg; +} + +/** returns the angle determined by its cos and the sign of its sin + result is positive if the angle is in [0:pi] + and negative if it is in [pi:2pi] +*/ +template +T angle(T _cos_angle, T _sin_angle) +{//sanity checks - otherwise acos will return nan + _cos_angle = sane_aarg(_cos_angle); + return (T) _sin_angle >= 0 ? acos(_cos_angle) : -acos(_cos_angle); +} + +template +inline T positive_angle(T _angle) +{ return _angle < 0 ? (2*M_PI + _angle) : _angle; } + +template +inline T positive_angle(T _cos_angle, T _sin_angle) +{ return positive_angle(angle(_cos_angle, _sin_angle)); } + +template +inline T deg_to_rad(const T& _angle) +{ return M_PI*(_angle/180); } + +template +inline T rad_to_deg(const T& _angle) +{ return 180*(_angle/M_PI); } + +inline double log_(double _value) +{ return log(_value); } + +}//namespace OpenMesh + +#endif//MATHDEFS_HH diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/NormalConeT.cc b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/NormalConeT.cc new file mode 100644 index 0000000..d5281bf --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/NormalConeT.cc @@ -0,0 +1,161 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + + + +//============================================================================= +// +// CLASS NormalConeT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_NORMALCONE_C + +//== INCLUDES ================================================================= + +#include +#include "NormalConeT.hh" + +#ifdef max +# undef max +#endif + +#ifdef min +# undef min +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +template +NormalConeT:: +NormalConeT(const Vec3& _center_normal, Scalar _angle) + : center_normal_(_center_normal), angle_(_angle) +{ +} + + +//---------------------------------------------------------------------------- + + +template +Scalar +NormalConeT:: +max_angle(const Vec3& _norm) const +{ + Scalar dotp = (center_normal_ | _norm); + return (dotp >= 1.0 ? 0.0 : (dotp <= -1.0 ? M_PI : acos(dotp))) + + angle_; +} + + +//---------------------------------------------------------------------------- + + +template +Scalar +NormalConeT:: +max_angle(const NormalConeT& _cone) const +{ + Scalar dotp = (center_normal_ | _cone.center_normal_); + Scalar centerAngle = dotp >= 1.0 ? 0.0 : (dotp <= -1.0 ? M_PI : acos(dotp)); + Scalar sideAngle0 = std::max(angle_-centerAngle, _cone.angle_); + Scalar sideAngle1 = std::max(_cone.angle_-centerAngle, angle_); + + return centerAngle + sideAngle0 + sideAngle1; +} + + +//---------------------------------------------------------------------------- + + +template +void +NormalConeT:: +merge(const NormalConeT& _cone) +{ + Scalar dotp = (center_normal_ | _cone.center_normal_); + + if (fabs(dotp) < 0.99999f) + { + // new angle + Scalar centerAngle = acos(dotp); + Scalar minAngle = std::min(-angle(), centerAngle - _cone.angle()); + Scalar maxAngle = std::max( angle(), centerAngle + _cone.angle()); + angle_ = (maxAngle - minAngle) * Scalar(0.5f); + + // axis by SLERP + Scalar axisAngle = Scalar(0.5f) * (minAngle + maxAngle); + center_normal_ = ((center_normal_ * sin(centerAngle-axisAngle) + + _cone.center_normal_ * sin(axisAngle)) + / sin(centerAngle)); + } + else + { + // axes point in same direction + if (dotp > 0.0f) + angle_ = std::max(angle_, _cone.angle_); + + // axes point in opposite directions + else + angle_ = Scalar(2.0f * M_PI); + } +} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/NormalConeT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/NormalConeT.hh new file mode 100644 index 0000000..796bbdd --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/NormalConeT.hh @@ -0,0 +1,132 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + + + +//============================================================================= +// +// CLASS NormalCone +// +//============================================================================= + + +#ifndef OPENMESH_NORMALCONE_HH +#define OPENMESH_NORMALCONE_HH + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** /class NormalCone NormalCone.hh + + NormalCone that can be merged with other normal cones. Provides + the center normal and the opening angle. +**/ + +template +class NormalConeT +{ +public: + + // typedefs + typedef VectorT Vec3; + + + //! default constructor (not initialized) + NormalConeT() {} + + //! Initialize cone with center (unit vector) and angle (radius in radians) + NormalConeT(const Vec3& _center_normal, Scalar _angle=0.0); + + //! return max. distance (radians) unit vector to cone (distant side) + Scalar max_angle(const Vec3&) const; + + //! return max. distance (radians) cone to cone (distant sides) + Scalar max_angle(const NormalConeT&) const; + + //! merge _cone; this instance will then enclose both former cones + void merge(const NormalConeT&); + + //! returns center normal + const Vec3& center_normal() const { return center_normal_; } + + //! returns size of cone (radius in radians) + inline Scalar angle() const { return angle_; } + +private: + + Vec3 center_normal_; + Scalar angle_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_NORMALCONE_C) +#define OPENMESH_NORMALCONE_TEMPLATES +#include "NormalConeT.cc" +#endif +//============================================================================= +#endif // OPENMESH_NORMALCONE_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Plane3d.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Plane3d.hh new file mode 100644 index 0000000..50e9ced --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Plane3d.hh @@ -0,0 +1,124 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS Plane3D +// +//============================================================================= + + +#ifndef OPENMESH_PLANE3D_HH +#define OPENMESH_PLANE3D_HH + + +//== INCLUDES ================================================================= + +#include + + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \class Plane3d Plane3d.hh + + ax + by + cz + d = 0 +*/ + + +class OPENMESHDLLEXPORT Plane3d +{ +public: + + typedef OpenMesh::Vec3f vector_type; + typedef vector_type::value_type value_type; + +public: + + Plane3d() + : d_(0) + { } + + Plane3d(const vector_type &_dir, const vector_type &_pnt) + : n_(_dir), d_(0) + { + n_.normalize(); + d_ = -dot(n_,_pnt); + } + + value_type signed_distance(const OpenMesh::Vec3f &_p) + { + return dot(n_ , _p) + d_; + } + + // back compatibility + value_type singed_distance(const OpenMesh::Vec3f &point) + { return signed_distance( point ); } + +public: + + vector_type n_; + value_type d_; + +}; + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PLANE3D_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/QuadricT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/QuadricT.hh new file mode 100644 index 0000000..8d2943a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/QuadricT.hh @@ -0,0 +1,291 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Core/Geometry/QuadricT.hh + + */ + +//============================================================================= +// +// CLASS QuadricT +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_QUADRIC_HH +#define OPENMESH_GEOMETRY_QUADRIC_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { //BEGIN_NS_OPENMESH +namespace Geometry { //BEGIN_NS_GEOMETRY + + +//== CLASS DEFINITION ========================================================= + + +/** /class QuadricT Geometry/QuadricT.hh + + Stores a quadric as a 4x4 symmetrix matrix. Used by the + error quadric based mesh decimation algorithms. +**/ + +template +class QuadricT +{ +public: + typedef Scalar value_type; + typedef QuadricT type; + typedef QuadricT Self; + // typedef VectorInterface > Vec3; + // typedef VectorInterface > Vec4; + //typedef Vector3Elem Vec3; + //typedef Vector4Elem Vec4; + + /// construct with upper triangle of symmetrix 4x4 matrix + QuadricT(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + : a_(_a), b_(_b), c_(_c), d_(_d), + e_(_e), f_(_f), g_(_g), + h_(_h), i_(_i), + j_(_j) + { + } + + + /// constructor from given plane equation: ax+by+cz+d_=0 + QuadricT( Scalar _a=0.0, Scalar _b=0.0, Scalar _c=0.0, Scalar _d=0.0 ) + : a_(_a*_a), b_(_a*_b), c_(_a*_c), d_(_a*_d), + e_(_b*_b), f_(_b*_c), g_(_b*_d), + h_(_c*_c), i_(_c*_d), + j_(_d*_d) + {} + + template + QuadricT(const _Point& _pt) + { + set_distance_to_point(_pt); + } + + template + QuadricT(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n,_p); + } + + //set operator + void set(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + { + a_ = _a; b_ = _b; c_ = _c; d_ = _d; + e_ = _e; f_ = _f; g_ = _g; + h_ = _h; i_ = _i; + j_ = _j; + } + + //sets the quadric representing the squared distance to _pt + template + void set_distance_to_point(const _Point& _pt) + { + set(1, 0, 0, -_pt[0], + 1, 0, -_pt[1], + 1, -_pt[2], + dot(_pt,_pt)); + } + + //sets the quadric representing the squared distance to the plane [_a,_b,_c,_d] + void set_distance_to_plane(Scalar _a, Scalar _b, Scalar _c, Scalar _d) + { + a_ = _a*_a; b_ = _a*_b; c_ = _a*_c; d_ = _a*_d; + e_ = _b*_b; f_ = _b*_c; g_ = _b*_d; + h_ = _c*_c; i_ = _c*_d; + j_ = _d*_d; + } + + //sets the quadric representing the squared distance to the plane + //determined by the normal _n and the point _p + template + void set_distance_to_plane(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n[0], _n[1], _n[2], -dot(_n,_p)); + } + + /// set all entries to zero + void clear() { a_ = b_ = c_ = d_ = e_ = f_ = g_ = h_ = i_ = j_ = 0.0; } + + /// add quadrics + QuadricT& operator+=( const QuadricT& _q ) + { + a_ += _q.a_; b_ += _q.b_; c_ += _q.c_; d_ += _q.d_; + e_ += _q.e_; f_ += _q.f_; g_ += _q.g_; + h_ += _q.h_; i_ += _q.i_; + j_ += _q.j_; + return *this; + } + + QuadricT operator+(const QuadricT& _other ) const + { + QuadricT result = *this; + return result += _other; + } + + + /// multiply by scalar + QuadricT& operator*=( Scalar _s) + { + a_ *= _s; b_ *= _s; c_ *= _s; d_ *= _s; + e_ *= _s; f_ *= _s; g_ *= _s; + h_ *= _s; i_ *= _s; + j_ *= _s; + return *this; + } + + QuadricT operator*(Scalar _s) const + { + QuadricT result = *this; + return result *= _s; + } + + /// multiply 4D vector from right: Q*v + template + _Vec4 operator*(const _Vec4& _v) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return _Vec4(x*a_ + y*b_ + z*c_ + w*d_, + x*b_ + y*e_ + z*f_ + w*g_, + x*c_ + y*f_ + z*h_ + w*i_, + x*d_ + y*g_ + z*i_ + w*j_); + } + + /// evaluate quadric Q at (3D or 4D) vector v: v*Q*v + template + Scalar operator()(const _Vec& _v) const + { + return evaluate(_v, GenProg::Int2Type::size_>()); + } + + Scalar a() const { return a_; } + Scalar b() const { return b_; } + Scalar c() const { return c_; } + Scalar d() const { return d_; } + Scalar e() const { return e_; } + Scalar f() const { return f_; } + Scalar g() const { return g_; } + Scalar h() const { return h_; } + Scalar i() const { return i_; } + Scalar j() const { return j_; } + + Scalar xx() const { return a_; } + Scalar xy() const { return b_; } + Scalar xz() const { return c_; } + Scalar xw() const { return d_; } + Scalar yy() const { return e_; } + Scalar yz() const { return f_; } + Scalar yw() const { return g_; } + Scalar zz() const { return h_; } + Scalar zw() const { return i_; } + Scalar ww() const { return j_; } + +protected: + + /// evaluate quadric Q at 3D vector v: v*Q*v + template + Scalar evaluate(const _Vec3& _v, GenProg::Int2Type<3>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y + + h_*z*z + 2.0*i_*z + + j_; + } + + /// evaluate quadric Q at 4D vector v: v*Q*v + template + Scalar evaluate(const _Vec4& _v, GenProg::Int2Type<4>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x*w + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y*w + + h_*z*z + 2.0*i_*z*w + + j_*w*w; + } + +private: + + Scalar a_, b_, c_, d_, + e_, f_, g_, + h_, i_, + j_; +}; + + +/// Quadric using floats +typedef QuadricT Quadricf; + +/// Quadric using double +typedef QuadricT Quadricd; + + +//============================================================================= +} // END_NS_GEOMETRY +} // END_NS_OPENMESH +//============================================================================ +#endif // OPENMESH_GEOMETRY_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Vector11T.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Vector11T.hh new file mode 100644 index 0000000..b9113a6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/Vector11T.hh @@ -0,0 +1,886 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ +#define OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This header is not needed by this file but expected by others including +// this file. +#include + + +/* + * Helpers for VectorT + */ +namespace { + +template +struct are_convertible_to; + +template +struct are_convertible_to { + static constexpr bool value = std::is_convertible::value + && are_convertible_to::value; +}; + +template +struct are_convertible_to : public std::is_convertible { +}; +} + +namespace OpenMesh { + +template +class VectorT { + + static_assert(DIM >= 1, "VectorT requires positive dimensionality."); + + private: + using container = std::array; + container values_; + + public: + + //---------------------------------------------------------------- class info + + /// the type of the scalar used in this template + typedef Scalar value_type; + + /// type of this vector + typedef VectorT vector_type; + + /// returns dimension of the vector (deprecated) + static constexpr int dim() { + return DIM; + } + + /// returns dimension of the vector + static constexpr size_t size() { + return DIM; + } + + static constexpr const size_t size_ = DIM; + + //-------------------------------------------------------------- constructors + + // Converting constructor: Constructs the vector from DIM values (of + // potentially heterogenous types) which are all convertible to Scalar. + template::type, + typename = typename std::enable_if< + are_convertible_to::value>::type> + constexpr VectorT(T v, Ts... vs) : values_ { {static_cast(v), static_cast(vs)...} } { + static_assert(sizeof...(Ts)+1 == DIM, + "Invalid number of components specified in constructor."); + static_assert(are_convertible_to::value, + "Not all components are convertible to Scalar."); + } + + /// default constructor creates uninitialized values. + constexpr VectorT() {} + + /** + * Creates a vector with all components set to v. + */ + explicit VectorT(const Scalar &v) { + vectorize(v); + } + + VectorT(const VectorT &rhs) = default; + VectorT(VectorT &&rhs) = default; + VectorT &operator=(const VectorT &rhs) = default; + VectorT &operator=(VectorT &&rhs) = default; + + /** + * Only for 4-component vectors with division operator on their + * Scalar: Dehomogenization. + */ + template + auto homogenized() const -> + typename std::enable_if()/std::declval()), DIM>>::type { + static_assert(D == DIM, "D and DIM need to be identical. (Never " + "override the default template arguments.)"); + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return VectorT( + values_[0]/values_[3], + values_[1]/values_[3], + values_[2]/values_[3], + 1); + } + + /// construct from a value array or any other iterator + template(), void(), + ++std::declval(), void())> + explicit VectorT(Iterator it) { + std::copy_n(it, DIM, values_.begin()); + } + + /// copy & cast constructor (explicit) + template::value>> + explicit VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template::value>> + vector_type& operator=(const VectorT& _rhs) { + std::transform(_rhs.cbegin(), _rhs.cend(), + this->begin(), [](OtherScalar rhs) { + return static_cast(std::move(rhs)); + }); + return *this; + } + + /// access to Scalar array + Scalar* data() { return values_.data(); } + + /// access to const Scalar array + const Scalar* data() const { return values_.data(); } + + //----------------------------------------------------------- element access + + /// get i'th element read-write + Scalar& operator[](size_t _i) { + assert(_i < DIM); + return values_[_i]; + } + + /// get i'th element read-only + const Scalar& operator[](size_t _i) const { + assert(_i < DIM); + return values_[_i]; + } + + //---------------------------------------------------------------- comparsion + + /// component-wise comparison + bool operator==(const vector_type& _rhs) const { + return std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin()); + } + + /// component-wise comparison + bool operator!=(const vector_type& _rhs) const { + return !std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin()); + } + + //---------------------------------------------------------- scalar operators + + /// component-wise self-multiplication with scalar + template + auto operator*=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] * _s), Scalar>::value, + VectorT&>::type { + for (auto& e : *this) { + e *= _s; + } + return *this; + } + + /// component-wise self-division by scalar + template + auto operator/=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] / _s), Scalar>::value, + VectorT&>::type { + for (auto& e : *this) { + e /= _s; + } + return *this; + } + + /// component-wise multiplication with scalar + template + typename std::enable_if() * std::declval()), + Scalar>::value, + VectorT>::type + operator*(const OtherScalar& _s) const { + return vector_type(*this) *= _s; + } + + /// component-wise division by with scalar + template + typename std::enable_if() / std::declval()), + Scalar>::value, + VectorT>::type + operator/(const OtherScalar& _s) const { + return vector_type(*this) /= _s; + } + + //---------------------------------------------------------- vector operators + + /// component-wise self-multiplication + template + auto operator*=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] *= _rhs.data()[i]; + } + return *this; + } + + /// component-wise self-division + template + auto operator/=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] /= _rhs.data()[i]; + } + return *this; + } + + /// vector difference from this + template + auto operator-=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] -= _rhs.data()[i]; + } + return *this; + } + + /// vector self-addition + template + auto operator+=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] += _rhs.data()[i]; + } + return *this; + } + + /// component-wise vector multiplication + template + auto operator*(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) *= _rhs; + } + + /// component-wise vector division + template + auto operator/(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) /= _rhs; + } + + /// component-wise vector addition + template + auto operator+(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) += _rhs; + } + + /// component-wise vector difference + template + auto operator-(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) -= _rhs; + } + + /// unary minus + vector_type operator-(void) const { + vector_type v; + std::transform(values_.begin(), values_.end(), v.values_.begin(), + [](const Scalar &s) { return -s; }); + return v; + } + + /// cross product: only defined for Vec3* as specialization + /// \see OpenMesh::cross + template + auto operator% (const VectorT &_rhs) const -> + typename std::enable_if>::type { + return { + values_[1] * _rhs[2] - values_[2] * _rhs[1], + values_[2] * _rhs[0] - values_[0] * _rhs[2], + values_[0] * _rhs[1] - values_[1] * _rhs[0] + }; + } + + /// compute scalar product + /// \see OpenMesh::dot + template + auto operator|(const VectorT& _rhs) const -> + decltype(*this->data() * *_rhs.data()) { + + return std::inner_product(begin() + 1, begin() + DIM, _rhs.begin() + 1, + *begin() * *_rhs.begin()); + } + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + + /// compute squared euclidean norm + template + decltype(std::declval() * std::declval()) sqrnorm() const { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + typedef decltype(values_[0] * values_[0]) RESULT; + return std::accumulate(values_.cbegin() + 1, values_.cend(), + values_[0] * values_[0], + [](const RESULT &l, const Scalar &r) { return l + r * r; }); + } + + /// compute euclidean norm + template + auto norm() const -> + decltype(std::sqrt(std::declval>().sqrnorm())) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return std::sqrt(sqrnorm()); + } + + template + auto length() const -> + decltype(std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return norm(); + } + + /** normalize vector, return normalized vector + */ + template + auto normalize() -> + decltype(*this /= std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this /= norm(); + } + + /** return normalized vector + */ + template + auto normalized() const -> + decltype(*this / std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + template + typename std::enable_if< + sizeof(decltype( + static_cast(0), + std::declval>().norm())) >= 0, + vector_type&>::type + normalize_cond() { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + auto n = norm(); + if (n != static_cast(0)) { + *this /= n; + } + return *this; + } + + //@} + + //------------------------------------------------------------ euclidean norm + + /// \name Non-Euclidean norm calculations + //@{ + + /// compute L1 (Manhattan) norm + Scalar l1_norm() const { + return std::accumulate( + values_.cbegin() + 1, values_.cend(), values_[0]); + } + + /// compute l8_norm + Scalar l8_norm() const { + return max_abs(); + } + + //@} + + //------------------------------------------------------------ max, min, mean + + /// \name Minimum maximum and mean + //@{ + + /// return the maximal component + Scalar max() const { + return *std::max_element(values_.cbegin(), values_.cend()); + } + + /// return the maximal absolute component + Scalar max_abs() const { + return std::abs( + *std::max_element(values_.cbegin(), values_.cend(), + [](const Scalar &a, const Scalar &b) { + return std::abs(a) < std::abs(b); + })); + } + + /// return the minimal component + Scalar min() const { + return *std::min_element(values_.cbegin(), values_.cend()); + } + + /// return the minimal absolute component + Scalar min_abs() const { + return std::abs( + *std::min_element(values_.cbegin(), values_.cend(), + [](const Scalar &a, const Scalar &b) { + return std::abs(a) < std::abs(b); + })); + } + + /// return arithmetic mean + Scalar mean() const { + return l1_norm()/DIM; + } + + /// return absolute arithmetic mean + Scalar mean_abs() const { + return std::accumulate(values_.cbegin() + 1, values_.cend(), + std::abs(values_[0]), + [](const Scalar &l, const Scalar &r) { + return l + std::abs(r); + }) / DIM; + } + + /// minimize values: same as *this = min(*this, _rhs), but faster + vector_type& minimize(const vector_type& _rhs) { + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [](const Scalar &l, const Scalar &r) { + return std::min(l, r); + }); + return *this; + } + + /// minimize values and signalize coordinate minimization + bool minimized(const vector_type& _rhs) { + bool result = false; + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [&result](const Scalar &l, const Scalar &r) { + if (l < r) { + return l; + } else { + result = true; + return r; + } + }); + return result; + } + + /// maximize values: same as *this = max(*this, _rhs), but faster + vector_type& maximize(const vector_type& _rhs) { + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [](const Scalar &l, const Scalar &r) { + return std::max(l, r); + }); + return *this; + } + + /// maximize values and signalize coordinate maximization + bool maximized(const vector_type& _rhs) { + bool result = false; + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [&result](const Scalar &l, const Scalar &r) { + if (l > r) { + return l; + } else { + result = true; + return r; + } + }); + return result; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) const { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) const { + return vector_type(*this).maximize(_rhs); + } + + //@} + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; + std::transform(result.values_.cbegin(), result.values_.cend(), + result.values_.begin(), _func); + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { + std::fill(values_.begin(), values_.end(), _s); + return *this; + } + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { + return std::lexicographical_compare( + values_.begin(), values_.end(), + _rhs.values_.begin(), _rhs.values_.end()); + } + + /// swap with another vector + void swap(VectorT& _other) + noexcept(noexcept(std::swap(values_, _other.values_))) { + std::swap(values_, _other.values_); + } + + //------------------------------------------------------------ component iterators + + /// \name Component iterators + //@{ + + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + using reverse_iterator = typename container::reverse_iterator; + using const_reverse_iterator = typename container::const_reverse_iterator; + + iterator begin() noexcept { return values_.begin(); } + const_iterator begin() const noexcept { return values_.cbegin(); } + const_iterator cbegin() const noexcept { return values_.cbegin(); } + + iterator end() noexcept { return values_.end(); } + const_iterator end() const noexcept { return values_.cend(); } + const_iterator cend() const noexcept { return values_.cend(); } + + reverse_iterator rbegin() noexcept { return values_.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return values_.crbegin(); } + const_reverse_iterator crbegin() const noexcept { return values_.crbegin(); } + + reverse_iterator rend() noexcept { return values_.rend(); } + const_reverse_iterator rend() const noexcept { return values_.crend(); } + const_reverse_iterator crend() const noexcept { return values_.crend(); } + + //@} +}; + +/// Component wise multiplication from the left +template +auto operator*(const OtherScalar& _s, const VectorT &rhs) -> + decltype(rhs.operator*(_s)) { + + return rhs * _s; +} + +/// output a vector by printing its space-separated compontens +template +auto operator<<(std::ostream& os, const VectorT &_vec) -> + typename std::enable_if< + sizeof(decltype(os << _vec[0])) >= 0, std::ostream&>::type { + + os << _vec[0]; + for (int i = 1; i < DIM; ++i) { + os << " " << _vec[i]; + } + return os; +} + +/// read the space-separated components of a vector from a stream +template +auto operator>> (std::istream& is, VectorT &_vec) -> + typename std::enable_if< + sizeof(decltype(is >> _vec[0])) >= 0, std::istream &>::type { + for (int i = 0; i < DIM; ++i) + is >> _vec[i]; + return is; +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +Scalar dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +auto +cross(const VectorT& _v1, const VectorT& _v2) -> + decltype(_v1 % _v2) { + return (_v1 % _v2); +} + +/// \relates OpenMesh::VectorT +/// non-member swap +template +void swap(VectorT& _v1, VectorT& _v2) +noexcept(noexcept(_v1.swap(_v2))) { + _v1.swap(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member norm +template +Scalar norm(const VectorT& _v) { + return _v.norm(); +} + +/// \relates OpenMesh::VectorT +/// non-member sqrnorm +template +Scalar sqrnorm(const VectorT& _v) { + return _v.sqrnorm(); +} +/// \relates OpenMesh::VectorT +/// non-member vectorize +template +VectorT& vectorize(VectorT& _v, OtherScalar const& _val) { + return _v.vectorize(_val); +} + +/// \relates OpenMesh::VectorT +/// non-member normalize +template +VectorT& normalize(VectorT& _v) { + return _v.normalize(); +} + +/// \relates OpenMesh::VectorT +/// non-member maximize +template +VectorT& maximize(VectorT& _v1, VectorT& _v2) { + return _v1.maximize(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member minimize +template +VectorT& minimize(VectorT& _v1, VectorT& _v2) { + return _v1.minimize(_v2); +} + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + +} // namespace OpenMesh + +/** + * Literal operator for inline specification of colors in HTML syntax. + * + * Example: + * \code{.cpp} + * OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor; + * \endcode + */ +constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) { + return OpenMesh::Vec4f( + ((raw_color >> 24) & 0xFF) / 255.0f, + ((raw_color >> 16) & 0xFF) / 255.0f, + ((raw_color >> 8) & 0xFF) / 255.0f, + ((raw_color >> 0) & 0xFF) / 255.0f); +} + +#endif /* OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ */ diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/VectorT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/VectorT.hh new file mode 100644 index 0000000..3384332 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/VectorT.hh @@ -0,0 +1,440 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS VectorT +// +//============================================================================= + +// Don't parse this header file with doxygen since +// for some reason (obviously due to a bug in doxygen, +// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182) +// macro expansion and preprocessor defines +// don't work properly. + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1900)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) +#include "Vector11T.hh" +#else +#ifndef DOXYGEN + +#ifndef OPENMESH_VECTOR_HH +#define OPENMESH_VECTOR_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && defined(__SSE__) +#include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** The N values of the template Scalar type are the only data members + of the class VectorT. This guarantees 100% compatibility + with arrays of type Scalar and size N, allowing us to define the + cast operators to and from arrays and array pointers. + + In addition, this class will be specialized for Vec4f to be 16 bit + aligned, so that aligned SSE instructions can be used on these + vectors. +*/ +template class VectorDataT { + public: + Scalar values_[N]; +}; + + +#if defined(__GNUC__) && defined(__SSE__) + +/// This specialization enables us to use aligned SSE instructions. +template<> class VectorDataT { + public: + union { + __m128 m128; + float values_[4]; + }; +}; + +#endif + + + + +//== CLASS DEFINITION ========================================================= + + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i + A vector is an array of \ values of type \. + The actual data is stored in an VectorDataT, this class just adds + the necessary operators. +*/ +#include "VectorT_inc.hh" + +#undef DIM +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED +#undef unroll + + + + +//== PARTIAL TEMPLATE SPECIALIZATIONS ========================================= +#if OM_PARTIAL_SPECIALIZATION + + +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT + + +#define DIM 2 +#define unroll(expr) expr(0) expr(1) +#define unroll_comb(expr, op) expr(0) op expr(1) +#define unroll_csv(expr) expr(0), expr(1) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 3 +#define unroll(expr) expr(0) expr(1) expr(2) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) +#define unroll_csv(expr) expr(0), expr(1), expr(2) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 4 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + +#define DIM 5 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) expr(4) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) op expr(4) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3), expr(4) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + +#define DIM 6 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) expr(4) expr(5) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) op expr(4) op expr(5) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3), expr(4), expr(5) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED + + + + +//== FULL TEMPLATE SPECIALIZATIONS ============================================ +#else + +/// cross product for Vec3f +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + + +/// cross product for Vec3d +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + +#endif + + + +//== GLOBAL FUNCTIONS ========================================================= + + +/// \relates OpenMesh::VectorT +/// scalar * vector +template +inline VectorT operator*(Scalar2 _s, const VectorT& _v) { + return _v*_s; +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +inline Scalar +dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +inline VectorT +cross(const VectorT& _v1, const VectorT& _v2) { + return (_v1 % _v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member norm +template +Scalar norm(const VectorT& _v) { + return _v.norm(); +} + + +/// \relates OpenMesh::VectorT +/// non-member sqrnorm +template +Scalar sqrnorm(const VectorT& _v) { + return _v.sqrnorm(); +} + + +/// \relates OpenMesh::VectorT +/// non-member vectorize +template +VectorT& vectorize(VectorT& _v, OtherScalar const& _val) { + return _v.vectorize(_val); +} + + +/// \relates OpenMesh::VectorT +/// non-member normalize +template +VectorT& normalize(VectorT& _v) { + return _v.normalize(); +} + + +/// \relates OpenMesh::VectorT +/// non-member maximize +template +VectorT& maximize(VectorT& _v1, VectorT& _v2) { + return _v1.maximize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member minimize +template +VectorT& minimize(VectorT& _v1, VectorT& _v2) { + return _v1.minimize(_v2); +} + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + + +#endif // OPENMESH_VECTOR_HH defined +//============================================================================= +#endif // DOXYGEN +#endif // C++11 diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Geometry/VectorT_inc.hh b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/VectorT_inc.hh new file mode 100644 index 0000000..96b6c10 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Geometry/VectorT_inc.hh @@ -0,0 +1,668 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +// Set template keywords and class names properly when +// parsing with doxygen. This only seems to work this way since +// the scope of preprocessor defines is limited to one file in doxy. +#ifdef DOXYGEN + +// Only used for correct doxygen parsing +#define OPENMESH_VECTOR_HH + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i vector_type; + + /// returns dimension of the vector (deprecated) + static inline int dim() { return DIM; } + + /// returns dimension of the vector + static inline size_t size() { return DIM; } + + static const size_t size_ = DIM; + + + //-------------------------------------------------------------- constructors + + /// default constructor creates uninitialized values. + inline VectorT() {} + + /// special constructor for 1D vectors + explicit inline VectorT(const Scalar& v) { +// assert(DIM==1); +// values_[0] = v0; + vectorize(v); + } + +#if DIM == 2 + /// special constructor for 2D vectors + inline VectorT(const Scalar v0, const Scalar v1) { + Base::values_[0] = v0; Base::values_[1] = v1; + } +#endif + +#if DIM == 3 + /// special constructor for 3D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + } +#endif + +#if DIM == 4 + /// special constructor for 4D vectors + inline VectorT(const Scalar v0, const Scalar v1, + const Scalar v2, const Scalar v3) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; Base::values_[3]=v3; + } + + VectorT homogenized() const { return VectorT(Base::values_[0]/Base::values_[3], Base::values_[1]/Base::values_[3], Base::values_[2]/Base::values_[3], 1); } +#endif + +#if DIM == 5 + /// special constructor for 5D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2, + const Scalar v3, const Scalar v4) { + Base::values_[0]=v0; Base::values_[1]=v1;Base::values_[2]=v2; Base::values_[3]=v3; Base::values_[4]=v4; + } +#endif + +#if DIM == 6 + /// special constructor for 6D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2, + const Scalar v3, const Scalar v4, const Scalar v5) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5; + } +#endif + + /// construct from a value array (explicit) + explicit inline VectorT(const Scalar _values[DIM]) { + memcpy(data(), _values, DIM*sizeof(Scalar)); + } + + +#ifdef OM_CC_MIPS + /// assignment from a vector of the same kind + // mipspro need this method + inline vector_type& operator=(const vector_type& _rhs) { + memcpy(Base::values_, _rhs.Base::values_, DIM*sizeof(Scalar)); + return *this; + } +#endif + + + /// copy & cast constructor (explicit) + template + explicit inline VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + + + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template + inline vector_type& operator=(const VectorT& _rhs) { +#define expr(i) Base::values_[i] = (Scalar)_rhs[i]; + unroll(expr); +#undef expr + return *this; + } + +// /// cast to Scalar array +// inline operator Scalar*() { return Base::values_; } + +// /// cast to const Scalar array +// inline operator const Scalar*() const { return Base::values_; } + + /// access to Scalar array + inline Scalar* data() { return Base::values_; } + + /// access to const Scalar array + inline const Scalar*data() const { return Base::values_; } + + + //----------------------------------------------------------- element access + +// /// get i'th element read-write +// inline Scalar& operator[](int _i) { +// assert(_i>=0 && _i=0 && _i operator%(const VectorT& _rhs) const +#if DIM==3 + { + return + VectorT(Base::values_[1]*_rhs.Base::values_[2]-Base::values_[2]*_rhs.Base::values_[1], + Base::values_[2]*_rhs.Base::values_[0]-Base::values_[0]*_rhs.Base::values_[2], + Base::values_[0]*_rhs.Base::values_[1]-Base::values_[1]*_rhs.Base::values_[0]); + } +#else + ; +#endif + + + /// compute scalar product + /// \see OpenMesh::dot + inline Scalar operator|(const vector_type& _rhs) const { + Scalar p(0); +#define expr(i) p += Base::values_[i] * _rhs.Base::values_[i]; + unroll(expr); +#undef expr + return p; + } + + + + + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + /// compute euclidean norm + inline Scalar norm() const { return (Scalar)sqrt(sqrnorm()); } + inline Scalar length() const { return norm(); } // OpenSG interface + + /// compute squared euclidean norm + inline Scalar sqrnorm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += Base::values_[i] * Base::values_[i]; + unroll(expr); +#undef expr + return s; +#else +#define expr(i) Base::values_[i]*Base::values_[i] + return (unroll_comb(expr, +)); +#undef expr +#endif + } + + /** normalize vector, return normalized vector + */ + + inline vector_type& normalize() + { + *this /= norm(); + return *this; + } + + /** return normalized vector + */ + + inline const vector_type normalized() const + { + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + inline vector_type& normalize_cond() + { + Scalar n = norm(); + if (n != (Scalar)0.0) + { + *this /= n; + } + return *this; + } + + //@} + + //------------------------------------------------------------ euclidean norm + + /// \name Non-Euclidean norm calculations + //@{ + + /// compute L1 (Manhattan) norm + inline Scalar l1_norm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += std::abs(Base::values_[i]); + unroll(expr); +#undef expr + return s; +#else +#define expr(i) std::abs(Base::values_[i]) + return (unroll_comb(expr, +)); +#undef expr +#endif + } + + /// compute l8_norm + inline Scalar l8_norm() const + { + return max_abs(); + } + + //@} + + //------------------------------------------------------------ max, min, mean + + /// \name Minimum maximum and mean + //@{ + + /// return the maximal component + inline Scalar max() const + { + Scalar m(Base::values_[0]); + for(int i=1; im) m=Base::values_[i]; + return m; + } + + /// return the maximal absolute component + inline Scalar max_abs() const + { + Scalar m(std::abs(Base::values_[0])); + for(int i=1; im) + m=std::abs(Base::values_[i]); + return m; + } + + + /// return the minimal component + inline Scalar min() const + { + Scalar m(Base::values_[0]); + for(int i=1; i Base::values_[i]) Base::values_[i] = _rhs[i]; + unroll(expr); +#undef expr + return *this; + } + + /// maximize values and signalize coordinate maximization + inline bool maximized(const vector_type& _rhs) { + bool result(false); +#define expr(i) if (_rhs[i] > Base::values_[i]) { Base::values_[i] =_rhs[i]; result = true; } + unroll(expr); +#undef expr + return result; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) const { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) const { + return vector_type(*this).maximize(_rhs); + } + + //@} + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; +#define expr(i) result[i] = _func(Base::values_[i]); + unroll(expr); +#undef expr + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { +#define expr(i) Base::values_[i] = _s; + unroll(expr); +#undef expr + return *this; + } + + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { +#define expr(i) if (Base::values_[i] != _rhs.Base::values_[i]) \ + return (Base::values_[i] < _rhs.Base::values_[i]); + unroll(expr); +#undef expr + return false; + } +}; + + + +/// read the space-separated components of a vector from a stream +TEMPLATE_HEADER +inline std::istream& +operator>>(std::istream& is, VectorT& vec) +{ +#define expr(i) is >> vec[i]; + unroll(expr); +#undef expr + return is; +} + + +/// output a vector by printing its space-separated compontens +TEMPLATE_HEADER +inline std::ostream& +operator<<(std::ostream& os, const VectorT& vec) +{ +#if DIM==N + for(int i=0; i +#include +// -------------------- OpenMesh +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + +//----------------------------------------------------------------------------- + +short int read_short(FILE* _in, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + fread((char*)sc.c, 1, 2, _in); + if (_swap) std::swap(sc.c[0], sc.c[1]); + return sc.s; +} + + +//----------------------------------------------------------------------------- + + +int read_int(FILE* _in, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + fread((char*)ic.c, 1, 4, _in); + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + return ic.i; +} + + +//----------------------------------------------------------------------------- + + +float read_float(FILE* _in, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + fread((char*)fc.c, 1, 4, _in); + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + return fc.f; +} + + +//----------------------------------------------------------------------------- + + +double read_double(FILE* _in, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + fread((char*)dc.c, 1, 8, _in); + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + return dc.d; +} + +//----------------------------------------------------------------------------- + +short int read_short(std::istream& _in, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + _in.read((char*)sc.c, 2); + if (_swap) std::swap(sc.c[0], sc.c[1]); + return sc.s; +} + + +//----------------------------------------------------------------------------- + + +int read_int(std::istream& _in, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + _in.read((char*)ic.c, 4); + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + return ic.i; +} + + +//----------------------------------------------------------------------------- + + +float read_float(std::istream& _in, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + _in.read((char*)fc.c, 4); + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + return fc.f; +} + + +//----------------------------------------------------------------------------- + + +double read_double(std::istream& _in, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + _in.read((char*)dc.c, 8); + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + return dc.d; +} + + +//----------------------------------------------------------------------------- + + +void write_short(short int _i, FILE* _out, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + sc.s = _i; + if (_swap) std::swap(sc.c[0], sc.c[1]); + fwrite((char*)sc.c, 1, 2, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_int(int _i, FILE* _out, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + ic.i = _i; + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + fwrite((char*)ic.c, 1, 4, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_float(float _f, FILE* _out, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + fc.f = _f; + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + fwrite((char*)fc.c, 1, 4, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_double(double _d, FILE* _out, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + dc.d = _d; + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + fwrite((char*)dc.c, 1, 8, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_short(short int _i, std::ostream& _out, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + sc.s = _i; + if (_swap) std::swap(sc.c[0], sc.c[1]); + _out.write((char*)sc.c, 2); +} + + +//----------------------------------------------------------------------------- + + +void write_int(int _i, std::ostream& _out, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + ic.i = _i; + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + _out.write((char*)ic.c, 4); +} + + +//----------------------------------------------------------------------------- + + +void write_float(float _f, std::ostream& _out, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + fc.f = _f; + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + _out.write((char*)fc.c, 4); +} + + +//----------------------------------------------------------------------------- + + +void write_double(double _d, std::ostream& _out, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + dc.d = _d; + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + _out.write((char*)dc.c, 8); +} + + +#endif + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/BinaryHelper.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/BinaryHelper.hh new file mode 100644 index 0000000..3e36e95 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/BinaryHelper.hh @@ -0,0 +1,164 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_BINARY_HELPER_HH +#define OPENMESH_BINARY_HELPER_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined( OM_CC_MIPS ) +# include +#else +# include +#endif +#include +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(FILE* _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(FILE* _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(FILE* _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(FILE* _in, bool _swap=false); + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(std::istream& _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(std::istream& _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(std::istream& _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(std::istream& _in, bool _swap=false); + + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, FILE* _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, FILE* _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, FILE* _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, FILE* _out, bool _swap=false); + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, std::ostream& _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, std::ostream& _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, std::ostream& _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, std::ostream& _out, bool _swap=false); + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/IOInstances.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/IOInstances.hh new file mode 100644 index 0000000..744b9a8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/IOInstances.hh @@ -0,0 +1,115 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper file for static builds +// +// In opposite to dynamic builds where the instance of every reader module +// is generated within the OpenMesh library, static builds only instanciate +// objects that are at least referenced once. As all reader modules are +// never used directly, they will not be part of a static build, hence +// this file. +// +//============================================================================= + + +#ifndef __IOINSTANCES_HH__ +#define __IOINSTANCES_HH__ + +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) + +//============================================================================= + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + +//============================================================================= + + +// Instanciate every Reader module +static BaseReader* OFFReaderInstance = &OFFReader(); +static BaseReader* OBJReaderInstance = &OBJReader(); +static BaseReader* PLYReaderInstance = &PLYReader(); +static BaseReader* STLReaderInstance = &STLReader(); +static BaseReader* OMReaderInstance = &OMReader(); + +// Instanciate every writer module +static BaseWriter* OBJWriterInstance = &OBJWriter(); +static BaseWriter* OFFWriterInstance = &OFFWriter(); +static BaseWriter* STLWriterInstance = &STLWriter(); +static BaseWriter* OMWriterInstance = &OMWriter(); +static BaseWriter* PLYWriterInstance = &PLYWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // static ? +#endif //__IOINSTANCES_HH__ +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/IOManager.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/IOManager.cc new file mode 100644 index 0000000..40f6ec6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/IOManager.cc @@ -0,0 +1,341 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +// Destructor never called. Moved into singleton getter function +// _IOManager_ *__IOManager_instance = 0; + +_IOManager_& IOManager() +{ + + static _IOManager_ __IOManager_instance; + + //if (!__IOManager_instance) + // __IOManager_instance = new _IOManager_(); + + return __IOManager_instance; +} + +//----------------------------------------------------------------------------- + +bool +_IOManager_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + + if( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No reading modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_read(_filename)) + { + _bi.prepare(); + bool ok = (*it)->read(_filename, _bi, _opt); + _bi.finish(); + return ok; + } + + // All modules failed to read + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +read(std::istream& _is, const std::string& _ext, BaseImporter& _bi, Options& _opt) +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->BaseReader::can_u_read(_ext)) //Use the extension check only (no file existence) + { + _bi.prepare(); + bool ok = (*it)->read(_is, _bi, _opt); + _bi.finish(); + return ok; + } + + // All modules failed to read + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + + if ( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + { + if ((*it)->can_u_write(_filename)) + { + return (*it)->write(_filename, _be, _opt, _precision); + } + } + + // All modules failed to save + return false; +} + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +write(std::ostream& _os,const std::string &_ext, BaseExporter& _be, Options _opt, std::streamsize _precision) +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + + if ( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + { + if ((*it)->BaseWriter::can_u_write(_ext)) //Restrict test to the extension check + { + return (*it)->write(_os, _be, _opt, _precision); + } + } + + // All modules failed to save + return false; +} + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +can_read( const std::string& _format ) const +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + std::string filename = "dummy." + _format; + + for(; it != it_end; ++it) + if ((*it)->can_u_read(filename)) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +can_write( const std::string& _format ) const +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + std::string filename = "dummy." + _format; + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_write(filename)) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- + + +const BaseWriter* +_IOManager_:: +find_writer(const std::string& _format) +{ + using std::string; + + string::size_type dot = _format.rfind('.'); + + string ext; + if (dot == string::npos) + ext = _format; + else + ext = _format.substr(dot+1,_format.length()-(dot+1)); + + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + std::string filename = "dummy." + ext; + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_write(filename)) + return *it; + + return NULL; +} + + +//----------------------------------------------------------------------------- + + +void +_IOManager_:: +update_read_filters() +{ + std::set::const_iterator it = reader_modules_.begin(), + it_end = reader_modules_.end(); + std::string all = ""; + std::string filters = ""; + + for(; it != it_end; ++it) + { + // Initialized with space, as a workaround for debug build with clang on mac + // which crashes if tmp is initialized with an empty string ?! + std::string tmp = " "; + + filters += (*it)->get_description() + " ("; + + std::istringstream iss((*it)->get_extensions()); + + while (iss && !iss.eof() && (iss >> tmp) ) + { + tmp = " *." + tmp; filters += tmp; all += tmp; + } + + filters += " );;"; + } + + all = "All files ( " + all + " );;"; + + read_filters_ = all + filters; +} + + +//----------------------------------------------------------------------------- + + +void +_IOManager_:: +update_write_filters() +{ + std::set::const_iterator it = writer_modules_.begin(), + it_end = writer_modules_.end(); + std::string all; + std::string filters; + + for(; it != it_end; ++it) + { + // Initialized with space, as a workaround for debug build with clang on mac + // which crashes if tmp is initialized with an empty string ?! + std::string s = " "; + + filters += (*it)->get_description() + " ("; + + std::istringstream iss((*it)->get_extensions()); + while (iss && !iss.eof() && (iss >> s)) + { s = " *." + s; filters += s; all += s; } + + filters += " );;"; + } + all = "All files ( " + all + " );;"; + + write_filters_ = all + filters; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/IOManager.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/IOManager.hh new file mode 100644 index 0000000..58c157f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/IOManager.hh @@ -0,0 +1,272 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + +#ifndef __IOMANAGER_HH__ +#define __IOMANAGER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** This is the real IOManager class that is later encapsulated by + SingletonT to enforce its uniqueness. _IOManager_ is not meant to be used + directly by the programmer - the IOManager alias exists for this task. + + All reader/writer modules register themselves at this class. For + reading or writing data all modules are asked to do the job. If no + suitable module is found, an error is returned. + + For the sake of reading, the target data structure is hidden + behind the BaseImporter interface that takes care of adding + vertices or faces. + + Writing from a source structure is encapsulate similarly behind a + BaseExporter interface, providing iterators over vertices/faces to + the writer modules. + + \see \ref mesh_io +*/ + +class OPENMESHDLLEXPORT _IOManager_ +{ +private: + + /// Constructor has nothing todo for the Manager + _IOManager_() {} + + /// Destructor has nothing todo for the Manager + ~_IOManager_() {}; + + /** Declare the singleton getter function as friend to access the private constructor + and destructor + */ + friend OPENMESHDLLEXPORT _IOManager_& IOManager(); + +public: + + /** + Read a mesh from file _filename. The target data structure is specified + by the given BaseImporter. The \c read method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to interprete _filename. + */ + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + +/** + Read a mesh from open std::istream _is. The target data structure is specified + by the given BaseImporter. The \c sread method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to use _is. + */ + bool read(std::istream& _filename, + const std::string& _ext, + BaseImporter& _bi, + Options& _opt); + + + /** Write a mesh to file _filename. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(const std::string& _filename, + BaseExporter& _be, + Options _opt=Options::Default, + std::streamsize _precision = 6); + +/** Write a mesh to open std::ostream _os. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(std::ostream& _filename, + const std::string& _ext, + BaseExporter& _be, + Options _opt=Options::Default, + std::streamsize _precision = 6); + + + /// Returns true if the format is supported by one of the reader modules. + bool can_read( const std::string& _format ) const; + + /// Returns true if the format is supported by one of the writer modules. + bool can_write( const std::string& _format ) const; + + + size_t binary_size(const std::string& _format, + BaseExporter& _be, + Options _opt = Options::Default) + { + const BaseWriter *bw = find_writer(_format); + return bw ? bw->binary_size(_be,_opt) : 0; + } + + + +public: //-- QT convenience function ------------------------------------------ + + + /** Returns all readable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_read_filters() const { return read_filters_; } + + + /** Returns all writeable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_write_filters() const { return write_filters_; } + + + +private: + + // collect all readable file extensions + void update_read_filters(); + + + // collect all writeable file extensions + void update_write_filters(); + + + +public: //-- SYSTEM PART------------------------------------------------------ + + + /** Registers a new reader module. A call to this function should be + implemented in the constructor of all classes derived from BaseReader. + */ + bool register_module(BaseReader* _bl) + { + reader_modules_.insert(_bl); + update_read_filters(); + return true; + } + + + + /** Registers a new writer module. A call to this function should be + implemented in the constructor of all classed derived from BaseWriter. + */ + bool register_module(BaseWriter* _bw) + { + writer_modules_.insert(_bw); + update_write_filters(); + return true; + } + + +private: + + const BaseWriter *find_writer(const std::string& _format); + + // stores registered reader modules + std::set reader_modules_; + + // stores registered writer modules + std::set writer_modules_; + + // input filters (e.g. for Qt file dialog) + std::string read_filters_; + + // output filters (e.g. for Qt file dialog) + std::string write_filters_; +}; + + +//============================================================================= + + +//_IOManager_* __IOManager_instance; Causes memory leak, as destructor is never called + +OPENMESHDLLEXPORT _IOManager_& IOManager(); + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/MeshIO.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/MeshIO.hh new file mode 100644 index 0000000..49b6f64 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/MeshIO.hh @@ -0,0 +1,296 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#ifndef OM_MESHIO_HH +#define OM_MESHIO_HH + + +//=== INCLUDES ================================================================ + +// -------------------- system settings +#include + +// -------------------- check include order +#if defined (OPENMESH_TRIMESH_ARRAY_KERNEL_HH) || \ + defined (OPENMESH_POLYMESH_ARRAY_KERNEL_HH) + + // Issue warning if MeshIO was not included before Mesh Type + // Nobody knows why this order was enforced. + // If somebody encounters an error resulting from a wrong order, please report it to the OpenMesh developers. + // If we don't here about any errors, this check will be removed + // @TODO: Remove after reasonable time + #ifdef WIN32 + #pragma message("MeshIO.hh was included after Mesh Type. You may ignore this warning. Please report errors resulting ifrom this order to the developers!") + #else + #warning "MeshIO.hh was included after Mesh Type. You may ignore this warning. Please report errors resulting from this order to the developers!" + #endif + +#endif + +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Convenience functions the map to IOManager functions. + \see OpenMesh::IO::_IOManager_ +*/ +//@{ + + +//----------------------------------------------------------------------------- + + +/** \brief Read a mesh from file _filename. + + The file format is determined by the file extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _filename fill to load + + @return Successful? + */ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename) +{ + Options opt; + return read_mesh(_mesh, _filename, opt, true); +} + + +/** \brief Read a mesh from file _filename. + + The file format is determined by the file extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _filename fill to load + @param _opt Reader options (e.g. skip loading of normals ... depends + on the reader capabilities). Note that simply passing an + Options::Flag enum is not sufficient. + @param _clear Clear the target data before filling it (allows to + load multiple files into one Mesh). If you only want to read a mesh + without clearing set _clear to false. Providing a default Options + object is sufficient in this case. + + @return Successful? +*/ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_filename, importer, _opt); +} + + +/** \brief Read a mesh from file open std::istream. + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _is stream to load the data from + @param _ext The file format that is written to the stream + @param _opt Reader options (e.g. skip loading of normals ... depends + on the reader capabilities) + @param _clear Clear the target data before filling it (allows to + load multiple files into one Mesh) + + @return Successful? +*/ +template +bool +read_mesh(Mesh& _mesh, + std::istream& _is, + const std::string& _ext, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_is,_ext, importer, _opt); +} + + + +//----------------------------------------------------------------------------- + + +/** \brief Write a mesh to the file _filename. + + The file format is determined by _filename's extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The mesh that will be written to file + @param _filename output filename + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + @param _precision specifies stream precision for ascii files + + @return Successful? +*/ +template +bool write_mesh(const Mesh& _mesh, + const std::string& _filename, + Options _opt = Options::Default, + std::streamsize _precision = 6) +{ + ExporterT exporter(_mesh); + return IOManager().write(_filename, exporter, _opt, _precision); +} + + +//----------------------------------------------------------------------------- + + +/** Write a mesh to an open std::ostream. + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The mesh that will be written to file + @param _os output stream to write into + @param _ext extension defining the type of output + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + @param _precision specifies stream precision for ascii files + + @return Successful? +*/ +template +bool write_mesh(const Mesh& _mesh, + std::ostream& _os, + const std::string& _ext, + Options _opt = Options::Default, + std::streamsize _precision = 6) +{ + ExporterT exporter(_mesh); + return IOManager().write(_os,_ext, exporter, _opt, _precision); +} + + +//----------------------------------------------------------------------------- + +/** \brief Get binary size of data + + This function calls the corresponding writer which calculates the size + of the data that would be written to a binary file + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + @param _mesh Mesh to write + @param _ext extension of the file (used to determine the writing module) + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + + @return Binary size in bytes used when writing the data +*/ +template +size_t binary_size(const Mesh& _mesh, + const std::string& _ext, + Options _opt = Options::Default) +{ + ExporterT exporter(_mesh); + return IOManager().binary_size(_ext, exporter, _opt); +} + + +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) +# include +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/OFFFormat.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/OFFFormat.hh new file mode 100644 index 0000000..bd87f56 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/OFFFormat.hh @@ -0,0 +1,99 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_IO_OFFFORMAT_HH +#define OPENMESH_IO_OFFFORMAT_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +struct OPENMESHDLLEXPORT OFFFormat +{ + typedef int integer_type; + typedef float float_type; +}; + +#endif + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormat.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormat.cc new file mode 100644 index 0000000..231dfac --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormat.cc @@ -0,0 +1,247 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { +namespace OMFormat { + +//== IMPLEMENTATION =========================================================== + + Chunk::Integer_Size needed_bits( size_t s ) + { + if (s <= 0x000100) return Chunk::Integer_8; + if (s <= 0x010000) return Chunk::Integer_16; + +#if 0 + // !Not tested yet! This most probably won't work! + // NEED a 64bit system! + if ( (sizeof( size_t ) == 8) && (s >= 0x100000000) ) + return Chunk::Integer_64; +#endif + + return Chunk::Integer_32; + } + +//----------------------------------------------------------------------------- + + uint16& + operator << (uint16& val, const Chunk::Header& hdr) + { + val = 0; + val |= hdr.name_ << OMFormat::Chunk::OFF_NAME; + val |= hdr.entity_ << OMFormat::Chunk::OFF_ENTITY; + val |= hdr.type_ << OMFormat::Chunk::OFF_TYPE; + val |= hdr.signed_ << OMFormat::Chunk::OFF_SIGNED; + val |= hdr.float_ << OMFormat::Chunk::OFF_FLOAT; + val |= hdr.dim_ << OMFormat::Chunk::OFF_DIM; + val |= hdr.bits_ << OMFormat::Chunk::OFF_BITS; + return val; + } + + +//----------------------------------------------------------------------------- + + Chunk::Header& + operator << (Chunk::Header& hdr, const uint16 val) + { + hdr.reserved_ = 0; + hdr.name_ = val >> OMFormat::Chunk::OFF_NAME; + hdr.entity_ = val >> OMFormat::Chunk::OFF_ENTITY; + hdr.type_ = val >> OMFormat::Chunk::OFF_TYPE; + hdr.signed_ = val >> OMFormat::Chunk::OFF_SIGNED; + hdr.float_ = val >> OMFormat::Chunk::OFF_FLOAT; + hdr.dim_ = val >> OMFormat::Chunk::OFF_DIM; + hdr.bits_ = val >> OMFormat::Chunk::OFF_BITS; + return hdr; + } + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Entity e) + { + switch(e) + { + case Chunk::Entity_Vertex: return "Vertex"; + case Chunk::Entity_Mesh: return "Mesh"; + case Chunk::Entity_Edge: return "Edge"; + case Chunk::Entity_Halfedge: return "Halfedge"; + case Chunk::Entity_Face: return "Face"; + default: + std::clog << "as_string(Chunk::Entity): Invalid value!"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Type t) + { + switch(t) + { + case Chunk::Type_Pos: return "Pos"; + case Chunk::Type_Normal: return "Normal"; + case Chunk::Type_Texcoord: return "Texcoord"; + case Chunk::Type_Status: return "Status"; + case Chunk::Type_Color: return "Color"; + case Chunk::Type_Custom: return "Custom"; + case Chunk::Type_Topology: return "Topology"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Dim d) + { + switch(d) + { + case Chunk::Dim_1D: return "1D"; + case Chunk::Dim_2D: return "2D"; + case Chunk::Dim_3D: return "3D"; + case Chunk::Dim_4D: return "4D"; + case Chunk::Dim_5D: return "5D"; + case Chunk::Dim_6D: return "6D"; + case Chunk::Dim_7D: return "7D"; + case Chunk::Dim_8D: return "8D"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Integer_Size d) + { + switch(d) + { + case Chunk::Integer_8 : return "8"; + case Chunk::Integer_16 : return "16"; + case Chunk::Integer_32 : return "32"; + case Chunk::Integer_64 : return "64"; + } + return NULL; + } + + const char *as_string(Chunk::Float_Size d) + { + switch(d) + { + case Chunk::Float_32 : return "32"; + case Chunk::Float_64 : return "64"; + case Chunk::Float_128: return "128"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ) + { + _os << "Chunk Header : 0x" << std::setw(4) + << std::hex << (*(uint16*)(&_c)) << std::dec << '\n'; + _os << "entity = " + << as_string(Chunk::Entity(_c.entity_)) << '\n'; + _os << "type = " + << as_string(Chunk::Type(_c.type_)); + if ( Chunk::Type(_c.type_)!=Chunk::Type_Custom) + { + _os << '\n' + << "signed = " + << _c.signed_ << '\n'; + _os << "float = " + << _c.float_ << '\n'; + _os << "dim = " + << as_string(Chunk::Dim(_c.dim_)) << '\n'; + _os << "bits = " + << (_c.float_ + ? as_string(Chunk::Float_Size(_c.bits_)) + : as_string(Chunk::Integer_Size(_c.bits_))); + } + return _os; + } + + +//----------------------------------------------------------------------------- + + std::ostream& operator << ( std::ostream& _os, const Header& _h ) + { + _os << "magic = '" << _h.magic_[0] << _h.magic_[1] << "'\n" + << "mesh = '" << _h.mesh_ << "'\n" + << "version = 0x" << std::hex << (uint16)_h.version_ << std::dec + << " (" << major_version(_h.version_) + << "." << minor_version(_h.version_) << ")\n" + << "#V = " << _h.n_vertices_ << '\n' + << "#F = " << _h.n_faces_ << '\n' + << "#E = " << _h.n_edges_; + return _os; + } + + +} // namespace OMFormat + // -------------------------------------------------------------------------- + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormat.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormat.hh new file mode 100644 index 0000000..9bbcd86 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormat.hh @@ -0,0 +1,751 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_IO_OMFORMAT_HH +#define OPENMESH_IO_OMFORMAT_HH + + +//=== INCLUDES ================================================================ + +#include +#include +#include +#include +#include +#include +// -------------------- +#include +#if defined(OM_CC_GCC) && (OM_GCC_VERSION < 30000) +# include +# define OM_MISSING_HEADER_LIMITS 1 +#else +# include +#endif + + +//== NAMESPACES ============================================================== + +#ifndef DOXY_IGNORE_THIS +namespace OpenMesh { +namespace IO { +namespace OMFormat { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing +*/ +//@{ + +//----------------------------------------------------------------------------- + + // <:Header> + // <:Comment> + // Chunk 0 + // <:ChunkHeader> + // <:Comment> + // data + // Chunk 1 + // <:ChunkHeader> + // <:Comment> + // data + // . + // . + // . + // Chunk N + + // + // NOTICE! + // + // The usage of data types who differ in size + // on different pc architectures (32/64 bit) and/or + // operating systems, e.g. (unsigned) long, size_t, + // is not recommended because of inconsistencies + // in case of cross writing and reading. + // + // Basic types that are supported are: + + + typedef unsigned char uchar; + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + typedef float32_t float32; + typedef float64_t float64; + + struct Header + { + uchar magic_[2]; // OM + uchar mesh_; // [T]riangles, [Q]uads, [P]olygonals + uint8 version_; + uint32 n_vertices_; + uint32 n_faces_; + uint32 n_edges_; + + size_t store( std::ostream& _os, bool _swap ) const + { + _os.write( (char*)this, 4); // magic_, mesh_, version_ + size_t bytes = 4; + bytes += binary::store( _os, n_vertices_, _swap ); + bytes += binary::store( _os, n_faces_, _swap ); + bytes += binary::store( _os, n_edges_, _swap ); + return bytes; + } + + size_t restore( std::istream& _is, bool _swap ) + { + if (_is.read( (char*)this, 4 ).eof()) + return 0; + + size_t bytes = 4; + bytes += binary::restore( _is, n_vertices_, _swap ); + bytes += binary::restore( _is, n_faces_, _swap ); + bytes += binary::restore( _is, n_edges_, _swap ); + return bytes; + } + + }; + + struct Chunk + { + // Hardcoded this size to an uint32 to make the system 32/64 bit compatible. + // Needs further investigation! + typedef uint32 esize_t; // element size, used for custom properties + + enum Type { + Type_Pos = 0x00, + Type_Normal = 0x01, + Type_Texcoord = 0x02, + Type_Status = 0x03, + Type_Color = 0x04, + Type_Custom = 0x06, + Type_Topology = 0x07 + }; + + enum Entity { + Entity_Vertex = 0x00, + Entity_Mesh = 0x01, + Entity_Face = 0x02, + Entity_Edge = 0x04, + Entity_Halfedge = 0x06, + Entity_Sentinel = 0x07 + }; + + enum Dim { + Dim_1D = 0x00, + Dim_2D = 0x01, + Dim_3D = 0x02, + Dim_4D = 0x03, + Dim_5D = 0x04, + Dim_6D = 0x05, + Dim_7D = 0x06, + Dim_8D = 0x07 + }; + + enum Integer_Size { + Integer_8 = 0x00, // 1 byte for (unsigned) char + Integer_16 = 0x01, // 2 bytes for short + Integer_32 = 0x02, // 4 bytes for long + Integer_64 = 0x03 // 8 bytes for long long + }; + + enum Float_Size { + Float_32 = 0x00, // 4 bytes for float + Float_64 = 0x01, // 8 bytes for double + Float_128 = 0x02 // 16 bytes for long double (an assumption!) + }; + + static const int SIZE_RESERVED = 1; // 1 + static const int SIZE_NAME = 1; // 2 + static const int SIZE_ENTITY = 3; // 5 + static const int SIZE_TYPE = 4; // 9 + + static const int SIZE_SIGNED = 1; // 10 + static const int SIZE_FLOAT = 1; // 11 + static const int SIZE_DIM = 3; // 14 + static const int SIZE_BITS = 2; // 16 + + static const int OFF_RESERVED = 0; // 0 + static const int OFF_NAME = SIZE_RESERVED + OFF_RESERVED; // 2 + static const int OFF_ENTITY = SIZE_NAME + OFF_NAME; // 3 + static const int OFF_TYPE = SIZE_ENTITY + OFF_ENTITY; // 5 + static const int OFF_SIGNED = SIZE_TYPE + OFF_TYPE; // 9 + static const int OFF_FLOAT = SIZE_SIGNED + OFF_SIGNED; // 10 + static const int OFF_DIM = SIZE_FLOAT + OFF_FLOAT; // 11 + static const int OFF_BITS = SIZE_DIM + OFF_DIM; // 14 + + // !Attention! When changing the bit size, the operators + // << (uint16, Header) and << (Header, uint16) must be changed as well + // + // Entries signed_, float_, dim_, bits_ are not used when type_ + // equals Type_Custom + // + struct Header // 16 bits long + { + unsigned reserved_: SIZE_RESERVED; + unsigned name_ : SIZE_NAME; // 1 named property, 0 anonymous + unsigned entity_ : SIZE_ENTITY; // 0 vertex, 1 mesh, 2 edge, + // 4 halfedge, 6 face + unsigned type_ : SIZE_TYPE; // 0 pos, 1 normal, 2 texcoord, + // 3 status, 4 color 6 custom 7 topology + unsigned signed_ : SIZE_SIGNED; // bool + unsigned float_ : SIZE_FLOAT; // bool + unsigned dim_ : SIZE_DIM; // 0 1D, 1 2D, 2 3D, .., 7 8D + unsigned bits_ : SIZE_BITS; // {8, 16, 32, 64} | {32, 64, 128} + // (integer) (float) + unsigned unused_ : 16; // fill up to 32 bits + }; // struct Header + + + class PropertyName : public std::string + { + public: + + static const size_t size_max = 256; + + PropertyName( ) { } + + PropertyName( const std::string& _name ) { *this = _name; } + + bool is_valid() const { return is_valid( size() ); } + + static bool is_valid( size_t _s ) { return _s <= size_max; } + + PropertyName& operator = ( const std::string& _rhs ) + { + assert( is_valid( _rhs.size() ) ); + + if ( is_valid( _rhs.size() ) ) + std::string::operator = ( _rhs ); + else + { + omerr() << "Warning! Property name too long. Will be shortened!\n"; + this->std::string::operator = ( _rhs.substr(0, size_max) ); + } + + return *this; + } + + }; + + }; // Chunk + + // ------------------------------------------------------------ Helper + + // -------------------- get size information + + /// Return size of header in bytes. + inline size_t header_size(void) { return sizeof(Header); } + + + /// Return size of chunk header in bytes. + inline size_t chunk_header_size( void ) { return sizeof(uint16); } + + + /// Return the size of a scale in bytes. + inline size_t scalar_size( const Chunk::Header& _hdr ) + { + return _hdr.float_ ? (0x01 << _hdr.bits_) : (0x04 << _hdr.bits_); + } + + + /// Return the dimension of the vector in a chunk + inline size_t dimensions(const Chunk::Header& _chdr) { return _chdr.dim_+1; } + + + /// Return the size of a vector in bytes. + inline size_t vector_size( const Chunk::Header& _chdr ) + { + return dimensions(_chdr)*scalar_size(_chdr); + } + + + /// Return the size of chunk data in bytes + inline size_t chunk_data_size( Header& _hdr, Chunk::Header& _chunk_hdr ) + { + size_t C; + switch( _chunk_hdr.entity_ ) + { + case Chunk::Entity_Vertex: C = _hdr.n_vertices_; break; + case Chunk::Entity_Face: C = _hdr.n_faces_; break; + case Chunk::Entity_Halfedge: C = _hdr.n_edges_*2; break; + case Chunk::Entity_Edge: C = _hdr.n_edges_; break; + case Chunk::Entity_Mesh: C = 1; break; + default: + C = 0; + std::cerr << "Invalid value in _chunk_hdr.entity_\n"; + assert( false ); + break; + } + + return C * vector_size( _chunk_hdr ); + } + + inline size_t chunk_size( Header& _hdr, Chunk::Header& _chunk_hdr ) + { + return chunk_header_size() + chunk_data_size( _hdr, _chunk_hdr ); + } + + // -------------------- convert from Chunk::Header to storage type + + uint16& operator << (uint16& val, const Chunk::Header& hdr); + Chunk::Header& operator << (Chunk::Header& hdr, const uint16 val); + + + // -------------------- type information + + template bool is_float(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return !Utils::NumLimitsT::is_integer(); +#else + return !std::numeric_limits::is_integer; +#endif + } + + template bool is_integer(const T) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_integer(); +#else + return std::numeric_limits::is_integer; +#endif + } + + template bool is_signed(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_signed(); +#else + return std::numeric_limits::is_signed; +#endif + } + + // -------------------- conversions (format type <- type/value) + + template + inline + Chunk::Dim dim( VecType ) + { + assert( vector_traits< VecType >::size() < 9 ); + return static_cast(vector_traits< VecType >::size() - 1); + } + + template + inline + Chunk::Dim dim( const Chunk::Header& _hdr ) + { + return static_cast( _hdr.dim_ ); + } + + // calc minimum (power-of-2) number of bits needed + Chunk::Integer_Size needed_bits( size_t s ); + + // Convert size of type to Integer_Size +#ifdef NDEBUG + template Chunk::Integer_Size integer_size(const T&) +#else + template Chunk::Integer_Size integer_size(const T& d) +#endif + { +#ifndef NDEBUG + assert( is_integer(d) ); +#endif + + switch( sizeof(T) ) + { + case 1: return OMFormat::Chunk::Integer_8; + case 2: return OMFormat::Chunk::Integer_16; + case 4: return OMFormat::Chunk::Integer_32; + case 8: return OMFormat::Chunk::Integer_64; + default: + std::cerr << "Invalid value in integer_size\n"; + assert( false ); + break; + } + return Chunk::Integer_Size(0); + } + + + // Convert size of type to FLoat_Size +#ifdef NDEBUG + template Chunk::Float_Size float_size(const T&) +#else + template Chunk::Float_Size float_size(const T& d) +#endif + { +#ifndef NDEBUG + assert( is_float(d) ); +#endif + + switch( sizeof(T) ) + { + case 4: return OMFormat::Chunk::Float_32; + case 8: return OMFormat::Chunk::Float_64; + case 16: return OMFormat::Chunk::Float_128; + default: + std::cerr << "Invalid value in float_size\n"; + assert( false ); + break; + } + return Chunk::Float_Size(0); + } + + // Return the storage type (Chunk::Header::bits_) + template + inline + unsigned int bits(const T& val) + { + return is_integer(val) + ? (static_cast(integer_size(val))) + : (static_cast(float_size(val))); + } + + // -------------------- create/read version + + inline uint8 mk_version(const uint16 major, const uint16 minor) + { return (major & 0x07) << 5 | (minor & 0x1f); } + + + inline uint16 major_version(const uint8 version) + { return (version >> 5) & 0x07; } + + + inline uint16 minor_version(const uint8 version) + { return (version & 0x001f); } + + + // ---------------------------------------- convenience functions + + const char *as_string(Chunk::Type t); + const char *as_string(Chunk::Entity e); + const char *as_string(Chunk::Dim d); + const char *as_string(Chunk::Integer_Size d); + const char *as_string(Chunk::Float_Size d); + + std::ostream& operator << ( std::ostream& _os, const Header& _h ); + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ); + +//@} +} // namespace OMFormat + + // -------------------- (re-)store header + + template <> inline + size_t store( std::ostream& _os, const OMFormat::Header& _hdr, bool _swap) + { return _hdr.store( _os, _swap ); } + + template <> inline + size_t restore( std::istream& _is, OMFormat::Header& _hdr, bool _swap ) + { return _hdr.restore( _is, _swap ); } + + + // -------------------- (re-)store chunk header + + template <> inline + size_t + store( std::ostream& _os, const OMFormat::Chunk::Header& _hdr, bool _swap) + { + OMFormat::uint16 val; val << _hdr; + return binary::store( _os, val, _swap ); + } + + template <> inline + size_t + restore( std::istream& _is, OMFormat::Chunk::Header& _hdr, bool _swap ) + { + OMFormat::uint16 val; + size_t bytes = binary::restore( _is, val, _swap ); + + _hdr << val; + + return bytes; + } + + // -------------------- (re-)store integer with wanted number of bits (bytes) + + typedef GenProg::TrueType t_signed; + typedef GenProg::FalseType t_unsigned; + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Store an integer with a wanted number of bits + template< typename T > + inline + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return store( _os, _val, _b, _swap, t_signed() ); + return store( _os, _val, _b, _swap, t_unsigned() ); + } + + // helper to store a an integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Restore an integer with a wanted number of bits + template< typename T > + inline + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return restore( _is, _val, _b, _swap, t_signed() ); + return restore( _is, _val, _b, _swap, t_unsigned() ); + } + + + // + // ---------------------------------------- storing vectors + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + bytes += store( _os, _vec[3], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return store( _os, _vec[0], _swap ); + } + + /// storing a vector type + template inline + size_t vector_store( std::ostream& _os, const VecT& _vec, bool _swap ) + { + return store( _os, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + // ---------------------------------------- restoring vectors + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = restore( _is, _vec[0], _swap ); + bytes += restore( _is, _vec[1], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + bytes += binary::restore( _is, _vec[3], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return restore( _is, _vec[0], _swap ); + } + + /// Restoring a vector type + template + inline + size_t + vector_restore( std::istream& _is, VecT& _vec, bool _swap ) + { + return restore( _is, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + + // ---------------------------------------- storing property names + + template <> + inline + size_t store( std::ostream& _os, const OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + store( _os, _pn.size(), OMFormat::Chunk::Integer_8, _swap ); // 1 byte + if ( _pn.size() ) + _os.write( _pn.c_str(), _pn.size() ); // size bytes + return _pn.size() + 1; + } + + template <> + inline + size_t restore( std::istream& _is, OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + size_t size; + + restore( _is, size, OMFormat::Chunk::Integer_8, _swap); // 1 byte + + assert( OMFormat::Chunk::PropertyName::is_valid( size ) ); + + if ( size > 0 ) + { + char buf[256]; + _is.read( buf, size ); // size bytes + buf[size] = '\0'; + _pn.resize(size); + _pn = buf; + } + return size+1; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +#endif +//============================================================================= +#if defined(OM_MISSING_HEADER_LIMITS) +# undef OM_MISSING_HEADER_LIMITS +#endif +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_IO_OMFORMAT_CC) +# define OPENMESH_IO_OMFORMAT_TEMPLATES +# include "OMFormatT.cc" +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormatT.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormatT.cc new file mode 100644 index 0000000..fa332b1 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/OMFormatT.cc @@ -0,0 +1,245 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#define OPENMESH_IO_OMFORMAT_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v = static_cast(_val); + return store( _os, v, _swap ); + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to restore a an integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + + + // helper to restore a an unsigned integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/Options.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/Options.hh new file mode 100644 index 0000000..f266725 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/Options.hh @@ -0,0 +1,250 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_IO_OPTIONS_HH +#define OPENMESH_IO_OPTIONS_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for reader and writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** \brief Set options for reader/writer modules. + * + * The class is used in a twofold way. + * -# In combination with reader modules the class is used + * - to pass hints to the reading module, whether the input is + * binary and what byte ordering the binary data has + * - to retrieve information about the file contents after + * succesful reading. + * -# In combination with write modules the class gives directions to + * the writer module, whether to + * - use binary mode or not and what byte order to use + * - store one of the standard properties. + * + * The option are defined in \c Options::Flag as bit values and stored in + * an \c int value as a bitset. + */ +class Options +{ +public: + typedef int enum_type; + typedef enum_type value_type; + + /// Definitions of %Options for reading and writing. The options can be + /// or'ed. + enum Flag { + Default = 0x0000, ///< No options + Binary = 0x0001, ///< Set binary mode for r/w + MSB = 0x0002, ///< Assume big endian byte ordering + LSB = 0x0004, ///< Assume little endian byte ordering + Swap = 0x0008, ///< Swap byte order in binary mode + VertexNormal = 0x0010, ///< Has (r) / store (w) vertex normals + VertexColor = 0x0020, ///< Has (r) / store (w) vertex colors + VertexTexCoord = 0x0040, ///< Has (r) / store (w) texture coordinates + EdgeColor = 0x0080, ///< Has (r) / store (w) edge colors + FaceNormal = 0x0100, ///< Has (r) / store (w) face normals + FaceColor = 0x0200, ///< Has (r) / store (w) face colors + FaceTexCoord = 0x0400, ///< Has (r) / store (w) face texture coordinates + ColorAlpha = 0x0800, ///< Has (r) / store (w) alpha values for colors + ColorFloat = 0x1000, ///< Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) + Custom = 0x2000 ///< Has (r) custom properties (currently only implemented in PLY Reader ASCII version) + }; + +public: + + /// Default constructor + Options() : flags_( Default ) + { } + + + /// Copy constructor + Options(const Options& _opt) : flags_(_opt.flags_) + { } + + + /// Initializing constructor setting a single option + Options(Flag _flg) : flags_( _flg) + { } + + + /// Initializing constructor setting multiple options + Options(const value_type _flgs) : flags_( _flgs) + { } + + + ~Options() + { } + + /// Restore state after default constructor. + void cleanup(void) + { flags_ = Default; } + + /// Clear all bits. + void clear(void) + { flags_ = 0; } + + /// Returns true if all bits are zero. + bool is_empty(void) const { return !flags_; } + +public: + + + //@{ + /// Copy options defined in _rhs. + + Options& operator = ( const Options& _rhs ) + { flags_ = _rhs.flags_; return *this; } + + Options& operator = ( const value_type _rhs ) + { flags_ = _rhs; return *this; } + + //@} + + + //@{ + /// Unset options defined in _rhs. + + Options& operator -= ( const value_type _rhs ) + { flags_ &= ~_rhs; return *this; } + + Options& unset( const value_type _rhs) + { return (*this -= _rhs); } + + //@} + + + + //@{ + /// Set options defined in _rhs + + Options& operator += ( const value_type _rhs ) + { flags_ |= _rhs; return *this; } + + Options& set( const value_type _rhs) + { return (*this += _rhs); } + + //@} + +public: + + + // Check if an option or several options are set. + bool check(const value_type _rhs) const + { + return (flags_ & _rhs)==_rhs; + } + + bool is_binary() const { return check(Binary); } + bool vertex_has_normal() const { return check(VertexNormal); } + bool vertex_has_color() const { return check(VertexColor); } + bool vertex_has_texcoord() const { return check(VertexTexCoord); } + bool edge_has_color() const { return check(EdgeColor); } + bool face_has_normal() const { return check(FaceNormal); } + bool face_has_color() const { return check(FaceColor); } + bool face_has_texcoord() const { return check(FaceTexCoord); } + bool color_has_alpha() const { return check(ColorAlpha); } + bool color_is_float() const { return check(ColorFloat); } + + + /// Returns true if _rhs has the same options enabled. + bool operator == (const value_type _rhs) const + { return flags_ == _rhs; } + + + /// Returns true if _rhs does not have the same options enabled. + bool operator != (const value_type _rhs) const + { return flags_ != _rhs; } + + + /// Returns the option set. + operator value_type () const { return flags_; } + +private: + + bool operator && (const value_type _rhs) const; + + value_type flags_; +}; + +//----------------------------------------------------------------------------- + + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary.hh new file mode 100644 index 0000000..05c9de8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary.hh @@ -0,0 +1,136 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_HH +#define OPENMESH_SR_BINARY_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#include +#include // accumulate +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +//----------------------------------------------------------------------------- + + const static size_t UnknownSize(size_t(-1)); + + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +#define X \ + std::ostringstream msg; \ + msg << "Type not supported: " << typeid(value_type).name(); \ + throw std::logic_error(msg.str()) + +/// \struct binary SR_binary.hh +/// +/// The struct defines how to store and restore the type T. +/// It's used by the OM reader/writer modules. +/// +/// The following specialization are provided: +/// - Fundamental types except \c long \c double +/// - %OpenMesh vector types +/// - %OpenMesh::StatusInfo +/// - std::string (max. length 65535) +/// +/// \todo Complete documentation of members +template < typename T > struct binary +{ + typedef T value_type; + + static const bool is_streamable = false; + + static size_t size_of(void) { return UnknownSize; } + static size_t size_of(const value_type&) { return UnknownSize; } + + static + size_t store( std::ostream& /* _os */, + const value_type& /* _v */, + bool /* _swap=false */) + { X; return 0; } + + static + size_t restore( std::istream& /* _is */, + value_type& /* _v */, + bool /* _swap=false */) + { X; return 0; } +}; + +#undef X + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_spec.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_spec.hh new file mode 100644 index 0000000..956b6e8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_spec.hh @@ -0,0 +1,329 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_SPEC_HH +#define OPENMESH_SR_BINARY_SPEC_HH + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) +# include +#else +# include +#endif +#include +#include // logic_error +#include // accumulate +// -------------------- OpenMesh +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +#ifndef DOXY_IGNORE_THIS + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + _os.write( (const char*)&tmp, sizeof(value_type) ); \ + return _os.good() ? sizeof(value_type) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + _is.read( (char*)&_val, sizeof(value_type) ); \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(value_type) : 0; \ + } \ + } + +SIMPLE_BINARY(bool); +//SIMPLE_BINARY(int); + +// Why is this needed? Should not be used as not 32 bit compatible +//SIMPLE_BINARY(unsigned long); +SIMPLE_BINARY(float); +SIMPLE_BINARY(double); +SIMPLE_BINARY(long double); +SIMPLE_BINARY(char); + +SIMPLE_BINARY(int8_t); +SIMPLE_BINARY(int16_t); +SIMPLE_BINARY(int32_t); +SIMPLE_BINARY(int64_t); +SIMPLE_BINARY(uint8_t); +SIMPLE_BINARY(uint16_t); +SIMPLE_BINARY(uint32_t); +SIMPLE_BINARY(uint64_t); + +#undef SIMPLE_BINARY + +// For unsigned long which is of size 64 bit on 64 bit +// architectures: convert into 32 bit unsigned integer value +// in order to stay compatible between 32/64 bit architectures. +// This allows cross reading BUT forbids storing unsigned longs +// as data type since higher order word (4 bytes) will be truncated. +// Does not work in case the data type that is to be stored +// exceeds the value range of unsigned int in size, which is improbable... + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + /* Convert unsigned long to unsigned int for compatibility reasons */ \ + unsigned int t1 = static_cast(tmp); \ + _os.write( (const char*)&t1, sizeof(unsigned int) ); \ + return _os.good() ? sizeof(unsigned int) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + unsigned int t1; \ + _is.read( (char*)&t1, sizeof(unsigned int) ); \ + _val = t1; \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(unsigned int) : 0; \ + } \ + } + +SIMPLE_BINARY(unsigned long); + +#undef SIMPLE_BINARY + +#define VECTORT_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t size_of(const value_type&) { return size_of(); } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + size_t i, b = size_of(_val), N = value_type::size_; \ + if (_swap) for (i=0; i struct binary< std::string > { + typedef std::string value_type; + typedef uint16_t length_t; + + static const bool is_streamable = true; + + static size_t size_of() { return UnknownSize; } + static size_t size_of(const value_type &_v) + { return sizeof(length_t) + _v.size(); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) + if (_v.size() < Utils::NumLimitsT::max() ) +#else + if (_v.size() < std::numeric_limits::max() ) +#endif + { + length_t len = length_t(_v.size()); + + size_t bytes = binary::store( _os, len, _swap ); + _os.write( _v.data(), len ); + return _os.good() ? len+bytes : 0; + } + throw std::runtime_error("Cannot store string longer than 64Kb"); + } + + static + size_t restore(std::istream& _is, value_type& _val, bool _swap=false) + { + length_t len; + size_t bytes = binary::restore( _is, len, _swap ); + _val.resize(len); + _is.read( const_cast(_val.data()), len ); + + return _is.good() ? (len+bytes) : 0; + } +}; + + +template <> struct binary +{ + typedef OpenMesh::Attributes::StatusInfo value_type; + typedef value_type::value_type status_t; + + static const bool is_streamable = true; + + static size_t size_of() { return sizeof(status_t); } + static size_t size_of(const value_type&) { return size_of(); } + + static size_t n_bytes(size_t _n_elem) + { return _n_elem*sizeof(status_t); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + status_t v=_v.bits(); + return binary::store(_os, v, _swap); + } + + static + size_t restore( std::istream& _os, value_type& _v, bool _swap=false) + { + status_t v; + size_t b = binary::restore(_os, v, _swap); + _v.set_bits(v); + return b; + } +}; + + +//----------------------------------------------------------------------------- +// std::vector specializations for struct binary<> + +template +struct FunctorStore { + FunctorStore( std::ostream& _os, bool _swap) : os_(_os), swap_(_swap) { } + size_t operator () ( size_t _v1, const T& _s2 ) + { return _v1+binary::store(os_, _s2, swap_ ); } + + std::ostream& os_; + bool swap_; +}; + + +template +struct FunctorRestore { + FunctorRestore( std::istream& _is, bool _swap) : is_(_is), swap_(_swap) { } + size_t operator () ( size_t _v1, T& _s2 ) + { return _v1+binary::restore(is_, _s2, swap_ ); } + std::istream& is_; + bool swap_; +}; + +#include +#include +#include + +// ---------------------------------------------------------------------------- + +#endif // DOXY_IGNORE_THIS + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_BINARY_SPEC_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_bool.inl b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_bool.inl new file mode 100644 index 0000000..3ec619c --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_bool.inl @@ -0,0 +1,98 @@ + +template <> struct binary< std::vector > +{ + + typedef std::vector< bool > value_type; + typedef value_type::value_type elem_type; + + static const bool is_streamable = true; + + static size_t size_of(void) { return UnknownSize; } + static size_t size_of(const value_type& _v) + { + return _v.size() / 8 + ((_v.size() % 8)!=0); + } + + static + size_t store( std::ostream& _ostr, const value_type& _v, bool ) + { + size_t bytes = 0; + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + size_t idx; // element index + unsigned char bits; // bitset + + for (idx=0; idx < N; ++idx) + { + bits = static_cast(_v[idx]) + | (static_cast(_v[idx+1]) << 1) + | (static_cast(_v[idx+2]) << 2) + | (static_cast(_v[idx+3]) << 3) + | (static_cast(_v[idx+4]) << 4) + | (static_cast(_v[idx+5]) << 5) + | (static_cast(_v[idx+6]) << 6) + | (static_cast(_v[idx+7]) << 7); + _ostr << bits; + } + bytes = N; + + if (R) + { + bits = 0; + switch(R) + { + case 7: bits |= (static_cast(_v[idx+6]) << 6); + case 6: bits |= (static_cast(_v[idx+5]) << 5); + case 5: bits |= (static_cast(_v[idx+4]) << 4); + case 4: bits |= (static_cast(_v[idx+3]) << 3); + case 3: bits |= (static_cast(_v[idx+2]) << 2); + case 2: bits |= (static_cast(_v[idx+1]) << 1); + case 1: bits |= static_cast(_v[idx+0]); + } + _ostr << bits; + ++bytes; + } + + assert( bytes == size_of(_v) ); + + return bytes; + } + + static + size_t restore( std::istream& _istr, value_type& _v, bool ) + { + size_t bytes = 0; + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + size_t idx; // element index + unsigned char bits; // bitset + + for (idx=0; idx < N; ++idx) + { + _istr >> bits; + _v[idx+0] = ((bits & 0x01)!=0); + _v[idx+1] = ((bits & 0x02)!=0); + _v[idx+2] = ((bits & 0x04)!=0); + _v[idx+3] = ((bits & 0x08)!=0); + _v[idx+4] = ((bits & 0x10)!=0); + _v[idx+5] = ((bits & 0x20)!=0); + _v[idx+6] = ((bits & 0x40)!=0); + _v[idx+7] = ((bits & 0x80)!=0); + } + bytes = N; + + if (R) + { + _istr >> bits; + for(; idx < _v.size(); ++idx) + _v[idx] = (bits & (1 << (idx%8)))!=0; + ++bytes; + } + + return bytes; + } +}; diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_fundamentals.inl b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_fundamentals.inl new file mode 100644 index 0000000..15ebae2 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_fundamentals.inl @@ -0,0 +1,53 @@ + +#define BINARY_VECTOR( T ) \ +template <> struct binary< std::vector< T > > { \ + typedef std::vector< T > value_type; \ + typedef value_type::value_type elem_type; \ + \ + static const bool is_streamable = true; \ + \ + static size_t size_of(void) \ + { return IO::UnknownSize; } \ + \ + static size_t size_of(const value_type& _v) \ + { return sizeof(elem_type)*_v.size(); } \ + \ + static \ + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) { \ + size_t bytes=0; \ + \ + if (_swap) \ + bytes = std::accumulate( _v.begin(), _v.end(), bytes, \ + FunctorStore(_os,_swap) ); \ + else { \ + bytes = size_of(_v); \ + _os.write( reinterpret_cast(&_v[0]), bytes ); \ + } \ + return _os.good() ? bytes : 0; \ + } \ + \ + static size_t restore(std::istream& _is, value_type& _v, bool _swap=false) { \ + size_t bytes=0; \ + \ + if ( _swap) \ + bytes = std::accumulate( _v.begin(), _v.end(), size_t(0), \ + FunctorRestore(_is, _swap) ); \ + else \ + { \ + bytes = size_of(_v); \ + _is.read( reinterpret_cast(&_v[0]), bytes ); \ + } \ + return _is.good() ? bytes : 0; \ + } \ +} + +BINARY_VECTOR( short ); +BINARY_VECTOR( unsigned short ); +BINARY_VECTOR( int ); +BINARY_VECTOR( unsigned int ); +BINARY_VECTOR( long ); +BINARY_VECTOR( unsigned long ); +BINARY_VECTOR( float ); +BINARY_VECTOR( double ); + +#undef BINARY_VECTOR diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_string.inl b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_string.inl new file mode 100644 index 0000000..c6201de --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_binary_vector_of_string.inl @@ -0,0 +1,39 @@ + +template <> struct binary< std::vector< std::string > > +{ + // struct binary interface + + typedef std::vector< std::string > value_type; + typedef value_type::value_type elem_type; + + static const bool is_streamable = true; + + // Helper + + struct Sum + { + size_t operator() ( size_t _v1, const elem_type& _s2 ) + { return _v1 + binary::size_of(_s2); } + }; + + // struct binary interface + + static size_t size_of(void) { return UnknownSize; } + + static size_t size_of(const value_type& _v) + { return std::accumulate( _v.begin(), _v.end(), size_t(0), Sum() ); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + return std::accumulate( _v.begin(), _v.end(), size_t(0), + FunctorStore(_os, _swap) ); + } + + static + size_t restore(std::istream& _is, value_type& _v, bool _swap=false) + { + return std::accumulate( _v.begin(), _v.end(), size_t(0), + FunctorRestore(_is, _swap) ); + } +}; diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_rbo.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_rbo.hh new file mode 100644 index 0000000..64275c4 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_rbo.hh @@ -0,0 +1,256 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_RBO_HH +#define OPENMESH_SR_RBO_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined(OM_CC_MIPS) +# include // size_t +#else +# include // size_t +#endif +#include +#include +// -------------------- OpenMesh +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ + +template < size_t N > inline +void _reverse_byte_order_N(uint8_t* _val); + +template <> inline +void _reverse_byte_order_N<1>(uint8_t* /*_val*/) { } + + +template <> inline +void _reverse_byte_order_N<2>(uint8_t* _val) +{ + _val[0] ^= _val[1]; _val[1] ^= _val[0]; _val[0] ^= _val[1]; +} + + +template <> inline +void _reverse_byte_order_N<4>(uint8_t* _val) +{ + _val[0] ^= _val[3]; _val[3] ^= _val[0]; _val[0] ^= _val[3]; // 0 <-> 3 + _val[1] ^= _val[2]; _val[2] ^= _val[1]; _val[1] ^= _val[2]; // 1 <-> 2 +} + + +template <> inline +void _reverse_byte_order_N<8>(uint8_t* _val) +{ + _val[0] ^= _val[7]; _val[7] ^= _val[0]; _val[0] ^= _val[7]; // 0 <-> 7 + _val[1] ^= _val[6]; _val[6] ^= _val[1]; _val[1] ^= _val[6]; // 1 <-> 6 + _val[2] ^= _val[5]; _val[5] ^= _val[2]; _val[2] ^= _val[5]; // 2 <-> 5 + _val[3] ^= _val[4]; _val[4] ^= _val[3]; _val[3] ^= _val[4]; // 3 <-> 4 +} + + +template <> inline +void _reverse_byte_order_N<12>(uint8_t* _val) +{ + _val[0] ^= _val[11]; _val[11] ^= _val[0]; _val[0] ^= _val[11]; // 0 <-> 11 + _val[1] ^= _val[10]; _val[10] ^= _val[1]; _val[1] ^= _val[10]; // 1 <-> 10 + _val[2] ^= _val[ 9]; _val[ 9] ^= _val[2]; _val[2] ^= _val[ 9]; // 2 <-> 9 + _val[3] ^= _val[ 8]; _val[ 8] ^= _val[3]; _val[3] ^= _val[ 8]; // 3 <-> 8 + _val[4] ^= _val[ 7]; _val[ 7] ^= _val[4]; _val[4] ^= _val[ 7]; // 4 <-> 7 + _val[5] ^= _val[ 6]; _val[ 6] ^= _val[5]; _val[5] ^= _val[ 6]; // 5 <-> 6 +} + + +template <> inline +void _reverse_byte_order_N<16>(uint8_t* _val) +{ + _reverse_byte_order_N<8>(_val); + _reverse_byte_order_N<8>(_val+8); + std::swap(*(uint64_t*)_val, *(((uint64_t*)_val)+1)); +} + + +//----------------------------------------------------------------------------- +// wrapper for byte reordering + +// reverting pointers makes no sense, hence forbid it. +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ +template inline T* reverse_byte_order(T* t); +// Should never reach this point. If so, then some operator were not +// overloaded. Especially check for IO::binary<> specialization on +// custom data types. + + +inline void compile_time_error__no_fundamental_type() +{ + // we should never reach this point + assert(false); +} + +// default action for byte reversal: cause an error to avoid +// surprising behaviour! +template T& reverse_byte_order( T& _t ) +{ + omerr() << "Not defined for type " << typeid(T).name() << std::endl; + compile_time_error__no_fundamental_type(); + return _t; +} + +template <> inline bool& reverse_byte_order(bool & _t) { return _t; } +template <> inline char& reverse_byte_order(char & _t) { return _t; } +#if defined(OM_CC_GCC) +template <> inline signed char& reverse_byte_order(signed char & _t) { return _t; } +#endif +template <> inline uchar& reverse_byte_order(uchar& _t) { return _t; } + +// Instead do specializations for the necessary types +#define REVERSE_FUNDAMENTAL_TYPE( T ) \ + template <> inline T& reverse_byte_order( T& _t ) {\ + _reverse_byte_order_N( reinterpret_cast(&_t) ); \ + return _t; \ + } + +// REVERSE_FUNDAMENTAL_TYPE(bool) +// REVERSE_FUNDAMENTAL_TYPE(char) +// REVERSE_FUNDAMENTAL_TYPE(uchar) +REVERSE_FUNDAMENTAL_TYPE(int16_t) +REVERSE_FUNDAMENTAL_TYPE(uint16_t) +// REVERSE_FUNDAMENTAL_TYPE(int) +// REVERSE_FUNDAMENTAL_TYPE(uint) + +REVERSE_FUNDAMENTAL_TYPE(unsigned long) +REVERSE_FUNDAMENTAL_TYPE(int32_t) +REVERSE_FUNDAMENTAL_TYPE(uint32_t) +REVERSE_FUNDAMENTAL_TYPE(int64_t) +REVERSE_FUNDAMENTAL_TYPE(uint64_t) +REVERSE_FUNDAMENTAL_TYPE(float) +REVERSE_FUNDAMENTAL_TYPE(double) +REVERSE_FUNDAMENTAL_TYPE(long double) + +#undef REVERSE_FUNDAMENTAL_TYPE + +#if 0 + +#define REVERSE_VECTORT_TYPE( T ) \ + template <> inline T& reverse_byte_order(T& _v) {\ + for (size_t i; i< T::size_; ++i) \ + _reverse_byte_order_N< sizeof(T::value_type) >( reinterpret_cast(&_v[i])); \ + return _v; \ + } + +#define REVERSE_VECTORT_TYPES( N ) \ + REVERSE_VECTORT_TYPE( Vec##N##c ) \ + REVERSE_VECTORT_TYPE( Vec##N##uc ) \ + REVERSE_VECTORT_TYPE( Vec##N##s ) \ + REVERSE_VECTORT_TYPE( Vec##N##us ) \ + REVERSE_VECTORT_TYPE( Vec##N##i ) \ + REVERSE_VECTORT_TYPE( Vec##N##ui ) \ + REVERSE_VECTORT_TYPE( Vec##N##f ) \ + REVERSE_VECTORT_TYPE( Vec##N##d ) \ + +REVERSE_VECTORT_TYPES(1) +REVERSE_VECTORT_TYPES(2) +REVERSE_VECTORT_TYPES(3) +REVERSE_VECTORT_TYPES(4) +REVERSE_VECTORT_TYPES(6) + +#undef REVERSE_VECTORT_TYPES +#undef REVERSE_VECTORT_TYPE + +#endif + +template inline +T reverse_byte_order(const T& a) +{ + compile_timer_error__const_means_const(a); + return a; +} + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_store.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_store.hh new file mode 100644 index 0000000..e1b99a0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_store.hh @@ -0,0 +1,72 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_STORE_HH +#define OPENMESH_SR_STORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include + +//============================================================================= +#endif // OPENMESH_STORE_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_types.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_types.hh new file mode 100644 index 0000000..9628f59 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/SR_types.hh @@ -0,0 +1,112 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_TYPES_HH +#define OPENMESH_SR_TYPES_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +typedef signed char int8_t; typedef unsigned char uint8_t; +typedef short int16_t; typedef unsigned short uint16_t; + +// Int should be 32 bit on all archs. +// long is 32 under windows but 64 under unix 64 bit +typedef int int32_t; typedef unsigned int uint32_t; +#if defined(OM_CC_MSVC) +typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#else +typedef long long int64_t; typedef unsigned long long uint64_t; +#endif + +typedef float float32_t; +typedef double float64_t; + +typedef uint8_t rgb_t[3]; +typedef uint8_t rgba_t[4]; + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/StoreRestore.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/StoreRestore.hh new file mode 100644 index 0000000..fff6708 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/StoreRestore.hh @@ -0,0 +1,117 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_STORERESTORE_HH +#define OPENMESH_STORERESTORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- +// StoreRestore definitions + +template inline +bool is_streamable(void) +{ return binary< T >::is_streamable; } + +template inline +bool is_streamable( const T& ) +{ return binary< T >::is_streamable; } + +template inline +size_t size_of( const T& _v ) +{ return binary< T >::size_of(_v); } + +template inline +size_t size_of(void) +{ return binary< T >::size_of(); } + +template inline +size_t store( std::ostream& _os, const T& _v, bool _swap=false) +{ return binary< T >::store( _os, _v, _swap ); } + +template inline +size_t restore( std::istream& _is, T& _v, bool _swap=false) +{ return binary< T >::restore( _is, _v, _swap ); } + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/exporter/BaseExporter.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/exporter/BaseExporter.hh new file mode 100644 index 0000000..477d95a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/exporter/BaseExporter.hh @@ -0,0 +1,165 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for MeshWriter exporter modules +// +//============================================================================= + + +#ifndef __BASEEXPORTER_HH__ +#define __BASEEXPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER ================================================================ + + +/** + Base class for exporter modules. + The exporter modules provide an interface between the writer modules and + the target data structure. +*/ + +class OPENMESHDLLEXPORT BaseExporter +{ +public: + + virtual ~BaseExporter() { } + + + // get vertex data + virtual Vec3f point(VertexHandle _vh) const = 0; + virtual Vec3f normal(VertexHandle _vh) const = 0; + virtual Vec3uc color(VertexHandle _vh) const = 0; + virtual Vec4uc colorA(VertexHandle _vh) const = 0; + virtual Vec3ui colori(VertexHandle _vh) const = 0; + virtual Vec4ui colorAi(VertexHandle _vh) const = 0; + virtual Vec3f colorf(VertexHandle _vh) const = 0; + virtual Vec4f colorAf(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0; + + + // get face data + virtual unsigned int + get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const=0; + /// + /// \brief getHeh returns the HalfEdgeHandle that belongs to the face + /// specified by _fh and has a toVertexHandle that corresponds to _vh. + /// \param _fh FaceHandle that is used to search for the half edge handle + /// \param _vh to_vertex_handle of the searched heh + /// \return HalfEdgeHandle or invalid HalfEdgeHandle if none is found. + /// + virtual HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const = 0; + virtual unsigned int + get_face_texcoords(std::vector& _hehandles) const = 0; + virtual Vec3f normal(FaceHandle _fh) const = 0; + virtual Vec3uc color (FaceHandle _fh) const = 0; + virtual Vec4uc colorA(FaceHandle _fh) const = 0; + virtual Vec3ui colori(FaceHandle _fh) const = 0; + virtual Vec4ui colorAi(FaceHandle _fh) const = 0; + virtual Vec3f colorf(FaceHandle _fh) const = 0; + virtual Vec4f colorAf(FaceHandle _fh) const = 0; + + // get edge data + virtual Vec3uc color(EdgeHandle _eh) const = 0; + virtual Vec4uc colorA(EdgeHandle _eh) const = 0; + virtual Vec3ui colori(EdgeHandle _eh) const = 0; + virtual Vec4ui colorAi(EdgeHandle _eh) const = 0; + virtual Vec3f colorf(EdgeHandle _eh) const = 0; + virtual Vec4f colorAf(EdgeHandle _eh) const = 0; + + // get reference to base kernel + virtual const BaseKernel* kernel() { return 0; } + + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // property information + virtual bool is_triangle_mesh() const { return false; } + virtual bool has_vertex_normals() const { return false; } + virtual bool has_vertex_colors() const { return false; } + virtual bool has_vertex_texcoords() const { return false; } + virtual bool has_edge_colors() const { return false; } + virtual bool has_face_normals() const { return false; } + virtual bool has_face_colors() const { return false; } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/exporter/ExporterT.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/exporter/ExporterT.hh new file mode 100644 index 0000000..9a9d9b3 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/exporter/ExporterT.hh @@ -0,0 +1,338 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an exporter module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __EXPORTERT_HH__ +#define __EXPORTERT_HH__ + + +//=== INCLUDES ================================================================ + +// C++ +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER CLASS ========================================================== + +/** + * This class template provides an exporter module for OpenMesh meshes. + */ +template +class ExporterT : public BaseExporter +{ +public: + + // Constructor + ExporterT(const Mesh& _mesh) : mesh_(_mesh) {} + + + // get vertex data + + Vec3f point(VertexHandle _vh) const + { + return vector_cast(mesh_.point(_vh)); + } + + Vec3f normal(VertexHandle _vh) const + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3uc color(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4f(0, 0, 0, 0)); + } + + Vec2f texcoord(VertexHandle _vh) const + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION<30000) + // Workaround! + // gcc 2.95.3 exits with internal compiler error at the + // code below!??? **) + if (mesh_.has_vertex_texcoords2D()) + return vector_cast(mesh_.texcoord2D(_vh)); + return Vec2f(0.0f, 0.0f); +#else // **) + return (mesh_.has_vertex_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_vh)) + : Vec2f(0.0f, 0.0f)); +#endif + } + + Vec2f texcoord(HalfedgeHandle _heh) const + { + return (mesh_.has_halfedge_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_heh)) + : Vec2f(0.0f, 0.0f)); + } + + // get edge data + + Vec3uc color(EdgeHandle _eh) const + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(EdgeHandle _eh) const + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(EdgeHandle _eh) const + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(EdgeHandle _eh) const + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(EdgeHandle _eh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(EdgeHandle _eh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4f(0, 0, 0, 0)); + } + + // get face data + + unsigned int get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const + { + unsigned int count(0); + _vhandles.clear(); + for (typename Mesh::CFVIter fv_it=mesh_.cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + _vhandles.push_back(*fv_it); + ++count; + } + return count; + } + + unsigned int get_face_texcoords(std::vector& _hehandles) const + { + unsigned int count(0); + _hehandles.clear(); + for(typename Mesh::CHIter he_it=mesh_.halfedges_begin(); + he_it != mesh_.halfedges_end(); ++he_it) + { + _hehandles.push_back(vector_cast(mesh_.texcoord2D( *he_it))); + ++count; + } + + return count; + } + + HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const + { + typename Mesh::ConstFaceHalfedgeIter fh_it; + for(fh_it = mesh_.cfh_iter(_fh); fh_it.is_valid();++fh_it) + { + if(mesh_.to_vertex_handle(*fh_it) == _vh) + return *fh_it; + } + return *fh_it; + } + + Vec3f normal(FaceHandle _fh) const + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3uc color(FaceHandle _fh) const + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(FaceHandle _fh) const + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(FaceHandle _fh) const + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(FaceHandle _fh) const + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(FaceHandle _fh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(FaceHandle _fh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4f(0, 0, 0, 0)); + } + + virtual const BaseKernel* kernel() { return &mesh_; } + + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const { return mesh_.n_vertices(); } + size_t n_faces() const { return mesh_.n_faces(); } + size_t n_edges() const { return mesh_.n_edges(); } + + + // property information + bool is_triangle_mesh() const + { return Mesh::is_triangles(); } + + bool has_vertex_normals() const { return mesh_.has_vertex_normals(); } + bool has_vertex_colors() const { return mesh_.has_vertex_colors(); } + bool has_vertex_texcoords() const { return mesh_.has_vertex_texcoords2D(); } + bool has_edge_colors() const { return mesh_.has_edge_colors(); } + bool has_face_normals() const { return mesh_.has_face_normals(); } + bool has_face_colors() const { return mesh_.has_face_colors(); } + +private: + + const Mesh& mesh_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/importer/BaseImporter.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/importer/BaseImporter.hh new file mode 100644 index 0000000..afcfd6c --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/importer/BaseImporter.hh @@ -0,0 +1,205 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for IOManager importer modules +// +//============================================================================= + + +#ifndef __BASEIMPORTER_HH__ +#define __BASEIMPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** Base class for importer modules. Importer modules provide an + * interface between the loader modules and the target data + * structure. This is basically a wrapper providing virtual versions + * for the required mesh functions. + */ +class OPENMESHDLLEXPORT BaseImporter +{ +public: + + // base class needs virtual destructor + virtual ~BaseImporter() {} + + + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3f& _point) = 0; + + // add a vertex without coordinate. Use set_point to set the position deferred + virtual VertexHandle add_vertex() = 0; + + // add a face with indices _indices refering to vertices + typedef std::vector VHandles; + virtual FaceHandle add_face(const VHandles& _indices) = 0; + + // add texture coordinates per face, _vh references the first texcoord + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; + + // add texture 3d coordinates per face, _vh references the first texcoord + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; + + // Set the texture index for a face + virtual void set_face_texindex( FaceHandle _fh, int _texId ) = 0; + + // Set coordinate of the given vertex. Use this function, if you created a vertex without coordinate + virtual void set_point(VertexHandle _vh, const Vec3f& _point) = 0; + + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3f& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4f& _color) = 0; + + // set vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; + + // set vertex texture coordinate + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0; + + // set 3d vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec3f& _texcoord) = 0; + + // set 3d vertex texture coordinate + virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec4uc& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec3f& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec4f& _color) = 0; + + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3f& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4f& _color) = 0; + + // Store a property in the mesh mapping from an int to a texture file + // Use set_face_texindex to set the index for each face + virtual void add_texture_information( int _id , std::string _name ) = 0; + + // get reference to base kernel + virtual BaseKernel* kernel() { return 0; } + + virtual bool is_triangle_mesh() const { return false; } + + // reserve mem for elements + virtual void reserve( unsigned int /* nV */, + unsigned int /* nE */, + unsigned int /* nF */) {} + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // pre-processing + virtual void prepare() {} + + // post-processing + virtual void finish() {} +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/importer/ImporterT.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/importer/ImporterT.hh new file mode 100644 index 0000000..fb6b669 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/importer/ImporterT.hh @@ -0,0 +1,408 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an importer module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __IMPORTERT_HH__ +#define __IMPORTERT_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + * This class template provides an importer module for OpenMesh meshes. + */ +template +class ImporterT : public BaseImporter +{ +public: + + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal Normal; + typedef typename Mesh::Color Color; + typedef typename Mesh::TexCoord2D TexCoord2D; + typedef typename Mesh::TexCoord3D TexCoord3D; + typedef std::vector VHandles; + + + ImporterT(Mesh& _mesh) : mesh_(_mesh), halfedgeNormals_() {} + + + virtual VertexHandle add_vertex(const Vec3f& _point) + { + return mesh_.add_vertex(vector_cast(_point)); + } + + virtual VertexHandle add_vertex() + { + return mesh_.new_vertex(); + } + + virtual FaceHandle add_face(const VHandles& _indices) + { + FaceHandle fh; + + if (_indices.size() > 2) + { + VHandles::const_iterator it, it2, end(_indices.end()); + + + // test for valid vertex indices + for (it=_indices.begin(); it!=end; ++it) + if (! mesh_.is_valid_handle(*it)) + { + omerr() << "ImporterT: Face contains invalid vertex index\n"; + return fh; + } + + + // don't allow double vertices + for (it=_indices.begin(); it!=end; ++it) + for (it2=it+1; it2!=end; ++it2) + if (*it == *it2) + { + omerr() << "ImporterT: Face has equal vertices\n"; + return fh; + } + + + // try to add face + fh = mesh_.add_face(_indices); + // separate non-manifold faces and mark them + if (!fh.is_valid()) + { + VHandles vhandles(_indices.size()); + + // double vertices + for (unsigned int j=0; j<_indices.size(); ++j) + { + // DO STORE p, reference may not work since vertex array + // may be relocated after adding a new vertex ! + Point p = mesh_.point(_indices[j]); + vhandles[j] = mesh_.add_vertex(p); + + // Mark vertices of failed face as non-manifold + if (mesh_.has_vertex_status()) { + mesh_.status(vhandles[j]).set_fixed_nonmanifold(true); + } + } + + // add face + fh = mesh_.add_face(vhandles); + + // Mark failed face as non-manifold + if (mesh_.has_face_status()) + mesh_.status(fh).set_fixed_nonmanifold(true); + + // Mark edges of failed face as non-two-manifold + if (mesh_.has_edge_status()) { + typename Mesh::FaceEdgeIter fe_it = mesh_.fe_iter(fh); + for(; fe_it.is_valid(); ++fe_it) { + mesh_.status(*fe_it).set_fixed_nonmanifold(true); + } + } + } + + //write the half edge normals + if (mesh_.has_halfedge_normals()) + { + //iterate over all incoming haldedges of the added face + for (typename Mesh::FaceHalfedgeIter fh_iter = mesh_.fh_begin(fh); + fh_iter != mesh_.fh_end(fh); ++fh_iter) + { + //and write the normals to it + typename Mesh::HalfedgeHandle heh = *fh_iter; + typename Mesh::VertexHandle vh = mesh_.to_vertex_handle(heh); + typename std::map::iterator it_heNs = halfedgeNormals_.find(vh); + if (it_heNs != halfedgeNormals_.end()) + mesh_.set_normal(heh,it_heNs->second); + } + halfedgeNormals_.clear(); + } + } + return fh; + } + + // vertex attributes + + virtual void set_point(VertexHandle _vh, const Vec3f& _point) + { + mesh_.set_point(_vh,vector_cast(_point)); + } + + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + + //saves normals for half edges. + //they will be written, when the face is added + if (mesh_.has_halfedge_normals()) + halfedgeNormals_[_vh] = vector_cast(_normal); + } + + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec4f& _color) + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3f& _color) + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) + { + if (mesh_.has_vertex_texcoords2D()) + mesh_.set_texcoord2D(_vh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) + { + if (mesh_.has_halfedge_texcoords2D()) + mesh_.set_texcoord2D(_heh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(VertexHandle _vh, const Vec3f& _texcoord) + { + if (mesh_.has_vertex_texcoords3D()) + mesh_.set_texcoord3D(_vh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) + { + if (mesh_.has_halfedge_texcoords3D()) + mesh_.set_texcoord3D(_heh, vector_cast(_texcoord)); + } + + + // edge attributes + + virtual void set_color(EdgeHandle _eh, const Vec4uc& _color) + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec4f& _color) + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec3f& _color) + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + // face attributes + + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec3f& _color) + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4f& _color) + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) + { + // get first halfedge handle + HalfedgeHandle cur_heh = mesh_.halfedge_handle(_fh); + HalfedgeHandle end_heh = mesh_.prev_halfedge_handle(cur_heh); + + // find start heh + while( mesh_.to_vertex_handle(cur_heh) != _vh && cur_heh != end_heh ) + cur_heh = mesh_.next_halfedge_handle( cur_heh); + + for(unsigned int i=0; i<_face_texcoords.size(); ++i) + { + set_texcoord( cur_heh, _face_texcoords[i]); + cur_heh = mesh_.next_halfedge_handle( cur_heh); + } + } + + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) + { + // get first halfedge handle + HalfedgeHandle cur_heh = mesh_.halfedge_handle(_fh); + HalfedgeHandle end_heh = mesh_.prev_halfedge_handle(cur_heh); + + // find start heh + while( mesh_.to_vertex_handle(cur_heh) != _vh && cur_heh != end_heh ) + cur_heh = mesh_.next_halfedge_handle( cur_heh); + + for(unsigned int i=0; i<_face_texcoords.size(); ++i) + { + set_texcoord( cur_heh, _face_texcoords[i]); + cur_heh = mesh_.next_halfedge_handle( cur_heh); + } + } + + virtual void set_face_texindex( FaceHandle _fh, int _texId ) { + if ( mesh_.has_face_texture_index() ) { + mesh_.set_texture_index(_fh , _texId); + } + } + + virtual void add_texture_information( int _id , std::string _name ) { + OpenMesh::MPropHandleT< std::map< int, std::string > > property; + + if ( !mesh_.get_property_handle(property,"TextureMapping") ) { + mesh_.add_property(property,"TextureMapping"); + } + + if ( mesh_.property(property).find( _id ) == mesh_.property(property).end() ) + mesh_.property(property)[_id] = _name; + } + + // low-level access to mesh + + virtual BaseKernel* kernel() { return &mesh_; } + + bool is_triangle_mesh() const + { return Mesh::is_triangles(); } + + void reserve(unsigned int nV, unsigned int nE, unsigned int nF) + { + mesh_.reserve(nV, nE, nF); + } + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const { return mesh_.n_vertices(); } + size_t n_faces() const { return mesh_.n_faces(); } + size_t n_edges() const { return mesh_.n_edges(); } + + + void prepare() { } + + + void finish() { } + + +private: + + Mesh& mesh_; + // stores normals for halfedges of the next face + std::map halfedgeNormals_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/BaseReader.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/BaseReader.cc new file mode 100644 index 0000000..d1cc8d9 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/BaseReader.cc @@ -0,0 +1,132 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//=== INCLUDES ================================================================ + +#include + +#if defined(OM_CC_MIPS) +# include +#else +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +static inline char tolower(char c) +{ + using namespace std; + return ::tolower(c); +} + + +//----------------------------------------------------------------------------- + + +bool +BaseReader:: +can_u_read(const std::string& _filename) const +{ + // get file extension + std::string extension; + std::string::size_type pos(_filename.rfind(".")); + + if (pos != std::string::npos) + extension = _filename.substr(pos+1, _filename.length()-pos-1); + else + extension = _filename; //check, if the whole filename defines the extension + + std::transform( extension.begin(), extension.end(), + extension.begin(), tolower ); + + // locate extension in extension string + return (get_extensions().find(extension) != std::string::npos); +} + + +//----------------------------------------------------------------------------- + + +bool +BaseReader:: +check_extension(const std::string& _fname, const std::string& _ext) const +{ + std::string cmpExt(_ext); + + std::transform( _ext.begin(), _ext.end(), cmpExt.begin(), tolower ); + + std::string::size_type pos(_fname.rfind(".")); + + if (pos != std::string::npos && !_ext.empty() ) + { + std::string ext; + + // extension without dot! + ext = _fname.substr(pos+1, _fname.length()-pos-1); + + std::transform( ext.begin(), ext.end(), ext.begin(), tolower ); + + return ext == cmpExt; + } + return false; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/BaseReader.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/BaseReader.hh new file mode 100644 index 0000000..463b9c7 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/BaseReader.hh @@ -0,0 +1,213 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for IOManager file access modules +// +//============================================================================= + + +#ifndef __BASEREADER_HH__ +#define __BASEREADER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for reader modules. + Reader modules access persistent data and pass them to the desired + data structure by the means of a BaseImporter derivative. + All reader modules must be derived from this class. +*/ +class OPENMESHDLLEXPORT BaseReader +{ +public: + + /// Destructor + virtual ~BaseReader() {}; + + /// Returns a brief description of the file type that can be parsed. + virtual std::string get_description() const = 0; + + /** Returns a string with the accepted file extensions separated by a + whitespace and in small caps. + */ + virtual std::string get_extensions() const = 0; + + /// Return magic bits used to determine file format + virtual std::string get_magic() const { return std::string(""); } + + + /** Reads a mesh given by a filename. Usually this method opens a stream + and passes it to stream read method. Acceptance checks by filename + extension can be placed here. + + Options can be passed via _opt. After execution _opt contains the Options + that were available + */ + virtual bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) = 0; + + /** Reads a mesh given by a std::stream. This method usually uses the same stream reading method + that read uses. Options can be passed via _opt. After execution _opt contains the Options + that were available. + + Please make sure that if _is is std::ifstream, the correct std::ios_base::openmode flags are set. + */ + virtual bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) = 0; + + + /** \brief Returns true if writer can parse _filename (checks extension). + * _filename can also provide an extension without a name for a file e.g. _filename == "om" checks, if the reader can read the "om" extension + * @param _filename complete name of a file or just the extension + * @result true, if reader can read data with the given extension + */ + virtual bool can_u_read(const std::string& _filename) const; + + +protected: + + // case insensitive search for _ext in _fname. + bool check_extension(const std::string& _fname, + const std::string& _ext) const; +}; + + +/** \brief Trim left whitespace + * + * Removes whitespace at the beginning of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &left_trim(std::string &_string) { + + // Find out if the compiler supports CXX11 + #if ( __cplusplus >= 201103L || _MSVC_LANG >= 201103L ) + // as with CXX11 we can use lambda expressions + _string.erase(_string.begin(), std::find_if(_string.begin(), _string.end(), [](int i)->int { return ! std::isspace(i); })); + #else + // we do what we did before + _string.erase(_string.begin(), std::find_if(_string.begin(), _string.end(), std::not1(std::ptr_fun(std::isspace)))); + #endif + + return _string; +} + +/** \brief Trim right whitespace + * + * Removes whitespace at the end of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &right_trim(std::string &_string) { + + // Find out if the compiler supports CXX11 + #if ( __cplusplus >= 201103L || _MSVC_LANG >= 201103L ) + // as with CXX11 we can use lambda expressions + _string.erase(std::find_if(_string.rbegin(), _string.rend(), [](int i)->int { return ! std::isspace(i); } ).base(), _string.end()); + #else + // we do what we did before + _string.erase(std::find_if(_string.rbegin(), _string.rend(), std::not1(std::ptr_fun(std::isspace))).base(), _string.end()); + #endif + + + + return _string; +} + +/** \brief Trim whitespace + * + * Removes whitespace at the beginning and end of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &trim(std::string &_string) { + return left_trim(right_trim(_string)); +} + + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OBJReader.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OBJReader.cc new file mode 100644 index 0000000..6be24e0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OBJReader.cc @@ -0,0 +1,808 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +// OpenMesh +#include +#include +#include +#include +// STL +#if defined(OM_CC_MIPS) +# include +/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std! +#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460) +# include +#else +using std::isspace; +#endif + +#ifndef WIN32 +#endif + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +_OBJReader_ __OBJReaderInstance; +_OBJReader_& OBJReader() { return __OBJReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + +//----------------------------------------------------------------------------- + +void trimString( std::string& _string) { + // Trim Both leading and trailing spaces + + size_t start = _string.find_first_not_of(" \t\r\n"); + size_t end = _string.find_last_not_of(" \t\r\n"); + + if(( std::string::npos == start ) || ( std::string::npos == end)) + _string = ""; + else + _string = _string.substr( start, end-start+1 ); +} + +//----------------------------------------------------------------------------- + +// remove duplicated indices from one face +void remove_duplicated_vertices(BaseImporter::VHandles& _indices) +{ + BaseImporter::VHandles::iterator endIter = _indices.end(); + for (BaseImporter::VHandles::iterator iter = _indices.begin(); iter != endIter; ++iter) + endIter = std::remove(iter+1, endIter, *(iter)); + + _indices.erase(endIter,_indices.end()); +} + +//----------------------------------------------------------------------------- + +_OBJReader_:: +_OBJReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OBJReader_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + std::fstream in( _filename.c_str(), std::ios_base::in ); + + if (!in.is_open() || !in.good()) + { + omerr() << "[OBJReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + { +#if defined(WIN32) + std::string::size_type dot = _filename.find_last_of("\\/"); +#else + std::string::size_type dot = _filename.rfind("/"); +#endif + path_ = (dot == std::string::npos) + ? "./" + : std::string(_filename.substr(0,dot+1)); + } + + bool result = read(in, _bi, _opt); + + in.close(); + return result; +} + +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read_material(std::fstream& _in) +{ + std::string line; + std::string keyWrd; + std::string textureName; + + std::stringstream stream; + + std::string key; + Material mat; + float f1,f2,f3; + bool indef = false; + int textureId = 1; + + + materials_.clear(); + mat.cleanup(); + + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + if ( line.empty() ) + continue; + + stream.str(line); + stream.clear(); + + stream >> keyWrd; + + if( ( isspace(line[0]) && line[0] != '\t' ) || line[0] == '#' ) + { + if (indef && !key.empty() && mat.is_valid()) + { + materials_[key] = mat; + mat.cleanup(); + } + } + + else if (keyWrd == "newmtl") // begin new material definition + { + stream >> key; + indef = true; + } + + else if (keyWrd == "Kd") // diffuse color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Kd(f1,f2,f3); + } + + else if (keyWrd == "Ka") // ambient color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Ka(f1,f2,f3); + } + + else if (keyWrd == "Ks") // specular color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Ks(f1,f2,f3); + } +#if 0 + else if (keyWrd == "illum") // diffuse/specular shading model + { + ; // just skip this + } + + else if (keyWrd == "Ns") // Shininess [0..200] + { + ; // just skip this + } + + else if (keyWrd == "map_") // map images + { + // map_Ks, specular map + // map_Ka, ambient map + // map_Bump, bump map + // map_d, opacity map + ; // just skip this + } +#endif + else if (keyWrd == "map_Kd" ) { + // Get the rest of the line, removing leading or trailing spaces + // This will define the filename of the texture + std::getline(stream,textureName); + trimString(textureName); + if ( ! textureName.empty() ) + mat.set_map_Kd( textureName, textureId++ ); + } + else if (keyWrd == "Tr") // transparency value + { + stream >> f1; + + if( !stream.fail() ) + mat.set_Tr(f1); + } + else if (keyWrd == "d") // transparency value + { + stream >> f1; + + if( !stream.fail() ) + mat.set_Tr(f1); + } + + if ( _in && indef && mat.is_valid() && !key.empty()) + materials_[key] = mat; + } + return true; +} +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt, + std::vector & normals, + std::vector & colors, + std::vector & texcoords3d, + std::vector & texcoords, + std::vector & vertexHandles, + Options & fileOptions) +{ + float x, y, z, u, v, w; + float r, g, b; + + std::string line; + std::string keyWrd; + + std::stringstream stream; + + + // Options supplied by the user + const Options & userOptions = _opt; + + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + // Trim Both leading and trailing spaces + trimString(line); + + // comment + if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) { + continue; + } + + stream.str(line); + stream.clear(); + + stream >> keyWrd; + + // vertex + if (keyWrd == "v") + { + stream >> x; stream >> y; stream >> z; + + if ( !stream.fail() ) + { + vertexHandles.push_back(_bi.add_vertex(OpenMesh::Vec3f(x,y,z))); + stream >> r; stream >> g; stream >> b; + + if ( !stream.fail() ) + { + if ( userOptions.vertex_has_color() ) { + fileOptions += Options::VertexColor; + colors.push_back(OpenMesh::Vec3f(r,g,b)); + } + } + } + } + + // texture coord + else if (keyWrd == "vt") + { + stream >> u; stream >> v; + + if ( !stream.fail() ){ + + if ( userOptions.vertex_has_texcoord() || userOptions.face_has_texcoord() ) { + texcoords.push_back(OpenMesh::Vec2f(u, v)); + + // Can be used for both! + fileOptions += Options::VertexTexCoord; + fileOptions += Options::FaceTexCoord; + + // try to read the w component as it is optional + stream >> w; + if ( !stream.fail() ) + texcoords3d.push_back(OpenMesh::Vec3f(u, v, w)); + + } + + }else{ + omerr() << "Only single 2D or 3D texture coordinate per vertex" + << "allowed!" << std::endl; + return false; + } + } + + // color per vertex + else if (keyWrd == "vc") + { + stream >> r; stream >> g; stream >> b; + + if ( !stream.fail() ){ + if ( userOptions.vertex_has_color() ) { + colors.push_back(OpenMesh::Vec3f(r,g,b)); + fileOptions += Options::VertexColor; + } + } + } + + // normal + else if (keyWrd == "vn") + { + stream >> x; stream >> y; stream >> z; + + if ( !stream.fail() ) { + if (userOptions.vertex_has_normal() ){ + normals.push_back(OpenMesh::Vec3f(x,y,z)); + fileOptions += Options::VertexNormal; + } + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read(std::istream& _in, BaseImporter& _bi, Options& _opt) +{ + std::string line; + std::string keyWrd; + + std::vector normals; + std::vector colors; + std::vector texcoords3d; + std::vector texcoords; + std::vector vertexHandles; + + BaseImporter::VHandles vhandles; + std::vector face_texcoords3d; + std::vector face_texcoords; + + std::string matname; + + std::stringstream stream, lineData, tmp; + + + // Options supplied by the user + Options userOptions = _opt; + + // Options collected via file parsing + Options fileOptions; + + // pass 1: read vertices + if ( !read_vertices(_in, _bi, _opt, + normals, colors, texcoords3d, texcoords, + vertexHandles, fileOptions) ){ + return false; + } + + // reset stream for second pass + _in.clear(); + _in.seekg(0, std::ios::beg); + + int nCurrentPositions = 0, + nCurrentTexcoords = 0, + nCurrentNormals = 0; + + // pass 2: read faces + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + // Trim Both leading and trailing spaces + trimString(line); + + // comment + if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) { + continue; + } + + stream.str(line); + stream.clear(); + + stream >> keyWrd; + + // material file + if (keyWrd == "mtllib") + { + std::string matFile; + + // Get the rest of the line, removing leading or trailing spaces + // This will define the filename of the texture + std::getline(stream,matFile); + trimString(matFile); + + matFile = path_ + matFile; + + //omlog() << "Load material file " << matFile << std::endl; + + std::fstream matStream( matFile.c_str(), std::ios_base::in ); + + if ( matStream ){ + + if ( !read_material( matStream ) ) + omerr() << " Warning! Could not read file properly!\n"; + matStream.close(); + + }else + omerr() << " Warning! Material file '" << matFile << "' not found!\n"; + + //omlog() << " " << materials_.size() << " materials loaded.\n"; + + for ( MaterialList::iterator material = materials_.begin(); material != materials_.end(); ++material ) + { + // Save the texture information in a property + if ( (*material).second.has_map_Kd() ) + _bi.add_texture_information( (*material).second.map_Kd_index() , (*material).second.map_Kd() ); + } + + } + + // usemtl + else if (keyWrd == "usemtl") + { + stream >> matname; + if (materials_.find(matname)==materials_.end()) + { + omerr() << "Warning! Material '" << matname + << "' not defined in material file.\n"; + matname=""; + } + } + + // track current number of parsed vertex attributes, + // to allow for OBJs negative indices + else if (keyWrd == "v") + { + ++nCurrentPositions; + } + else if (keyWrd == "vt") + { + ++nCurrentTexcoords; + } + else if (keyWrd == "vn") + { + ++nCurrentNormals; + } + + // faces + else if (keyWrd == "f") + { + int component(0), nV(0); + int value; + + vhandles.clear(); + face_texcoords.clear(); + face_texcoords3d.clear(); + + // read full line after detecting a face + std::string faceLine; + std::getline(stream,faceLine); + lineData.str( faceLine ); + lineData.clear(); + + FaceHandle fh; + BaseImporter::VHandles faceVertices; + + // work on the line until nothing left to read + while ( !lineData.eof() ) + { + // read one block from the line ( vertex/texCoord/normal ) + std::string vertex; + lineData >> vertex; + + do{ + + //get the component (vertex/texCoord/normal) + size_t found=vertex.find("/"); + + // parts are seperated by '/' So if no '/' found its the last component + if( found != std::string::npos ){ + + // read the index value + tmp.str( vertex.substr(0,found) ); + tmp.clear(); + + // If we get an empty string this property is undefined in the file + if ( vertex.substr(0,found).empty() ) { + // Switch to next field + vertex = vertex.substr(found+1); + + // Now we are at the next component + ++component; + + // Skip further processing of this component + continue; + } + + // Read current value + tmp >> value; + + // remove the read part from the string + vertex = vertex.substr(found+1); + + } else { + + // last component of the vertex, read it. + tmp.str( vertex ); + tmp.clear(); + tmp >> value; + + // Clear vertex after finished reading the line + vertex=""; + + // Nothing to read here ( garbage at end of line ) + if ( tmp.fail() ) { + continue; + } + } + + // store the component ( each component is referenced by the index here! ) + switch (component) + { + case 0: // vertex + if ( value < 0 ) { + // Calculation of index : + // -1 is the last vertex in the list + // As obj counts from 1 and not zero add +1 + value = nCurrentPositions + value + 1; + } + // Obj counts from 1 and not zero .. array counts from zero therefore -1 + vhandles.push_back(VertexHandle(value-1)); + faceVertices.push_back(VertexHandle(value-1)); + if (fileOptions.vertex_has_color()) { + if ((unsigned int)(value - 1) < colors.size()) { + _bi.set_color(vhandles.back(), colors[value - 1]); + } + else { + omerr() << "Error setting vertex color" << std::endl; + } + } + break; + + case 1: // texture coord + if ( value < 0 ) { + // Calculation of index : + // -1 is the last vertex in the list + // As obj counts from 1 and not zero add +1 + value = nCurrentTexcoords + value + 1; + } + assert(!vhandles.empty()); + + + if ( fileOptions.vertex_has_texcoord() && userOptions.vertex_has_texcoord() ) { + + if (!texcoords.empty() && (unsigned int) (value - 1) < texcoords.size()) { + // Obj counts from 1 and not zero .. array counts from zero therefore -1 + _bi.set_texcoord(vhandles.back(), texcoords[value - 1]); + if(!texcoords3d.empty() && (unsigned int) (value -1) < texcoords3d.size()) + _bi.set_texcoord(vhandles.back(), texcoords3d[value - 1]); + } else { + omerr() << "Error setting Texture coordinates" << std::endl; + } + + } + + if (fileOptions.face_has_texcoord() && userOptions.face_has_texcoord() ) { + + if (!texcoords.empty() && (unsigned int) (value - 1) < texcoords.size()) { + face_texcoords.push_back( texcoords[value-1] ); + if(!texcoords3d.empty() && (unsigned int) (value -1) < texcoords3d.size()) + face_texcoords3d.push_back( texcoords3d[value-1] ); + } else { + omerr() << "Error setting Texture coordinates" << std::endl; + } + } + + + break; + + case 2: // normal + if ( value < 0 ) { + // Calculation of index : + // -1 is the last vertex in the list + // As obj counts from 1 and not zero add +1 + value = nCurrentNormals + value + 1; + } + + // Obj counts from 1 and not zero .. array counts from zero therefore -1 + if (fileOptions.vertex_has_normal() ) { + assert(!vhandles.empty()); + if ((unsigned int)(value - 1) < normals.size()) { + _bi.set_normal(vhandles.back(), normals[value - 1]); + } + else { + omerr() << "Error setting vertex normal" << std::endl; + } + } + break; + } + + // Prepare for reading next component + ++component; + + // Read until line does not contain any other info + } while ( !vertex.empty() ); + + component = 0; + nV++; + + } + + // note that add_face can possibly triangulate the faces, which is why we have to + // store the current number of faces first + size_t n_faces = _bi.n_faces(); + remove_duplicated_vertices(faceVertices); + + //A minimum of three vertices are required. + if (faceVertices.size() > 2) + fh = _bi.add_face(faceVertices); + + if (!vhandles.empty() && fh.is_valid() ) + { + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords); + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords3d); + } + + if ( !matname.empty() ) + { + std::vector newfaces; + + for( size_t i=0; i < _bi.n_faces()-n_faces; ++i ) + newfaces.push_back(FaceHandle(int(n_faces+i))); + + Material& mat = materials_[matname]; + + if ( mat.has_Kd() ) { + Vec3uc fc = color_cast(mat.Kd()); + + if ( userOptions.face_has_color()) { + + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_color(*it, fc); + + fileOptions += Options::FaceColor; + } + } + + // Set the texture index in the face index property + if ( mat.has_map_Kd() ) { + + if (userOptions.face_has_texcoord()) { + + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_face_texindex(*it, mat.map_Kd_index()); + + fileOptions += Options::FaceTexCoord; + + } + + } else { + + // If we don't have the info, set it to no texture + if (userOptions.face_has_texcoord()) { + + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_face_texindex(*it, 0); + + } + } + + } else { + std::vector newfaces; + + for( size_t i=0; i < _bi.n_faces()-n_faces; ++i ) + newfaces.push_back(FaceHandle(int(n_faces+i))); + + // Set the texture index to zero as we don't have any information + if ( userOptions.face_has_texcoord() ) + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_face_texindex(*it, 0); + } + + } + + } + + // If we do not have any faces, + // assume this is a point cloud and read the normals and colors directly + if (_bi.n_faces() == 0) + { + int i = 0; + // add normal per vertex + + if (normals.size() == _bi.n_vertices()) { + if ( fileOptions.vertex_has_normal() && userOptions.vertex_has_normal() ) { + for (std::vector::iterator it = vertexHandles.begin(); it != vertexHandles.end(); ++it, i++) + _bi.set_normal(*it, normals[i]); + } + } + + // add color per vertex + i = 0; + if (colors.size() >= _bi.n_vertices()) + if (fileOptions.vertex_has_color() && userOptions.vertex_has_color()) { + for (std::vector::iterator it = vertexHandles.begin(); it != vertexHandles.end(); ++it, i++) + _bi.set_color(*it, colors[i]); + } + + } + + // Return, what we actually read + _opt = fileOptions; + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OBJReader.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OBJReader.hh new file mode 100644 index 0000000..70c3a2f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OBJReader.hh @@ -0,0 +1,201 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an reader module for OBJ files +// +//============================================================================= + + +#ifndef __OBJREADER_HH__ +#define __OBJREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OBJ format reader. +*/ +class OPENMESHDLLEXPORT _OBJReader_ : public BaseReader +{ +public: + + _OBJReader_(); + + virtual ~_OBJReader_() { } + + std::string get_description() const { return "Alias/Wavefront"; } + std::string get_extensions() const { return "obj"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + bool read(std::istream& _in, + BaseImporter& _bi, + Options& _opt); + +private: + +#ifndef DOXY_IGNORE_THIS + class Material + { + public: + + Material() { cleanup(); } + + void cleanup() + { + Kd_is_set_ = false; + Ka_is_set_ = false; + Ks_is_set_ = false; + Tr_is_set_ = false; + map_Kd_is_set_ = false; + } + + bool is_valid(void) const + { return Kd_is_set_ || Ka_is_set_ || Ks_is_set_ || Tr_is_set_ || map_Kd_is_set_; } + + bool has_Kd(void) { return Kd_is_set_; } + bool has_Ka(void) { return Ka_is_set_; } + bool has_Ks(void) { return Ks_is_set_; } + bool has_Tr(void) { return Tr_is_set_; } + bool has_map_Kd(void) { return map_Kd_is_set_; } + + void set_Kd( float r, float g, float b ) + { Kd_=Vec3f(r,g,b); Kd_is_set_=true; } + + void set_Ka( float r, float g, float b ) + { Ka_=Vec3f(r,g,b); Ka_is_set_=true; } + + void set_Ks( float r, float g, float b ) + { Ks_=Vec3f(r,g,b); Ks_is_set_=true; } + + void set_Tr( float t ) + { Tr_=t; Tr_is_set_=true; } + + void set_map_Kd( std::string _name, int _index_Kd ) + { map_Kd_ = _name, index_Kd_ = _index_Kd; map_Kd_is_set_ = true; }; + + const Vec3f& Kd( void ) const { return Kd_; } + const Vec3f& Ka( void ) const { return Ka_; } + const Vec3f& Ks( void ) const { return Ks_; } + float Tr( void ) const { return Tr_; } + const std::string& map_Kd( void ) { return map_Kd_ ; } + const int& map_Kd_index( void ) { return index_Kd_ ; } + + private: + + Vec3f Kd_; bool Kd_is_set_; // diffuse + Vec3f Ka_; bool Ka_is_set_; // ambient + Vec3f Ks_; bool Ks_is_set_; // specular + float Tr_; bool Tr_is_set_; // transperency + + std::string map_Kd_; int index_Kd_; bool map_Kd_is_set_; // Texture + + }; +#endif + + typedef std::map MaterialList; + + MaterialList materials_; + + bool read_material( std::fstream& _in ); + + +private: + + bool read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt, + std::vector & normals, + std::vector & colors, + std::vector & texcoords3d, + std::vector & texcoords, + std::vector & vertexHandles, + Options & fileOptions); + + std::string path_; + +}; + + +//== TYPE DEFINITION ========================================================== + + +extern _OBJReader_ __OBJReaderInstance; +OPENMESHDLLEXPORT _OBJReader_& OBJReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OFFReader.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OFFReader.cc new file mode 100644 index 0000000..896b999 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OFFReader.cc @@ -0,0 +1,689 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#define LINE_LEN 4096 + + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include +// #include + +//STL +#include +#include +#include +#include + +#if defined(OM_CC_MIPS) +# include +/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std! +#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460) +# include +#else +using std::isspace; +#endif + +#ifndef WIN32 +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_OFFReader_ __OFFReaderInstance; +_OFFReader_& OFFReader() { return __OFFReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + + +_OFFReader_::_OFFReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OFFReader_::read(const std::string& _filename, BaseImporter& _bi, + Options& _opt) +{ + std::ifstream ifile(_filename.c_str(), (options_.is_binary() ? std::ios::binary | std::ios::in + : std::ios::in) ); + + if (!ifile.is_open() || !ifile.good()) + { + omerr() << "[OFFReader] : cannot not open file " + << _filename + << std::endl; + + return false; + } + + assert(ifile); + + bool result = read(ifile, _bi, _opt); + + ifile.close(); + return result; +} + +//----------------------------------------------------------------------------- + + +bool +_OFFReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt ) +{ + if (!_in.good()) + { + omerr() << "[OMReader] : cannot not use stream " + << std::endl; + return false; + } + + // filter relevant options for reading + bool swap = _opt.check( Options::Swap ); + + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) _opt += Options::VertexNormal; + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) _opt += Options::VertexTexCoord; + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) _opt += Options::VertexColor; + if (options_.face_has_color() && userOptions_.face_has_color()) _opt += Options::FaceColor; + if (options_.is_binary()) _opt += Options::Binary; + + //force user-choice for the alpha value when reading binary + if ( options_.is_binary() && userOptions_.color_has_alpha() ) + options_ += Options::ColorAlpha; + + return (options_.is_binary() ? + read_binary(_in, _bi, _opt, swap) : + read_ascii(_in, _bi, _opt)); + +} + + + +//----------------------------------------------------------------------------- + +bool +_OFFReader_::read_ascii(std::istream& _in, BaseImporter& _bi, Options& _opt) const +{ + + + unsigned int i, j, k, l, idx; + unsigned int nV, nF, dummy; + OpenMesh::Vec3f v, n; + OpenMesh::Vec2f t; + OpenMesh::Vec3i c3; + OpenMesh::Vec3f c3f; + OpenMesh::Vec4i c4; + OpenMesh::Vec4f c4f; + BaseImporter::VHandles vhandles; + VertexHandle vh; + std::stringstream stream; + std::string trash; + + // read header line + std::string header; + std::getline(_in,header); + + // + #Vertice, #Faces, #Edges + _in >> nV; + _in >> nF; + _in >> dummy; + + _bi.reserve(nV, 3*nV, nF); + + // read vertices: coord [hcoord] [normal] [color] [texcoord] + for (i=0; i> v[0]; _in >> v[1]; _in >> v[2]; + + vh = _bi.add_vertex(v); + + //perhaps read NORMAL + if ( options_.vertex_has_normal() ){ + + _in >> n[0]; _in >> n[1]; _in >> n[2]; + + if ( userOptions_.vertex_has_normal() ) + _bi.set_normal(vh, n); + } + + //take the rest of the line and check how colors are defined + std::string line; + std::getline(_in,line); + + int colorType = getColorType(line, options_.vertex_has_texcoord() ); + + stream.str(line); + stream.clear(); + + //perhaps read COLOR + if ( options_.vertex_has_color() ){ + + switch (colorType){ + case 0 : break; //no color + case 1 : stream >> trash; break; //one int (isn't handled atm) + case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore) + // rgb int + case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, Vec3uc( c3 ) ); + break; + // rgba int + case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, Vec4uc( c4 ) ); + break; + // rgb floats + case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2]; + if ( userOptions_.vertex_has_color() ) { + _bi.set_color( vh, c3f ); + _opt += Options::ColorFloat; + } + break; + // rgba floats + case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3]; + if ( userOptions_.vertex_has_color() ) { + _bi.set_color( vh, c4f ); + _opt += Options::ColorFloat; + } + break; + + default: + std::cerr << "Error in file format (colorType = " << colorType << ")\n"; + break; + } + } + //perhaps read TEXTURE COORDs + if ( options_.vertex_has_texcoord() ){ + stream >> t[0]; stream >> t[1]; + if ( userOptions_.vertex_has_texcoord() ) + _bi.set_texcoord(vh, t); + } + } + + // faces + // #N .. [color spec] + for (i=0; i> nV; + + if (nV == 3) + { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else + { + vhandles.clear(); + for (j=0; j> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + FaceHandle fh = _bi.add_face(vhandles); + + //perhaps read face COLOR + if ( options_.face_has_color() ){ + + //take the rest of the line and check how colors are defined + std::string line; + std::getline(_in,line); + + int colorType = getColorType(line, false ); + + stream.str(line); + stream.clear(); + + switch (colorType){ + case 0 : break; //no color + case 1 : stream >> trash; break; //one int (isn't handled atm) + case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore) + // rgb int + case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, Vec3uc( c3 ) ); + break; + // rgba int + case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, Vec4uc( c4 ) ); + break; + // rgb floats + case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2]; + if ( userOptions_.face_has_color() ) { + _bi.set_color( fh, c3f ); + _opt += Options::ColorFloat; + } + break; + // rgba floats + case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3]; + if ( userOptions_.face_has_color() ) { + _bi.set_color( fh, c4f ); + _opt += Options::ColorFloat; + } + break; + + default: + std::cerr << "Error in file format (colorType = " << colorType << ")\n"; + break; + } + } + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +int _OFFReader_::getColorType(std::string& _line, bool _texCoordsAvailable) const +{ +/* + 0 : no Color + 1 : one int (e.g colormap index) + 2 : two items (error!) + 3 : 3 ints + 4 : 3 ints + 5 : 3 floats + 6 : 4 floats + +*/ + // Check if we have any additional information here + if ( _line.size() < 1 ) + return 0; + + //first remove spaces at start/end of the line + while (_line.size() > 0 && std::isspace(_line[0])) + _line = _line.substr(1); + while (_line.size() > 0 && std::isspace(_line[ _line.length()-1 ])) + _line = _line.substr(0, _line.length()-1); + + //count the remaining items in the line + size_t found; + int count = 0; + + found=_line.find_first_of(" "); + while (found!=std::string::npos){ + count++; + found=_line.find_first_of(" ",found+1); + } + + if (!_line.empty()) count++; + + if (_texCoordsAvailable) count -= 2; + + if (count == 3 || count == 4){ + //get first item + found = _line.find(" "); + std::string c1 = _line.substr (0,found); + + if (c1.find(".") != std::string::npos){ + if (count == 3) + count = 5; + else + count = 6; + } + } + return count; +} + +void _OFFReader_::readValue(std::istream& _in, float& _value) const{ + float32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +void _OFFReader_::readValue(std::istream& _in, int& _value) const{ + uint32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +void _OFFReader_::readValue(std::istream& _in, unsigned int& _value) const{ + uint32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +bool +_OFFReader_::read_binary(std::istream& _in, BaseImporter& _bi, Options& _opt, bool /*_swap*/) const +{ + unsigned int i, j, k, l, idx; + unsigned int nV, nF, dummy; + OpenMesh::Vec3f v, n; + OpenMesh::Vec3i c; + OpenMesh::Vec4i cA; + OpenMesh::Vec3f cf; + OpenMesh::Vec4f cAf; + OpenMesh::Vec2f t; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + // read header line + std::string header; + std::getline(_in,header); + + // + #Vertice, #Faces, #Edges + readValue(_in, nV); + readValue(_in, nF); + readValue(_in, dummy); + + _bi.reserve(nV, 3*nV, nF); + + // read vertices: coord [hcoord] [normal] [color] [texcoord] + for (i=0; i .. [color spec] + // So far color spec is unsupported! + for (i=0; i 1 ) && ( p[0] == 'S' && p[1] == 'T') ) + { options_ += Options::VertexTexCoord; p += 2; remainingChars -= 2; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'C') ) + { options_ += Options::VertexColor; + options_ += Options::FaceColor; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'N') ) + { options_ += Options::VertexNormal; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && (p[0] == '4' ) ) + { vertexDimensionTooHigh = true; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'n') ) + { vertexDimensionTooHigh = true; ++p; --remainingChars; } + + if ( ( remainingChars < 3 ) || (!(p[0] == 'O' && p[1] == 'F' && p[2] == 'F') ) ) + return false; + + p += 4; + + // Detect possible garbage and make sure, we don't have an underflow + if ( remainingChars >= 4 ) + remainingChars -= 4; + else + remainingChars = 0; + + if ( ( remainingChars >= 6 ) && ( strncmp(p, "BINARY", 6) == 0 ) ) + options_+= Options::Binary; + + // vertex Dimensions != 3 are currently not supported + if (vertexDimensionTooHigh) + return false; + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OFFReader.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OFFReader.hh new file mode 100644 index 0000000..755093a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OFFReader.hh @@ -0,0 +1,171 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __OFFREADER_HH__ +#define __OFFREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OFF format reader. This class is singleton'ed by + SingletonT to OFFReader. + + By passing Options to the read function you can manipulate the reading behavoir. + The following options can be set: + + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha [only when reading binary] + + These options define if the corresponding data should be read (if available) + or if it should be omitted. + + After execution of the read function. The options object contains information about + what was actually read. + + e.g. if VertexNormal was true when the read function was called, but the file + did not contain vertex normals then it is false afterwards. + + When reading a binary off with Color Flag in the header it is assumed that all vertices + and faces have colors in the format "int int int". + If ColorAlpha is set the format "int int int int" is assumed. + +*/ + +class OPENMESHDLLEXPORT _OFFReader_ : public BaseReader +{ +public: + + _OFFReader_(); + + /// Destructor + virtual ~_OFFReader_() {}; + + std::string get_description() const { return "Object File Format"; } + std::string get_extensions() const { return "off"; } + std::string get_magic() const { return "OFF"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + bool can_u_read(const std::string& _filename) const; + + bool read(std::istream& _in, BaseImporter& _bi, Options& _opt ); + +private: + + bool can_u_read(std::istream& _is) const; + + bool read_ascii(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_binary(std::istream& _in, BaseImporter& _bi, Options& _opt, bool swap) const; + + void readValue(std::istream& _in, float& _value) const; + void readValue(std::istream& _in, int& _value) const; + void readValue(std::istream& _in, unsigned int& _value) const; + + int getColorType(std::string & _line, bool _texCoordsAvailable) const; + + //available options for reading + mutable Options options_; + //options that the user wants to read + mutable Options userOptions_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF reader +extern _OFFReader_ __OFFReaderInstance; +OPENMESHDLLEXPORT _OFFReader_& OFFReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OMReader.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OMReader.cc new file mode 100644 index 0000000..b66684e --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OMReader.cc @@ -0,0 +1,591 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +//STL +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OMReader singleton with MeshReader +_OMReader_ __OMReaderInstance; +_OMReader_& OMReader() { return __OMReaderInstance; } + + + +//=== IMPLEMENTATION ========================================================== + + +_OMReader_::_OMReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool _OMReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + // check whether importer can give us an OpenMesh BaseKernel + if (!_bi.kernel()) + return false; + + _opt += Options::Binary; // only binary format supported! + fileOptions_ = Options::Binary; + + // Open file + std::ifstream ifs(_filename.c_str(), std::ios::binary); + + /* Clear formatting flag skipws (Skip whitespaces). If set, operator>> will + * skip bytes set to whitespace chars (e.g. 0x20 bytes) in + * Property::restore. + */ + ifs.unsetf(std::ios::skipws); + + if (!ifs.is_open() || !ifs.good()) { + omerr() << "[OMReader] : cannot not open file " << _filename << std::endl; + return false; + } + + // Pass stream to read method, remember result + bool result = read(ifs, _bi, _opt); + + // close input stream + ifs.close(); + + _opt = _opt & fileOptions_; + + return result; +} + +//----------------------------------------------------------------------------- + + +bool _OMReader_::read(std::istream& _is, BaseImporter& _bi, Options& _opt) +{ + // check whether importer can give us an OpenMesh BaseKernel + if (!_bi.kernel()) + return false; + + _opt += Options::Binary; // only binary format supported! + fileOptions_ = Options::Binary; + + if (!_is.good()) { + omerr() << "[OMReader] : cannot read from stream " << std::endl; + return false; + } + + // Pass stream to read method, remember result + bool result = read_binary(_is, _bi, _opt); + + if (result) + _opt += Options::Binary; + + _opt = _opt & fileOptions_; + + return result; +} + + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_ascii(std::istream& /* _is */, BaseImporter& /* _bi */, Options& /* _opt */) const +{ + // not supported yet! + return false; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt) const +{ + bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); + + // Initialize byte counter + bytes_ = 0; + + bytes_ += restore(_is, header_, swap); + + + while (!_is.eof()) { + bytes_ += restore(_is, chunk_header_, swap); + + if (_is.eof()) + break; + + // Is this a named property restore the name + if (chunk_header_.name_) { + OMFormat::Chunk::PropertyName pn; + bytes_ += restore(_is, property_name_, swap); + } + + // Read in the property data. If it is an anonymous or unknown named + // property, then skip data. + switch (chunk_header_.entity_) { + case OMFormat::Chunk::Entity_Vertex: + if (!read_binary_vertex_chunk(_is, _bi, _opt, swap)) + return false; + break; + case OMFormat::Chunk::Entity_Face: + if (!read_binary_face_chunk(_is, _bi, _opt, swap)) + return false; + break; + case OMFormat::Chunk::Entity_Edge: + if (!read_binary_edge_chunk(_is, _bi, _opt, swap)) + return false; + break; + case OMFormat::Chunk::Entity_Halfedge: + if (!read_binary_halfedge_chunk(_is, _bi, _opt, swap)) + return false; + break; + case OMFormat::Chunk::Entity_Mesh: + if (!read_binary_mesh_chunk(_is, _bi, _opt, swap)) + return false; + break; + case OMFormat::Chunk::Entity_Sentinel: + return true; + default: + return false; + } + + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::can_u_read(const std::string& _filename) const +{ + // !!! Assuming BaseReader::can_u_parse( std::string& ) + // does not call BaseReader::read_magic()!!! + if (this->BaseReader::can_u_read(_filename)) { + std::ifstream ifile(_filename.c_str()); + if (ifile && can_u_read(ifile)) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- + +bool _OMReader_::can_u_read(std::istream& _is) const +{ + std::vector evt; + evt.reserve(20); + + // read first 4 characters into a buffer + while (evt.size() < 4) + evt.push_back(static_cast(_is.get())); + + // put back all read characters + std::vector::reverse_iterator it = evt.rbegin(); + while (it != evt.rend()) + _is.putback(*it++); + + // evaluate header information + OMFormat::Header *hdr = (OMFormat::Header*) &evt[0]; + + // first two characters must be 'OM' + if (hdr->magic_[0] != 'O' || hdr->magic_[1] != 'M') + return false; + + // 3rd characters defines the mesh type: + switch (hdr->mesh_) { + case 'T': // Triangle Mesh + case 'Q': // Quad Mesh + case 'P': // Polygonal Mesh + break; + default: // ? + return false; + } + + // 4th characters encodes the version + return supports(hdr->version_); +} + +//----------------------------------------------------------------------------- + +bool _OMReader_::supports(const OMFormat::uint8 /* version */) const +{ + return true; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, Options &_opt, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Vertex); + + OpenMesh::Vec3f v3f; + OpenMesh::Vec2f v2f; + OpenMesh::Vec3uc v3uc; // rgb + + OMFormat::Chunk::PropertyName custom_prop; + + size_t vidx = 0; + switch (chunk_header_.type_) { + case Chunk::Type_Pos: + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3f, _swap); + _bi.add_vertex(v3f); + } + break; + + case Chunk::Type_Normal: + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + fileOptions_ += Options::VertexNormal; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3f, _swap); + if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal()) + _bi.set_normal(VertexHandle(int(vidx)), v3f); + } + break; + + case Chunk::Type_Texcoord: + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim())); + + fileOptions_ += Options::VertexTexCoord; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v2f, _swap); + if (fileOptions_.vertex_has_texcoord() && _opt.vertex_has_texcoord()) + _bi.set_texcoord(VertexHandle(int(vidx)), v2f); + } + break; + + case Chunk::Type_Color: + + assert( OMFormat::dimensions(chunk_header_) == 3); + + fileOptions_ += Options::VertexColor; + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3uc, _swap); + if (fileOptions_.vertex_has_color() && _opt.vertex_has_color()) + _bi.set_color(VertexHandle(int(vidx)), v3uc); + } + break; + + case Chunk::Type_Custom: + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap); + + vidx = header_.n_vertices_; + + break; + + default: // skip unknown chunks + { + omerr() << "Unknown chunk type ignored!\n"; + size_t size_of = header_.n_vertices_ * OMFormat::vector_size(chunk_header_); + _is.ignore(size_of); + bytes_ += size_of; + } + } + + // all chunk data has been read..?! + return vidx == header_.n_vertices_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Options &_opt, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Face); + + size_t fidx = 0; + OpenMesh::Vec3f v3f; // normal + OpenMesh::Vec3uc v3uc; // rgb + + switch (chunk_header_.type_) { + case Chunk::Type_Topology: { + BaseImporter::VHandles vhandles; + size_t nV = 0; + size_t vidx = 0; + + switch (header_.mesh_) { + case 'T': + nV = 3; + break; + case 'Q': + nV = 4; + break; + } + + for (; fidx < header_.n_faces_; ++fidx) { + if (header_.mesh_ == 'P') + bytes_ += restore(_is, nV, Chunk::Integer_16, _swap); + + vhandles.clear(); + for (size_t j = 0; j < nV; ++j) { + bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap); + + vhandles.push_back(VertexHandle(int(vidx))); + } + + _bi.add_face(vhandles); + } + } + break; + + case Chunk::Type_Normal: + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + fileOptions_ += Options::FaceNormal; + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3f, _swap); + if( fileOptions_.face_has_normal() && _opt.face_has_normal()) + _bi.set_normal(FaceHandle(int(fidx)), v3f); + } + break; + + case Chunk::Type_Color: + + assert( OMFormat::dimensions(chunk_header_) == 3); + + fileOptions_ += Options::FaceColor; + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3uc, _swap); + if( fileOptions_.face_has_color() && _opt.face_has_color()) + _bi.set_color(FaceHandle(int(fidx)), v3uc); + } + break; + + case Chunk::Type_Custom: + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_fprop(property_name_), header_.n_faces_, _swap); + + fidx = header_.n_faces_; + + break; + + default: // skip unknown chunks + { + omerr() << "Unknown chunk type ignore!\n"; + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(size_of); + bytes_ += size_of; + } + } + return fidx == header_.n_faces_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Options &/*_opt */, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Edge); + + size_t b = bytes_; + + switch (chunk_header_.type_) { + case Chunk::Type_Custom: + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_eprop(property_name_), header_.n_edges_, _swap); + + break; + + default: + // skip unknown type + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(size_of); + bytes_ += size_of; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi, Options &/* _opt */, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Halfedge); + + size_t b = bytes_; + + switch (chunk_header_.type_) { + case Chunk::Type_Custom: + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap); + break; + + default: + // skip unknown chunk + omerr() << "Unknown chunk type ignored!\n"; + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(size_of); + bytes_ += size_of; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_mesh_chunk(std::istream &_is, BaseImporter &_bi, Options & /* _opt */, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Mesh); + + size_t b = bytes_; + + switch (chunk_header_.type_) { + case Chunk::Type_Custom: + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_mprop(property_name_), 1, _swap); + + break; + + default: + // skip unknown chunk + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(size_of); + bytes_ += size_of; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + + +size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _bp, size_t _n_elem, bool _swap) const +{ + assert( !_bp || (_bp->name() == property_name_)); + + using OMFormat::Chunk; + + size_t bytes = 0; + Chunk::esize_t block_size; + Chunk::PropertyName custom_prop; + + bytes += restore(_is, block_size, OMFormat::Chunk::Integer_32, _swap); + + if (_bp) { + size_t n_bytes = _bp->size_of(_n_elem); + + if (((n_bytes == BaseProperty::UnknownSize) || (n_bytes == block_size)) + && (_bp->element_size() == BaseProperty::UnknownSize || (_n_elem * _bp->element_size() == block_size))) { +#if defined(OM_DEBUG) + size_t b; + bytes += (b=_bp->restore( _is, _swap )); +#else + bytes += _bp->restore(_is, _swap); +#endif + +#if defined(OM_DEBUG) + assert( block_size == b ); +#endif + + assert( block_size == _bp->size_of()); + + block_size = 0; + } else { + omerr() << "Warning! Property " << _bp->name() << " not loaded: " << "Mismatching data sizes!n"; + } + } + + if (block_size) { + _is.ignore(block_size); + bytes += block_size; + } + + return bytes; +} + + +//----------------------------------------------------------------------------- + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OMReader.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OMReader.hh new file mode 100644 index 0000000..4b1f67d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/OMReader.hh @@ -0,0 +1,178 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __OMREADER_HH__ +#define __OMREADER_HH__ + + +//=== INCLUDES ================================================================ + +// OpenMesh +#include +#include +#include +#include +#include +#include + +// STD C++ +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OM format reader. This class is singleton'ed by + SingletonT to OMReader. +*/ +class OPENMESHDLLEXPORT _OMReader_ : public BaseReader +{ +public: + + _OMReader_(); + virtual ~_OMReader_() { } + + std::string get_description() const { return "OpenMesh File Format"; } + std::string get_extensions() const { return "om"; } + std::string get_magic() const { return "OM"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt ); + +//! Stream Reader for std::istream input in binary format + bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt ); + + virtual bool can_u_read(const std::string& _filename) const; + virtual bool can_u_read(std::istream& _is) const; + + +private: + + bool supports( const OMFormat::uint8 version ) const; + + bool read_ascii(std::istream& _is, BaseImporter& _bi, Options& _opt) const; + bool read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt) const; + + typedef OMFormat::Header Header; + typedef OMFormat::Chunk::Header ChunkHeader; + typedef OMFormat::Chunk::PropertyName PropertyName; + + // initialized/updated by read_binary*/read_ascii* + mutable size_t bytes_; + mutable Options fileOptions_; + mutable Header header_; + mutable ChunkHeader chunk_header_; + mutable PropertyName property_name_; + + bool read_binary_vertex_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_face_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_edge_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_halfedge_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_mesh_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + size_t restore_binary_custom_data( std::istream& _is, + BaseProperty* _bp, + size_t _n_elem, + bool _swap) const; + +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM reader. +extern _OMReader_ __OMReaderInstance; +OPENMESHDLLEXPORT _OMReader_& OMReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/PLYReader.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/PLYReader.cc new file mode 100644 index 0000000..618f347 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/PLYReader.cc @@ -0,0 +1,1407 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +#define LINE_LEN 4096 + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include + +//STL +#include +#include +#include + +#ifndef WIN32 +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_PLYReader_ __PLYReaderInstance; +_PLYReader_& PLYReader() { + return __PLYReaderInstance; +} + +//=== IMPLEMENTATION ========================================================== + + +_PLYReader_::_PLYReader_() { + IOManager().register_module(this); + + // Store sizes in byte of each property type + scalar_size_[ValueTypeINT8] = 1; + scalar_size_[ValueTypeUINT8] = 1; + scalar_size_[ValueTypeINT16] = 2; + scalar_size_[ValueTypeUINT16] = 2; + scalar_size_[ValueTypeINT32] = 4; + scalar_size_[ValueTypeUINT32] = 4; + scalar_size_[ValueTypeFLOAT32] = 4; + scalar_size_[ValueTypeFLOAT64] = 8; + + scalar_size_[ValueTypeCHAR] = 1; + scalar_size_[ValueTypeUCHAR] = 1; + scalar_size_[ValueTypeSHORT] = 2; + scalar_size_[ValueTypeUSHORT] = 2; + scalar_size_[ValueTypeINT] = 4; + scalar_size_[ValueTypeUINT] = 4; + scalar_size_[ValueTypeFLOAT] = 4; + scalar_size_[ValueTypeDOUBLE] = 8; +} + +//----------------------------------------------------------------------------- + + +bool _PLYReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) { + + std::fstream in(_filename.c_str(), (std::ios_base::binary | std::ios_base::in) ); + + if (!in.is_open() || !in.good()) { + omerr() << "[PLYReader] : cannot not open file " << _filename << std::endl; + return false; + } + + bool result = read(in, _bi, _opt); + + in.close(); + return result; +} + +//----------------------------------------------------------------------------- + + +bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) { + + if (!_in.good()) { + omerr() << "[PLYReader] : cannot not use stream" << std::endl; + return false; + } + + // filter relevant options for reading + bool swap = _opt.check(Options::Swap); + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) { + _opt += Options::VertexNormal; + } + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) { + _opt += Options::VertexTexCoord; + } + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) { + _opt += Options::VertexColor; + } + if (options_.face_has_color() && userOptions_.face_has_color()) { + _opt += Options::FaceColor; + } + if (options_.is_binary()) { + _opt += Options::Binary; + } + if (options_.color_is_float()) { + _opt += Options::ColorFloat; + } + if (options_.check(Options::Custom) && userOptions_.check(Options::Custom)) { + _opt += Options::Custom; + } + + // //force user-choice for the alpha value when reading binary + // if ( options_.is_binary() && userOptions_.color_has_alpha() ) + // options_ += Options::ColorAlpha; + + return (options_.is_binary() ? read_binary(_in, _bi, swap, _opt) : read_ascii(_in, _bi, _opt)); + +} + +template +struct Handle2Prop; + +template +struct Handle2Prop +{ + typedef OpenMesh::VPropHandleT PropT; +}; + +template +struct Handle2Prop +{ + typedef OpenMesh::FPropHandleT PropT; +}; + +//read and assign custom properties with the given type. Also creates property, if not exist +template +void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listType) const +{ + if (_listType == Unsupported) //no list type defined -> property is not a list + { + //get/add property + typename Handle2Prop::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + { + _bi.kernel()->add_property(prop,_propName); + _bi.kernel()->property(prop).set_persistent(true); + } + + //read and assign + T in; + read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type()); + _bi.kernel()->property(prop,_h) = in; + } + else + { + //get/add property + typename Handle2Prop,Handle>::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + { + _bi.kernel()->add_property(prop,_propName); + _bi.kernel()->property(prop).set_persistent(true); + } + + //init vector + int numberOfValues; + read(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); + std::vector vec; + vec.reserve(numberOfValues); + //read and assign + for (int i = 0; i < numberOfValues; ++i) + { + T in; + read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type()); + vec.push_back(in); + } + _bi.kernel()->property(prop,_h) = vec; + } +} + +template +void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const +{ + switch (_valueType) + { + case ValueTypeINT8: + case ValueTypeCHAR: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT8: + case ValueTypeUCHAR: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeINT16: + case ValueTypeSHORT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT16: + case ValueTypeUSHORT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeINT32: + case ValueTypeINT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT32: + case ValueTypeUINT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeFLOAT64: + case ValueTypeDOUBLE: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + default: + std::cerr << "unsupported type" << std::endl; + break; + } +} + + +//----------------------------------------------------------------------------- + +bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const { + + // Reparse the header + if (!can_u_read(_in)) { + omerr() << "[PLYReader] : Unable to parse header\n"; + return false; + } + + unsigned int i, j, k, l, idx; + unsigned int nV; + OpenMesh::Vec3f v, n; + std::string trash; + OpenMesh::Vec2f t; + OpenMesh::Vec4i c; + float tmp; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); + + if (vertexDimension_ != 3) { + omerr() << "[PLYReader] : Only vertex dimension 3 is supported." << std::endl; + return false; + } + + const bool err_enabled = omerr().is_enabled(); + size_t complex_faces = 0; + if (err_enabled) + omerr().disable(); + + for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) + { + if (e_it->element_== VERTEX) + { + // read vertices: + for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { + vh = _bi.add_vertex(); + + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + n[0] = 0.0; + n[1] = 0.0; + n[2] = 0.0; + + t[0] = 0.0; + t[1] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + case XCOORD: + _in >> v[0]; + break; + case YCOORD: + _in >> v[1]; + break; + case ZCOORD: + _in >> v[2]; + break; + case XNORM: + _in >> n[0]; + break; + case YNORM: + _in >> n[1]; + break; + case ZNORM: + _in >> n[2]; + break; + case TEXX: + _in >> t[0]; + break; + case TEXY: + _in >> t[1]; + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[0] = static_cast (tmp * 255.0f); + } + else + _in >> c[0]; + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[1] = static_cast (tmp * 255.0f); + } + else + _in >> c[1]; + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[2] = static_cast (tmp * 255.0f); + } + else + _in >> c[2]; + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[3] = static_cast (tmp * 255.0f); + } + else + _in >> c[3]; + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom)) + readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); + else + _in >> trash; + break; + default: + _in >> trash; + break; + } + } + + _bi.set_point(vh, v); + if (_opt.vertex_has_normal()) + _bi.set_normal(vh, n); + if (_opt.vertex_has_texcoord()) + _bi.set_texcoord(vh, t); + if (_opt.vertex_has_color()) + _bi.set_color(vh, Vec4uc(c)); + } + } + else if (e_it->element_ == FACE) + { + // faces + for (i = 0; i < faceCount_ && !_in.eof(); ++i) { + FaceHandle fh; + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + + case VERTEX_INDICES: + // nV = number of Vertices for current face + _in >> nV; + + if (nV == 3) { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else { + vhandles.clear(); + for (j = 0; j < nV; ++j) { + _in >> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + fh = _bi.add_face(vhandles); + if (!fh.is_valid()) + ++complex_faces; + break; + + case CUSTOM_PROP: + if (_opt.check(Options::Custom) && fh.is_valid()) + readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); + else + _in >> trash; + break; + + default: + _in >> trash; + break; + } + } + + } + } + else + { + // other elements + for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + // just skip the values + _in >> trash; + } + } + } + + if (_in.eof()) { + if (err_enabled) + omerr().enable(); + + omerr() << "Unexpected end of file while reading." << std::endl; + return false; + } + + if(e_it->element_== FACE) + // stop reading after the faces since additional elements are not preserved anyway + break; + } + + if (err_enabled) + omerr().enable(); + + if (complex_faces) + omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; + + // File was successfully parsed. + return true; +} + +//----------------------------------------------------------------------------- + +bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap*/, const Options& _opt) const { + + // Reparse the header + if (!can_u_read(_in)) { + omerr() << "[PLYReader] : Unable to parse header\n"; + return false; + } + + OpenMesh::Vec3f v, n; // Vertex + OpenMesh::Vec2f t; // TexCoords + BaseImporter::VHandles vhandles; + VertexHandle vh; + OpenMesh::Vec4i c; // Color + float tmp; + + _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); + + const bool err_enabled = omerr().is_enabled(); + size_t complex_faces = 0; + if (err_enabled) + omerr().disable(); + + for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) + { + if (e_it->element_ == VERTEX) + { + // read vertices: + for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) { + vh = _bi.add_vertex(); + + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + n[0] = 0.0; + n[1] = 0.0; + n[2] = 0.0; + + t[0] = 0.0; + t[1] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + case XCOORD: + readValue(prop.value, _in, v[0]); + break; + case YCOORD: + readValue(prop.value, _in, v[1]); + break; + case ZCOORD: + readValue(prop.value, _in, v[2]); + break; + case XNORM: + readValue(prop.value, _in, n[0]); + break; + case YNORM: + readValue(prop.value, _in, n[1]); + break; + case ZNORM: + readValue(prop.value, _in, n[2]); + break; + case TEXX: + readValue(prop.value, _in, t[0]); + break; + case TEXY: + readValue(prop.value, _in, t[1]); + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + + c[0] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[0]); + + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[1] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[1]); + + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[2] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[2]); + + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[3] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[3]); + + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom)) + readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); + else + consume_input(_in, scalar_size_[prop.value]); + break; + default: + // Read unsupported property + consume_input(_in, scalar_size_[prop.value]); + break; + } + + } + + _bi.set_point(vh, v); + if (_opt.vertex_has_normal()) + _bi.set_normal(vh, n); + if (_opt.vertex_has_texcoord()) + _bi.set_texcoord(vh, t); + if (_opt.vertex_has_color()) + _bi.set_color(vh, Vec4uc(c)); + } + } + else if (e_it->element_ == FACE) { + for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) { + FaceHandle fh; + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + + case VERTEX_INDICES: + // nV = number of Vertices for current face + unsigned int nV; + readInteger(prop.listIndexType, _in, nV); + + if (nV == 3) { + vhandles.resize(3); + unsigned int j, k, l; + readInteger(prop.value, _in, j); + readInteger(prop.value, _in, k); + readInteger(prop.value, _in, l); + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else { + vhandles.clear(); + for (unsigned j = 0; j < nV; ++j) { + unsigned int idx; + readInteger(prop.value, _in, idx); + vhandles.push_back(VertexHandle(idx)); + } + } + + fh = _bi.add_face(vhandles); + if (!fh.is_valid()) + ++complex_faces; + break; + + case CUSTOM_PROP: + if (_opt.check(Options::Custom) && fh.is_valid()) + readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); + else + consume_input(_in, scalar_size_[prop.value]); + break; + + default: + consume_input(_in, scalar_size_[prop.value]); + break; + } + } + } + } + else { + for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) + { + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + PropertyInfo prop = e_it->properties_[propertyIndex]; + // skip element values + consume_input(_in, scalar_size_[prop.value]); + } + } + } + + if (_in.eof()) { + if (err_enabled) + omerr().enable(); + + omerr() << "Unexpected end of file while reading." << std::endl; + return false; + } + + if (e_it->element_ == FACE) + // stop reading after the faces since additional elements are not preserved anyway + break; + } + if (err_enabled) + omerr().enable(); + + if (complex_faces) + omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; + + + return true; +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, float& _value) const { + + switch (_type) { + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + float32_t tmp; + restore(_in, tmp, options_.check(Options::MSB)); + _value = tmp; + break; + default: + _value = 0.0; + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, double& _value) const { + + switch (_type) { + + case ValueTypeFLOAT64: + + case ValueTypeDOUBLE: + + float64_t tmp; + restore(_in, tmp, options_.check(Options::MSB)); + _value = tmp; + + break; + + default: + + _value = 0.0; + std::cerr << "unsupported conversion type to double: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned char& _value) const{ + unsigned int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned short& _value) const{ + unsigned int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, signed char& _value) const{ + int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, short& _value) const{ + int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + + +//----------------------------------------------------------------------------- +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned int& _value) const { + + uint32_t tmp_uint32_t; + uint16_t tmp_uint16_t; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeUSHORT: + + case ValueTypeUINT16: + + restore(_in, tmp_uint16_t, options_.check(Options::MSB)); + _value = tmp_uint16_t; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, int& _value) const { + + int32_t tmp_int32_t; + int16_t tmp_int16_t; + int8_t tmp_char; + + switch (_type) { + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeSHORT: + + case ValueTypeINT16: + + restore(_in, tmp_int16_t, options_.check(Options::MSB)); + _value = tmp_int16_t; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readInteger(ValueType _type, std::istream& _in, int& _value) const { + + int32_t tmp_int32_t; + uint32_t tmp_uint32_t; + int8_t tmp_char; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const { + + int32_t tmp_int32_t; + uint32_t tmp_uint32_t; + int8_t tmp_char; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; + + break; + } +} + + +//------------------------------------------------------------------------------ + + +bool _PLYReader_::can_u_read(const std::string& _filename) const { + + // !!! Assuming BaseReader::can_u_parse( std::string& ) + // does not call BaseReader::read_magic()!!! + + if (BaseReader::can_u_read(_filename)) { + std::ifstream ifs(_filename.c_str()); + if (ifs.is_open() && can_u_read(ifs)) { + ifs.close(); + return true; + } + } + return false; +} + + + +//----------------------------------------------------------------------------- + +std::string get_property_name(std::string _string1, std::string _string2) { + + if (_string1 == "float32" || _string1 == "float64" || _string1 == "float" || _string1 == "double" || + _string1 == "int8" || _string1 == "uint8" || _string1 == "char" || _string1 == "uchar" || + _string1 == "int32" || _string1 == "uint32" || _string1 == "int" || _string1 == "uint" || + _string1 == "int16" || _string1 == "uint16" || _string1 == "short" || _string1 == "ushort") + return _string2; + + if (_string2 == "float32" || _string2 == "float64" || _string2 == "float" || _string2 == "double" || + _string2 == "int8" || _string2 == "uint8" || _string2 == "char" || _string2 == "uchar" || + _string2 == "int32" || _string2 == "uint32" || _string2 == "int" || _string2 == "uint" || + _string2 == "int16" || _string2 == "uint16" || _string2 == "short" || _string2 == "ushort") + return _string1; + + + std::cerr << "Unsupported entry type" << std::endl; + return "Unsupported"; +} + +//----------------------------------------------------------------------------- + +_PLYReader_::ValueType get_property_type(std::string& _string1, std::string& _string2) { + + if (_string1 == "float32" || _string2 == "float32") + + return _PLYReader_::ValueTypeFLOAT32; + + else if (_string1 == "float64" || _string2 == "float64") + + return _PLYReader_::ValueTypeFLOAT64; + + else if (_string1 == "float" || _string2 == "float") + + return _PLYReader_::ValueTypeFLOAT; + + else if (_string1 == "double" || _string2 == "double") + + return _PLYReader_::ValueTypeDOUBLE; + + else if (_string1 == "int8" || _string2 == "int8") + + return _PLYReader_::ValueTypeINT8; + + else if (_string1 == "uint8" || _string2 == "uint8") + + return _PLYReader_::ValueTypeUINT8; + + else if (_string1 == "char" || _string2 == "char") + + return _PLYReader_::ValueTypeCHAR; + + else if (_string1 == "uchar" || _string2 == "uchar") + + return _PLYReader_::ValueTypeUCHAR; + + else if (_string1 == "int32" || _string2 == "int32") + + return _PLYReader_::ValueTypeINT32; + + else if (_string1 == "uint32" || _string2 == "uint32") + + return _PLYReader_::ValueTypeUINT32; + + else if (_string1 == "int" || _string2 == "int") + + return _PLYReader_::ValueTypeINT; + + else if (_string1 == "uint" || _string2 == "uint") + + return _PLYReader_::ValueTypeUINT; + + else if (_string1 == "int16" || _string2 == "int16") + + return _PLYReader_::ValueTypeINT16; + + else if (_string1 == "uint16" || _string2 == "uint16") + + return _PLYReader_::ValueTypeUINT16; + + else if (_string1 == "short" || _string2 == "short") + + return _PLYReader_::ValueTypeSHORT; + + else if (_string1 == "ushort" || _string2 == "ushort") + + return _PLYReader_::ValueTypeUSHORT; + + return _PLYReader_::Unsupported; +} + + +//----------------------------------------------------------------------------- + +bool _PLYReader_::can_u_read(std::istream& _is) const { + + // Clear per file options + options_.cleanup(); + + // clear element list + elements_.clear(); + + // read 1st line + std::string line; + std::getline(_is, line); + trim(line); + + // Handle '\r\n' newlines + const size_t s = line.size(); + if( s > 0 && line[s - 1] == '\r') line.resize(s - 1); + + //Check if this file is really a ply format + if (line != "PLY" && line != "ply") + return false; + + vertexCount_ = 0; + faceCount_ = 0; + vertexDimension_ = 0; + + unsigned int elementCount = 0; + + std::string keyword; + std::string fileType; + std::string elementName = ""; + std::string propertyName; + std::string listIndexType; + std::string listEntryType; + float version; + + _is >> keyword; + _is >> fileType; + _is >> version; + + if (_is.bad()) { + omerr() << "Defect PLY header detected" << std::endl; + return false; + } + + if (fileType == "ascii") { + options_ -= Options::Binary; + } else if (fileType == "binary_little_endian") { + options_ += Options::Binary; + options_ += Options::LSB; + //if (Endian::local() == Endian::MSB) + + // options_ += Options::Swap; + } else if (fileType == "binary_big_endian") { + options_ += Options::Binary; + options_ += Options::MSB; + //if (Endian::local() == Endian::LSB) + + // options_ += Options::Swap; + } else { + omerr() << "Unsupported PLY format: " << fileType << std::endl; + return false; + } + + std::streamoff streamPos = _is.tellg(); + _is >> keyword; + while (keyword != "end_header") { + + if (keyword == "comment") { + std::getline(_is, line); + } else if (keyword == "element") { + _is >> elementName; + _is >> elementCount; + + ElementInfo element; + element.name_ = elementName; + element.count_ = elementCount; + + if (elementName == "vertex") { + vertexCount_ = elementCount; + element.element_ = VERTEX; + } else if (elementName == "face") { + faceCount_ = elementCount; + element.element_ = FACE; + } else { + omerr() << "PLY header unsupported element type: " << elementName << std::endl; + element.element_ = UNKNOWN; + } + + elements_.push_back(element); + } else if (keyword == "property") { + std::string tmp1; + std::string tmp2; + + // Read first keyword, as it might be a list + _is >> tmp1; + + if (tmp1 == "list") { + _is >> listIndexType; + _is >> listEntryType; + _is >> propertyName; + + ValueType indexType = Unsupported; + ValueType entryType = Unsupported; + + if (listIndexType == "uint8") { + indexType = ValueTypeUINT8; + } else if (listIndexType == "uchar") { + indexType = ValueTypeUCHAR; + } else if (listIndexType == "int") { + indexType = ValueTypeINT; + } else { + omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl; + continue; + } + + entryType = get_property_type(listEntryType, listEntryType); + + if (entryType == Unsupported) { + omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl; + } + + PropertyInfo property(CUSTOM_PROP, entryType, propertyName); + property.listIndexType = indexType; + + if (elementName == "face") + { + // special case for vertex indices + if (propertyName == "vertex_index" || propertyName == "vertex_indices") + { + property.property = VERTEX_INDICES; + + if (!elements_.back().properties_.empty()) + { + omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl; + elements_.back().properties_.clear(); + } + } + + } + else + omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl; + + elements_.back().properties_.push_back(property); + + } else { + // as this is not a list property, read second value of property + _is >> tmp2; + + + // Extract name and type of property + // As the order seems to be different in some files, autodetect it. + ValueType valueType = get_property_type(tmp1, tmp2); + propertyName = get_property_name(tmp1, tmp2); + + PropertyInfo entry; + + //special treatment for some vertex properties. + if (elementName == "vertex") { + if (propertyName == "x") { + entry = PropertyInfo(XCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "y") { + entry = PropertyInfo(YCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "z") { + entry = PropertyInfo(ZCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "nx") { + entry = PropertyInfo(XNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "ny") { + entry = PropertyInfo(YNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "nz") { + entry = PropertyInfo(ZNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "u" || propertyName == "s") { + entry = PropertyInfo(TEXX, valueType); + options_ += Options::VertexTexCoord; + } else if (propertyName == "v" || propertyName == "t") { + entry = PropertyInfo(TEXY, valueType); + options_ += Options::VertexTexCoord; + } else if (propertyName == "red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "alpha") { + entry = PropertyInfo(COLORALPHA, valueType); + options_ += Options::VertexColor; + options_ += Options::ColorAlpha; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } + } + + //not a special property, load as custom + if (entry.value == Unsupported){ + Property prop = CUSTOM_PROP; + options_ += Options::Custom; + entry = PropertyInfo(prop, valueType, propertyName); + } + + if (entry.property != UNSUPPORTED) + { + elements_.back().properties_.push_back(entry); + } + } + + } else { + omlog() << "Unsupported keyword : " << keyword << std::endl; + } + + streamPos = _is.tellg(); + _is >> keyword; + if (_is.bad()) { + omerr() << "Error while reading PLY file header" << std::endl; + return false; + } + } + + // As the binary data is directy after the end_header keyword + // and the stream removes too many bytes, seek back to the right position + if (options_.is_binary()) { + _is.seekg(streamPos); + + char c1 = 0; + char c2 = 0; + _is.get(c1); + _is.get(c2); + + if (c1 == 0x0D && c2 == 0x0A) { + _is.seekg(streamPos + 14); + } + else { + _is.seekg(streamPos + 12); + } + } + + return true; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/PLYReader.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/PLYReader.hh new file mode 100644 index 0000000..c887a5b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/PLYReader.hh @@ -0,0 +1,244 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __PLYREADER_HH__ +#define __PLYREADER_HH__ + + +//=== INCLUDES ================================================================ + + + +#include +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the PLY format reader. This class is singleton'ed by + SingletonT to OFFReader. It can read custom properties, accessible via the name + of the custom properties. List properties has the type std::vector. + +*/ + +class OPENMESHDLLEXPORT _PLYReader_ : public BaseReader +{ +public: + + _PLYReader_(); + + std::string get_description() const { return "PLY polygon file format"; } + std::string get_extensions() const { return "ply"; } + std::string get_magic() const { return "PLY"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt); + + bool can_u_read(const std::string& _filename) const; + + enum ValueType { + Unsupported, + ValueTypeINT8, ValueTypeCHAR, + ValueTypeUINT8, ValueTypeUCHAR, + ValueTypeINT16, ValueTypeSHORT, + ValueTypeUINT16, ValueTypeUSHORT, + ValueTypeINT32, ValueTypeINT, + ValueTypeUINT32, ValueTypeUINT, + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeFLOAT64, ValueTypeDOUBLE + }; + +private: + + bool can_u_read(std::istream& _is) const; + + bool read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const; + bool read_binary(std::istream& _in, BaseImporter& _bi, bool swap, const Options& _opt) const; + + float readToFloatValue(ValueType _type , std::fstream& _in) const; + + void readValue(ValueType _type , std::istream& _in, float& _value) const; + void readValue(ValueType _type , std::istream& _in, double& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned int& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned short& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned char& _value) const; + void readValue(ValueType _type , std::istream& _in, int& _value) const; + void readValue(ValueType _type , std::istream& _in, short& _value) const; + void readValue(ValueType _type , std::istream& _in, signed char& _value) const; + + void readInteger(ValueType _type, std::istream& _in, int& _value) const; + void readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const; + + /// Read unsupported properties in PLY file + void consume_input(std::istream& _in, int _count) const { + _in.read(reinterpret_cast(&buff[0]), _count); + } + + mutable unsigned char buff[8]; + + /// Available per file options for reading + mutable Options options_; + + /// Options that the user wants to read + mutable Options userOptions_; + + mutable unsigned int vertexCount_; + mutable unsigned int faceCount_; + + mutable uint vertexDimension_; + + enum Property { + XCOORD,YCOORD,ZCOORD, + TEXX,TEXY, + COLORRED,COLORGREEN,COLORBLUE,COLORALPHA, + XNORM,YNORM,ZNORM, CUSTOM_PROP, VERTEX_INDICES, + UNSUPPORTED + }; + + /// Stores sizes of property types + mutable std::map scalar_size_; + + // Number of vertex properties + struct PropertyInfo + { + Property property; + ValueType value; + std::string name;//for custom properties + ValueType listIndexType;//if type is unsupported, the poerty is not a list. otherwise, it the index type + PropertyInfo():property(UNSUPPORTED),value(Unsupported),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v):property(_p),value(_v),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v, const std::string& _n):property(_p),value(_v),name(_n),listIndexType(Unsupported){} + }; + + enum Element { + VERTEX, + FACE, + UNKNOWN + }; + + // Information on the elements + struct ElementInfo + { + Element element_; + std::string name_; + unsigned int count_; + std::vector< PropertyInfo > properties_; + }; + + mutable std::vector< ElementInfo > elements_; + + template + inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + readValue(_type, _in, _value); + } + + template + inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _in >> _value; + } + + //read and assign custom properties with the given type. Also creates property, if not exist + template + void readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listType) const; + + template + void readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY reader +extern _PLYReader_ __PLYReaderInstance; +OPENMESHDLLEXPORT _PLYReader_& PLYReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/STLReader.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/STLReader.cc new file mode 100644 index 0000000..b3c5af0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/STLReader.cc @@ -0,0 +1,520 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +// STL +#include + +#include +#include +#include + +// OpenMesh +#include +#include +#include + +//comppare strings crossplatform ignorign case +#ifdef _WIN32 + #define strnicmp _strnicmp +#else + #define strnicmp strncasecmp +#endif + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the STLReader singleton with MeshReader +_STLReader_ __STLReaderInstance; +_STLReader_& STLReader() { return __STLReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_STLReader_:: +_STLReader_() + : eps_(FLT_MIN) +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_STLReader_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + bool result = false; + + STL_Type file_type = NONE; + + if ( check_extension( _filename, "stla" ) ) + { + file_type = STLA; + } + + else if ( check_extension( _filename, "stlb" ) ) + { + file_type = STLB; + } + + else if ( check_extension( _filename, "stl" ) ) + { + file_type = check_stl_type(_filename); + } + + + switch (file_type) + { + case STLA: + { + result = read_stla(_filename, _bi, _opt); + _opt -= Options::Binary; + break; + } + + case STLB: + { + result = read_stlb(_filename, _bi, _opt); + _opt += Options::Binary; + break; + } + + default: + { + result = false; + break; + } + } + + + return result; +} + +bool +_STLReader_::read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) +{ + + bool result = false; + + if (_opt & Options::Binary) + result = read_stlb(_is, _bi, _opt); + else + result = read_stla(_is, _bi, _opt); + + return result; +} + + +//----------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +class CmpVec +{ +public: + + explicit CmpVec(float _eps=FLT_MIN) : eps_(_eps) {} + + bool operator()( const Vec3f& _v0, const Vec3f& _v1 ) const + { + if (fabs(_v0[0] - _v1[0]) <= eps_) + { + if (fabs(_v0[1] - _v1[1]) <= eps_) + { + return (_v0[2] < _v1[2] - eps_); + } + else return (_v0[1] < _v1[1] - eps_); + } + else return (_v0[0] < _v1[0] - eps_); + } + +private: + float eps_; +}; + +#endif + + +//----------------------------------------------------------------------------- + +void trimStdString( std::string& _string) { + // Trim Both leading and trailing spaces + + size_t start = _string.find_first_not_of(" \t\r\n"); + size_t end = _string.find_last_not_of(" \t\r\n"); + + if(( std::string::npos == start ) || ( std::string::npos == end)) + _string = ""; + else + _string = _string.substr( start, end-start+1 ); +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const +{ + std::fstream in( _filename.c_str(), std::ios_base::in ); + + if (!in) + { + omerr() << "[STLReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + bool res = read_stla(in, _bi, _opt); + + if (in) + in.close(); + + return res; +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const +{ + + unsigned int i; + OpenMesh::Vec3f v; + OpenMesh::Vec3f n; + BaseImporter::VHandles vhandles; + + CmpVec comp(eps_); + std::map vMap(comp); + std::map::iterator vMapIt; + + std::string line; + + std::string garbage; + std::stringstream strstream; + + bool facet_normal(false); + + while( _in && !_in.eof() ) { + + // Get one line + std::getline(_in, line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read stream properly!\n"; + return false; + } + + // Trim Both leading and trailing spaces + trimStdString(line); + + // Normal found? + if (line.find("facet normal") != std::string::npos) { + strstream.str(line); + strstream.clear(); + + // facet + strstream >> garbage; + + // normal + strstream >> garbage; + + strstream >> n[0]; + strstream >> n[1]; + strstream >> n[2]; + + facet_normal = true; + } + + // Detected a triangle + if ( (line.find("outer") != std::string::npos) || (line.find("OUTER") != std::string::npos ) ) { + + vhandles.clear(); + + for (i=0; i<3; ++i) { + // Get one vertex + std::getline(_in, line); + trimStdString(line); + + strstream.str(line); + strstream.clear(); + + strstream >> garbage; + + strstream >> v[0]; + strstream >> v[1]; + strstream >> v[2]; + + // has vector been referenced before? + if ((vMapIt=vMap.find(v)) == vMap.end()) + { + // No : add vertex and remember idx/vector mapping + VertexHandle handle = _bi.add_vertex(v); + vhandles.push_back(handle); + vMap[v] = handle; + } + else + // Yes : get index from map + vhandles.push_back(vMapIt->second); + + } + + // Add face only if it is not degenerated + if ((vhandles[0] != vhandles[1]) && + (vhandles[0] != vhandles[2]) && + (vhandles[1] != vhandles[2])) { + + + FaceHandle fh = _bi.add_face(vhandles); + + // set the normal if requested + // if a normal was requested but could not be found we unset the option + if (facet_normal) { + if (fh.is_valid() && _opt.face_has_normal()) + _bi.set_normal(fh, n); + } else + _opt -= Options::FaceNormal; + } + + facet_normal = false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const +{ + std::fstream in( _filename.c_str(), std::ios_base::in | std::ios_base::binary); + + if (!in) + { + omerr() << "[STLReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + bool res = read_stlb(in, _bi, _opt); + + if (in) + in.close(); + + return res; +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const +{ + char dummy[100]; + bool swapFlag; + unsigned int i, nT; + OpenMesh::Vec3f v, n; + BaseImporter::VHandles vhandles; + + std::map vMap; + std::map::iterator vMapIt; + + + // check size of types + if ((sizeof(float) != 4) || (sizeof(int) != 4)) { + omerr() << "[STLReader] : wrong type size\n"; + return false; + } + + // determine endian mode + union { unsigned int i; unsigned char c[4]; } endian_test; + endian_test.i = 1; + swapFlag = (endian_test.c[3] == 1); + + // read number of triangles + _in.read(dummy, 80); + nT = read_int(_in, swapFlag); + + // read triangles + while (nT) + { + vhandles.clear(); + + // read triangle normal + n[0] = read_float(_in, swapFlag); + n[1] = read_float(_in, swapFlag); + n[2] = read_float(_in, swapFlag); + + // triangle's vertices + for (i=0; i<3; ++i) + { + v[0] = read_float(_in, swapFlag); + v[1] = read_float(_in, swapFlag); + v[2] = read_float(_in, swapFlag); + + // has vector been referenced before? + if ((vMapIt=vMap.find(v)) == vMap.end()) + { + // No : add vertex and remember idx/vector mapping + VertexHandle handle = _bi.add_vertex(v); + vhandles.push_back(handle); + vMap[v] = handle; + } + else + // Yes : get index from map + vhandles.push_back(vMapIt->second); + } + + + // Add face only if it is not degenerated + if ((vhandles[0] != vhandles[1]) && + (vhandles[0] != vhandles[2]) && + (vhandles[1] != vhandles[2])) { + FaceHandle fh = _bi.add_face(vhandles); + + if (fh.is_valid() && _opt.face_has_normal()) + _bi.set_normal(fh, n); + } + + _in.read(dummy, 2); + --nT; + } + + return true; +} + +//----------------------------------------------------------------------------- + +_STLReader_::STL_Type +_STLReader_:: +check_stl_type(const std::string& _filename) const +{ + + // open file + std::ifstream ifs (_filename.c_str(), std::ifstream::binary); + if(!ifs.good()) + { + omerr() << "could not open file" << _filename << std::endl; + return NONE; + } + + //find first non whitespace character + std::string line = ""; + std::size_t firstChar; + while(line.empty() && ifs.good()) + { + std::getline(ifs,line); + firstChar = line.find_first_not_of("\t "); + } + + //check for ascii keyword solid + if(strnicmp("solid",&line[firstChar],5) == 0) + { + return STLA; + } + ifs.close(); + + //if the file does not start with solid it is probably STLB + //check the file size to verify it. + + //open the file + FILE* in = fopen(_filename.c_str(), "rb"); + if (!in) return NONE; + + // determine endian mode + union { unsigned int i; unsigned char c[4]; } endian_test; + endian_test.i = 1; + bool swapFlag = (endian_test.c[3] == 1); + + + // read number of triangles + char dummy[100]; + fread(dummy, 1, 80, in); + size_t nT = read_int(in, swapFlag); + + + // compute file size from nT + size_t binary_size = 84 + nT*50; + + // get actual file size + size_t file_size(0); + rewind(in); + while (!feof(in)) + file_size += fread(dummy, 1, 100, in); + fclose(in); + + // if sizes match -> it's STLB + return (binary_size == file_size ? STLB : NONE); +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/STLReader.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/STLReader.hh new file mode 100644 index 0000000..b642623 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/reader/STLReader.hh @@ -0,0 +1,151 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an reader module for STL files +// +//============================================================================= + + +#ifndef __STLREADER_HH__ +#define __STLREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//== FORWARDS ================================================================= + +class BaseImporter; + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the STL format reader. This class is singleton'ed by + SingletonT to STLReader. +*/ +class OPENMESHDLLEXPORT _STLReader_ : public BaseReader +{ +public: + + // constructor + _STLReader_(); + + /// Destructor + virtual ~_STLReader_() {}; + + + std::string get_description() const + { return "Stereolithography Interface Format"; } + std::string get_extensions() const { return "stl stla stlb"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + bool read(std::istream& _in, + BaseImporter& _bi, + Options& _opt); + + /** Set the threshold to be used for considering two point to be equal. + Can be used to merge small gaps */ + void set_epsilon(float _eps) { eps_=_eps; } + + /// Returns the threshold to be used for considering two point to be equal. + float epsilon() const { return eps_; } + + + +private: + + enum STL_Type { STLA, STLB, NONE }; + STL_Type check_stl_type(const std::string& _filename) const; + + bool read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + + +private: + + float eps_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the STL reader +extern _STLReader_ __STLReaderInstance; +OPENMESHDLLEXPORT _STLReader_& STLReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/BaseWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/BaseWriter.cc new file mode 100644 index 0000000..7b7f29b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/BaseWriter.cc @@ -0,0 +1,107 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//=== INCLUDES ================================================================ + + +#include + +#if defined(OM_CC_MIPS) +# include +#else +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + +#ifndef DOXY_IGNORE_THIS + +static inline char tolower(char c) +{ + using namespace std; + return ::tolower(c); +} + +#endif + +//----------------------------------------------------------------------------- + + +bool +BaseWriter:: +can_u_write(const std::string& _filename) const +{ + // get file extension + std::string extension; + std::string::size_type pos(_filename.rfind(".")); + + if (pos != std::string::npos) + extension = _filename.substr(pos+1, _filename.length()-pos-1); + else + extension = _filename; //check, if the whole filename defines the extension + + std::transform( extension.begin(), extension.end(), + extension.begin(), tolower ); + + // locate extension in extension string + return (get_extensions().find(extension) != std::string::npos); +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/BaseWriter.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/BaseWriter.hh new file mode 100644 index 0000000..3e1688f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/BaseWriter.hh @@ -0,0 +1,155 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for IOManager writer modules +// +//============================================================================= + + +#ifndef __BASEWRITER_HH__ +#define __BASEWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for all writer modules. The module should register itself at + the IOManager by calling the register_module function. +*/ +class OPENMESHDLLEXPORT BaseWriter +{ +public: + + typedef unsigned int Option; + + /// Destructor + virtual ~BaseWriter() {}; + + /// Return short description of the supported file format. + virtual std::string get_description() const = 0; + + /// Return file format's extension. + virtual std::string get_extensions() const = 0; + + /** \brief Returns true if writer can write _filename (checks extension). + * _filename can also provide an extension without a name for a file e.g. _filename == "om" checks, if the writer can write the "om" extension + * @param _filename complete name of a file or just the extension + * @result true, if writer can write data with the given extension + */ + virtual bool can_u_write(const std::string& _filename) const; + + /** Write to a file + * @param _filename write to file with the given filename + * @param _be BaseExporter, which specifies the data source + * @param _opt writing options + * @param _precision can be used to specify the precision of the floating point notation. + */ + virtual bool write(const std::string& _filename, + BaseExporter& _be, + Options _opt, + std::streamsize _precision = 6) const = 0; + + /** Write to a std::ostream + * @param _os write to std::ostream + * @param _be BaseExporter, which specifies the data source + * @param _opt writing options + * @param _precision can be used to specify the precision of the floating point notation. + */ + virtual bool write(std::ostream& _os, + BaseExporter& _be, + Options _opt, + std::streamsize _precision = 6) const = 0; + + /// Returns expected size of file if binary format is supported else 0. + virtual size_t binary_size(BaseExporter&, Options) const { return 0; } + + + +protected: + + bool check(BaseExporter& _be, Options _opt) const + { + return (_opt.check(Options::VertexNormal ) <= _be.has_vertex_normals()) + && (_opt.check(Options::VertexTexCoord)<= _be.has_vertex_texcoords()) + && (_opt.check(Options::VertexColor) <= _be.has_vertex_colors()) + && (_opt.check(Options::FaceNormal) <= _be.has_face_normals()) + && (_opt.check(Options::FaceColor) <= _be.has_face_colors()); + } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OBJWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OBJWriter.cc new file mode 100644 index 0000000..a592e0d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OBJWriter.cc @@ -0,0 +1,401 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +//STL +#include +#include + +// OpenMesh +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OBJLoader singleton with MeshLoader +_OBJWriter_ __OBJWriterinstance; +_OBJWriter_& OBJWriter() { return __OBJWriterinstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OBJWriter_::_OBJWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_OBJWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + std::fstream out(_filename.c_str(), std::ios_base::out ); + + if (!out) + { + omerr() << "[OBJWriter] : cannot open file " + << _filename << std::endl; + return false; + } + + out.precision(_precision); + + { +#if defined(WIN32) + std::string::size_type dot = _filename.find_last_of("\\/"); +#else + std::string::size_type dot = _filename.rfind("/"); +#endif + + if (dot == std::string::npos){ + path_ = "./"; + objName_ = _filename; + }else{ + path_ = _filename.substr(0,dot+1); + objName_ = _filename.substr(dot+1); + } + + //remove the file extension + dot = objName_.find_last_of("."); + + if(dot != std::string::npos) + objName_ = objName_.substr(0,dot); + } + + bool result = write(out, _be, _opt, _precision); + + out.close(); + return result; +} + +//----------------------------------------------------------------------------- + +size_t _OBJWriter_::getMaterial(OpenMesh::Vec3f _color) const +{ + for (size_t i=0; i < material_.size(); i++) + if(material_[i] == _color) + return i; + + //not found add new material + material_.push_back( _color ); + return material_.size()-1; +} + +//----------------------------------------------------------------------------- + +size_t _OBJWriter_::getMaterial(OpenMesh::Vec4f _color) const +{ + for (size_t i=0; i < materialA_.size(); i++) + if(materialA_[i] == _color) + return i; + + //not found add new material + materialA_.push_back( _color ); + return materialA_.size()-1; +} + +//----------------------------------------------------------------------------- + +bool +_OBJWriter_:: +writeMaterial(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + material_.clear(); + materialA_.clear(); + + //iterate over faces + for (size_t i=0, nF=_be.n_faces(); i (_be.colorA( FaceHandle(int(i)) )); + getMaterial(cA); + }else{ + //and without alpha + c = color_cast (_be.color( FaceHandle(int(i)) )); + getMaterial(c); + } + } + + //write the materials + if ( _opt.color_has_alpha() ) + for (size_t i=0; i < materialA_.size(); i++){ + _out << "newmtl " << "mat" << i << '\n'; + _out << "Ka 0.5000 0.5000 0.5000" << '\n'; + _out << "Kd " << materialA_[i][0] << ' ' << materialA_[i][1] << ' ' << materialA_[i][2] << '\n'; + _out << "Tr " << materialA_[i][3] << '\n'; + _out << "illum 1" << '\n'; + } + else + for (size_t i=0; i < material_.size(); i++){ + _out << "newmtl " << "mat" << i << '\n'; + _out << "Ka 0.5000 0.5000 0.5000" << '\n'; + _out << "Kd " << material_[i][0] << ' ' << material_[i][1] << ' ' << material_[i][2] << '\n'; + _out << "illum 1" << '\n'; + } + + return true; +} + +//----------------------------------------------------------------------------- + + +bool +_OBJWriter_:: +write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + unsigned int idx; + size_t i, j,nV, nF; + Vec3f v, n; + Vec2f t; + VertexHandle vh; + std::vector vhandles; + bool useMatrial = false; + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + omlog() << "[OBJWriter] : write file\n"; + + _out.precision(_precision); + + // check exporter features + if (!check( _be, _opt)) + return false; + + // No binary mode for OBJ + if ( _opt.check(Options::Binary) ) { + omout() << "[OBJWriter] : Warning, Binary mode requested for OBJ Writer (No support for Binary mode), falling back to standard." << std::endl; + } + + // check for unsupported writer features + if (_opt.check(Options::FaceNormal) ) { + omerr() << "[OBJWriter] : FaceNormal not supported by OBJ Writer" << std::endl; + return false; + } + + // check for unsupported writer features + if (_opt.check(Options::VertexColor) ) { + omerr() << "[OBJWriter] : VertexColor not supported by OBJ Writer" << std::endl; + return false; + } + + //create material file if needed + if ( _opt.check(Options::FaceColor) ){ + + std::string matFile = path_ + objName_ + ".mat"; + + std::fstream matStream(matFile.c_str(), std::ios_base::out ); + + if (!matStream) + { + omerr() << "[OBJWriter] : cannot write material file " << matFile << std::endl; + + }else{ + useMatrial = writeMaterial(matStream, _be, _opt); + + matStream.close(); + } + } + + // header + _out << "# " << _be.n_vertices() << " vertices, "; + _out << _be.n_faces() << " faces" << '\n'; + + // material file + if (useMatrial && _opt.check(Options::FaceColor) ) + _out << "mtllib " << objName_ << ".mat" << '\n'; + + std::map texMap; + //collect Texturevertices from halfedges + if(_opt.check(Options::FaceTexCoord)) + { + std::vector texCoords; + //add all texCoords to map + unsigned int num = _be.get_face_texcoords(texCoords); + for(unsigned int i = 0; i < num ; ++i) + { + texMap[texCoords[i]] = i; + } + } + + //collect Texture coordinates from vertices + if(_opt.check(Options::VertexTexCoord)) + { + for (size_t i=0, nV=_be.n_vertices(); i(i)); + t = _be.texcoord(vh); + texMap[t] = static_cast(i); + } + } + + // assign each texcoord in the map its id + // and write the vt entries + if(_opt.check(Options::VertexTexCoord) || _opt.check(Options::FaceTexCoord)) + { + int texCount = 0; + for(std::map::iterator it = texMap.begin(); it != texMap.end() ; ++it) + { + _out << "vt " << it->first[0] << " " << it->first[1] << '\n'; + it->second = ++texCount; + } + } + + // vertex data (point, normals, texcoords) + for (i=0, nV=_be.n_vertices(); i::max(); + + // we do not want to write seperators if we only write vertex indices + bool onlyVertices = !_opt.check(Options::VertexTexCoord) + && !_opt.check(Options::VertexNormal) + && !_opt.check(Options::FaceTexCoord); + + // faces (indices starting at 1 not 0) + for (i=0, nF=_be.n_faces(); i::max(); + + //color with alpha + if ( _opt.color_has_alpha() ){ + cA = color_cast (_be.colorA( FaceHandle(int(i)) )); + material = getMaterial(cA); + } else{ + //and without alpha + c = color_cast (_be.color( FaceHandle(int(i)) )); + material = getMaterial(c); + } + + // if we are ina a new material block, specify in the file which material to use + if(lastMat != material) { + _out << "usemtl mat" << material << '\n'; + lastMat = material; + } + } + + _out << "f"; + + _be.get_vhandles(FaceHandle(int(i)), vhandles); + + for (j=0; j< vhandles.size(); ++j) + { + + // Write vertex index + idx = vhandles[j].idx() + 1; + _out << " " << idx; + + if (!onlyVertices) { + // write separator + _out << "/" ; + + //write texCoords index from halfedge + if(_opt.check(Options::FaceTexCoord)) + { + _out << texMap[_be.texcoord(_be.getHeh(FaceHandle(int(i)),vhandles[j]))]; + } + + else + { + // write vertex texture coordinate index + if (_opt.check(Options::VertexTexCoord)) + _out << texMap[_be.texcoord(vhandles[j])]; + } + + // write vertex normal index + if ( _opt.check(Options::VertexNormal) ) { + // write separator + _out << "/" ; + _out << idx; + } + } + } + + _out << '\n'; + } + + material_.clear(); + materialA_.clear(); + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OBJWriter.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OBJWriter.hh new file mode 100644 index 0000000..6adc772 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OBJWriter.hh @@ -0,0 +1,136 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an IOManager writer module for OBJ files +// +//============================================================================= + + +#ifndef __OBJWRITER_HH__ +#define __OBJWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + This class defines the OBJ writer. This class is further singleton'ed + by SingletonT to OBJWriter. +*/ +class OPENMESHDLLEXPORT _OBJWriter_ : public BaseWriter +{ +public: + + _OBJWriter_(); + + /// Destructor + virtual ~_OBJWriter_() {}; + + std::string get_description() const { return "Alias/Wavefront"; } + std::string get_extensions() const { return "obj"; } + + bool write(const std::string&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + size_t binary_size(BaseExporter&, Options) const { return 0; } + +private: + + mutable std::string path_; + mutable std::string objName_; + + mutable std::vector< OpenMesh::Vec3f > material_; + mutable std::vector< OpenMesh::Vec4f > materialA_; + + size_t getMaterial(OpenMesh::Vec3f _color) const; + + size_t getMaterial(OpenMesh::Vec4f _color) const; + + bool writeMaterial(std::ostream& _out, BaseExporter&, Options) const; + + +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OBJ writer +extern _OBJWriter_ __OBJWriterinstance; +OPENMESHDLLEXPORT _OBJWriter_& OBJWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OFFWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OFFWriter.cc new file mode 100644 index 0000000..c0d2b11 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OFFWriter.cc @@ -0,0 +1,527 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OFFLoader singleton with MeshLoader +_OFFWriter_ __OFFWriterInstance; +_OFFWriter_& OFFWriter() { return __OFFWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OFFWriter_::_OFFWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + std::ofstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + + return write(out, _be, _opt, _precision); +} + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + // check exporter features + if ( !check( _be, _opt ) ) + return false; + + + // check writer features + if ( _opt.check(Options::FaceNormal) ) // not supported by format + return false; + + + if (!_os.good()) + { + omerr() << "[OFFWriter] : cannot write to stream " + << std::endl; + return false; + } + + // write header line + if (_opt.check(Options::VertexTexCoord)) _os << "ST"; + if (_opt.check(Options::VertexColor) || _opt.check(Options::FaceColor)) _os << "C"; + if (_opt.check(Options::VertexNormal)) _os << "N"; + _os << "OFF"; + if (_opt.check(Options::Binary)) _os << " BINARY"; + _os << "\n"; + + if (!_opt.check(Options::Binary)) + _os.precision(_precision); + + // write to file + bool result = (_opt.check(Options::Binary) ? + write_binary(_os, _be, _opt) : + write_ascii(_os, _be, _opt)); + + + // return result + return result; +} + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + + unsigned int i, nV, nF; + Vec3f v, n; + Vec2f t; + OpenMesh::Vec3i c; + OpenMesh::Vec4i cA; + OpenMesh::Vec3f cf; + OpenMesh::Vec4f cAf; + VertexHandle vh; + std::vector vhandles; + + + // #vertices, #faces + _out << _be.n_vertices() << " "; + _out << _be.n_faces() << " "; + _out << 0 << "\n"; + + if (_opt.color_is_float()) + _out << std::fixed; + + + // vertex data (point, normals, colors, texcoords) + for (i=0, nV=int(_be.n_vertices()); i vhandles; + + // #vertices, #faces + writeValue(_out, (uint)_be.n_vertices() ); + writeValue(_out, (uint) _be.n_faces() ); + writeValue(_out, 0 ); + + // vertex data (point, normals, texcoords) + for (i=0, nV=int(_be.n_vertices()); i vhandles; + + for (i=0, nF=int(_be.n_faces()); i +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the OFF format writer. This class is singleton'ed by + SingletonT to OFFWriter. + + By passing Options to the write function you can manipulate the writing behavoir. + The following options can be set: + + Binary + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha + +*/ +class OPENMESHDLLEXPORT _OFFWriter_ : public BaseWriter +{ +public: + + _OFFWriter_(); + + virtual ~_OFFWriter_() {}; + + std::string get_description() const { return "no description"; } + std::string get_extensions() const { return "off"; } + + bool write(const std::string&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + size_t binary_size(BaseExporter& _be, Options _opt) const; + + +protected: + void writeValue(std::ostream& _out, int value) const; + void writeValue(std::ostream& _out, unsigned int value) const; + void writeValue(std::ostream& _out, float value) const; + + bool write_ascii(std::ostream& _in, BaseExporter&, Options) const; + bool write_binary(std::ostream& _in, BaseExporter&, Options) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF writer. +extern _OFFWriter_ __OFFWriterInstance; +OPENMESHDLLEXPORT _OFFWriter_& OFFWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OMWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OMWriter.cc new file mode 100644 index 0000000..9c32282 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OMWriter.cc @@ -0,0 +1,515 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined( OM_CC_MIPS ) + #include + #include +#else + #include + #include +#endif + +#include +#include + +// -------------------- OpenMesh +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OMLoader singleton with MeshLoader +_OMWriter_ __OMWriterInstance; +_OMWriter_& OMWriter() { return __OMWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +const OMFormat::uchar _OMWriter_::magic_[3] = "OM"; +const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(1,2); + + +_OMWriter_:: +_OMWriter_() +{ + IOManager().register_module(this); +} + + +bool +_OMWriter_::write(const std::string& _filename, BaseExporter& _be, + Options _opt, std::streamsize /*_precision*/) const +{ + // check whether exporter can give us an OpenMesh BaseKernel + if (!_be.kernel()) return false; + + + // check for om extension in filename, we can only handle OM + if (_filename.rfind(".om") == std::string::npos) + return false; + + _opt += Options::Binary; // only binary format supported + + std::ofstream ofs(_filename.c_str(), std::ios::binary); + + // check if file is open + if (!ofs.is_open()) + { + omerr() << "[OMWriter] : cannot open file " << _filename << std::endl; + return false; + } + + // call stream save method + bool rc = write(ofs, _be, _opt); + + // close filestream + ofs.close(); + + // return success/failure notice + return rc; +} + + +//----------------------------------------------------------------------------- + +bool +_OMWriter_::write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize /*_precision*/) const +{ +// std::clog << "[OMWriter]::write( stream )\n"; + + // check exporter features + if ( !check( _be, _opt ) ) + { + omerr() << "[OMWriter]: exporter does not support wanted feature!\n"; + return false; + } + + // Maybe an ascii version will be implemented in the future. + // For now, support only a binary format + if ( !_opt.check( Options::Binary ) ) + _opt += Options::Binary; + + // Ignore LSB/MSB bit. Always store in LSB (little endian) + _opt += Options::LSB; + _opt -= Options::MSB; + + return write_binary(_os, _be, _opt); +} + + +//----------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS +template struct Enabler +{ + explicit Enabler( T& obj ) : obj_(obj) + {} + + ~Enabler() { obj_.enable(); } + + T& obj_; +}; +#endif + + +bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, + Options _opt) const +{ + #ifndef DOXY_IGNORE_THIS + Enabler enabler(omlog()); + #endif + + size_t bytes = 0; + + bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); + + unsigned int i, nV, nF; + Vec3f v; + Vec2f t; + std::vector vhandles; + + + // -------------------- write header + OMFormat::Header header; + + header.magic_[0] = 'O'; + header.magic_[1] = 'M'; + header.mesh_ = _be.is_triangle_mesh() ? 'T' : 'P'; + header.version_ = version_; + header.n_vertices_ = int(_be.n_vertices()); + header.n_faces_ = int(_be.n_faces()); + header.n_edges_ = int(_be.n_edges()); + + bytes += store( _os, header, swap ); + + // ---------------------------------------- write chunks + + OMFormat::Chunk::Header chunk_header; + + + // -------------------- write vertex data + + // ---------- write vertex position + if (_be.n_vertices()) + { + v = _be.point(VertexHandle(0)); + chunk_header.reserved_ = 0; + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Pos; + chunk_header.signed_ = OMFormat::is_signed(v[0]); + chunk_header.float_ = OMFormat::is_float(v[0]); + chunk_header.dim_ = OMFormat::dim(v); + chunk_header.bits_ = OMFormat::bits(v[0]); + + bytes += store( _os, chunk_header, swap ); + for (i=0, nV=header.n_vertices_; istore(_os, swap ); + } + else + return false; +#endif +#undef NEW_STYLE + } + + + // ---------- write face color + + if (_be.n_faces() && _be.has_face_colors() && _opt.check( Options::FaceColor )) + { +#define NEW_STYLE 0 +#if NEW_STYLE + const BaseProperty *bp = _be.kernel()._get_fprop("f:colors"); + + if (bp) + { +#endif + Vec3uc c; + + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Face; + chunk_header.type_ = OMFormat::Chunk::Type_Color; + chunk_header.signed_ = OMFormat::is_signed( c[0] ); + chunk_header.float_ = OMFormat::is_float( c[0] ); + chunk_header.dim_ = OMFormat::dim( c ); + chunk_header.bits_ = OMFormat::bits( c[0] ); + + bytes += store( _os, chunk_header, swap ); +#if !NEW_STYLE + for (i=0, nF=header.n_faces_; istore(_os, swap); + } + else + return false; +#endif + } + + // -------------------- write custom properties + + + BaseKernel::const_prop_iterator prop; + + for (prop = _be.kernel()->vprops_begin(); + prop != _be.kernel()->vprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Vertex, swap ); + } + for (prop = _be.kernel()->fprops_begin(); + prop != _be.kernel()->fprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Face, swap ); + } + for (prop = _be.kernel()->eprops_begin(); + prop != _be.kernel()->eprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Edge, swap ); + } + for (prop = _be.kernel()->hprops_begin(); + prop != _be.kernel()->hprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Halfedge, swap ); + } + for (prop = _be.kernel()->mprops_begin(); + prop != _be.kernel()->mprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Mesh, swap ); + } + + memset(&chunk_header, 0, sizeof(chunk_header)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Sentinel; + bytes += store(_os, chunk_header, swap); + + std::clog << "#bytes written: " << bytes << std::endl; + + return true; +} + +// ---------------------------------------------------------------------------- + +size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os, + const BaseProperty& _bp, + OMFormat::Chunk::Entity _entity, + bool _swap) const +{ + //omlog() << "Custom Property " << OMFormat::as_string(_entity) << " property [" + // << _bp.name() << "]" << std::endl; + + // Don't store if + // 1. it is not persistent + // 2. it's name is empty + if ( !_bp.persistent() || _bp.name().empty() ) + { + //omlog() << " skipped\n"; + return 0; + } + + size_t bytes = 0; + + OMFormat::Chunk::esize_t element_size = OMFormat::Chunk::esize_t(_bp.element_size()); + OMFormat::Chunk::Header chdr; + + // set header + chdr.name_ = true; + chdr.entity_ = _entity; + chdr.type_ = OMFormat::Chunk::Type_Custom; + chdr.signed_ = 0; + chdr.float_ = 0; + chdr.dim_ = OMFormat::Chunk::Dim_1D; // ignored + chdr.bits_ = element_size; + + + // write custom chunk + + // 1. chunk header + bytes += store( _os, chdr, _swap ); + + // 2. property name + bytes += store( _os, OMFormat::Chunk::PropertyName(_bp.name()), _swap ); + + // 3. block size + bytes += store( _os, _bp.size_of(), OMFormat::Chunk::Integer_32, _swap ); + //omlog() << " n_bytes = " << _bp.size_of() << std::endl; + + // 4. data + { + size_t b; + bytes += ( b=_bp.store( _os, _swap ) ); + //omlog() << " b = " << b << std::endl; + assert( b == _bp.size_of() ); + } + return bytes; +} + +// ---------------------------------------------------------------------------- + +size_t _OMWriter_::binary_size(BaseExporter& /* _be */, Options /* _opt */) const +{ + // std::clog << "[OMWriter]: binary_size()" << std::endl; + size_t bytes = sizeof( OMFormat::Header ); + + // !!!TODO!!! + + return bytes; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OMWriter.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OMWriter.hh new file mode 100644 index 0000000..efc48a8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/OMWriter.hh @@ -0,0 +1,147 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a writer module for OM files +// +//============================================================================= + + +#ifndef __OMWRITER_HH__ +#define __OMWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//=== FORWARDS ================================================================ + + +class BaseExporter; + + +//=== IMPLEMENTATION ========================================================== + + +/** + * Implementation of the OM format writer. This class is singleton'ed by + * SingletonT to OMWriter. + */ +class OPENMESHDLLEXPORT _OMWriter_ : public BaseWriter +{ +public: + + /// Constructor + _OMWriter_(); + + /// Destructor + virtual ~_OMWriter_() {}; + + std::string get_description() const + { return "OpenMesh Format"; } + + std::string get_extensions() const + { return "om"; } + + bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + + + size_t binary_size(BaseExporter& _be, Options _opt) const; + + +protected: + + static const OMFormat::uchar magic_[3]; + static const OMFormat::uint8 version_; + + bool write(const std::string&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + bool write_binary(std::ostream&, BaseExporter&, Options) const; + + + size_t store_binary_custom_chunk( std::ostream&, const BaseProperty&, + OMFormat::Chunk::Entity, bool) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM writer. +extern _OMWriter_ __OMWriterInstance; +OPENMESHDLLEXPORT _OMWriter_& OMWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/PLYWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/PLYWriter.cc new file mode 100644 index 0000000..0314b5a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/PLYWriter.cc @@ -0,0 +1,721 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the PLYLoader singleton with MeshLoader +_PLYWriter_ __PLYWriterInstance; +_PLYWriter_& PLYWriter() { return __PLYWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_PLYWriter_::_PLYWriter_() +{ + IOManager().register_module(this); + + nameOfType_[Unsupported] = ""; + nameOfType_[ValueTypeCHAR] = "char"; + nameOfType_[ValueTypeUCHAR] = nameOfType_[ValueTypeUINT8] = "uchar"; + nameOfType_[ValueTypeUSHORT] = "ushort"; + nameOfType_[ValueTypeSHORT] = "short"; + nameOfType_[ValueTypeUINT] = "uint"; + nameOfType_[ValueTypeINT] = "int"; + nameOfType_[ValueTypeFLOAT32] = nameOfType_[ValueTypeFLOAT] = "float"; + nameOfType_[ValueTypeDOUBLE] = "double"; +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + + // open file + std::ofstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + return write(out, _be, _opt, _precision); +} + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + // check exporter features + if ( !check( _be, _opt ) ) + return false; + + + // check writer features + if ( _opt.check(Options::FaceNormal) ) { + // Face normals are not supported + // Uncheck these options and output message that + // they are not written out even though they were requested + _opt.unset(Options::FaceNormal); + omerr() << "[PLYWriter] : Warning: Face normals are not supported and thus not exported! " << std::endl; + } + + if ( _opt.check(Options::FaceColor) ) { + // Face normals are not supported + // Uncheck these options and output message that + // they are not written out even though they were requested + _opt.unset(Options::FaceColor); + omerr() << "[PLYWriter] : Warning: Face colors are not supported and thus not exported! " << std::endl; + } + + options_ = _opt; + + + if (!_os.good()) + { + omerr() << "[PLYWriter] : cannot write to stream " + << std::endl; + return false; + } + + if (!_opt.check(Options::Binary)) + _os.precision(_precision); + + // write to file + bool result = (_opt.check(Options::Binary) ? + write_binary(_os, _be, _opt) : + write_ascii(_os, _be, _opt)); + + return result; +} + +//----------------------------------------------------------------------------- + +// helper function for casting a property +template +const PropertyT* castProperty(const BaseProperty* _prop) +{ + return dynamic_cast< const PropertyT* >(_prop); +} + +//----------------------------------------------------------------------------- +std::vector<_PLYWriter_::CustomProperty> _PLYWriter_::writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const +{ + std::vector customProps; + for (;_begin != _end; ++_begin) + { + BaseProperty* prop = *_begin; + + + // check, if property is persistant + if (!prop || !prop->persistent()) + continue; + + + // identify type of property + CustomProperty cProp(prop); + size_t propSize = prop->element_size(); + switch (propSize) + { + case 1: + { + assert_compile(sizeof(char) == 1); + //check, if prop is a char or unsigned char by dynamic_cast + //char, unsigned char and signed char are 3 distinct types + if (castProperty(prop) != 0 || castProperty(prop) != 0) //treat char as signed char + cProp.type = ValueTypeCHAR; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeUCHAR; + break; + } + case 2: + { + assert_compile (sizeof(short) == 2); + if (castProperty(prop) != 0) + cProp.type = ValueTypeSHORT; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeUSHORT; + break; + } + case 4: + { + assert_compile (sizeof(int) == 4); + assert_compile (sizeof(float) == 4); + if (castProperty(prop) != 0) + cProp.type = ValueTypeINT; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeUINT; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeFLOAT; + break; + + } + case 8: + assert_compile (sizeof(double) == 8); + if (castProperty(prop) != 0) + cProp.type = ValueTypeDOUBLE; + break; + default: + break; + } + + if (cProp.type != Unsupported) + { + // property type was identified and it is persistant, write into header + customProps.push_back(cProp); + _out << "property " << nameOfType_[cProp.type] << " " << cProp.property->name() << "\n"; + } + } + return customProps; +} + +//----------------------------------------------------------------------------- + +template +void _PLYWriter_::write_customProp(std::ostream& _out, const CustomProperty& _prop, size_t _index) const +{ + if (_prop.type == ValueTypeCHAR) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeUCHAR || _prop.type == ValueTypeUINT8) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeSHORT) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeUSHORT) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeUINT) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeINT || _prop.type == ValueTypeINT32) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeFLOAT || _prop.type == ValueTypeFLOAT32) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeDOUBLE) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); +} + + +//----------------------------------------------------------------------------- + + + +void _PLYWriter_::write_header(std::ostream& _out, BaseExporter& _be, Options& _opt, std::vector& _ovProps, std::vector& _ofProps) const { + //writing header + _out << "ply" << '\n'; + + if (_opt.is_binary()) { + _out << "format "; + if ( options_.check(Options::MSB) ) + _out << "binary_big_endian "; + else + _out << "binary_little_endian "; + _out << "1.0" << '\n'; + } else + _out << "format ascii 1.0" << '\n'; + + _out << "element vertex " << _be.n_vertices() << '\n'; + + _out << "property float x" << '\n'; + _out << "property float y" << '\n'; + _out << "property float z" << '\n'; + + if ( _opt.vertex_has_normal() ){ + _out << "property float nx" << '\n'; + _out << "property float ny" << '\n'; + _out << "property float nz" << '\n'; + } + + if ( _opt.vertex_has_texcoord() ){ + _out << "property float u" << '\n'; + _out << "property float v" << '\n'; + } + + if ( _opt.vertex_has_color() ){ + if ( _opt.color_is_float() ) { + _out << "property float red" << '\n'; + _out << "property float green" << '\n'; + _out << "property float blue" << '\n'; + + if ( _opt.color_has_alpha() ) + _out << "property float alpha" << '\n'; + } else { + _out << "property uchar red" << '\n'; + _out << "property uchar green" << '\n'; + _out << "property uchar blue" << '\n'; + + if ( _opt.color_has_alpha() ) + _out << "property uchar alpha" << '\n'; + } + } + + _ovProps = writeCustomTypeHeader(_out, _be.kernel()->vprops_begin(), _be.kernel()->vprops_end()); + + _out << "element face " << _be.n_faces() << '\n'; + _out << "property list uchar int vertex_indices" << '\n'; + + _ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end()); + + _out << "end_header" << '\n'; +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + + unsigned int i, nV, nF; + Vec3f v, n; + OpenMesh::Vec3ui c; + OpenMesh::Vec4ui cA; + OpenMesh::Vec3f cf; + OpenMesh::Vec4f cAf; + OpenMesh::Vec2f t; + VertexHandle vh; + std::vector vhandles; + + std::vector vProps; + std::vector fProps; + + write_header(_out, _be, _opt, vProps, fProps); + + if (_opt.color_is_float()) + _out << std::fixed; + + // vertex data (point, normals, colors, texcoords) + for (i=0, nV=int(_be.n_vertices()); i::iterator iter = vProps.begin(); iter < vProps.end(); ++iter) + write_customProp(_out,*iter,i); + + _out << "\n"; + } + + // faces (indices starting at 0) + for (i=0, nF=int(_be.n_faces()); i::iterator iter = fProps.begin(); iter < fProps.end(); ++iter) + write_customProp(_out,*iter,i); + _out << "\n"; + } + + + return true; +} + + +//----------------------------------------------------------------------------- + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, int value) const { + + uint32_t tmp32; + uint8_t tmp8; + + switch (_type) { + case ValueTypeINT: + case ValueTypeINT32: + tmp32 = value; + store(_out, tmp32, options_.check(Options::MSB) ); + break; +// case ValueTypeUINT8: +default : + tmp8 = value; + store(_out, tmp8, options_.check(Options::MSB) ); + break; +// default : +// std::cerr << "unsupported conversion type to int: " << _type << std::endl; +// break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned int value) const { + + uint32_t tmp32; + uint8_t tmp8; + + switch (_type) { + case ValueTypeINT: + case ValueTypeINT32: + tmp32 = value; + store(_out, tmp32, options_.check(Options::MSB) ); + break; +// case ValueTypeUINT8: +default : + tmp8 = value; + store(_out, tmp8, options_.check(Options::MSB) ); + break; +// default : +// std::cerr << "unsupported conversion type to int: " << _type << std::endl; +// break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, float value) const { + + float32_t tmp; + + switch (_type) { + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + tmp = value; + store( _out , tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, double value) const { + + float64_t tmp; + + switch (_type) { + case ValueTypeDOUBLE: + tmp = value; + store( _out , tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, signed char value) const{ + + int8_t tmp; + + switch (_type) { + case ValueTypeCHAR: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned char value) const{ + + uint8_t tmp; + + switch (_type) { + case ValueTypeUCHAR: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, short value) const{ + + int16_t tmp; + + switch (_type) { + case ValueTypeSHORT: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned short value) const{ + + uint16_t tmp; + + switch (_type) { + case ValueTypeUSHORT: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} + +bool +_PLYWriter_:: +write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + + unsigned int i, nV, nF; + Vec3f v, n; + Vec2f t; + OpenMesh::Vec4uc c; + OpenMesh::Vec4f cf; + VertexHandle vh; + std::vector vhandles; + + // vProps and fProps will be empty, until custom properties are supported by the binary writer + std::vector vProps; + std::vector fProps; + + write_header(_out, _be, _opt, vProps, fProps); + + // vertex data (point, normals, texcoords) + for (i=0, nV=int(_be.n_vertices()); i::iterator iter = vProps.begin(); iter < vProps.end(); ++iter) + write_customProp(_out,*iter,i); + } + + + for (i=0, nF=int(_be.n_faces()); i::iterator iter = fProps.begin(); iter < fProps.end(); ++iter) + write_customProp(_out,*iter,i); + } + + return true; +} + +// ---------------------------------------------------------------------------- + + +size_t +_PLYWriter_:: +binary_size(BaseExporter& _be, Options _opt) const +{ + size_t header(0); + size_t data(0); + size_t _3floats(3*sizeof(float)); + size_t _3ui(3*sizeof(unsigned int)); + size_t _4ui(4*sizeof(unsigned int)); + + if ( !_opt.is_binary() ) + return 0; + else + { + + size_t _3longs(3*sizeof(long)); + + header += 11; // 'OFF BINARY\n' + header += _3longs; // #V #F #E + data += _be.n_vertices() * _3floats; // vertex data + } + + if ( _opt.vertex_has_normal() && _be.has_vertex_normals() ) + { + header += 1; // N + data += _be.n_vertices() * _3floats; + } + + if ( _opt.vertex_has_color() && _be.has_vertex_colors() ) + { + header += 1; // C + data += _be.n_vertices() * _3floats; + } + + if ( _opt.vertex_has_texcoord() && _be.has_vertex_texcoords() ) + { + size_t _2floats(2*sizeof(float)); + header += 2; // ST + data += _be.n_vertices() * _2floats; + } + + // topology + if (_be.is_triangle_mesh()) + { + data += _be.n_faces() * _4ui; + } + else + { + unsigned int i, nF; + std::vector vhandles; + + for (i=0, nF=int(_be.n_faces()); i +#include +#include + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the PLY format writer. This class is singleton'ed by + SingletonT to PLYWriter. + + currently supported options: + - VertexColors + - Binary + - Binary -> MSB +*/ +class OPENMESHDLLEXPORT _PLYWriter_ : public BaseWriter +{ +public: + + _PLYWriter_(); + + /// Destructor + virtual ~_PLYWriter_() {}; + + std::string get_description() const { return "PLY polygon file format"; } + std::string get_extensions() const { return "ply"; } + + bool write(const std::string&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + size_t binary_size(BaseExporter& _be, Options _opt) const; + + enum ValueType { + Unsupported = 0, + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeINT32, ValueTypeINT , ValueTypeUINT, + ValueTypeUCHAR, ValueTypeCHAR, ValueTypeUINT8, + ValueTypeUSHORT, ValueTypeSHORT, + ValueTypeDOUBLE + }; + +private: + mutable Options options_; + + struct CustomProperty + { + ValueType type; + const BaseProperty* property; + CustomProperty(const BaseProperty* const _p):type(Unsupported),property(_p){} + }; + + const char* nameOfType_[12]; + + /// write custom persistant properties into the header for the current element, returns all properties, which were written sorted + std::vector writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const; + template + void write_customProp(std::ostream& _our, const CustomProperty& _prop, size_t _index) const; + template + void writeProxy(ValueType _type, std::ostream& _out, T _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + writeValue(_type, _out, _value); + } + template + void writeProxy(ValueType _type, std::ostream& _out, T _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _out << " " << _value; + } + +protected: + void writeValue(ValueType _type, std::ostream& _out, signed char value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned char value) const; + void writeValue(ValueType _type, std::ostream& _out, short value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned short value) const; + void writeValue(ValueType _type, std::ostream& _out, int value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned int value) const; + void writeValue(ValueType _type, std::ostream& _out, float value) const; + void writeValue(ValueType _type, std::ostream& _out, double value) const; + + bool write_ascii(std::ostream& _out, BaseExporter&, Options) const; + bool write_binary(std::ostream& _out, BaseExporter&, Options) const; + /// write header into the stream _out. Returns custom properties (vertex and face) which are written into the header + void write_header(std::ostream& _out, BaseExporter& _be, Options& _opt, std::vector& _ovProps, std::vector& _ofProps) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY writer. +extern _PLYWriter_ __PLYWriterInstance; +OPENMESHDLLEXPORT _PLYWriter_& PLYWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/STLWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/STLWriter.cc new file mode 100644 index 0000000..54e8f70 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/STLWriter.cc @@ -0,0 +1,440 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +//STL +#include + +// OpenMesh +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +_STLWriter_ __STLWriterInstance; +_STLWriter_& STLWriter() { return __STLWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_STLWriter_::_STLWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + // binary or ascii ? + if (_filename.rfind(".stla") != std::string::npos) + { + _opt -= Options::Binary; + } + else if (_filename.rfind(".stlb") != std::string::npos) + { + _opt += Options::Binary; + } + + // open file + std::fstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + + bool result = write(out, _be, _opt, _precision); + + out.close(); + + return result; +} + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + // check exporter features + if (!check(_be, _opt)) return false; + + // check writer features + if (_opt.check(Options::VertexNormal) || + _opt.check(Options::VertexTexCoord) || + _opt.check(Options::FaceColor)) + return false; + + if (!_opt.check(Options::Binary)) + _os.precision(_precision); + + if (_opt & Options::Binary) + return write_stlb(_os, _be, _opt); + else + return write_stla(_os, _be, _opt); + + return false; +} + + + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write_stla(const std::string& _filename, BaseExporter& _be, Options /* _opt */) const +{ + omlog() << "[STLWriter] : write ascii file\n"; + + + // open file + FILE* out = fopen(_filename.c_str(), "w"); + if (!out) + { + omerr() << "[STLWriter] : cannot open file " << _filename << std::endl; + return false; + } + + + + + int i, nF(int(_be.n_faces())); + Vec3f a, b, c, n; + std::vector vhandles; + FaceHandle fh; + + + // header + fprintf(out, "solid \n"); + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + _out.precision(_precision); + + + // header + _out << "solid \n"; + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + + + // write header + const char header[80] = + "binary stl file" + " "; + fwrite(header, 1, 80, out); + + + // number of faces + write_int( int(_be.n_faces()), out); + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + _out.precision(_precision); + + + // write header + const char header[80] = + "binary stl file" + " "; + _out.write(header, 80); + + + // number of faces + write_int(int(_be.n_faces()), _out); + + + // write face set + for (i=0; i vhandles; + + for (i=0; i +#include +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the STL format writer. This class is singleton'ed by + SingletonT to STLWriter. +*/ +class OPENMESHDLLEXPORT _STLWriter_ : public BaseWriter +{ +public: + + _STLWriter_(); + + /// Destructor + virtual ~_STLWriter_() {}; + + std::string get_description() const { return "Stereolithography Format"; } + std::string get_extensions() const { return "stl stla stlb"; } + + bool write(const std::string&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + size_t binary_size(BaseExporter&, Options) const; + +private: + bool write_stla(const std::string&, BaseExporter&, Options) const; + bool write_stla(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + bool write_stlb(const std::string&, BaseExporter&, Options) const; + bool write_stlb(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +// Declare the single entity of STL writer. +extern _STLWriter_ __STLWriterInstance; +OPENMESHDLLEXPORT _STLWriter_& STLWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/VTKWriter.cc b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/VTKWriter.cc new file mode 100644 index 0000000..a178ce5 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/VTKWriter.cc @@ -0,0 +1,103 @@ +//== INCLUDES ================================================================= + +#include +#include + +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + +//=== INSTANTIATE ============================================================= + +_VTKWriter_ __VTKWriterinstance; +_VTKWriter_& VTKWriter() { return __VTKWriterinstance; } + +//=== IMPLEMENTATION ========================================================== + +_VTKWriter_::_VTKWriter_() { IOManager().register_module(this); } + +//----------------------------------------------------------------------------- + +bool _VTKWriter_::write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + std::ofstream out(_filename.c_str()); + + if (!out) { + omerr() << "[VTKWriter] : cannot open file " << _filename << std::endl; + return false; + } + + return write(out, _be, _opt, _precision); +} + +//----------------------------------------------------------------------------- + +bool _VTKWriter_::write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _precision) const +{ + Vec3f v, n; + Vec2f t; + VertexHandle vh; + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + // check exporter features + if (!check(_be, _opt)) { + return false; + } + + // check writer features + if (!_opt.is_empty()) { + omlog() << "[VTKWriter] : writer does not support any options\n"; + return false; + } + + omlog() << "[VTKWriter] : write file\n"; + _out.precision(_precision); + + std::vector vhandles; + size_t polygon_table_size = 0; + size_t nf = _be.n_faces(); + for (size_t i = 0; i < nf; ++i) { + polygon_table_size += _be.get_vhandles(FaceHandle(int(i)), vhandles); + } + polygon_table_size += nf; + + // header + _out << "# vtk DataFile Version 3.0\n"; + _out << "Generated by OpenMesh\n"; + _out << "ASCII\n"; + _out << "DATASET POLYDATA\n"; + + // points + _out << "POINTS " << _be.n_vertices() << " float\n"; + size_t nv = _be.n_vertices(); + for (size_t i = 0; i < nv; ++i) { + Vec3f v = _be.point(VertexHandle(int(i))); + _out << v[0] << ' ' << v[1] << ' ' << v[2] << '\n'; + } + + // faces + _out << "POLYGONS " << nf << ' ' << polygon_table_size << '\n'; + for (size_t i = 0; i < nf; ++i) { + _be.get_vhandles(FaceHandle(int(i)), vhandles); + + _out << vhandles.size() << ' '; + for (size_t j = 0; j < vhandles.size(); ++j) { + _out << " " << vhandles[j].idx(); + } + _out << '\n'; + } + + return true; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/VTKWriter.hh b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/VTKWriter.hh new file mode 100644 index 0000000..40d9e11 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/IO/writer/VTKWriter.hh @@ -0,0 +1,52 @@ +//============================================================================= +// +// Implements an IOManager writer module for VTK files +// +//============================================================================= + +#ifndef __VTKWRITER_HH__ +#define __VTKWRITER_HH__ + +//=== INCLUDES ================================================================ + +#include +#include + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + +//=== IMPLEMENTATION ========================================================== + +class OPENMESHDLLEXPORT _VTKWriter_ : public BaseWriter +{ +public: + _VTKWriter_(); + + std::string get_description() const { return "VTK"; } + std::string get_extensions() const { return "vtk"; } + + bool write(const std::string&, BaseExporter&, Options, std::streamsize _precision = 6) const; + bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; + + size_t binary_size(BaseExporter&, Options) const { return 0; } +}; + +//== TYPE DEFINITION ========================================================== + +/// Declare the single entity of the OBJ writer +extern _VTKWriter_ __VTKWriterinstance; +OPENMESHDLLEXPORT _VTKWriter_& VTKWriter(); + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayItems.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayItems.hh new file mode 100644 index 0000000..c49944b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayItems.hh @@ -0,0 +1,130 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_ARRAY_ITEMS_HH +#define OPENMESH_ARRAY_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Definition of mesh items for use in the ArrayKernel +struct ArrayItems +{ + + //------------------------------------------------------ internal vertex type + + /// The vertex item + class Vertex + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; + + + //---------------------------------------------------- internal halfedge type + +#ifndef DOXY_IGNORE_THIS + class Halfedge_without_prev + { + friend class ArrayKernel; + FaceHandle face_handle_; + VertexHandle vertex_handle_; + HalfedgeHandle next_halfedge_handle_; + }; +#endif + +#ifndef DOXY_IGNORE_THIS + class Halfedge_with_prev : public Halfedge_without_prev + { + friend class ArrayKernel; + HalfedgeHandle prev_halfedge_handle_; + }; +#endif + + //TODO: should be selected with config.h define + typedef Halfedge_with_prev Halfedge; + typedef GenProg::Bool2Type HasPrevHalfedge; + + //-------------------------------------------------------- internal edge type +#ifndef DOXY_IGNORE_THIS + class Edge + { + friend class ArrayKernel; + Halfedge halfedges_[2]; + }; +#endif + + //-------------------------------------------------------- internal face type +#ifndef DOXY_IGNORE_THIS + class Face + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; +}; +#endif + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ITEMS_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernel.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernel.cc new file mode 100644 index 0000000..a22f878 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernel.cc @@ -0,0 +1,259 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#include + +namespace OpenMesh +{ + +ArrayKernel::ArrayKernel() +: refcount_vstatus_(0), refcount_hstatus_(0), + refcount_estatus_(0), refcount_fstatus_(0) +{ + init_bit_masks(); //Status bit masks initialization +} + +ArrayKernel::~ArrayKernel() +{ + clear(); +} + +// ArrayKernel::ArrayKernel(const ArrayKernel& _rhs) +// : BaseKernel(_rhs), +// vertices_(_rhs.vertices_), edges_(_rhs.edges_), faces_(_rhs.faces_), +// vertex_status_(_rhs.vertex_status_), halfedge_status_(_rhs.halfedge_status_), +// edge_status_(_rhs.edge_status_), face_status_(_rhs.face_status_), +// refcount_vstatus_(_rhs.refcount_vstatus_), refcount_hstatus_(_rhs.refcount_hstatus_), +// refcount_estatus_(_rhs.refcount_estatus_), refcount_fstatus_(_rhs.refcount_fstatus_) +// {} + + +void ArrayKernel::assign_connectivity(const ArrayKernel& _other) +{ + vertices_ = _other.vertices_; + edges_ = _other.edges_; + faces_ = _other.faces_; + + vprops_resize(n_vertices()); + hprops_resize(n_halfedges()); + eprops_resize(n_edges()); + fprops_resize(n_faces()); + + //just copy status properties for now, + //until a proper solution for refcounted + //properties is available + vertex_status_ = _other.vertex_status_; + halfedge_status_ = _other.halfedge_status_; + edge_status_ = _other.edge_status_; + face_status_ = _other.face_status_; + + //initialize refcounter to 1 for the new mesh, + //if status is available. + refcount_estatus_ = _other.refcount_estatus_ > 0 ? 1 : 0; + refcount_vstatus_ = _other.refcount_vstatus_ > 0 ? 1 : 0; + refcount_hstatus_ = _other.refcount_hstatus_ > 0 ? 1 : 0; + refcount_fstatus_ = _other.refcount_fstatus_ > 0 ? 1 : 0; +} + +// --- handle -> item --- +VertexHandle ArrayKernel::handle(const Vertex& _v) const +{ + return VertexHandle( int( &_v - &vertices_.front())); +} + +HalfedgeHandle ArrayKernel::handle(const Halfedge& _he) const +{ + // Calculate edge belonging to given halfedge + // There are two halfedges stored per edge + // Get memory position inside edge vector and devide by size of an edge + // to get the corresponding edge for the requested halfedge + size_t eh = ( (char*)&_he - (char*)&edges_.front() ) / sizeof(Edge) ; + assert((&_he == &edges_[eh].halfedges_[0]) || + (&_he == &edges_[eh].halfedges_[1])); + return ((&_he == &edges_[eh].halfedges_[0]) ? + HalfedgeHandle( int(eh)<<1) : HalfedgeHandle((int(eh)<<1)+1)); +} + +EdgeHandle ArrayKernel::handle(const Edge& _e) const +{ + return EdgeHandle( int(&_e - &edges_.front() ) ); +} + +FaceHandle ArrayKernel::handle(const Face& _f) const +{ + return FaceHandle( int(&_f - &faces_.front()) ); +} + +#define SIGNED(x) signed( (x) ) + +bool ArrayKernel::is_valid_handle(VertexHandle _vh) const +{ + return 0 <= _vh.idx() && _vh.idx() < SIGNED(n_vertices()); +} + +bool ArrayKernel::is_valid_handle(HalfedgeHandle _heh) const +{ + return 0 <= _heh.idx() && _heh.idx() < SIGNED(n_edges()*2); +} + +bool ArrayKernel::is_valid_handle(EdgeHandle _eh) const +{ + return 0 <= _eh.idx() && _eh.idx() < SIGNED(n_edges()); +} + +bool ArrayKernel::is_valid_handle(FaceHandle _fh) const +{ + return 0 <= _fh.idx() && _fh.idx() < SIGNED(n_faces()); +} + +#undef SIGNED + +unsigned int ArrayKernel::delete_isolated_vertices() +{ + assert(has_vertex_status());//this function requires vertex status property + unsigned int n_isolated = 0; + for (KernelVertexIter v_it = vertices_begin(); v_it != vertices_end(); ++v_it) + { + if (is_isolated(handle(*v_it))) + { + status(handle(*v_it)).set_deleted(true); + n_isolated++; + } + } + return n_isolated; +} + +void ArrayKernel::garbage_collection(bool _v, bool _e, bool _f) +{ + std::vector empty_vh; + std::vector empty_hh; + std::vector empty_fh; + garbage_collection( empty_vh,empty_hh,empty_fh,_v, _e, _f); +} + +void ArrayKernel::clean_keep_reservation() +{ + vertices_.clear(); + + edges_.clear(); + + faces_.clear(); + +} + +void ArrayKernel::clean() +{ + + vertices_.clear(); + VertexContainer().swap( vertices_ ); + + edges_.clear(); + EdgeContainer().swap( edges_ ); + + faces_.clear(); + FaceContainer().swap( faces_ ); + +} + + +void ArrayKernel::clear() +{ + vprops_clear(); + eprops_clear(); + hprops_clear(); + fprops_clear(); + + clean(); +} + + + +void ArrayKernel::resize( size_t _n_vertices, size_t _n_edges, size_t _n_faces ) +{ + vertices_.resize(_n_vertices); + edges_.resize(_n_edges); + faces_.resize(_n_faces); + + vprops_resize(n_vertices()); + hprops_resize(n_halfedges()); + eprops_resize(n_edges()); + fprops_resize(n_faces()); +} + +void ArrayKernel::reserve(size_t _n_vertices, size_t _n_edges, size_t _n_faces ) +{ + vertices_.reserve(_n_vertices); + edges_.reserve(_n_edges); + faces_.reserve(_n_faces); + + vprops_reserve(_n_vertices); + hprops_reserve(_n_edges*2); + eprops_reserve(_n_edges); + fprops_reserve(_n_faces); +} + +// Status Sets API +void ArrayKernel::init_bit_masks(BitMaskContainer& _bmc) +{ + for (unsigned int i = Attributes::UNUSED; i != 0; i <<= 1) + { + _bmc.push_back(i); + } +} + +void ArrayKernel::init_bit_masks() +{ + init_bit_masks(vertex_bit_masks_); + edge_bit_masks_ = vertex_bit_masks_;//init_bit_masks(edge_bit_masks_); + face_bit_masks_ = vertex_bit_masks_;//init_bit_masks(face_bit_masks_); + halfedge_bit_masks_= vertex_bit_masks_;//init_bit_masks(halfedge_bit_masks_); +} + + +}; + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernel.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernel.hh new file mode 100644 index 0000000..ccf2748 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernel.hh @@ -0,0 +1,915 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS ArrayKernel +// +//============================================================================= + + +#ifndef OPENMESH_ARRAY_KERNEL_HH +#define OPENMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= +#include + +#include +#include + +#include +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= +/** \ingroup mesh_kernels_group + + Mesh kernel using arrays for mesh item storage. + + This mesh kernel uses the std::vector as container to store the + mesh items. Therefore all handle types are internally represented + by integers. To get the index from a handle use the handle's \c + idx() method. + + \note For a description of the minimal kernel interface see + OpenMesh::Mesh::BaseKernel. + \note You do not have to use this class directly, use the predefined + mesh-kernel combinations in \ref mesh_types_group. + \see OpenMesh::Concepts::KernelT, \ref mesh_type +*/ + +class OPENMESHDLLEXPORT ArrayKernel : public BaseKernel, public ArrayItems +{ +public: + + // handles + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef Attributes::StatusInfo StatusInfo; + typedef VPropHandleT VertexStatusPropertyHandle; + typedef HPropHandleT HalfedgeStatusPropertyHandle; + typedef EPropHandleT EdgeStatusPropertyHandle; + typedef FPropHandleT FaceStatusPropertyHandle; + +public: + + // --- constructor/destructor --- + ArrayKernel(); + virtual ~ArrayKernel(); + + /** ArrayKernel uses the default copy constructor and assignment operator, which means + that the connectivity and all properties are copied, including reference + counters, allocated bit status masks, etc.. In contrast assign_connectivity + copies only the connectivity, i.e. vertices, edges, faces and their status fields. + NOTE: The geometry (the points property) is NOT copied. Poly/TriConnectivity + override(and hide) that function to provide connectivity consistence.*/ + void assign_connectivity(const ArrayKernel& _other); + + // --- handle -> item --- + VertexHandle handle(const Vertex& _v) const; + + HalfedgeHandle handle(const Halfedge& _he) const; + + EdgeHandle handle(const Edge& _e) const; + + FaceHandle handle(const Face& _f) const; + + + ///checks handle validity - useful for debugging + bool is_valid_handle(VertexHandle _vh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(HalfedgeHandle _heh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(EdgeHandle _eh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(FaceHandle _fh) const; + + + // --- item -> handle --- + const Vertex& vertex(VertexHandle _vh) const + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + Vertex& vertex(VertexHandle _vh) + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + const Halfedge& halfedge(HalfedgeHandle _heh) const + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + Halfedge& halfedge(HalfedgeHandle _heh) + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + const Edge& edge(EdgeHandle _eh) const + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + Edge& edge(EdgeHandle _eh) + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + const Face& face(FaceHandle _fh) const + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + Face& face(FaceHandle _fh) + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + // --- get i'th items --- + + VertexHandle vertex_handle(unsigned int _i) const + { return (_i < n_vertices()) ? handle( vertices_[_i] ) : VertexHandle(); } + + HalfedgeHandle halfedge_handle(unsigned int _i) const + { + return (_i < n_halfedges()) ? + halfedge_handle(edge_handle(_i/2), _i%2) : HalfedgeHandle(); + } + + EdgeHandle edge_handle(unsigned int _i) const + { return (_i < n_edges()) ? handle(edges_[_i]) : EdgeHandle(); } + + FaceHandle face_handle(unsigned int _i) const + { return (_i < n_faces()) ? handle(faces_[_i]) : FaceHandle(); } + +public: + + /** + * \brief Add a new vertex. + * + * If you are rebuilding a mesh that you previously erased using clean() or + * clean_keep_reservation() you probably want to use new_vertex_dirty() + * instead. + * + * \sa new_vertex_dirty() + */ + inline VertexHandle new_vertex() + { + vertices_.push_back(Vertex()); + vprops_resize(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + /** + * Same as new_vertex() but uses PropertyContainer::resize_if_smaller() to + * resize the vertex property container. + * + * If you are rebuilding a mesh that you erased with clean() or + * clean_keep_reservation() using this method instead of new_vertex() saves + * reallocation and reinitialization of property memory. + * + * \sa new_vertex() + */ + inline VertexHandle new_vertex_dirty() + { + vertices_.push_back(Vertex()); + vprops_resize_if_smaller(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + inline HalfedgeHandle new_edge(VertexHandle _start_vh, VertexHandle _end_vh) + { +// assert(_start_vh != _end_vh); + edges_.push_back(Edge()); + eprops_resize(n_edges());//TODO:should it be push_back()? + hprops_resize(n_halfedges());//TODO:should it be push_back()? + + EdgeHandle eh(handle(edges_.back())); + HalfedgeHandle heh0(halfedge_handle(eh, 0)); + HalfedgeHandle heh1(halfedge_handle(eh, 1)); + set_vertex_handle(heh0, _end_vh); + set_vertex_handle(heh1, _start_vh); + return heh0; + } + + inline FaceHandle new_face() + { + faces_.push_back(Face()); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + + inline FaceHandle new_face(const Face& _f) + { + faces_.push_back(_f); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + +public: + // --- resize/reserve --- + void resize( size_t _n_vertices, size_t _n_edges, size_t _n_faces ); + void reserve(size_t _n_vertices, size_t _n_edges, size_t _n_faces ); + + // --- deletion --- + /** \brief garbage collection + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass them to the second garbage collection + * function, which will update a vector of handles. + * See also \ref deletedElements. + * + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + * + */ + void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + + /** \brief garbage collection with handle tracking + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass them to this function. The handles that the + * given pointers point to are updated in place. + * See also \ref deletedElements. + * + * @param vh_to_update Pointers to vertex handles that should get updated + * @param hh_to_update Pointers to halfedge handles that should get updated + * @param fh_to_update Pointers to face handles that should get updated + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + */ + template + void garbage_collection(std_API_Container_VHandlePointer& vh_to_update, + std_API_Container_HHandlePointer& hh_to_update, + std_API_Container_FHandlePointer& fh_to_update, + bool _v=true, bool _e=true, bool _f=true); + + /// \brief Does the same as clean() and in addition erases all properties. + void clear(); + + /** \brief Remove all vertices, edges and faces and deallocates their memory. + * + * In contrast to clear() this method does neither erases the properties + * nor clears the property vectors. Depending on how you add any new entities + * to the mesh after calling this method, your properties will be initialized + * with old values. + * + * \sa clean_keep_reservation() + */ + void clean(); + + /** \brief Remove all vertices, edges and faces but keep memory allocated. + * + * This method behaves like clean() (also regarding the properties) but + * leaves the memory used for vertex, edge and face storage allocated. This + * leads to no reduction in memory consumption but allows for faster + * performance when rebuilding the mesh. + */ + void clean_keep_reservation(); + + // --- number of items --- + size_t n_vertices() const { return vertices_.size(); } + size_t n_halfedges() const { return 2*edges_.size(); } + size_t n_edges() const { return edges_.size(); } + size_t n_faces() const { return faces_.size(); } + + bool vertices_empty() const { return vertices_.empty(); } + bool halfedges_empty() const { return edges_.empty(); } + bool edges_empty() const { return edges_.empty(); } + bool faces_empty() const { return faces_.empty(); } + + // --- vertex connectivity --- + + HalfedgeHandle halfedge_handle(VertexHandle _vh) const + { return vertex(_vh).halfedge_handle_; } + + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + vertex(_vh).halfedge_handle_ = _heh; + } + + bool is_isolated(VertexHandle _vh) const + { return !halfedge_handle(_vh).is_valid(); } + + void set_isolated(VertexHandle _vh) + { vertex(_vh).halfedge_handle_.invalidate(); } + + unsigned int delete_isolated_vertices(); + + // --- halfedge connectivity --- + VertexHandle to_vertex_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).vertex_handle_; } + + VertexHandle from_vertex_handle(HalfedgeHandle _heh) const + { return to_vertex_handle(opposite_halfedge_handle(_heh)); } + + void set_vertex_handle(HalfedgeHandle _heh, VertexHandle _vh) + { +// assert(is_valid_handle(_vh)); + halfedge(_heh).vertex_handle_ = _vh; + } + + FaceHandle face_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).face_handle_; } + + void set_face_handle(HalfedgeHandle _heh, FaceHandle _fh) + { +// assert(is_valid_handle(_fh)); + halfedge(_heh).face_handle_ = _fh; + } + + void set_boundary(HalfedgeHandle _heh) + { halfedge(_heh).face_handle_.invalidate(); } + + /// Is halfedge _heh a boundary halfedge (is its face handle invalid) ? + bool is_boundary(HalfedgeHandle _heh) const + { return !face_handle(_heh).is_valid(); } + + HalfedgeHandle next_halfedge_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).next_halfedge_handle_; } + + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh) + { + assert(is_valid_handle(_nheh)); +// assert(to_vertex_handle(_heh) == from_vertex_handle(_nheh)); + halfedge(_heh).next_halfedge_handle_ = _nheh; + set_prev_halfedge_handle(_nheh, _heh); + } + + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh) + { + assert(is_valid_handle(_pheh)); + set_prev_halfedge_handle(_heh, _pheh, HasPrevHalfedge()); + } + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh, + GenProg::TrueType) + { halfedge(_heh).prev_halfedge_handle_ = _pheh; } + + void set_prev_halfedge_handle(HalfedgeHandle /* _heh */, HalfedgeHandle /* _pheh */, + GenProg::FalseType) + {} + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh) const + { return prev_halfedge_handle(_heh, HasPrevHalfedge() ); } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::TrueType) const + { return halfedge(_heh).prev_halfedge_handle_; } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::FalseType) const + { + if (is_boundary(_heh)) + {//iterating around the vertex should be faster than iterating the boundary + HalfedgeHandle curr_heh(opposite_halfedge_handle(_heh)); + HalfedgeHandle next_heh(next_halfedge_handle(curr_heh)); + do + { + curr_heh = opposite_halfedge_handle(next_heh); + next_heh = next_halfedge_handle(curr_heh); + } + while (next_heh != _heh); + return curr_heh; + } + else + { + HalfedgeHandle heh(_heh); + HalfedgeHandle next_heh(next_halfedge_handle(heh)); + while (next_heh != _heh) { + heh = next_heh; + next_heh = next_halfedge_handle(next_heh); + } + return heh; + } + } + + + HalfedgeHandle opposite_halfedge_handle(HalfedgeHandle _heh) const + { return HalfedgeHandle(_heh.idx() ^ 1); } + + + HalfedgeHandle ccw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return opposite_halfedge_handle(prev_halfedge_handle(_heh)); } + + + HalfedgeHandle cw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return next_halfedge_handle(opposite_halfedge_handle(_heh)); } + + // --- edge connectivity --- + static HalfedgeHandle s_halfedge_handle(EdgeHandle _eh, unsigned int _i) + { + assert(_i<=1); + return HalfedgeHandle((_eh.idx() << 1) + _i); + } + + static EdgeHandle s_edge_handle(HalfedgeHandle _heh) + { return EdgeHandle(_heh.idx() >> 1); } + + HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i) const + { + return s_halfedge_handle(_eh, _i); + } + + EdgeHandle edge_handle(HalfedgeHandle _heh) const + { return s_edge_handle(_heh); } + + // --- face connectivity --- + HalfedgeHandle halfedge_handle(FaceHandle _fh) const + { return face(_fh).halfedge_handle_; } + + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + face(_fh).halfedge_handle_ = _heh; + } + + /// Status Query API + //------------------------------------------------------------ vertex status + const StatusInfo& status(VertexHandle _vh) const + { return property(vertex_status_, _vh); } + + StatusInfo& status(VertexHandle _vh) + { return property(vertex_status_, _vh); } + + /** + * Reinitializes the status of all vertices using the StatusInfo default + * constructor, i.e. all flags will be set to false. + */ + void reset_status() { + PropertyT &status_prop = property(vertex_status_); + PropertyT::vector_type &sprop_v = status_prop.data_vector(); + std::fill(sprop_v.begin(), sprop_v.begin() + n_vertices(), StatusInfo()); + } + + //----------------------------------------------------------- halfedge status + const StatusInfo& status(HalfedgeHandle _hh) const + { return property(halfedge_status_, _hh); } + + StatusInfo& status(HalfedgeHandle _hh) + { return property(halfedge_status_, _hh); } + + //--------------------------------------------------------------- edge status + const StatusInfo& status(EdgeHandle _eh) const + { return property(edge_status_, _eh); } + + StatusInfo& status(EdgeHandle _eh) + { return property(edge_status_, _eh); } + + //--------------------------------------------------------------- face status + const StatusInfo& status(FaceHandle _fh) const + { return property(face_status_, _fh); } + + StatusInfo& status(FaceHandle _fh) + { return property(face_status_, _fh); } + + inline bool has_vertex_status() const + { return vertex_status_.is_valid(); } + + inline bool has_halfedge_status() const + { return halfedge_status_.is_valid(); } + + inline bool has_edge_status() const + { return edge_status_.is_valid(); } + + inline bool has_face_status() const + { return face_status_.is_valid(); } + + inline VertexStatusPropertyHandle vertex_status_pph() const + { return vertex_status_; } + + inline HalfedgeStatusPropertyHandle halfedge_status_pph() const + { return halfedge_status_; } + + inline EdgeStatusPropertyHandle edge_status_pph() const + { return edge_status_; } + + inline FaceStatusPropertyHandle face_status_pph() const + { return face_status_; } + + /// status property by handle + inline VertexStatusPropertyHandle status_pph(VertexHandle /*_hnd*/) const + { return vertex_status_pph(); } + + inline HalfedgeStatusPropertyHandle status_pph(HalfedgeHandle /*_hnd*/) const + { return halfedge_status_pph(); } + + inline EdgeStatusPropertyHandle status_pph(EdgeHandle /*_hnd*/) const + { return edge_status_pph(); } + + inline FaceStatusPropertyHandle status_pph(FaceHandle /*_hnd*/) const + { return face_status_pph(); } + + /// Status Request API + void request_vertex_status() + { + if (!refcount_vstatus_++) + add_property( vertex_status_, "v:status" ); + } + + void request_halfedge_status() + { + if (!refcount_hstatus_++) + add_property( halfedge_status_, "h:status" ); + } + + void request_edge_status() + { + if (!refcount_estatus_++) + add_property( edge_status_, "e:status" ); + } + + void request_face_status() + { + if (!refcount_fstatus_++) + add_property( face_status_, "f:status" ); + } + + /// Status Release API + void release_vertex_status() + { + if ((refcount_vstatus_ > 0) && (! --refcount_vstatus_)) + remove_property(vertex_status_); + } + + void release_halfedge_status() + { + if ((refcount_hstatus_ > 0) && (! --refcount_hstatus_)) + remove_property(halfedge_status_); + } + + void release_edge_status() + { + if ((refcount_estatus_ > 0) && (! --refcount_estatus_)) + remove_property(edge_status_); + } + + void release_face_status() + { + if ((refcount_fstatus_ > 0) && (! --refcount_fstatus_)) + remove_property(face_status_); + } + + /// --- StatusSet API --- + + /*! + Implements a set of connectivity entities (vertex, edge, face, halfedge) + using the available bits in the corresponding mesh status field. + + Status-based sets are much faster than std::set<> and equivalent + in performance to std::vector, but much more convenient. + */ + template + class StatusSetT + { + public: + typedef HandleT Handle; + + protected: + ArrayKernel& kernel_; + + public: + const unsigned int bit_mask_; + + public: + StatusSetT(ArrayKernel& _kernel, const unsigned int _bit_mask) + : kernel_(_kernel), bit_mask_(_bit_mask) + {} + + ~StatusSetT() + {} + + inline bool is_in(Handle _hnd) const + { return kernel_.status(_hnd).is_bit_set(bit_mask_); } + + inline void insert(Handle _hnd) + { kernel_.status(_hnd).set_bit(bit_mask_); } + + inline void erase(Handle _hnd) + { kernel_.status(_hnd).unset_bit(bit_mask_); } + + //! Note: 0(n) complexity + size_t size() const + { + const int n = kernel_.status_pph(Handle()).is_valid() ? + (int)kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + + size_t sz = 0; + for (int i = 0; i < n; ++i) + sz += (size_t)is_in(Handle(i)); + return sz; + } + + //! Note: O(n) complexity + void clear() + { + const int n = kernel_.status_pph(Handle()).is_valid() ? + (int)kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + + for (int i = 0; i < n; ++i) + erase(Handle(i)); + } + }; + + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + + //! AutoStatusSetT: A status set that automatically picks a status bit + template + class AutoStatusSetT : public StatusSetT + { + private: + typedef HandleT Handle; + typedef StatusSetT Base; + + public: + AutoStatusSetT(ArrayKernel& _kernel) + : StatusSetT(_kernel, _kernel.pop_bit_mask(Handle())) + { /*assert(size() == 0);*/ } //the set should be empty on creation + + ~AutoStatusSetT() + { + //assert(size() == 0);//the set should be empty on leave? + Base::kernel_.push_bit_mask(Handle(), Base::bit_mask_); + } + }; + + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + + typedef AutoStatusSetT VertexStatusSet; + typedef AutoStatusSetT EdgeStatusSet; + typedef AutoStatusSetT FaceStatusSet; + typedef AutoStatusSetT HalfedgeStatusSet; + + //! ExtStatusSet: A status set augmented with an array + template + class ExtStatusSetT : public AutoStatusSetT + { + public: + typedef HandleT Handle; + typedef AutoStatusSetT Base; + + protected: + typedef std::vector HandleContainer; + HandleContainer handles_; + + public: + typedef typename HandleContainer::iterator + iterator; + typedef typename HandleContainer::const_iterator + const_iterator; + public: + ExtStatusSetT(ArrayKernel& _kernel, size_t _capacity_hint = 0) + : Base(_kernel) + { handles_.reserve(_capacity_hint); } + + ~ExtStatusSetT() + { clear(); } + + // Complexity: O(1) + inline void insert(Handle _hnd) + { + if (!is_in(_hnd)) + { + Base::insert(_hnd); + handles_.push_back(_hnd); + } + } + + //! Complexity: O(k), (k - number of the elements in the set) + inline void erase(Handle _hnd) + { + if (is_in(_hnd)) + { + iterator it = std::find(begin(), end(), _hnd); + erase(it); + } + } + + //! Complexity: O(1) + inline void erase(iterator _it) + { + assert(_it != end() && is_in(*_it)); + Base::erase(*_it); + *_it = handles_.back(); + _it.pop_back(); + } + + inline void clear() + { + for (iterator it = begin(); it != end(); ++it) + { + assert(is_in(*it)); + Base::erase(*it); + } + handles_.clear(); + } + + /// Complexity: 0(1) + inline unsigned int size() const + { return handles_.size(); } + inline bool empty() const + { return handles_.empty(); } + + //Vector API + inline iterator begin() + { return handles_.begin(); } + inline const_iterator begin() const + { return handles_.begin(); } + + inline iterator end() + { return handles_.end(); } + inline const_iterator end() const + { return handles_.end(); } + + inline Handle& front() + { return handles_.front(); } + inline const Handle& front() const + { return handles_.front(); } + + inline Handle& back() + { return handles_.back(); } + inline const Handle& back() const + { return handles_.back(); } + }; + + typedef ExtStatusSetT ExtFaceStatusSet; + typedef ExtStatusSetT ExtVertexStatusSet; + typedef ExtStatusSetT ExtEdgeStatusSet; + typedef ExtStatusSetT ExtHalfedgeStatusSet; + +private: + // iterators + typedef std::vector VertexContainer; + typedef std::vector EdgeContainer; + typedef std::vector FaceContainer; + typedef VertexContainer::iterator KernelVertexIter; + typedef VertexContainer::const_iterator KernelConstVertexIter; + typedef EdgeContainer::iterator KernelEdgeIter; + typedef EdgeContainer::const_iterator KernelConstEdgeIter; + typedef FaceContainer::iterator KernelFaceIter; + typedef FaceContainer::const_iterator KernelConstFaceIter; + typedef std::vector BitMaskContainer; + + + KernelVertexIter vertices_begin() { return vertices_.begin(); } + KernelConstVertexIter vertices_begin() const { return vertices_.begin(); } + KernelVertexIter vertices_end() { return vertices_.end(); } + KernelConstVertexIter vertices_end() const { return vertices_.end(); } + + KernelEdgeIter edges_begin() { return edges_.begin(); } + KernelConstEdgeIter edges_begin() const { return edges_.begin(); } + KernelEdgeIter edges_end() { return edges_.end(); } + KernelConstEdgeIter edges_end() const { return edges_.end(); } + + KernelFaceIter faces_begin() { return faces_.begin(); } + KernelConstFaceIter faces_begin() const { return faces_.begin(); } + KernelFaceIter faces_end() { return faces_.end(); } + KernelConstFaceIter faces_end() const { return faces_.end(); } + + /// bit mask container by handle + inline BitMaskContainer& bit_masks(VertexHandle /*_dummy_hnd*/) + { return vertex_bit_masks_; } + inline BitMaskContainer& bit_masks(EdgeHandle /*_dummy_hnd*/) + { return edge_bit_masks_; } + inline BitMaskContainer& bit_masks(FaceHandle /*_dummy_hnd*/) + { return face_bit_masks_; } + inline BitMaskContainer& bit_masks(HalfedgeHandle /*_dummy_hnd*/) + { return halfedge_bit_masks_; } + + template + unsigned int pop_bit_mask(Handle _hnd) + { + assert(!bit_masks(_hnd).empty());//check if the client request too many status sets + unsigned int bit_mask = bit_masks(_hnd).back(); + bit_masks(_hnd).pop_back(); + return bit_mask; + } + + template + void push_bit_mask(Handle _hnd, unsigned int _bit_mask) + { + assert(std::find(bit_masks(_hnd).begin(), bit_masks(_hnd).end(), _bit_mask) == + bit_masks(_hnd).end());//this mask should be not already used + bit_masks(_hnd).push_back(_bit_mask); + } + + void init_bit_masks(BitMaskContainer& _bmc); + void init_bit_masks(); + +protected: + + VertexStatusPropertyHandle vertex_status_; + HalfedgeStatusPropertyHandle halfedge_status_; + EdgeStatusPropertyHandle edge_status_; + FaceStatusPropertyHandle face_status_; + + unsigned int refcount_vstatus_; + unsigned int refcount_hstatus_; + unsigned int refcount_estatus_; + unsigned int refcount_fstatus_; + +private: + VertexContainer vertices_; + EdgeContainer edges_; + FaceContainer faces_; + + BitMaskContainer halfedge_bit_masks_; + BitMaskContainer edge_bit_masks_; + BitMaskContainer vertex_bit_masks_; + BitMaskContainer face_bit_masks_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_ARRAY_KERNEL_C) +# define OPENMESH_ARRAY_KERNEL_TEMPLATES +# include "ArrayKernelT.cc" +#endif +//============================================================================= +#endif // OPENMESH_ARRAY_KERNEL_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernelT.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernelT.cc new file mode 100644 index 0000000..d38d093 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/ArrayKernelT.cc @@ -0,0 +1,315 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 362 $ * + * $Date: 2011-01-26 10:21:12 +0100 (Mi, 26 Jan 2011) $ * + * * +\*===========================================================================*/ + +#define OPENMESH_ARRAY_KERNEL_C + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh +{ + +//== IMPLEMENTATION ========================================================== + +template +void ArrayKernel::garbage_collection(std_API_Container_VHandlePointer& vh_to_update, + std_API_Container_HHandlePointer& hh_to_update, + std_API_Container_FHandlePointer& fh_to_update, + bool _v, bool _e, bool _f) +{ + +#ifdef DEBUG + #ifndef OM_GARBAGE_NO_STATUS_WARNING + if ( !this->has_vertex_status() ) + omerr() << "garbage_collection: No vertex status available. You can request it: mesh.request_vertex_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + if ( !this->has_edge_status() ) + omerr() << "garbage_collection: No edge status available. You can request it: mesh.request_edge_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + if ( !this->has_face_status() ) + omerr() << "garbage_collection: No face status available. You can request it: mesh.request_face_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + #endif +#endif + + const bool track_vhandles = ( !vh_to_update.empty() ); + const bool track_hhandles = ( !hh_to_update.empty() ); + const bool track_fhandles = ( !fh_to_update.empty() ); + + int i, i0, i1; + + int nV = int(n_vertices()); + int nE = int(n_edges()); + int nH = int(2*n_edges()); + int nF = (int(n_faces())); + + std::vector vh_map; + std::vector hh_map; + std::vector fh_map; + + std::map vertex_inverse_map; + std::map halfedge_inverse_map; + std::map face_inverse_map; + + // setup handle mapping: + vh_map.reserve(nV); + for (i=0; i 0 && this->has_vertex_status() ) + { + i0=0; i1=nV-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(VertexHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(VertexHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the vertex handles for updates, + // we need to have the opposite direction + if ( track_vhandles ) { + vertex_inverse_map[i1] = i0; + vertex_inverse_map[i0] = -1; + } + + // swap + std::swap(vertices_[i0], vertices_[i1]); + std::swap(vh_map[i0], vh_map[i1]); + vprops_swap(i0, i1); + }; + + vertices_.resize(status(VertexHandle(i0)).deleted() ? i0 : i0+1); + vprops_resize(n_vertices()); + } + + + // remove deleted edges + if (_e && n_edges() > 0 && this->has_edge_status() ) + { + i0=0; i1=nE-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(EdgeHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(EdgeHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the vertex handles for updates, + // we need to have the opposite direction + if ( track_hhandles ) { + halfedge_inverse_map[2*i1] = 2 * i0; + halfedge_inverse_map[2*i0] = -1; + + halfedge_inverse_map[2*i1 + 1] = 2 * i0 + 1; + halfedge_inverse_map[2*i0 + 1] = -1; + } + + // swap + std::swap(edges_[i0], edges_[i1]); + std::swap(hh_map[2*i0], hh_map[2*i1]); + std::swap(hh_map[2*i0+1], hh_map[2*i1+1]); + eprops_swap(i0, i1); + hprops_swap(2*i0, 2*i1); + hprops_swap(2*i0+1, 2*i1+1); + }; + + edges_.resize(status(EdgeHandle(i0)).deleted() ? i0 : i0+1); + eprops_resize(n_edges()); + hprops_resize(n_halfedges()); + } + + + // remove deleted faces + if (_f && n_faces() > 0 && this->has_face_status() ) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(FaceHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(FaceHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the face handles for updates, + // we need to have the opposite direction + if ( track_fhandles ) { + face_inverse_map[i1] = i0; + face_inverse_map[i0] = -1; + } + + // swap + std::swap(faces_[i0], faces_[i1]); + std::swap(fh_map[i0], fh_map[i1]); + fprops_swap(i0, i1); + }; + + faces_.resize(status(FaceHandle(i0)).deleted() ? i0 : i0+1); + fprops_resize(n_faces()); + } + + + // update handles of vertices + if (_e) + { + KernelVertexIter v_it(vertices_begin()), v_end(vertices_end()); + VertexHandle vh; + + for (; v_it!=v_end; ++v_it) + { + vh = handle(*v_it); + if (!is_isolated(vh)) + { + set_halfedge_handle(vh, hh_map[halfedge_handle(vh).idx()]); + } + } + } + + HalfedgeHandle hh; + // update handles of halfedges + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the first pass update the (half)edges vertices + hh = halfedge_handle(handle(*e_it), 0); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + hh = halfedge_handle(handle(*e_it), 1); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + } + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the second pass update the connectivity of the (half)edges + hh = halfedge_handle(handle(*e_it), 0); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + hh = halfedge_handle(handle(*e_it), 1); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + } + + // update handles of faces + if (_e) + { + KernelFaceIter f_it(faces_begin()), f_end(faces_end()); + FaceHandle fh; + + for (; f_it!=f_end; ++f_it) + { + fh = handle(*f_it); + set_halfedge_handle(fh, hh_map[halfedge_handle(fh).idx()]); + } + } + + const int vertexCount = int(vertices_.size()); + const int halfedgeCount = int(edges_.size() * 2); + const int faceCount = int(faces_.size()); + + // Update the vertex handles in the vertex handle vector + typename std_API_Container_VHandlePointer::iterator v_it(vh_to_update.begin()), v_it_end(vh_to_update.end()); + for(; v_it != v_it_end; ++v_it) + { + + // Only changed vertices need to be considered + if ( (*v_it)->idx() != vh_map[(*v_it)->idx()].idx() ) { + *(*v_it) = VertexHandle(vertex_inverse_map[(*v_it)->idx()]); + + // Vertices above the vertex count have to be already mapped, or they are invalid now! + } else if ( ((*v_it)->idx() >= vertexCount) && (vertex_inverse_map.find((*v_it)->idx()) == vertex_inverse_map.end()) ) { + (*v_it)->invalidate(); + } + + } + + // Update the halfedge handles in the halfedge handle vector + typename std_API_Container_HHandlePointer::iterator hh_it(hh_to_update.begin()), hh_it_end(hh_to_update.end()); + for(; hh_it != hh_it_end; ++hh_it) + { + // Only changed faces need to be considered + if ( (*hh_it)->idx() != hh_map[(*hh_it)->idx()].idx() ) { + *(*hh_it) = HalfedgeHandle(halfedge_inverse_map[(*hh_it)->idx()]); + + // Vertices above the face count have to be already mapped, or they are invalid now! + } else if ( ((*hh_it)->idx() >= halfedgeCount) && (halfedge_inverse_map.find((*hh_it)->idx()) == halfedge_inverse_map.end()) ) { + (*hh_it)->invalidate(); + } + + } + + // Update the face handles in the face handle vector + typename std_API_Container_FHandlePointer::iterator fh_it(fh_to_update.begin()), fh_it_end(fh_to_update.end()); + for(; fh_it != fh_it_end; ++fh_it) + { + + // Only changed faces need to be considered + if ( (*fh_it)->idx() != fh_map[(*fh_it)->idx()].idx() ) { + *(*fh_it) = FaceHandle(face_inverse_map[(*fh_it)->idx()]); + + // Vertices above the face count have to be already mapped, or they are invalid now! + } else if ( ((*fh_it)->idx() >= faceCount) && (face_inverse_map.find((*fh_it)->idx()) == face_inverse_map.end()) ) { + (*fh_it)->invalidate(); + } + + } +} + +} + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/AttribKernelT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/AttribKernelT.hh new file mode 100644 index 0000000..c0d52a8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/AttribKernelT.hh @@ -0,0 +1,782 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_ATTRIBKERNEL_HH +#define OPENMESH_ATTRIBKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/** \class AttribKernelT AttribKernelT.hh + + The attribute kernel adds all standard properties to the kernel. Therefore + the functions/types defined here provide a subset of the kernel + interface as described in Concepts::KernelT. + + \see Concepts::KernelT +*/ +template +class AttribKernelT : public Connectivity +{ +public: + + //---------------------------------------------------------------- item types + + typedef MeshItems MeshItemsT; + typedef Connectivity ConnectivityT; + typedef typename Connectivity::Vertex Vertex; + typedef typename Connectivity::Halfedge Halfedge; + typedef typename Connectivity::Edge Edge; + typedef typename Connectivity::Face Face; + + typedef typename MeshItems::Point Point; + typedef typename MeshItems::Normal Normal; + typedef typename MeshItems::Color Color; + typedef typename MeshItems::TexCoord1D TexCoord1D; + typedef typename MeshItems::TexCoord2D TexCoord2D; + typedef typename MeshItems::TexCoord3D TexCoord3D; + typedef typename MeshItems::Scalar Scalar; + typedef typename MeshItems::TextureIndex TextureIndex; + + typedef typename MeshItems::VertexData VertexData; + typedef typename MeshItems::HalfedgeData HalfedgeData; + typedef typename MeshItems::EdgeData EdgeData; + typedef typename MeshItems::FaceData FaceData; + + typedef AttribKernelT AttribKernel; + + enum Attribs { + VAttribs = MeshItems::VAttribs, + HAttribs = MeshItems::HAttribs, + EAttribs = MeshItems::EAttribs, + FAttribs = MeshItems::FAttribs + }; + + typedef VPropHandleT DataVPropHandle; + typedef HPropHandleT DataHPropHandle; + typedef EPropHandleT DataEPropHandle; + typedef FPropHandleT DataFPropHandle; + +public: + + //-------------------------------------------------- constructor / destructor + + AttribKernelT() + : refcount_vnormals_(0), + refcount_vcolors_(0), + refcount_vtexcoords1D_(0), + refcount_vtexcoords2D_(0), + refcount_vtexcoords3D_(0), + refcount_htexcoords1D_(0), + refcount_htexcoords2D_(0), + refcount_htexcoords3D_(0), + refcount_henormals_(0), + refcount_hecolors_(0), + refcount_ecolors_(0), + refcount_fnormals_(0), + refcount_fcolors_(0), + refcount_ftextureIndex_(0) + { + this->add_property( points_, "v:points" ); + + if (VAttribs & Attributes::Normal) + request_vertex_normals(); + + if (VAttribs & Attributes::Color) + request_vertex_colors(); + + if (VAttribs & Attributes::TexCoord1D) + request_vertex_texcoords1D(); + + if (VAttribs & Attributes::TexCoord2D) + request_vertex_texcoords2D(); + + if (VAttribs & Attributes::TexCoord3D) + request_vertex_texcoords3D(); + + if (HAttribs & Attributes::TexCoord1D) + request_halfedge_texcoords1D(); + + if (HAttribs & Attributes::TexCoord2D) + request_halfedge_texcoords2D(); + + if (HAttribs & Attributes::TexCoord3D) + request_halfedge_texcoords3D(); + + if (HAttribs & Attributes::Color) + request_halfedge_colors(); + + if (VAttribs & Attributes::Status) + Connectivity::request_vertex_status(); + + if (HAttribs & Attributes::Status) + Connectivity::request_halfedge_status(); + + if (HAttribs & Attributes::Normal) + request_halfedge_normals(); + + if (EAttribs & Attributes::Status) + Connectivity::request_edge_status(); + + if (EAttribs & Attributes::Color) + request_edge_colors(); + + if (FAttribs & Attributes::Normal) + request_face_normals(); + + if (FAttribs & Attributes::Color) + request_face_colors(); + + if (FAttribs & Attributes::Status) + Connectivity::request_face_status(); + + if (FAttribs & Attributes::TextureIndex) + request_face_texture_index(); + + //FIXME: data properties might actually cost storage even + //if there are no data traits?? + this->add_property(data_vpph_); + this->add_property(data_fpph_); + this->add_property(data_hpph_); + this->add_property(data_epph_); + } + + virtual ~AttribKernelT() + { + // should remove properties, but this will be done in + // BaseKernel's destructor anyway... + } + + /** Assignment from another mesh of \em another type. + \note All that's copied is connectivity and vertex positions. + All other information (like e.g. attributes or additional + elements from traits classes) is not copied. + \note If you want to copy all information, including *custom* properties, + use PolyMeshT::operator=() instead. + */ + template + void assign(const _AttribKernel& _other, bool copyStandardProperties = false) + { + //copy standard properties if necessary + if(copyStandardProperties) + this->copy_all_kernel_properties(_other); + + this->assign_connectivity(_other); + for (typename Connectivity::VertexIter v_it = Connectivity::vertices_begin(); + v_it != Connectivity::vertices_end(); ++v_it) + {//assumes Point constructor supports cast from _AttribKernel::Point + set_point(*v_it, (Point)_other.point(*v_it)); + } + + //initialize standard properties if necessary + if(copyStandardProperties) + initializeStandardProperties(); + } + + //-------------------------------------------------------------------- points + + const Point* points() const + { return this->property(points_).data(); } + + const Point& point(VertexHandle _vh) const + { return this->property(points_, _vh); } + + Point& point(VertexHandle _vh) + { return this->property(points_, _vh); } + + void set_point(VertexHandle _vh, const Point& _p) + { this->property(points_, _vh) = _p; } + + + //------------------------------------------------------------ vertex normals + + const Normal* vertex_normals() const + { return this->property(vertex_normals_).data(); } + + const Normal& normal(VertexHandle _vh) const + { return this->property(vertex_normals_, _vh); } + + void set_normal(VertexHandle _vh, const Normal& _n) + { this->property(vertex_normals_, _vh) = _n; } + + + //------------------------------------------------------------- vertex colors + + const Color* vertex_colors() const + { return this->property(vertex_colors_).data(); } + + const Color& color(VertexHandle _vh) const + { return this->property(vertex_colors_, _vh); } + + void set_color(VertexHandle _vh, const Color& _c) + { this->property(vertex_colors_, _vh) = _c; } + + + //------------------------------------------------------- vertex 1D texcoords + + const TexCoord1D* texcoords1D() const { + return this->property(vertex_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(VertexHandle _vh) const { + return this->property(vertex_texcoords1D_, _vh); + } + + void set_texcoord1D(VertexHandle _vh, const TexCoord1D& _t) { + this->property(vertex_texcoords1D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 2D texcoords + + const TexCoord2D* texcoords2D() const { + return this->property(vertex_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(VertexHandle _vh) const { + return this->property(vertex_texcoords2D_, _vh); + } + + void set_texcoord2D(VertexHandle _vh, const TexCoord2D& _t) { + this->property(vertex_texcoords2D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 3D texcoords + + const TexCoord3D* texcoords3D() const { + return this->property(vertex_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(VertexHandle _vh) const { + return this->property(vertex_texcoords3D_, _vh); + } + + void set_texcoord3D(VertexHandle _vh, const TexCoord3D& _t) { + this->property(vertex_texcoords3D_, _vh) = _t; + } + + //.------------------------------------------------------ halfedge 1D texcoords + + const TexCoord1D* htexcoords1D() const { + return this->property(halfedge_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords1D_, _heh); + } + + void set_texcoord1D(HalfedgeHandle _heh, const TexCoord1D& _t) { + this->property(halfedge_texcoords1D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 2D texcoords + + const TexCoord2D* htexcoords2D() const { + return this->property(halfedge_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords2D_, _heh); + } + + void set_texcoord2D(HalfedgeHandle _heh, const TexCoord2D& _t) { + this->property(halfedge_texcoords2D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 3D texcoords + + const TexCoord3D* htexcoords3D() const { + return this->property(halfedge_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords3D_, _heh); + } + + void set_texcoord3D(HalfedgeHandle _heh, const TexCoord3D& _t) { + this->property(halfedge_texcoords3D_, _heh) = _t; + } + + //------------------------------------------------------------- edge colors + + const Color* edge_colors() const + { return this->property(edge_colors_).data(); } + + const Color& color(EdgeHandle _eh) const + { return this->property(edge_colors_, _eh); } + + void set_color(EdgeHandle _eh, const Color& _c) + { this->property(edge_colors_, _eh) = _c; } + + + //------------------------------------------------------------- halfedge normals + + const Normal& normal(HalfedgeHandle _heh) const + { return this->property(halfedge_normals_, _heh); } + + void set_normal(HalfedgeHandle _heh, const Normal& _n) + { this->property(halfedge_normals_, _heh) = _n; } + + + //------------------------------------------------------------- halfedge colors + + const Color* halfedge_colors() const + { return this->property(halfedge_colors_).data(); } + + const Color& color(HalfedgeHandle _heh) const + { return this->property(halfedge_colors_, _heh); } + + void set_color(HalfedgeHandle _heh, const Color& _c) + { this->property(halfedge_colors_, _heh) = _c; } + + //-------------------------------------------------------------- face normals + + const Normal& normal(FaceHandle _fh) const + { return this->property(face_normals_, _fh); } + + void set_normal(FaceHandle _fh, const Normal& _n) + { this->property(face_normals_, _fh) = _n; } + + //-------------------------------------------------------------- per Face Texture index + + const TextureIndex& texture_index(FaceHandle _fh) const + { return this->property(face_texture_index_, _fh); } + + void set_texture_index(FaceHandle _fh, const TextureIndex& _t) + { this->property(face_texture_index_, _fh) = _t; } + + //--------------------------------------------------------------- face colors + + const Color& color(FaceHandle _fh) const + { return this->property(face_colors_, _fh); } + + void set_color(FaceHandle _fh, const Color& _c) + { this->property(face_colors_, _fh) = _c; } + + //------------------------------------------------ request / alloc properties + + void request_vertex_normals() + { + if (!refcount_vnormals_++) + this->add_property( vertex_normals_, "v:normals" ); + } + + void request_vertex_colors() + { + if (!refcount_vcolors_++) + this->add_property( vertex_colors_, "v:colors" ); + } + + void request_vertex_texcoords1D() + { + if (!refcount_vtexcoords1D_++) + this->add_property( vertex_texcoords1D_, "v:texcoords1D" ); + } + + void request_vertex_texcoords2D() + { + if (!refcount_vtexcoords2D_++) + this->add_property( vertex_texcoords2D_, "v:texcoords2D" ); + } + + void request_vertex_texcoords3D() + { + if (!refcount_vtexcoords3D_++) + this->add_property( vertex_texcoords3D_, "v:texcoords3D" ); + } + + void request_halfedge_texcoords1D() + { + if (!refcount_htexcoords1D_++) + this->add_property( halfedge_texcoords1D_, "h:texcoords1D" ); + } + + void request_halfedge_texcoords2D() + { + if (!refcount_htexcoords2D_++) + this->add_property( halfedge_texcoords2D_, "h:texcoords2D" ); + } + + void request_halfedge_texcoords3D() + { + if (!refcount_htexcoords3D_++) + this->add_property( halfedge_texcoords3D_, "h:texcoords3D" ); + } + + void request_edge_colors() + { + if (!refcount_ecolors_++) + this->add_property( edge_colors_, "e:colors" ); + } + + void request_halfedge_normals() + { + if (!refcount_henormals_++) + this->add_property( halfedge_normals_, "h:normals" ); + } + + void request_halfedge_colors() + { + if (!refcount_hecolors_++) + this->add_property( halfedge_colors_, "h:colors" ); + } + + void request_face_normals() + { + if (!refcount_fnormals_++) + this->add_property( face_normals_, "f:normals" ); + } + + void request_face_colors() + { + if (!refcount_fcolors_++) + this->add_property( face_colors_, "f:colors" ); + } + + void request_face_texture_index() + { + if (!refcount_ftextureIndex_++) + this->add_property( face_texture_index_, "f:textureindex" ); + } + + //------------------------------------------------- release / free properties + + void release_vertex_normals() + { + if ((refcount_vnormals_ > 0) && (! --refcount_vnormals_)) + this->remove_property(vertex_normals_); + } + + void release_vertex_colors() + { + if ((refcount_vcolors_ > 0) && (! --refcount_vcolors_)) + this->remove_property(vertex_colors_); + } + + void release_vertex_texcoords1D() { + if ((refcount_vtexcoords1D_ > 0) && (! --refcount_vtexcoords1D_)) + this->remove_property(vertex_texcoords1D_); + } + + void release_vertex_texcoords2D() { + if ((refcount_vtexcoords2D_ > 0) && (! --refcount_vtexcoords2D_)) + this->remove_property(vertex_texcoords2D_); + } + + void release_vertex_texcoords3D() { + if ((refcount_vtexcoords3D_ > 0) && (! --refcount_vtexcoords3D_)) + this->remove_property(vertex_texcoords3D_); + } + + void release_halfedge_texcoords1D() { + if ((refcount_htexcoords1D_ > 0) && (! --refcount_htexcoords1D_)) + this->remove_property(halfedge_texcoords1D_); + } + + void release_halfedge_texcoords2D() { + if ((refcount_htexcoords2D_ > 0) && (! --refcount_htexcoords2D_)) + this->remove_property(halfedge_texcoords2D_); + } + + void release_halfedge_texcoords3D() { + if ((refcount_htexcoords3D_ > 0) && (! --refcount_htexcoords3D_)) + this->remove_property(halfedge_texcoords3D_); + } + + void release_edge_colors() + { + if ((refcount_ecolors_ > 0) && (! --refcount_ecolors_)) + this->remove_property(edge_colors_); + } + + void release_halfedge_normals() + { + if ((refcount_henormals_ > 0) && (! --refcount_henormals_)) + this->remove_property(halfedge_normals_); + } + + void release_halfedge_colors() + { + if ((refcount_hecolors_ > 0) && (! --refcount_hecolors_)) + this->remove_property(halfedge_colors_); + } + + void release_face_normals() + { + if ((refcount_fnormals_ > 0) && (! --refcount_fnormals_)) + this->remove_property(face_normals_); + } + + void release_face_colors() + { + if ((refcount_fcolors_ > 0) && (! --refcount_fcolors_)) + this->remove_property(face_colors_); + } + + void release_face_texture_index() + { + if ((refcount_ftextureIndex_ > 0) && (! --refcount_ftextureIndex_)) + this->remove_property(face_texture_index_); + } + + //---------------------------------------------- dynamic check for properties + + bool has_vertex_normals() const { return vertex_normals_.is_valid(); } + bool has_vertex_colors() const { return vertex_colors_.is_valid(); } + bool has_vertex_texcoords1D() const { return vertex_texcoords1D_.is_valid(); } + bool has_vertex_texcoords2D() const { return vertex_texcoords2D_.is_valid(); } + bool has_vertex_texcoords3D() const { return vertex_texcoords3D_.is_valid(); } + bool has_halfedge_texcoords1D() const { return halfedge_texcoords1D_.is_valid();} + bool has_halfedge_texcoords2D() const { return halfedge_texcoords2D_.is_valid();} + bool has_halfedge_texcoords3D() const { return halfedge_texcoords3D_.is_valid();} + bool has_edge_colors() const { return edge_colors_.is_valid(); } + bool has_halfedge_normals() const { return halfedge_normals_.is_valid(); } + bool has_halfedge_colors() const { return halfedge_colors_.is_valid(); } + bool has_face_normals() const { return face_normals_.is_valid(); } + bool has_face_colors() const { return face_colors_.is_valid(); } + bool has_face_texture_index() const { return face_texture_index_.is_valid(); } + +public: + + typedef VPropHandleT PointsPropertyHandle; + typedef VPropHandleT VertexNormalsPropertyHandle; + typedef VPropHandleT VertexColorsPropertyHandle; + typedef VPropHandleT VertexTexCoords1DPropertyHandle; + typedef VPropHandleT VertexTexCoords2DPropertyHandle; + typedef VPropHandleT VertexTexCoords3DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords1DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords2DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords3DPropertyHandle; + typedef EPropHandleT EdgeColorsPropertyHandle; + typedef HPropHandleT HalfedgeNormalsPropertyHandle; + typedef HPropHandleT HalfedgeColorsPropertyHandle; + typedef FPropHandleT FaceNormalsPropertyHandle; + typedef FPropHandleT FaceColorsPropertyHandle; + typedef FPropHandleT FaceTextureIndexPropertyHandle; + +public: + //standard vertex properties + PointsPropertyHandle points_pph() const + { return points_; } + + VertexNormalsPropertyHandle vertex_normals_pph() const + { return vertex_normals_; } + + VertexColorsPropertyHandle vertex_colors_pph() const + { return vertex_colors_; } + + VertexTexCoords1DPropertyHandle vertex_texcoords1D_pph() const + { return vertex_texcoords1D_; } + + VertexTexCoords2DPropertyHandle vertex_texcoords2D_pph() const + { return vertex_texcoords2D_; } + + VertexTexCoords3DPropertyHandle vertex_texcoords3D_pph() const + { return vertex_texcoords3D_; } + + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_pph() const + { return halfedge_texcoords1D_; } + + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_pph() const + { return halfedge_texcoords2D_; } + + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_pph() const + { return halfedge_texcoords3D_; } + + // standard edge properties + HalfedgeNormalsPropertyHandle halfedge_normals_pph() const + { return halfedge_normals_; } + + + // standard edge properties + HalfedgeColorsPropertyHandle halfedge_colors_pph() const + { return halfedge_colors_; } + + // standard edge properties + EdgeColorsPropertyHandle edge_colors_pph() const + { return edge_colors_; } + + //standard face properties + FaceNormalsPropertyHandle face_normals_pph() const + { return face_normals_; } + + FaceColorsPropertyHandle face_colors_pph() const + { return face_colors_; } + + FaceTextureIndexPropertyHandle face_texture_index_pph() const + { return face_texture_index_; } + + VertexData& data(VertexHandle _vh) + { return this->property(data_vpph_, _vh); } + + const VertexData& data(VertexHandle _vh) const + { return this->property(data_vpph_, _vh); } + + FaceData& data(FaceHandle _fh) + { return this->property(data_fpph_, _fh); } + + const FaceData& data(FaceHandle _fh) const + { return this->property(data_fpph_, _fh); } + + EdgeData& data(EdgeHandle _eh) + { return this->property(data_epph_, _eh); } + + const EdgeData& data(EdgeHandle _eh) const + { return this->property(data_epph_, _eh); } + + HalfedgeData& data(HalfedgeHandle _heh) + { return this->property(data_hpph_, _heh); } + + const HalfedgeData& data(HalfedgeHandle _heh) const + { return this->property(data_hpph_, _heh); } + +private: + //standard vertex properties + PointsPropertyHandle points_; + VertexNormalsPropertyHandle vertex_normals_; + VertexColorsPropertyHandle vertex_colors_; + VertexTexCoords1DPropertyHandle vertex_texcoords1D_; + VertexTexCoords2DPropertyHandle vertex_texcoords2D_; + VertexTexCoords3DPropertyHandle vertex_texcoords3D_; + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_; + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_; + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_; + HalfedgeNormalsPropertyHandle halfedge_normals_; + HalfedgeColorsPropertyHandle halfedge_colors_; + // standard edge properties + EdgeColorsPropertyHandle edge_colors_; + //standard face properties + FaceNormalsPropertyHandle face_normals_; + FaceColorsPropertyHandle face_colors_; + FaceTextureIndexPropertyHandle face_texture_index_; + //data properties handles + DataVPropHandle data_vpph_; + DataHPropHandle data_hpph_; + DataEPropHandle data_epph_; + DataFPropHandle data_fpph_; + + unsigned int refcount_vnormals_; + unsigned int refcount_vcolors_; + unsigned int refcount_vtexcoords1D_; + unsigned int refcount_vtexcoords2D_; + unsigned int refcount_vtexcoords3D_; + unsigned int refcount_htexcoords1D_; + unsigned int refcount_htexcoords2D_; + unsigned int refcount_htexcoords3D_; + unsigned int refcount_henormals_; + unsigned int refcount_hecolors_; + unsigned int refcount_ecolors_; + unsigned int refcount_fnormals_; + unsigned int refcount_fcolors_; + unsigned int refcount_ftextureIndex_; + + /** + * @brief initializeStandardProperties Initializes the standard properties + * and sets refcount to 1 if found. (e.g. when the copy constructor was used) + */ + void initializeStandardProperties() + { + if(!this->get_property_handle(points_, + "v:points")) + { + //mesh has no points? + } + refcount_vnormals_ = this->get_property_handle(vertex_normals_, + "v:normals") ? 1 : 0 ; + refcount_vcolors_ = this->get_property_handle(vertex_colors_, + "v:colors") ? 1 : 0 ; + refcount_vtexcoords1D_ = this->get_property_handle(vertex_texcoords1D_, + "v:texcoords1D") ? 1 : 0 ; + refcount_vtexcoords2D_ = this->get_property_handle(vertex_texcoords2D_, + "v:texcoords2D") ? 1 : 0 ; + refcount_vtexcoords3D_ = this->get_property_handle(vertex_texcoords3D_, + "v:texcoords3D") ? 1 : 0 ; + refcount_htexcoords1D_ = this->get_property_handle(halfedge_texcoords1D_, + "h:texcoords1D") ? 1 : 0 ; + refcount_htexcoords2D_ = this->get_property_handle(halfedge_texcoords2D_, + "h:texcoords2D") ? 1 : 0 ; + refcount_htexcoords3D_ = this->get_property_handle(halfedge_texcoords3D_, + "h:texcoords3D") ? 1 : 0 ; + refcount_henormals_ = this->get_property_handle(halfedge_normals_, + "h:normals") ? 1 : 0 ; + refcount_hecolors_ = this->get_property_handle(halfedge_colors_, + "h:colors") ? 1 : 0 ; + refcount_ecolors_ = this->get_property_handle(edge_colors_, + "e:colors") ? 1 : 0 ; + refcount_fnormals_ = this->get_property_handle(face_normals_, + "f:normals") ? 1 : 0 ; + refcount_fcolors_ = this->get_property_handle(face_colors_, + "f:colors") ? 1 : 0 ; + refcount_ftextureIndex_ = this->get_property_handle(face_texture_index_, + "f:textureindex") ? 1 : 0 ; + } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBKERNEL_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Attributes.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Attributes.hh new file mode 100644 index 0000000..e53f021 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Attributes.hh @@ -0,0 +1,103 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +/** + \file Attributes.hh + This file provides some macros containing attribute usage. +*/ + + +#ifndef OPENMESH_ATTRIBUTES_HH +#define OPENMESH_ATTRIBUTES_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + +/** Attribute bits + * + * Use the bits to define a standard property at compile time using traits. + * + * \include traits5.cc + * + * \see \ref mesh_type + */ +enum AttributeBits +{ + None = 0, ///< Clear all attribute bits + Normal = 1, ///< Add normals to mesh item (vertices/faces) + Color = 2, ///< Add colors to mesh item (vertices/faces/edges) + PrevHalfedge = 4, ///< Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits. + Status = 8, ///< Add status to mesh item (all items) + TexCoord1D = 16, ///< Add 1D texture coordinates (vertices, halfedges) + TexCoord2D = 32, ///< Add 2D texture coordinates (vertices, halfedges) + TexCoord3D = 64, ///< Add 3D texture coordinates (vertices, halfedges) + TextureIndex = 128 ///< Add texture index (faces) +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTES_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseKernel.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseKernel.cc new file mode 100644 index 0000000..c0e174f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseKernel.cc @@ -0,0 +1,239 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#include +#include + +namespace OpenMesh +{ + +void BaseKernel::property_stats() const +{ + property_stats(std::clog); +} +void BaseKernel::property_stats(std::ostream& _ostr) const +{ + const PropertyContainer::Properties& vps = vprops_.properties(); + const PropertyContainer::Properties& hps = hprops_.properties(); + const PropertyContainer::Properties& eps = eprops_.properties(); + const PropertyContainer::Properties& fps = fprops_.properties(); + const PropertyContainer::Properties& mps = mprops_.properties(); + + PropertyContainer::Properties::const_iterator it; + + _ostr << vprops_.size() << " vprops:\n"; + for (it=vps.begin(); it!=vps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << hprops_.size() << " hprops:\n"; + for (it=hps.begin(); it!=hps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << eprops_.size() << " eprops:\n"; + for (it=eps.begin(); it!=eps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << fprops_.size() << " fprops:\n"; + for (it=fps.begin(); it!=fps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << mprops_.size() << " mprops:\n"; + for (it=mps.begin(); it!=mps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } +} + + + +void BaseKernel::vprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& vps = vprops_.properties(); + for (it=vps.begin(); it!=vps.end(); ++it) + if ( *it == NULL ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::hprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& hps = hprops_.properties(); + for (it=hps.begin(); it!=hps.end(); ++it) + if ( *it == NULL ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::eprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& eps = eprops_.properties(); + for (it=eps.begin(); it!=eps.end(); ++it) + if ( *it == NULL ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} +void BaseKernel::fprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& fps = fprops_.properties(); + for (it=fps.begin(); it!=fps.end(); ++it) + if ( *it == NULL ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::mprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& mps = mprops_.properties(); + for (it=mps.begin(); it!=mps.end(); ++it) + if ( *it == NULL ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::vprop_stats() const +{ + vprop_stats(std::clog); +} +void BaseKernel::vprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& vps = vprops_.properties(); + for (it=vps.begin(); it!=vps.end(); ++it) + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::hprop_stats() const +{ + hprop_stats(std::clog); +} +void BaseKernel::hprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& hps = hprops_.properties(); + for (it=hps.begin(); it!=hps.end(); ++it) + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::eprop_stats() const +{ + eprop_stats(std::clog); +} +void BaseKernel::eprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& eps = eprops_.properties(); + for (it=eps.begin(); it!=eps.end(); ++it) + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::fprop_stats() const +{ + fprop_stats(std::clog); +} +void BaseKernel::fprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& fps = fprops_.properties(); + for (it=fps.begin(); it!=fps.end(); ++it) + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::mprop_stats() const +{ + mprop_stats(std::clog); +} +void BaseKernel::mprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& mps = mprops_.properties(); + for (it=mps.begin(); it!=mps.end(); ++it) + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} + + +} diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseKernel.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseKernel.hh new file mode 100644 index 0000000..6bca014 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseKernel.hh @@ -0,0 +1,826 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS BaseKernel +// +//============================================================================= + + +#ifndef OPENMESH_BASE_KERNEL_HH +#define OPENMESH_BASE_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +// -------------------- +#include +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// This class provides low-level property management like adding/removing +/// properties and access to properties. Under most circumstances, it is +/// advisable to use the high-level property management provided by +/// PropertyManager, instead. +/// +/// All operations provided by %BaseKernel need at least a property handle +/// (VPropHandleT, EPropHandleT, HPropHandleT, FPropHandleT, MPropHandleT). +/// which keeps the data type of the property, too. +/// +/// There are two types of properties: +/// -# Standard properties - mesh data (e.g. vertex normal or face color) +/// -# Custom properties - user defined data +/// +/// The differentiation is only semantically, technically both are +/// equally handled. Therefore the methods provided by the %BaseKernel +/// are applicable to both property types. +/// +/// \attention Since the class PolyMeshT derives from a kernel, hence all public +/// elements of %BaseKernel are usable. + +class OPENMESHDLLEXPORT BaseKernel +{ +public: //-------------------------------------------- constructor / destructor + + BaseKernel() {} + virtual ~BaseKernel() { + vprops_.clear(); + eprops_.clear(); + hprops_.clear(); + fprops_.clear(); + } + + +public: //-------------------------------------------------- add new properties + + /// \name Add a property to a mesh item + + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper and/or one of its helper functions such as + * makePropertyManagerFromNew, makePropertyManagerFromExisting, or + * makePropertyManagerFromExistingOrNew. + * + * Adds a property + * + * Depending on the property handle type a vertex, (half-)edge, face or + * mesh property is added to the mesh. If the action fails the handle + * is invalid. + * On success the handle must be used to access the property data with + * property(). + * + * \param _ph A property handle defining the data type to bind to mesh. + * On success the handle is valid else invalid. + * \param _name Optional name of property. Following restrictions apply + * to the name: + * -# Maximum length of name is 256 characters + * -# The prefixes matching "^[vhefm]:" are reserved for + * internal usage. + * -# The expression "^<.*>$" is reserved for internal usage. + * + */ + + template + void add_property( VPropHandleT& _ph, const std::string& _name="") + { + _ph = VPropHandleT( vprops_.add(T(), _name) ); + vprops_.resize(n_vertices()); + } + + template + void add_property( HPropHandleT& _ph, const std::string& _name="") + { + _ph = HPropHandleT( hprops_.add(T(), _name) ); + hprops_.resize(n_halfedges()); + } + + template + void add_property( EPropHandleT& _ph, const std::string& _name="") + { + _ph = EPropHandleT( eprops_.add(T(), _name) ); + eprops_.resize(n_edges()); + } + + template + void add_property( FPropHandleT& _ph, const std::string& _name="") + { + _ph = FPropHandleT( fprops_.add(T(), _name) ); + fprops_.resize(n_faces()); + } + + template + void add_property( MPropHandleT& _ph, const std::string& _name="") + { + _ph = MPropHandleT( mprops_.add(T(), _name) ); + mprops_.resize(1); + } + + //@} + + +public: //--------------------------------------------------- remove properties + + /// \name Removing a property from a mesh tiem + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper to manage (and remove) properties. + * + * Remove a property. + * + * Removes the property represented by the handle from the apropriate + * mesh item. + * \param _ph Property to be removed. The handle is invalid afterwords. + */ + + template + void remove_property(VPropHandleT& _ph) + { + if (_ph.is_valid()) + vprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(HPropHandleT& _ph) + { + if (_ph.is_valid()) + hprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(EPropHandleT& _ph) + { + if (_ph.is_valid()) + eprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(FPropHandleT& _ph) + { + if (_ph.is_valid()) + fprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(MPropHandleT& _ph) + { + if (_ph.is_valid()) + mprops_.remove(_ph); + _ph.reset(); + } + + //@} + +public: //------------------------------------------------ get handle from name + + /// \name Get property handle by name + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::propertyExists) or one of + * its higher level helper functions such as + * makePropertyManagerFromExisting, or makePropertyManagerFromExistingOrNew. + * + * Retrieves the handle to a named property by it's name. + * + * \param _ph A property handle. On success the handle is valid else + * invalid. + * \param _name Name of wanted property. + * \return \c true if such a named property is available, else \c false. + */ + + template + bool get_property_handle(VPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = VPropHandleT(vprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(HPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = HPropHandleT(hprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(EPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = EPropHandleT(eprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(FPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = FPropHandleT(fprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(MPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = MPropHandleT(mprops_.handle(T(), _name))).is_valid(); + } + + //@} + +public: //--------------------------------------------------- access properties + + /// \name Access a property + //@{ + + /** In most cases you should use the convenient PropertyManager wrapper + * and use of this function should not be necessary. Under some + * circumstances, however (i.e. making a property persistent), it might be + * necessary to use this function. + * + * Access a property + * + * This method returns a reference to property. The property handle + * must be valid! The result is unpredictable if the handle is invalid! + * + * \param _ph A \em valid (!) property handle. + * \return The wanted property if the handle is valid. + */ + + template + PropertyT& property(VPropHandleT _ph) { + return vprops_.property(_ph); + } + template + const PropertyT& property(VPropHandleT _ph) const { + return vprops_.property(_ph); + } + + template + PropertyT& property(HPropHandleT _ph) { + return hprops_.property(_ph); + } + template + const PropertyT& property(HPropHandleT _ph) const { + return hprops_.property(_ph); + } + + template + PropertyT& property(EPropHandleT _ph) { + return eprops_.property(_ph); + } + template + const PropertyT& property(EPropHandleT _ph) const { + return eprops_.property(_ph); + } + + template + PropertyT& property(FPropHandleT _ph) { + return fprops_.property(_ph); + } + template + const PropertyT& property(FPropHandleT _ph) const { + return fprops_.property(_ph); + } + + template + PropertyT& mproperty(MPropHandleT _ph) { + return mprops_.property(_ph); + } + template + const PropertyT& mproperty(MPropHandleT _ph) const { + return mprops_.property(_ph); + } + + //@} + +public: //-------------------------------------------- access property elements + + /// \name Access a property element using a handle to a mesh item + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper. + * + * Return value of property for an item + */ + + template + typename VPropHandleT::reference + property(VPropHandleT _ph, VertexHandle _vh) { + return vprops_.property(_ph)[_vh.idx()]; + } + + template + typename VPropHandleT::const_reference + property(VPropHandleT _ph, VertexHandle _vh) const { + return vprops_.property(_ph)[_vh.idx()]; + } + + + template + typename HPropHandleT::reference + property(HPropHandleT _ph, HalfedgeHandle _hh) { + return hprops_.property(_ph)[_hh.idx()]; + } + + template + typename HPropHandleT::const_reference + property(HPropHandleT _ph, HalfedgeHandle _hh) const { + return hprops_.property(_ph)[_hh.idx()]; + } + + + template + typename EPropHandleT::reference + property(EPropHandleT _ph, EdgeHandle _eh) { + return eprops_.property(_ph)[_eh.idx()]; + } + + template + typename EPropHandleT::const_reference + property(EPropHandleT _ph, EdgeHandle _eh) const { + return eprops_.property(_ph)[_eh.idx()]; + } + + + template + typename FPropHandleT::reference + property(FPropHandleT _ph, FaceHandle _fh) { + return fprops_.property(_ph)[_fh.idx()]; + } + + template + typename FPropHandleT::const_reference + property(FPropHandleT _ph, FaceHandle _fh) const { + return fprops_.property(_ph)[_fh.idx()]; + } + + + template + typename MPropHandleT::reference + property(MPropHandleT _ph) { + return mprops_.property(_ph)[0]; + } + + template + typename MPropHandleT::const_reference + property(MPropHandleT _ph) const { + return mprops_.property(_ph)[0]; + } + + //@} + + +public: //------------------------------------------------ copy property + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A vertex property handle + * @param _vh_from From vertex handle + * @param _vh_to To vertex handle + */ + template + void copy_property(VPropHandleT& _ph, VertexHandle _vh_from, VertexHandle _vh_to) { + if(_vh_from.is_valid() && _vh_to.is_valid()) + vprops_.property(_ph)[_vh_to.idx()] = vprops_.property(_ph)[_vh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A halfedge property handle + * @param _hh_from From halfedge handle + * @param _hh_to To halfedge handle + */ + template + void copy_property(HPropHandleT _ph, HalfedgeHandle _hh_from, HalfedgeHandle _hh_to) { + if(_hh_from.is_valid() && _hh_to.is_valid()) + hprops_.property(_ph)[_hh_to.idx()] = hprops_.property(_ph)[_hh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph An edge property handle + * @param _eh_from From edge handle + * @param _eh_to To edge handle + */ + template + void copy_property(EPropHandleT _ph, EdgeHandle _eh_from, EdgeHandle _eh_to) { + if(_eh_from.is_valid() && _eh_to.is_valid()) + eprops_.property(_ph)[_eh_to.idx()] = eprops_.property(_ph)[_eh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A face property handle + * @param _fh_from From face handle + * @param _fh_to To face handle + */ + template + void copy_property(FPropHandleT _ph, FaceHandle _fh_from, FaceHandle _fh_to) { + if(_fh_from.is_valid() && _fh_to.is_valid()) + fprops_.property(_ph)[_fh_to.idx()] = fprops_.property(_ph)[_fh_from.idx()]; + } + + +public: + //------------------------------------------------ copy all properties + + /** Copies all properties from one mesh element to another (of the same type) + * + * + * @param _vh_from A vertex handle - source + * @param _vh_to A vertex handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(VertexHandle _vh_from, VertexHandle _vh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = vprops_.begin(); + p_it != vprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) ) + (*p_it)->copy(_vh_from.idx(), _vh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _hh_from A halfedge handle - source + * @param _hh_to A halfedge handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(HalfedgeHandle _hh_from, HalfedgeHandle _hh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = hprops_.begin(); + p_it != hprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "h:") ) + (*p_it)->copy(_hh_from.idx(), _hh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _eh_from An edge handle - source + * @param _eh_to An edge handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(EdgeHandle _eh_from, EdgeHandle _eh_to, bool _copyBuildIn = false) { + for( PropertyContainer::iterator p_it = eprops_.begin(); + p_it != eprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "e:") ) + (*p_it)->copy(_eh_from.idx(), _eh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _fh_from A face handle - source + * @param _fh_to A face handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + * + */ + void copy_all_properties(FaceHandle _fh_from, FaceHandle _fh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = fprops_.begin(); + p_it != fprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "f:") ) + (*p_it)->copy(_fh_from.idx(), _fh_to.idx()); + } + + } + + /** + * @brief copy_all_kernel_properties uses the = operator to copy all properties from a given other BaseKernel. + * @param _other Another BaseKernel, to copy the properties from. + */ + void copy_all_kernel_properties(const BaseKernel & _other) + { + this->vprops_ = _other.vprops_; + this->eprops_ = _other.eprops_; + this->hprops_ = _other.hprops_; + this->fprops_ = _other.fprops_; + } + +protected: //------------------------------------------------- low-level access + +public: // used by non-native kernel and MeshIO, should be protected + + size_t n_vprops(void) const { return vprops_.size(); } + + size_t n_eprops(void) const { return eprops_.size(); } + + size_t n_hprops(void) const { return hprops_.size(); } + + size_t n_fprops(void) const { return fprops_.size(); } + + size_t n_mprops(void) const { return mprops_.size(); } + + BaseProperty* _get_vprop( const std::string& _name) + { return vprops_.property(_name); } + + BaseProperty* _get_eprop( const std::string& _name) + { return eprops_.property(_name); } + + BaseProperty* _get_hprop( const std::string& _name) + { return hprops_.property(_name); } + + BaseProperty* _get_fprop( const std::string& _name) + { return fprops_.property(_name); } + + BaseProperty* _get_mprop( const std::string& _name) + { return mprops_.property(_name); } + + const BaseProperty* _get_vprop( const std::string& _name) const + { return vprops_.property(_name); } + + const BaseProperty* _get_eprop( const std::string& _name) const + { return eprops_.property(_name); } + + const BaseProperty* _get_hprop( const std::string& _name) const + { return hprops_.property(_name); } + + const BaseProperty* _get_fprop( const std::string& _name) const + { return fprops_.property(_name); } + + const BaseProperty* _get_mprop( const std::string& _name) const + { return mprops_.property(_name); } + + BaseProperty& _vprop( size_t _idx ) { return vprops_._property( _idx ); } + BaseProperty& _eprop( size_t _idx ) { return eprops_._property( _idx ); } + BaseProperty& _hprop( size_t _idx ) { return hprops_._property( _idx ); } + BaseProperty& _fprop( size_t _idx ) { return fprops_._property( _idx ); } + BaseProperty& _mprop( size_t _idx ) { return mprops_._property( _idx ); } + + const BaseProperty& _vprop( size_t _idx ) const + { return vprops_._property( _idx ); } + const BaseProperty& _eprop( size_t _idx ) const + { return eprops_._property( _idx ); } + const BaseProperty& _hprop( size_t _idx ) const + { return hprops_._property( _idx ); } + const BaseProperty& _fprop( size_t _idx ) const + { return fprops_._property( _idx ); } + const BaseProperty& _mprop( size_t _idx ) const + { return mprops_._property( _idx ); } + + size_t _add_vprop( BaseProperty* _bp ) { return vprops_._add( _bp ); } + size_t _add_eprop( BaseProperty* _bp ) { return eprops_._add( _bp ); } + size_t _add_hprop( BaseProperty* _bp ) { return hprops_._add( _bp ); } + size_t _add_fprop( BaseProperty* _bp ) { return fprops_._add( _bp ); } + size_t _add_mprop( BaseProperty* _bp ) { return mprops_._add( _bp ); } + +protected: // low-level access non-public + + BaseProperty& _vprop( BaseHandle _h ) + { return vprops_._property( _h.idx() ); } + BaseProperty& _eprop( BaseHandle _h ) + { return eprops_._property( _h.idx() ); } + BaseProperty& _hprop( BaseHandle _h ) + { return hprops_._property( _h.idx() ); } + BaseProperty& _fprop( BaseHandle _h ) + { return fprops_._property( _h.idx() ); } + BaseProperty& _mprop( BaseHandle _h ) + { return mprops_._property( _h.idx() ); } + + const BaseProperty& _vprop( BaseHandle _h ) const + { return vprops_._property( _h.idx() ); } + const BaseProperty& _eprop( BaseHandle _h ) const + { return eprops_._property( _h.idx() ); } + const BaseProperty& _hprop( BaseHandle _h ) const + { return hprops_._property( _h.idx() ); } + const BaseProperty& _fprop( BaseHandle _h ) const + { return fprops_._property( _h.idx() ); } + const BaseProperty& _mprop( BaseHandle _h ) const + { return mprops_._property( _h.idx() ); } + + +public: //----------------------------------------------------- element numbers + + + virtual size_t n_vertices() const { return 0; } + virtual size_t n_halfedges() const { return 0; } + virtual size_t n_edges() const { return 0; } + virtual size_t n_faces() const { return 0; } + + +protected: //------------------------------------------- synchronize properties + + /// Reserves space for \p _n elements in all vertex property vectors. + void vprops_reserve(size_t _n) const { vprops_.reserve(_n); } + + /// Resizes all vertex property vectors to the specified size. + void vprops_resize(size_t _n) const { vprops_.resize(_n); } + + /** + * Same as vprops_resize() but ignores vertex property vectors that have + * a size larger than \p _n. + * + * Use this method instead of vprops_resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void vprops_resize_if_smaller(size_t _n) const { vprops_.resize_if_smaller(_n); } + + void vprops_clear() { + vprops_.clear(); + } + + void vprops_swap(unsigned int _i0, unsigned int _i1) const { + vprops_.swap(_i0, _i1); + } + + void hprops_reserve(size_t _n) const { hprops_.reserve(_n); } + void hprops_resize(size_t _n) const { hprops_.resize(_n); } + void hprops_clear() { + hprops_.clear(); + } + void hprops_swap(unsigned int _i0, unsigned int _i1) const { + hprops_.swap(_i0, _i1); + } + + void eprops_reserve(size_t _n) const { eprops_.reserve(_n); } + void eprops_resize(size_t _n) const { eprops_.resize(_n); } + void eprops_clear() { + eprops_.clear(); + } + void eprops_swap(unsigned int _i0, unsigned int _i1) const { + eprops_.swap(_i0, _i1); + } + + void fprops_reserve(size_t _n) const { fprops_.reserve(_n); } + void fprops_resize(size_t _n) const { fprops_.resize(_n); } + void fprops_clear() { + fprops_.clear(); + } + void fprops_swap(unsigned int _i0, unsigned int _i1) const { + fprops_.swap(_i0, _i1); + } + + void mprops_resize(size_t _n) const { mprops_.resize(_n); } + void mprops_clear() { + mprops_.clear(); + } + +public: + + // uses std::clog as output stream + void property_stats() const; + void property_stats(std::ostream& _ostr) const; + + void vprop_stats( std::string& _string ) const; + void hprop_stats( std::string& _string ) const; + void eprop_stats( std::string& _string ) const; + void fprop_stats( std::string& _string ) const; + void mprop_stats( std::string& _string ) const; + + // uses std::clog as output stream + void vprop_stats() const; + void hprop_stats() const; + void eprop_stats() const; + void fprop_stats() const; + void mprop_stats() const; + + void vprop_stats(std::ostream& _ostr) const; + void hprop_stats(std::ostream& _ostr) const; + void eprop_stats(std::ostream& _ostr) const; + void fprop_stats(std::ostream& _ostr) const; + void mprop_stats(std::ostream& _ostr) const; + +public: + + typedef PropertyContainer::iterator prop_iterator; + typedef PropertyContainer::const_iterator const_prop_iterator; + + prop_iterator vprops_begin() { return vprops_.begin(); } + prop_iterator vprops_end() { return vprops_.end(); } + const_prop_iterator vprops_begin() const { return vprops_.begin(); } + const_prop_iterator vprops_end() const { return vprops_.end(); } + + prop_iterator eprops_begin() { return eprops_.begin(); } + prop_iterator eprops_end() { return eprops_.end(); } + const_prop_iterator eprops_begin() const { return eprops_.begin(); } + const_prop_iterator eprops_end() const { return eprops_.end(); } + + prop_iterator hprops_begin() { return hprops_.begin(); } + prop_iterator hprops_end() { return hprops_.end(); } + const_prop_iterator hprops_begin() const { return hprops_.begin(); } + const_prop_iterator hprops_end() const { return hprops_.end(); } + + prop_iterator fprops_begin() { return fprops_.begin(); } + prop_iterator fprops_end() { return fprops_.end(); } + const_prop_iterator fprops_begin() const { return fprops_.begin(); } + const_prop_iterator fprops_end() const { return fprops_.end(); } + + prop_iterator mprops_begin() { return mprops_.begin(); } + prop_iterator mprops_end() { return mprops_.end(); } + const_prop_iterator mprops_begin() const { return mprops_.begin(); } + const_prop_iterator mprops_end() const { return mprops_.end(); } + +private: + + PropertyContainer vprops_; + PropertyContainer hprops_; + PropertyContainer eprops_; + PropertyContainer fprops_; + PropertyContainer mprops_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_BASE_KERNEL_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseMesh.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseMesh.hh new file mode 100644 index 0000000..bcf75eb --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/BaseMesh.hh @@ -0,0 +1,97 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS BaseMesh +// +//============================================================================= + + +#ifndef OPENMESH_BASEMESH_HH +#define OPENMESH_BASEMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class BaseMesh BaseMesh.hh + + Base class for all meshes. +*/ + +class BaseMesh { +public: + virtual ~BaseMesh(void) {;} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_BASEMESH_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Casts.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Casts.hh new file mode 100644 index 0000000..136c16f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Casts.hh @@ -0,0 +1,77 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_CASTS_HH +#define OPENMESH_CASTS_HH +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh +{ + +template +inline TriMesh_ArrayKernelT& TRIMESH_CAST(PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline const TriMesh_ArrayKernelT& TRIMESH_CAST(const PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< const TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline PolyMesh_ArrayKernelT& POLYMESH_CAST(TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< PolyMesh_ArrayKernelT& >(_tri_mesh); } + +template +inline const PolyMesh_ArrayKernelT& POLYMESH_CAST(const TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< const PolyMesh_ArrayKernelT& >(_tri_mesh); } + +}; +#endif//OPENMESH_CASTS_HH diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/CirculatorsT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/CirculatorsT.hh new file mode 100644 index 0000000..0656059 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/CirculatorsT.hh @@ -0,0 +1,598 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_CIRCULATORS_HH +#define OPENMESH_CIRCULATORS_HH +//============================================================================= +// +// Vertex and Face circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + +template +class GenericCirculator_CenterEntityFnsT { + public: + static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter); + static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter); +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->cw_rotated_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->ccw_rotated_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->next_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->prev_halfedge_handle(heh); + } +}; + +///////////////////////////////////////////////////////////// +// CCW + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->ccw_rotated_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->cw_rotated_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->prev_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->next_halfedge_handle(heh); + } +}; +///////////////////////////////////////////////////////////// + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + //inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int &lap_counter); +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(mesh->opposite_halfedge_handle(heh)).is_valid(); + } +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(heh).is_valid(); + } +}; + +template +class GenericCirculator_ValueHandleFnsT { + public: + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) { + return ( heh.is_valid() && (lap_counter == 0 ) ); + } + inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {}; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } +}; + +template +class GenericCirculator_ValueHandleFnsT { + public: + typedef GenericCirculator_DereferenciabilityCheckT GenericCirculator_DereferenciabilityCheck; + + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) { + return ( heh.is_valid() && (lap_counter == 0)); + } + inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 ) + increment(mesh, heh, start, lap_counter); + }; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } +}; + +template +class GenericCirculatorBaseT { + public: + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; + + public: + GenericCirculatorBaseT() : mesh_(0), lap_counter_(0) {} + + GenericCirculatorBaseT(mesh_ref mesh, HalfedgeHandle heh, bool end = false) : + mesh_(&mesh), start_(heh), heh_(heh), lap_counter_(static_cast(end && heh.is_valid())) {} + + GenericCirculatorBaseT(const GenericCirculatorBaseT &rhs) : + mesh_(rhs.mesh_), start_(rhs.start_), heh_(rhs.heh_), lap_counter_(rhs.lap_counter_) {} + + inline typename Mesh::FaceHandle toFaceHandle() const { + return mesh_->face_handle(heh_); + } + + inline typename Mesh::FaceHandle toOppositeFaceHandle() const { + return mesh_->face_handle(toOppositeHalfedgeHandle()); + } + + inline typename Mesh::EdgeHandle toEdgeHandle() const { + return mesh_->edge_handle(heh_); + } + + inline typename Mesh::HalfedgeHandle toHalfedgeHandle() const { + return heh_; + } + + inline typename Mesh::HalfedgeHandle toOppositeHalfedgeHandle() const { + return mesh_->opposite_halfedge_handle(heh_); + } + + inline typename Mesh::VertexHandle toVertexHandle() const { + return mesh_->to_vertex_handle(heh_); + } + + inline GenericCirculatorBaseT &operator=(const GenericCirculatorBaseT &rhs) { + mesh_ = rhs.mesh_; + start_ = rhs.start_; + heh_ = rhs.heh_; + lap_counter_ = rhs.lap_counter_; + return *this; + } + + inline bool operator==(const GenericCirculatorBaseT &rhs) const { + return mesh_ == rhs.mesh_ && start_ == rhs.start_ && heh_ == rhs.heh_ && lap_counter_ == rhs.lap_counter_; + } + + inline bool operator!=(const GenericCirculatorBaseT &rhs) const { + return !operator==(rhs); + } + + protected: + mesh_ptr mesh_; + typename Mesh::HalfedgeHandle start_, heh_; + int lap_counter_; +}; + +template::*Handle2Value)() const, bool CW = true > +class GenericCirculatorT : protected GenericCirculatorBaseT { + public: + typedef std::ptrdiff_t difference_type; + typedef ValueHandle value_type; + typedef const value_type& reference; + typedef const value_type* pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename GenericCirculatorBaseT::mesh_ptr mesh_ptr; + typedef typename GenericCirculatorBaseT::mesh_ref mesh_ref; + typedef GenericCirculator_ValueHandleFnsT GenericCirculator_ValueHandleFns; + + public: + GenericCirculatorT() {} + GenericCirculatorT(mesh_ref mesh, CenterEntityHandle start, bool end = false) : + GenericCirculatorBaseT(mesh, mesh.halfedge_handle(start), end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT(mesh_ref mesh, HalfedgeHandle heh, bool end = false) : + GenericCirculatorBaseT(mesh, heh, end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT(const GenericCirculatorT &rhs) : GenericCirculatorBaseT(rhs) {} + + friend class GenericCirculatorT; + explicit GenericCirculatorT( const GenericCirculatorT& rhs ) + :GenericCirculatorBaseT(rhs){} + + GenericCirculatorT& operator++() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + GenericCirculatorT& operator--() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + + /// Post-increment + GenericCirculatorT operator++(int) { + assert(this->mesh_); + GenericCirculatorT cpy(*this); + ++(*this); + return cpy; + } + + /// Post-decrement + GenericCirculatorT operator--(int) { + assert(this->mesh_); + GenericCirculatorT cpy(*this); + --(*this); + return cpy; + } + + /// Standard dereferencing operator. + value_type operator*() const { + // We can't use this due to a GCC6 compiler bug + const GenericCirculatorBaseT* self = this; +#ifndef NDEBUG + assert(this->heh_.is_valid()); + value_type res = (self->*Handle2Value)(); + assert(res.is_valid()); + return res; +#else + return (self->*Handle2Value)(); +#endif + } + + /** + * @brief Pointer dereferentiation. + * + * This returns a pointer which points to a handle + * that loses its validity once this dereferentiation is + * invoked again. Thus, do not store the result of + * this operation. + */ + pointer operator->() const { + pointer_deref_value = **this; + return &pointer_deref_value; + } + + GenericCirculatorT &operator=(const GenericCirculatorT &rhs) { + GenericCirculatorBaseT::operator=(rhs); + return *this; + }; + + bool operator==(const GenericCirculatorT &rhs) const { + return GenericCirculatorBaseT::operator==(rhs); + } + + bool operator!=(const GenericCirculatorT &rhs) const { + return GenericCirculatorBaseT::operator!=(rhs); + } + + bool is_valid() const { + return GenericCirculator_ValueHandleFns::is_valid(this->heh_, this->lap_counter_); + } + + template + friend STREAM &operator<< (STREAM &s, const GenericCirculatorT &self) { + return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_; + } + + private: + mutable value_type pointer_deref_value; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// OLD /////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// OLD CIRCULATORS +// deprecated circulators, will be removed soon +// if you remove these circulators and go to the old ones, PLEASE ENABLE FOLLOWING UNITTESTS: +// +// OpenMeshTrimeshCirculatorVertexIHalfEdge.VertexIHalfEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexEdge.VertexEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexVertex.VertexVertexIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexOHalfEdge.VertexOHalfEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterWithoutHolesDecrement +// OpenMeshTrimeshCirculatorFaceEdge.FaceEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceFace.FaceFaceIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterWithoutHolesIncrement +// OpenMeshTrimeshCirculatorFaceVertex.FaceVertexIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterCheckInvalidationAtEnds +// + +template +class GenericCirculator_ValueHandleFnsT_DEPRECATED { + public: + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh,const typename Mesh::HalfedgeHandle &start, const int lap_counter) { + return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )) ); + } + inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {}; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } +}; + +template +class GenericCirculator_ValueHandleFnsT_DEPRECATED { + public: + typedef GenericCirculator_DereferenciabilityCheckT GenericCirculator_DereferenciabilityCheck; + + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int lap_counter) { + return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 ))); + } + inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 ) + increment(mesh, heh, start, lap_counter); + }; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } +}; + +template::*Handle2Value)() const> +class GenericCirculatorT_DEPRECATED : protected GenericCirculatorBaseT { + public: + typedef std::ptrdiff_t difference_type; + typedef ValueHandle value_type; + typedef const value_type& reference; + typedef const value_type* pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename GenericCirculatorBaseT::mesh_ptr mesh_ptr; + typedef typename GenericCirculatorBaseT::mesh_ref mesh_ref; + typedef GenericCirculator_ValueHandleFnsT_DEPRECATED GenericCirculator_ValueHandleFns; + + public: + GenericCirculatorT_DEPRECATED() {} + GenericCirculatorT_DEPRECATED(mesh_ref mesh, CenterEntityHandle start, bool end = false) : + GenericCirculatorBaseT(mesh, mesh.halfedge_handle(start), end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT_DEPRECATED(mesh_ref mesh, HalfedgeHandle heh, bool end = false) : + GenericCirculatorBaseT(mesh, heh, end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT_DEPRECATED(const GenericCirculatorT_DEPRECATED &rhs) : GenericCirculatorBaseT(rhs) {} + + GenericCirculatorT_DEPRECATED& operator++() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } +#ifndef NO_DECREMENT_DEPRECATED_WARNINGS +#define DECREMENT_DEPRECATED_WARNINGS_TEXT "The current decrement operator has the unintended behavior that it stays\ + valid when iterating below the start and will visit the first entity\ + twice before getting invalid. Furthermore it gets valid again, if you\ + increment at the end.\ + When you are sure that you don't iterate below the start anywhere in\ + your code or rely on this behaviour, you can disable this warning by\ + setting the define NO_DECREMENT_DEPRECATED_WARNINGS at the command line (or enable it via the\ + cmake flags).\ + To be save, you can use the CW/CCW circulator definitions, which behave\ + the same as the original ones, without the previously mentioned issues." + + DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT ) +#endif // NO_DECREMENT_DEPRECATED_WARNINGS + GenericCirculatorT_DEPRECATED& operator--() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + + /// Post-increment + GenericCirculatorT_DEPRECATED operator++(int) { + assert(this->mesh_); + GenericCirculatorT_DEPRECATED cpy(*this); + ++(*this); + return cpy; + } + + /// Post-decrement +#ifndef NO_DECREMENT_DEPRECATED_WARNINGS + DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT ) +#undef DECREMENT_DEPRECATED_WARNINGS_TEXT +#endif //NO_DECREMENT_DEPRECATED_WARNINGS + GenericCirculatorT_DEPRECATED operator--(int) { + assert(this->mesh_); + GenericCirculatorT_DEPRECATED cpy(*this); + --(*this); + return cpy; + } + + /// Standard dereferencing operator. + value_type operator*() const { + // We can't use this due to a GCC6 compiler bug + const GenericCirculatorBaseT* self = this; +#ifndef NDEBUG + assert(this->heh_.is_valid()); + value_type res = (self->*Handle2Value)(); + assert(res.is_valid()); + return res; +#else + return (self->*Handle2Value)(); +#endif + } + + /** + * @brief Pointer dereferentiation. + * + * This returns a pointer which points to a handle + * that loses its validity once this dereferentiation is + * invoked again. Thus, do not store the result of + * this operation. + */ + pointer operator->() const { + pointer_deref_value = **this; + return &pointer_deref_value; + } + + GenericCirculatorT_DEPRECATED &operator=(const GenericCirculatorT_DEPRECATED &rhs) { + GenericCirculatorBaseT::operator=(rhs); + return *this; + }; + + bool operator==(const GenericCirculatorT_DEPRECATED &rhs) const { + return GenericCirculatorBaseT::operator==(rhs); + } + + bool operator!=(const GenericCirculatorT_DEPRECATED &rhs) const { + return GenericCirculatorBaseT::operator!=(rhs); + } + + bool is_valid() const { + return GenericCirculator_ValueHandleFns::is_valid(this->heh_,this->start_, this->lap_counter_); + } + + DEPRECATED("current_halfedge_handle() is an implementation detail and should not be accessed from outside the iterator class.") + /** + * \deprecated + * current_halfedge_handle() is an implementation detail and should not + * be accessed from outside the iterator class. + */ + const HalfedgeHandle ¤t_halfedge_handle() const { + return this->heh_; + } + + DEPRECATED("Do not use this error prone implicit cast. Compare to end-iterator or use is_valid(), instead.") + /** + * \deprecated + * Do not use this error prone implicit cast. Compare to the + * end-iterator or use is_valid() instead. + */ + operator bool() const { + return is_valid(); + } + + /** + * \brief Return the handle of the current target. + * \deprecated + * This function clutters your code. Use dereferencing operators -> and * instead. + */ + DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.") + value_type handle() const { + return **this; + } + + /** + * \brief Cast to the handle of the current target. + * \deprecated + * Implicit casts of iterators are unsafe. Use dereferencing operators + * -> and * instead. + */ + DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.") + operator value_type() const { + return **this; + } + + template + friend STREAM &operator<< (STREAM &s, const GenericCirculatorT_DEPRECATED &self) { + return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_; + } + + private: + mutable value_type pointer_deref_value; +}; + +} // namespace Iterators +} // namespace OpenMesh + +#endif diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/FinalMeshItemsT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/FinalMeshItemsT.hh new file mode 100644 index 0000000..cbed2e5 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/FinalMeshItemsT.hh @@ -0,0 +1,227 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_MESH_ITEMS_HH +#define OPENMESH_MESH_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// Definition of the mesh entities (items). +template +struct FinalMeshItemsT +{ + //--- build Refs structure --- +#ifndef DOXY_IGNORE_THIS + struct Refs + { + typedef typename Traits::Point Point; + typedef typename vector_traits::value_type Scalar; + + typedef typename Traits::Normal Normal; + typedef typename Traits::Color Color; + typedef typename Traits::TexCoord1D TexCoord1D; + typedef typename Traits::TexCoord2D TexCoord2D; + typedef typename Traits::TexCoord3D TexCoord3D; + typedef typename Traits::TextureIndex TextureIndex; + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + }; +#endif + //--- export Refs types --- + typedef typename Refs::Point Point; + typedef typename Refs::Scalar Scalar; + typedef typename Refs::Normal Normal; + typedef typename Refs::Color Color; + typedef typename Refs::TexCoord1D TexCoord1D; + typedef typename Refs::TexCoord2D TexCoord2D; + typedef typename Refs::TexCoord3D TexCoord3D; + typedef typename Refs::TextureIndex TextureIndex; + + //--- get attribute bits from Traits --- + enum Attribs + { + VAttribs = Traits::VertexAttributes, + HAttribs = Traits::HalfedgeAttributes, + EAttribs = Traits::EdgeAttributes, + FAttribs = Traits::FaceAttributes + }; + //--- merge internal items with traits items --- + + +/* + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + typename InternalItems::Halfedge_with_prev, + typename InternalItems::Halfedge_without_prev + >::Result InternalHalfedge; +*/ + //typedef typename InternalItems::Vertex InternalVertex; + //typedef typename InternalItems::template Edge InternalEdge; + //typedef typename InternalItems::template Face InternalFace; + class ITraits + {}; + + typedef typename Traits::template VertexT VertexData; + typedef typename Traits::template HalfedgeT HalfedgeData; + typedef typename Traits::template EdgeT EdgeData; + typedef typename Traits::template FaceT FaceData; +}; + + +#ifndef DOXY_IGNORE_THIS +namespace { +namespace TM { +template struct TypeEquality; +template struct TypeEquality {}; + +template struct ItemsEquality { + TypeEquality te1; + TypeEquality te2; + TypeEquality te3; + TypeEquality te4; + TypeEquality te5; + TypeEquality te6; + TypeEquality te7; + TypeEquality te8; +}; + +} /* namespace TM */ +} /* anonymous namespace */ +#endif + +/** + * @brief Cast a mesh with different but identical traits into each other. + * + * Note that there exists a syntactically more convenient global method + * mesh_cast(). + * + * Example: + * @code{.cpp} + * struct TriTraits1 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits2 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits3 : public OpenMesh::DefaultTraits { + * typedef Vec3f Point; + * }; + * + * TriMesh_ArrayKernelT a; + * TriMesh_ArrayKernelT &b = MeshCast&, TriMesh_ArrayKernelT&>::cast(a); // OK + * TriMesh_ArrayKernelT &c = MeshCast&, TriMesh_ArrayKernelT&>::cast(a); // ERROR + * @endcode + * + * @see mesh_cast() + * + * @param rhs + * @return + */ +template struct MeshCast; + +template +struct MeshCast { + static LhsMeshT &cast(RhsMeshT &rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static const LhsMeshT &cast(const RhsMeshT &rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static LhsMeshT *cast(RhsMeshT *rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static const LhsMeshT *cast(const RhsMeshT *rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESH_ITEMS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Handles.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Handles.hh new file mode 100644 index 0000000..68ac1d7 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Handles.hh @@ -0,0 +1,238 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_HANDLES_HH +#define OPENMESH_HANDLES_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/// Base class for all handle types +class BaseHandle +{ +public: + + explicit BaseHandle(int _idx=-1) : idx_(_idx) {} + + /// Get the underlying index of this handle + int idx() const { return idx_; } + + /// The handle is valid iff the index is not negative. + bool is_valid() const { return idx_ >= 0; } + + /// reset handle to be invalid + void reset() { idx_=-1; } + /// reset handle to be invalid + void invalidate() { idx_ = -1; } + + bool operator==(const BaseHandle& _rhs) const { + return (this->idx_ == _rhs.idx_); + } + + bool operator!=(const BaseHandle& _rhs) const { + return (this->idx_ != _rhs.idx_); + } + + bool operator<(const BaseHandle& _rhs) const { + return (this->idx_ < _rhs.idx_); + } + + + // this is to be used only by the iterators + void __increment() { ++idx_; } + void __decrement() { --idx_; } + + void __increment(int amount) { idx_ += amount; } + void __decrement(int amount) { idx_ -= amount; } + +private: + + int idx_; +}; + +// this is used by boost::unordered_set/map +inline size_t hash_value(const BaseHandle& h) { return h.idx(); } + +//----------------------------------------------------------------------------- + +/// Write handle \c _hnd to stream \c _os +inline std::ostream& operator<<(std::ostream& _os, const BaseHandle& _hnd) +{ + return (_os << _hnd.idx()); +} + + +//----------------------------------------------------------------------------- + + +/// Handle for a vertex entity +struct VertexHandle : public BaseHandle +{ + explicit VertexHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a halfedge entity +struct HalfedgeHandle : public BaseHandle +{ + explicit HalfedgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a edge entity +struct EdgeHandle : public BaseHandle +{ + explicit EdgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a face entity +struct FaceHandle : public BaseHandle +{ + explicit FaceHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +#ifdef OM_HAS_HASH +#include +namespace std { + +#if defined(_MSVC_VER) +# pragma warning(push) +# pragma warning(disable:4099) // For VC++ it is class hash +#endif + + +template <> +struct hash +{ + typedef OpenMesh::BaseHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::BaseHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + typedef OpenMesh::VertexHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::VertexHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::HalfedgeHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::HalfedgeHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::EdgeHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::EdgeHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::FaceHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::FaceHandle& h) const + { + return h.idx(); + } +}; + +#if defined(_MSVC_VER) +# pragma warning(pop) +#endif + +} +#endif // OM_HAS_HASH + + +#endif // OPENMESH_HANDLES_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/IteratorsT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/IteratorsT.hh new file mode 100644 index 0000000..6d2c92b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/IteratorsT.hh @@ -0,0 +1,259 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_ITERATORS_HH +#define OPENMESH_ITERATORS_HH + +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class ConstVertexIterT; +template class VertexIterT; +template class ConstHalfedgeIterT; +template class HalfedgeIterT; +template class ConstEdgeIterT; +template class EdgeIterT; +template class ConstFaceIterT; +template class FaceIterT; + + +template +class GenericIteratorT { + public: + //--- Typedefs --- + + typedef ValueHandle value_handle; + typedef value_handle value_type; + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; + + /// Default constructor. + GenericIteratorT() + : mesh_(0), skip_bits_(0) + {} + + /// Construct with mesh and a target handle. + GenericIteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + /// Standard dereferencing operator. + reference operator*() const { + return hnd_; + } + + /// Standard pointer operator. + pointer operator->() const { + return &hnd_; + } + + /** + * \brief Get the handle of the item the iterator refers to. + * \deprecated + * This function clutters your code. Use dereferencing operators -> and * instead. + */ + DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.") + value_handle handle() const { + return hnd_; + } + + /** + * \brief Cast to the handle of the item the iterator refers to. + * \deprecated + * Implicit casts of iterators are unsafe. Use dereferencing operators + * -> and * instead. + */ + DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.") + operator value_handle() const { + return hnd_; + } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const GenericIteratorT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); + } + + /// Not equal? + bool operator!=(const GenericIteratorT& _rhs) const { + return !operator==(_rhs); + } + + /// Standard pre-increment operator + GenericIteratorT& operator++() { + hnd_.__increment(); + if (skip_bits_) + skip_fwd(); + return *this; + } + + /// Standard post-increment operator + GenericIteratorT operator++(int) { + GenericIteratorT cpy(*this); + ++(*this); + return cpy; + } + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + template + auto operator+=(int amount) -> + typename std::enable_if< + sizeof(decltype(std::declval().__increment(amount))) >= 0, + GenericIteratorT&>::type { + static_assert(std::is_same::value, + "Template parameter must not deviate from default."); + if (skip_bits_) + throw std::logic_error("Skipping iterators do not support " + "random access."); + hnd_.__increment(amount); + return *this; + } + + template + auto operator+(int rhs) -> + typename std::enable_if< + sizeof(decltype(std::declval().__increment(rhs), void (), int {})) >= 0, + GenericIteratorT>::type { + static_assert(std::is_same::value, + "Template parameter must not deviate from default."); + if (skip_bits_) + throw std::logic_error("Skipping iterators do not support " + "random access."); + GenericIteratorT result = *this; + result.hnd_.__increment(rhs); + return result; + } +#endif + + /// Standard pre-decrement operator + GenericIteratorT& operator--() { + hnd_.__decrement(); + if (skip_bits_) + skip_bwd(); + return *this; + } + + /// Standard post-decrement operator + GenericIteratorT operator--(int) { + GenericIteratorT cpy(*this); + --(*this); + return cpy; + } + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() { + if (mesh_ && (mesh_->*PrimitiveStatusMember)()) { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } else + skip_bits_ = 0; + } + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { + skip_bits_ = 0; + } + + private: + + void skip_fwd() { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) (mesh_->*PrimitiveCountMember)()) + && (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + void skip_bwd() { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + protected: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyConnectivity.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyConnectivity.cc new file mode 100644 index 0000000..e311f5c --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyConnectivity.cc @@ -0,0 +1,1243 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//== IMPLEMENTATION ========================================================== +#include +#include + +namespace OpenMesh { + +const PolyConnectivity::VertexHandle PolyConnectivity::InvalidVertexHandle; +const PolyConnectivity::HalfedgeHandle PolyConnectivity::InvalidHalfedgeHandle; +const PolyConnectivity::EdgeHandle PolyConnectivity::InvalidEdgeHandle; +const PolyConnectivity::FaceHandle PolyConnectivity::InvalidFaceHandle; + +//----------------------------------------------------------------------------- + +PolyConnectivity::HalfedgeHandle +PolyConnectivity::find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh ) const +{ + assert(_start_vh.is_valid() && _end_vh.is_valid()); + + for (ConstVertexOHalfedgeIter voh_it = cvoh_iter(_start_vh); voh_it.is_valid(); ++voh_it) + if (to_vertex_handle(*voh_it) == _end_vh) + return *voh_it; + + return InvalidHalfedgeHandle; +} + + +bool PolyConnectivity::is_boundary(FaceHandle _fh, bool _check_vertex) const +{ + for (ConstFaceEdgeIter cfeit = cfe_iter( _fh ); cfeit.is_valid(); ++cfeit) + if (is_boundary( *cfeit ) ) + return true; + + if (_check_vertex) + { + for (ConstFaceVertexIter cfvit = cfv_iter( _fh ); cfvit.is_valid(); ++cfvit) + if (is_boundary( *cfvit ) ) + return true; + } + return false; +} + +bool PolyConnectivity::is_manifold(VertexHandle _vh) const +{ + /* The vertex is non-manifold if more than one gap exists, i.e. + more than one outgoing boundary halfedge. If (at least) one + boundary halfedge exists, the vertex' halfedge must be a + boundary halfedge. If iterating around the vertex finds another + boundary halfedge, the vertex is non-manifold. */ + + ConstVertexOHalfedgeIter vh_it(*this, _vh); + if (vh_it.is_valid()) + for (++vh_it; vh_it.is_valid(); ++vh_it) + if (is_boundary(*vh_it)) + return false; + return true; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::adjust_outgoing_halfedge(VertexHandle _vh) +{ + for (ConstVertexOHalfedgeIter vh_it=cvoh_iter(_vh); vh_it.is_valid(); ++vh_it) + { + if (is_boundary(*vh_it)) + { + set_halfedge_handle(_vh, *vh_it); + break; + } + } +} + +//----------------------------------------------------------------------------- + +PolyConnectivity::FaceHandle +PolyConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size) +{ + VertexHandle vh; + size_t i, ii, n(_vhs_size); + HalfedgeHandle inner_next, inner_prev, + outer_next, outer_prev, + boundary_next, boundary_prev, + patch_start, patch_end; + + + // Check sufficient working storage available + if (edgeData_.size() < n) + { + edgeData_.resize(n); + next_cache_.resize(6*n); + } + + size_t next_cache_count = 0; + + // don't allow degenerated faces + assert (n > 2); + + // test for topological errors + for (i=0, ii=1; i& _vhandles) +{ return add_face(&_vhandles.front(), _vhandles.size()); } + + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_collapse_ok(HalfedgeHandle v0v1) +{ + //is edge already deleteed? + if (status(edge_handle(v0v1)).deleted()) + { + return false; + } + + HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1)); + VertexHandle v0(to_vertex_handle(v1v0)); + VertexHandle v1(to_vertex_handle(v0v1)); + + bool v0v1_triangle = false; + bool v1v0_triangle = false; + + if (!is_boundary(v0v1)) + v0v1_triangle = valence(face_handle(v0v1)) == 3; + + if (!is_boundary(v1v0)) + v1v0_triangle = valence(face_handle(v1v0)) == 3; + + //in a quadmesh we dont have the "next" or "previous" vhandle, so we need to look at previous and next on both sides + //VertexHandle v_01_p = from_vertex_handle(prev_halfedge_handle(v0v1)); + VertexHandle v_01_n = to_vertex_handle(next_halfedge_handle(v0v1)); + + //VertexHandle v_10_p = from_vertex_handle(prev_halfedge_handle(v1v0)); + VertexHandle v_10_n = to_vertex_handle(next_halfedge_handle(v1v0)); + + //are the vertices already deleted ? + if (status(v0).deleted() || status(v1).deleted()) + { + return false; + } + + //the edges v1-vl and vl-v0 must not be both boundary edges + //this test makes only sense in a polymesh if the side face is a triangle + if (!is_boundary(v0v1)) + { + if (v0v1_triangle) + { + //VertexHandle vl = to_vertex_handle(next_halfedge_handle(v0v1)); + + HalfedgeHandle h1 = next_halfedge_handle(v0v1); + HalfedgeHandle h2 = next_halfedge_handle(h1); + if (is_boundary(opposite_halfedge_handle(h1)) && is_boundary(opposite_halfedge_handle(h2))) + return false; + } + } + + //the edges v0-vr and vr-v1 must not be both boundary edges + //this test makes only sense in a polymesh if the side face is a triangle + if (!is_boundary(v1v0)) + { + if (v1v0_triangle) + { + //VertexHandle vr = to_vertex_handle(next_halfedge_handle(v1v0)); + + HalfedgeHandle h1 = next_halfedge_handle(v1v0); + HalfedgeHandle h2 = next_halfedge_handle(h1); + if (is_boundary(opposite_halfedge_handle(h1)) && is_boundary(opposite_halfedge_handle(h2))) + return false; + } + } + + // edge between two boundary vertices should be a boundary edge + if ( is_boundary(v0) && is_boundary(v1) && !is_boundary(v0v1) && !is_boundary(v1v0)) + return false; + + VertexVertexIter vv_it; + // test intersection of the one-rings of v0 and v1 + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + { + status(*vv_it).set_tagged(false); + } + + for (vv_it = vv_iter(v1); vv_it.is_valid(); ++vv_it) + { + status(*vv_it).set_tagged(true); + } + + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + { + if (status(*vv_it).tagged() && + !(*vv_it == v_01_n && v0v1_triangle) && + !(*vv_it == v_10_n && v1v0_triangle) + ) + { + return false; + } + } + + //test for a face on the backside/other side that might degenerate + if (v0v1_triangle) + { + HalfedgeHandle one, two; + one = next_halfedge_handle(v0v1); + two = next_halfedge_handle(one); + + one = opposite_halfedge_handle(one); + two = opposite_halfedge_handle(two); + + if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3) + { + return false; + } + } + + if (v1v0_triangle) + { + HalfedgeHandle one, two; + one = next_halfedge_handle(v1v0); + two = next_halfedge_handle(one); + + one = opposite_halfedge_handle(one); + two = opposite_halfedge_handle(two); + + if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3) + { + return false; + } + } + + if (status(*vv_it).tagged() && v_01_n == v_10_n && v0v1_triangle && v1v0_triangle) + { + return false; + } + + // passed all tests + return true; +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices) +{ + // store incident faces + std::vector face_handles; + face_handles.reserve(8); + for (VFIter vf_it(vf_iter(_vh)); vf_it.is_valid(); ++vf_it) + face_handles.push_back(*vf_it); + + + // delete collected faces + std::vector::iterator fh_it(face_handles.begin()), + fh_end(face_handles.end()); + + for (; fh_it!=fh_end; ++fh_it) + delete_face(*fh_it, _delete_isolated_vertices); + + status(_vh).set_deleted(true); +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices) +{ + FaceHandle fh0(face_handle(halfedge_handle(_eh, 0))); + FaceHandle fh1(face_handle(halfedge_handle(_eh, 1))); + + if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices); + if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices); + + // If there is no face, we delete the edge + // here + if ( ! fh0.is_valid() && !fh1.is_valid()) { + // mark edge deleted if the mesh has a edge status + if ( has_edge_status() ) + status(_eh).set_deleted(true); + + // mark corresponding halfedges as deleted + // As the deleted edge is boundary, + // all corresponding halfedges will also be deleted. + if ( has_halfedge_status() ) { + status(halfedge_handle(_eh, 0)).set_deleted(true); + status(halfedge_handle(_eh, 1)).set_deleted(true); + } + } +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices) +{ + assert(_fh.is_valid() && !status(_fh).deleted()); + + // mark face deleted + status(_fh).set_deleted(true); + + + // this vector will hold all boundary edges of face _fh + // these edges will be deleted + std::vector deleted_edges; + deleted_edges.reserve(3); + + + // this vector will hold all vertices of face _fh + // for updating their outgoing halfedge + std::vector vhandles; + vhandles.reserve(3); + + + // for all halfedges of face _fh do: + // 1) invalidate face handle. + // 2) collect all boundary halfedges, set them deleted + // 3) store vertex handles + HalfedgeHandle hh; + for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it.is_valid(); ++fh_it) + { + hh = *fh_it; + + set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle); + + if (is_boundary(opposite_halfedge_handle(hh))) + deleted_edges.push_back(edge_handle(hh)); + + vhandles.push_back(to_vertex_handle(hh)); + } + + + // delete all collected (half)edges + // these edges were all boundary + // delete isolated vertices (if _delete_isolated_vertices is true) + if (!deleted_edges.empty()) + { + std::vector::iterator del_it(deleted_edges.begin()), + del_end(deleted_edges.end()); + HalfedgeHandle h0, h1, next0, next1, prev0, prev1; + VertexHandle v0, v1; + + for (; del_it!=del_end; ++del_it) + { + h0 = halfedge_handle(*del_it, 0); + v0 = to_vertex_handle(h0); + next0 = next_halfedge_handle(h0); + prev0 = prev_halfedge_handle(h0); + + h1 = halfedge_handle(*del_it, 1); + v1 = to_vertex_handle(h1); + next1 = next_halfedge_handle(h1); + prev1 = prev_halfedge_handle(h1); + + // adjust next and prev handles + set_next_halfedge_handle(prev0, next1); + set_next_halfedge_handle(prev1, next0); + + // mark edge deleted if the mesh has a edge status + if ( has_edge_status() ) + status(*del_it).set_deleted(true); + + + // mark corresponding halfedges as deleted + // As the deleted edge is boundary, + // all corresponding halfedges will also be deleted. + if ( has_halfedge_status() ) { + status(h0).set_deleted(true); + status(h1).set_deleted(true); + } + + // update v0 + if (halfedge_handle(v0) == h1) + { + // isolated ? + if (next0 == h1) + { + if (_delete_isolated_vertices) + status(v0).set_deleted(true); + set_isolated(v0); + } + else set_halfedge_handle(v0, next0); + } + + // update v1 + if (halfedge_handle(v1) == h0) + { + // isolated ? + if (next1 == h0) + { + if (_delete_isolated_vertices) + status(v1).set_deleted(true); + set_isolated(v1); + } + else set_halfedge_handle(v1, next1); + } + } + } + + // update outgoing halfedge handles of remaining vertices + std::vector::iterator v_it(vhandles.begin()), + v_end(vhandles.end()); + for (; v_it!=v_end; ++v_it) + adjust_outgoing_halfedge(*v_it); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::VertexIter PolyConnectivity::vertices_begin() +{ + return VertexIter(*this, VertexHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_begin() const +{ + return ConstVertexIter(*this, VertexHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::VertexIter PolyConnectivity::vertices_end() +{ + return VertexIter(*this, VertexHandle( int(n_vertices() ) )); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_end() const +{ + return ConstVertexIter(*this, VertexHandle( int(n_vertices()) )); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_begin() +{ + return HalfedgeIter(*this, HalfedgeHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_begin() const +{ + return ConstHalfedgeIter(*this, HalfedgeHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_end() +{ + return HalfedgeIter(*this, HalfedgeHandle(int(n_halfedges()))); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_end() const +{ + return ConstHalfedgeIter(*this, HalfedgeHandle(int(n_halfedges()))); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::EdgeIter PolyConnectivity::edges_begin() +{ + return EdgeIter(*this, EdgeHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_begin() const +{ + return ConstEdgeIter(*this, EdgeHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::EdgeIter PolyConnectivity::edges_end() +{ + return EdgeIter(*this, EdgeHandle(int(n_edges()))); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_end() const +{ + return ConstEdgeIter(*this, EdgeHandle(int(n_edges()))); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::FaceIter PolyConnectivity::faces_begin() +{ + return FaceIter(*this, FaceHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstFaceIter PolyConnectivity::faces_begin() const +{ + return ConstFaceIter(*this, FaceHandle(0)); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::FaceIter PolyConnectivity::faces_end() +{ + return FaceIter(*this, FaceHandle(int(n_faces()))); +} + +//----------------------------------------------------------------------------- +PolyConnectivity::ConstFaceIter PolyConnectivity::faces_end() const +{ + return ConstFaceIter(*this, FaceHandle(int(n_faces()))); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse(HalfedgeHandle _hh) +{ + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle(h0); + HalfedgeHandle o0 = opposite_halfedge_handle(h0); + HalfedgeHandle o1 = next_halfedge_handle(o0); + + // remove edge + collapse_edge(h0); + + // remove loops + if (next_halfedge_handle(next_halfedge_handle(h1)) == h1) + collapse_loop(next_halfedge_handle(h1)); + if (next_halfedge_handle(next_halfedge_handle(o1)) == o1) + collapse_loop(o1); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse_edge(HalfedgeHandle _hh) +{ + HalfedgeHandle h = _hh; + HalfedgeHandle hn = next_halfedge_handle(h); + HalfedgeHandle hp = prev_halfedge_handle(h); + + HalfedgeHandle o = opposite_halfedge_handle(h); + HalfedgeHandle on = next_halfedge_handle(o); + HalfedgeHandle op = prev_halfedge_handle(o); + + FaceHandle fh = face_handle(h); + FaceHandle fo = face_handle(o); + + VertexHandle vh = to_vertex_handle(h); + VertexHandle vo = to_vertex_handle(o); + + + + // halfedge -> vertex + for (VertexIHalfedgeIter vih_it(vih_iter(vo)); vih_it.is_valid(); ++vih_it) + set_vertex_handle(*vih_it, vh); + + + // halfedge -> halfedge + set_next_halfedge_handle(hp, hn); + set_next_halfedge_handle(op, on); + + + // face -> halfedge + if (fh.is_valid()) set_halfedge_handle(fh, hn); + if (fo.is_valid()) set_halfedge_handle(fo, on); + + + // vertex -> halfedge + if (halfedge_handle(vh) == o) set_halfedge_handle(vh, hn); + adjust_outgoing_halfedge(vh); + set_isolated(vo); + + // delete stuff + status(edge_handle(h)).set_deleted(true); + status(vo).set_deleted(true); + if (has_halfedge_status()) + { + status(h).set_deleted(true); + status(o).set_deleted(true); + } +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse_loop(HalfedgeHandle _hh) +{ + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle(h0); + + HalfedgeHandle o0 = opposite_halfedge_handle(h0); + HalfedgeHandle o1 = opposite_halfedge_handle(h1); + + VertexHandle v0 = to_vertex_handle(h0); + VertexHandle v1 = to_vertex_handle(h1); + + FaceHandle fh = face_handle(h0); + FaceHandle fo = face_handle(o0); + + + + // is it a loop ? + assert ((next_halfedge_handle(h1) == h0) && (h1 != o0)); + + + // halfedge -> halfedge + set_next_halfedge_handle(h1, next_halfedge_handle(o0)); + set_next_halfedge_handle(prev_halfedge_handle(o0), h1); + + + // halfedge -> face + set_face_handle(h1, fo); + + + // vertex -> halfedge + set_halfedge_handle(v0, h1); adjust_outgoing_halfedge(v0); + set_halfedge_handle(v1, o1); adjust_outgoing_halfedge(v1); + + + // face -> halfedge + if (fo.is_valid() && halfedge_handle(fo) == o0) + { + set_halfedge_handle(fo, h1); + } + + // delete stuff + if (fh.is_valid()) + { + set_halfedge_handle(fh, InvalidHalfedgeHandle); + status(fh).set_deleted(true); + } + status(edge_handle(h0)).set_deleted(true); + if (has_halfedge_status()) + { + status(h0).set_deleted(true); + status(o0).set_deleted(true); + } +} + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_simple_link(EdgeHandle _eh) const +{ + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + + //FaceHandle fh0 = face_handle(heh0);//fh0 or fh1 might be a invalid, + FaceHandle fh1 = face_handle(heh1);//i.e., representing the boundary + + HalfedgeHandle next_heh = next_halfedge_handle(heh0); + while (next_heh != heh0) + {//check if there are no other edges shared between fh0 & fh1 + if (opposite_face_handle(next_heh) == fh1) + { + return false; + } + next_heh = next_halfedge_handle(next_heh); + } + return true; +} + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_simply_connected(FaceHandle _fh) const +{ + std::set nb_fhs; + for (ConstFaceFaceIter cff_it = cff_iter(_fh); cff_it.is_valid(); ++cff_it) + { + if (nb_fhs.find(*cff_it) == nb_fhs.end()) + { + nb_fhs.insert(*cff_it); + } + else + {//there is more than one link + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +PolyConnectivity::FaceHandle +PolyConnectivity::remove_edge(EdgeHandle _eh) +{ + //don't allow "dangling" vertices and edges + assert(!status(_eh).deleted() && is_simple_link(_eh)); + + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + + //deal with the faces + FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); + if (!del_fh.is_valid()) + {//boundary case - we must delete the rem_fh + std::swap(del_fh, rem_fh); + } + assert(del_fh.is_valid()); +/* for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it) + {//set the face handle of the halfedges of del_fh to point to rem_fh + set_face_handle(fh_it, rem_fh); + } */ + //fix the halfedge relations + HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); + HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); + + HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); + HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); + + set_next_halfedge_handle(prev_heh0, next_heh1); + set_next_halfedge_handle(prev_heh1, next_heh0); + //correct outgoing vertex handles for the _eh vertices (if needed) + VertexHandle vh0 = to_vertex_handle(heh0); + VertexHandle vh1 = to_vertex_handle(heh1); + + if (halfedge_handle(vh0) == heh1) + { + set_halfedge_handle(vh0, next_heh0); + } + if (halfedge_handle(vh1) == heh0) + { + set_halfedge_handle(vh1, next_heh1); + } + + //correct the hafledge handle of rem_fh if needed and preserve its first vertex + if (halfedge_handle(rem_fh) == heh0) + {//rem_fh is the face at heh0 + set_halfedge_handle(rem_fh, prev_heh1); + } + else if (halfedge_handle(rem_fh) == heh1) + {//rem_fh is the face at heh1 + set_halfedge_handle(rem_fh, prev_heh0); + } + for (FaceHalfedgeIter fh_it = fh_iter(rem_fh); fh_it.is_valid(); ++fh_it) + {//set the face handle of the halfedges of del_fh to point to rem_fh + set_face_handle(*fh_it, rem_fh); + } + + status(_eh).set_deleted(true); + status(del_fh).set_deleted(true); + return rem_fh;//returns the remaining face handle +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::reinsert_edge(EdgeHandle _eh) +{ + //this does not work without prev_halfedge_handle + assert_compile(sizeof(Halfedge) == sizeof(Halfedge_with_prev)); + //shoudl be deleted + assert(status(_eh).deleted()); + status(_eh).set_deleted(false); + + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); + if (!del_fh.is_valid()) + {//boundary case - we must delete the rem_fh + std::swap(del_fh, rem_fh); + } + assert(status(del_fh).deleted()); + status(del_fh).set_deleted(false); + + //restore halfedge relations + HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); + HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); + + HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); + HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); + + set_next_halfedge_handle(prev_heh0, heh0); + set_prev_halfedge_handle(next_heh0, heh0); + + set_next_halfedge_handle(prev_heh1, heh1); + set_prev_halfedge_handle(next_heh1, heh1); + + for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it.is_valid(); ++fh_it) + {//reassign halfedges to del_fh + set_face_handle(*fh_it, del_fh); + } + + if (face_handle(halfedge_handle(rem_fh)) == del_fh) + {//correct the halfedge handle of rem_fh + if (halfedge_handle(rem_fh) == prev_heh0) + {//rem_fh is the face at heh1 + set_halfedge_handle(rem_fh, heh1); + } + else + {//rem_fh is the face at heh0 + assert(halfedge_handle(rem_fh) == prev_heh1); + set_halfedge_handle(rem_fh, heh0); + } + } +} + +//----------------------------------------------------------------------------- +PolyConnectivity::HalfedgeHandle +PolyConnectivity::insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh) +{ + assert(face_handle(_prev_heh) == face_handle(_next_heh));//only the manifold case + assert(next_halfedge_handle(_prev_heh) != _next_heh);//this can not be done + VertexHandle vh0 = to_vertex_handle(_prev_heh); + VertexHandle vh1 = from_vertex_handle(_next_heh); + //create the link between vh0 and vh1 + HalfedgeHandle heh0 = new_edge(vh0, vh1); + HalfedgeHandle heh1 = opposite_halfedge_handle(heh0); + HalfedgeHandle next_prev_heh = next_halfedge_handle(_prev_heh); + HalfedgeHandle prev_next_heh = prev_halfedge_handle(_next_heh); + set_next_halfedge_handle(_prev_heh, heh0); + set_next_halfedge_handle(heh0, _next_heh); + set_next_halfedge_handle(prev_next_heh, heh1); + set_next_halfedge_handle(heh1, next_prev_heh); + + //now set the face handles - the new face is assigned to heh0 + FaceHandle new_fh = new_face(); + set_halfedge_handle(new_fh, heh0); + for (FaceHalfedgeIter fh_it = fh_iter(new_fh); fh_it.is_valid(); ++fh_it) + { + set_face_handle(*fh_it, new_fh); + } + FaceHandle old_fh = face_handle(next_prev_heh); + set_face_handle(heh1, old_fh); + if (old_fh.is_valid() && face_handle(halfedge_handle(old_fh)) == new_fh) + {//fh pointed to one of the halfedges now assigned to new_fh + set_halfedge_handle(old_fh, heh1); + } + adjust_outgoing_halfedge(vh0); + adjust_outgoing_halfedge(vh1); + return heh0; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::triangulate(FaceHandle _fh) +{ + /* + Split an arbitrary face into triangles by connecting + each vertex of fh after its second to vh. + + - fh will remain valid (it will become one of the + triangles) + - the halfedge handles of the new triangles will + point to the old halfedges + */ + + HalfedgeHandle base_heh(halfedge_handle(_fh)); + VertexHandle start_vh = from_vertex_handle(base_heh); + HalfedgeHandle prev_heh(prev_halfedge_handle(base_heh)); + HalfedgeHandle next_heh(next_halfedge_handle(base_heh)); + + while (to_vertex_handle(next_halfedge_handle(next_heh)) != start_vh) + { + HalfedgeHandle next_next_heh(next_halfedge_handle(next_heh)); + + FaceHandle new_fh = new_face(); + set_halfedge_handle(new_fh, base_heh); + + HalfedgeHandle new_heh = new_edge(to_vertex_handle(next_heh), start_vh); + + set_next_halfedge_handle(base_heh, next_heh); + set_next_halfedge_handle(next_heh, new_heh); + set_next_halfedge_handle(new_heh, base_heh); + + set_face_handle(base_heh, new_fh); + set_face_handle(next_heh, new_fh); + set_face_handle(new_heh, new_fh); + + copy_all_properties(prev_heh, new_heh, true); + copy_all_properties(prev_heh, opposite_halfedge_handle(new_heh), true); + copy_all_properties(_fh, new_fh, true); + + base_heh = opposite_halfedge_handle(new_heh); + next_heh = next_next_heh; + } + set_halfedge_handle(_fh, base_heh); //the last face takes the handle _fh + + set_next_halfedge_handle(base_heh, next_heh); + set_next_halfedge_handle(next_halfedge_handle(next_heh), base_heh); + + set_face_handle(base_heh, _fh); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::triangulate() +{ + /* The iterators will stay valid, even though new faces are added, + because they are now implemented index-based instead of + pointer-based. + */ + FaceIter f_it(faces_begin()), f_end(faces_end()); + for (; f_it!=f_end; ++f_it) + triangulate(*f_it); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::split(FaceHandle fh, VertexHandle vh) +{ + HalfedgeHandle hend = halfedge_handle(fh); + HalfedgeHandle hh = next_halfedge_handle(hend); + + HalfedgeHandle hold = new_edge(to_vertex_handle(hend), vh); + + set_next_halfedge_handle(hend, hold); + set_face_handle(hold, fh); + + hold = opposite_halfedge_handle(hold); + + while (hh != hend) { + + HalfedgeHandle hnext = next_halfedge_handle(hh); + + FaceHandle fnew = new_face(); + set_halfedge_handle(fnew, hh); + + HalfedgeHandle hnew = new_edge(to_vertex_handle(hh), vh); + + set_next_halfedge_handle(hnew, hold); + set_next_halfedge_handle(hold, hh); + set_next_halfedge_handle(hh, hnew); + + set_face_handle(hnew, fnew); + set_face_handle(hold, fnew); + set_face_handle(hh, fnew); + + hold = opposite_halfedge_handle(hnew); + + hh = hnext; + } + + set_next_halfedge_handle(hold, hend); + set_next_halfedge_handle(next_halfedge_handle(hend), hold); + + set_face_handle(hold, fh); + + set_halfedge_handle(vh, hold); +} + + +void PolyConnectivity::split_copy(FaceHandle fh, VertexHandle vh) { + + // Split the given face (fh will still be valid) + split(fh, vh); + + // Copy the property of the original face to all new faces + for(VertexFaceIter vf_it = vf_iter(vh); vf_it.is_valid(); ++vf_it) + copy_all_properties(fh, *vf_it, true); +} + +//----------------------------------------------------------------------------- +uint PolyConnectivity::valence(VertexHandle _vh) const +{ + uint count(0); + for (ConstVertexVertexIter vv_it=cvv_iter(_vh); vv_it.is_valid(); ++vv_it) + ++count; + return count; +} + +//----------------------------------------------------------------------------- +uint PolyConnectivity::valence(FaceHandle _fh) const +{ + uint count(0); + for (ConstFaceVertexIter fv_it=cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + ++count; + return count; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::split_edge(EdgeHandle _eh, VertexHandle _vh) +{ + HalfedgeHandle h0 = halfedge_handle(_eh, 0); + HalfedgeHandle h1 = halfedge_handle(_eh, 1); + + VertexHandle vfrom = from_vertex_handle(h0); + + HalfedgeHandle ph0 = prev_halfedge_handle(h0); + //HalfedgeHandle ph1 = prev_halfedge_handle(h1); + + //HalfedgeHandle nh0 = next_halfedge_handle(h0); + HalfedgeHandle nh1 = next_halfedge_handle(h1); + + bool boundary0 = is_boundary(h0); + bool boundary1 = is_boundary(h1); + + //add the new edge + HalfedgeHandle new_e = new_edge(from_vertex_handle(h0), _vh); + + //fix the vertex of the opposite halfedge + set_vertex_handle(h1, _vh); + + //fix the halfedge connectivity + set_next_halfedge_handle(new_e, h0); + set_next_halfedge_handle(h1, opposite_halfedge_handle(new_e)); + + set_next_halfedge_handle(ph0, new_e); + set_next_halfedge_handle(opposite_halfedge_handle(new_e), nh1); + +// set_prev_halfedge_handle(new_e, ph0); +// set_prev_halfedge_handle(opposite_halfedge_handle(new_e), h1); + +// set_prev_halfedge_handle(nh1, opposite_halfedge_handle(new_e)); +// set_prev_halfedge_handle(h0, new_e); + + if (!boundary0) + { + set_face_handle(new_e, face_handle(h0)); + } + else + { + set_boundary(new_e); + } + + if (!boundary1) + { + set_face_handle(opposite_halfedge_handle(new_e), face_handle(h1)); + } + else + { + set_boundary(opposite_halfedge_handle(new_e)); + } + + set_halfedge_handle( _vh, h0 ); + adjust_outgoing_halfedge( _vh ); + + if (halfedge_handle(vfrom) == h0) + { + set_halfedge_handle(vfrom, new_e); + adjust_outgoing_halfedge( vfrom ); + } +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::split_edge_copy(EdgeHandle _eh, VertexHandle _vh) +{ + // Split the edge (handle is kept!) + split_edge(_eh, _vh); + + // Navigate to the new edge + EdgeHandle eh0 = edge_handle( next_halfedge_handle( halfedge_handle(_eh, 1) ) ); + + // Copy the property from the original to the new edge + copy_all_properties(_eh, eh0, true); +} + +} // namespace OpenMesh + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyConnectivity.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyConnectivity.hh new file mode 100644 index 0000000..d2ce667 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyConnectivity.hh @@ -0,0 +1,1635 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_POLYCONNECTIVITY_HH +#define OPENMESH_POLYCONNECTIVITY_HH + +#include +#include +#include + +namespace OpenMesh +{ + +/** \brief Connectivity Class for polygonal meshes +*/ +class OPENMESHDLLEXPORT PolyConnectivity : public ArrayKernel +{ +public: + /// \name Mesh Handles + //@{ + /// Invalid handle + static const VertexHandle InvalidVertexHandle; + /// Invalid handle + static const HalfedgeHandle InvalidHalfedgeHandle; + /// Invalid handle + static const EdgeHandle InvalidEdgeHandle; + /// Invalid handle + static const FaceHandle InvalidFaceHandle; + //@} + + typedef PolyConnectivity This; + + //--- iterators --- + + /** \name Mesh Iterators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators for + documentation. + */ + //@{ + /// Linear iterator + typedef Iterators::GenericIteratorT VertexIter; + typedef Iterators::GenericIteratorT HalfedgeIter; + typedef Iterators::GenericIteratorT EdgeIter; + typedef Iterators::GenericIteratorT FaceIter; + + typedef VertexIter ConstVertexIter; + typedef HalfedgeIter ConstHalfedgeIter; + typedef EdgeIter ConstEdgeIter; + typedef FaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + + /* + * Vertex-centered circulators + */ + + /** + * Enumerates 1-ring vertices in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toVertexHandle> + VertexVertexIter; + typedef Iterators::GenericCirculatorT::toVertexHandle> VertexVertexCWIter; + + /** + * Enumerates 1-ring vertices in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toVertexHandle, false> + VertexVertexCCWIter; + + /** + * Enumerates outgoing half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toHalfedgeHandle> + VertexOHalfedgeIter; + typedef Iterators::GenericCirculatorT::toHalfedgeHandle> VertexOHalfedgeCWIter; + + /** + * Enumerates outgoing half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toHalfedgeHandle, false> + VertexOHalfedgeCCWIter; + + /** + * Enumerates incoming half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toOppositeHalfedgeHandle> + VertexIHalfedgeIter; + typedef Iterators::GenericCirculatorT::toOppositeHalfedgeHandle> VertexIHalfedgeCWIter; + + /** + * Enumerates incoming half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toOppositeHalfedgeHandle, false> + VertexIHalfedgeCCWIter; + + /** + * Enumerates incident faces in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toFaceHandle> + VertexFaceIter; + typedef Iterators::GenericCirculatorT::toFaceHandle> VertexFaceCWIter; + + /** + * Enumerates incident faces in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toFaceHandle, false> + VertexFaceCCWIter; + + /** + * Enumerates incident edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toEdgeHandle> + VertexEdgeIter; + typedef Iterators::GenericCirculatorT::toEdgeHandle> VertexEdgeCWIter; + /** + * Enumerates incident edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toEdgeHandle, false> + VertexEdgeCCWIter; + + /** + * Identical to #FaceHalfedgeIter. God knows why this typedef exists. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toHalfedgeHandle> + HalfedgeLoopIter; + typedef Iterators::GenericCirculatorT::toHalfedgeHandle, false> HalfedgeLoopCWIter; + /** + * Identical to #FaceHalfedgeIter. God knows why this typedef exists. + */ + typedef Iterators::GenericCirculatorT::toHalfedgeHandle> + HalfedgeLoopCCWIter; + + typedef VertexVertexIter ConstVertexVertexIter; + typedef VertexVertexCWIter ConstVertexVertexCWIter; + typedef VertexVertexCCWIter ConstVertexVertexCCWIter; + typedef VertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef VertexOHalfedgeCWIter ConstVertexOHalfedgeCWIter; + typedef VertexOHalfedgeCCWIter ConstVertexOHalfedgeCCWIter; + typedef VertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef VertexIHalfedgeCWIter ConstVertexIHalfedgeCWIter; + typedef VertexIHalfedgeCCWIter ConstVertexIHalfedgeCCWIter; + typedef VertexFaceIter ConstVertexFaceIter; + typedef VertexFaceCWIter ConstVertexFaceCWIter; + typedef VertexFaceCCWIter ConstVertexFaceCCWIter; + typedef VertexEdgeIter ConstVertexEdgeIter; + typedef VertexEdgeCWIter ConstVertexEdgeCWIter; + typedef VertexEdgeCCWIter ConstVertexEdgeCCWIter; + + /* + * Face-centered circulators + */ + + /** + * Enumerate incident vertices in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toVertexHandle> + FaceVertexIter; + typedef Iterators::GenericCirculatorT::toVertexHandle> FaceVertexCCWIter; + + /** + * Enumerate incident vertices in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toVertexHandle, false> + FaceVertexCWIter; + + /** + * Enumerate incident half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toHalfedgeHandle> + FaceHalfedgeIter; + typedef Iterators::GenericCirculatorT::toHalfedgeHandle> FaceHalfedgeCCWIter; + + /** + * Enumerate incident half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toHalfedgeHandle, false> + FaceHalfedgeCWIter; + + /** + * Enumerate incident edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toEdgeHandle> + FaceEdgeIter; + typedef Iterators::GenericCirculatorT::toEdgeHandle> FaceEdgeCCWIter; + + /** + * Enumerate incident edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toEdgeHandle, false> + FaceEdgeCWIter; + + /** + * Enumerate adjacent faces in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED::toOppositeFaceHandle> + FaceFaceIter; + typedef Iterators::GenericCirculatorT::toOppositeFaceHandle> FaceFaceCCWIter; + + /** + * Enumerate adjacent faces in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT::toOppositeFaceHandle, false> + FaceFaceCWIter; + + typedef FaceVertexIter ConstFaceVertexIter; + typedef FaceVertexCWIter ConstFaceVertexCWIter; + typedef FaceVertexCCWIter ConstFaceVertexCCWIter; + typedef FaceHalfedgeIter ConstFaceHalfedgeIter; + typedef FaceHalfedgeCWIter ConstFaceHalfedgeCWIter; + typedef FaceHalfedgeCCWIter ConstFaceHalfedgeCCWIter; + typedef FaceEdgeIter ConstFaceEdgeIter; + typedef FaceEdgeCWIter ConstFaceEdgeCWIter; + typedef FaceEdgeCCWIter ConstFaceEdgeCCWIter; + typedef FaceFaceIter ConstFaceFaceIter; + typedef FaceFaceCWIter ConstFaceFaceCWIter; + typedef FaceFaceCCWIter ConstFaceFaceCCWIter; + + /* + * Halfedge circulator + */ + typedef HalfedgeLoopIter ConstHalfedgeLoopIter; + typedef HalfedgeLoopCWIter ConstHalfedgeLoopCWIter; + typedef HalfedgeLoopCCWIter ConstHalfedgeLoopCCWIter; + + //@} + + // --- shortcuts + + /** \name Typedef Shortcuts + Provided for convenience only + */ + //@{ + /// Alias typedef + typedef VertexHandle VHandle; + typedef HalfedgeHandle HHandle; + typedef EdgeHandle EHandle; + typedef FaceHandle FHandle; + + typedef VertexIter VIter; + typedef HalfedgeIter HIter; + typedef EdgeIter EIter; + typedef FaceIter FIter; + + typedef ConstVertexIter CVIter; + typedef ConstHalfedgeIter CHIter; + typedef ConstEdgeIter CEIter; + typedef ConstFaceIter CFIter; + + typedef VertexVertexIter VVIter; + typedef VertexVertexCWIter VVCWIter; + typedef VertexVertexCCWIter VVCCWIter; + typedef VertexOHalfedgeIter VOHIter; + typedef VertexOHalfedgeCWIter VOHCWIter; + typedef VertexOHalfedgeCCWIter VOHCCWIter; + typedef VertexIHalfedgeIter VIHIter; + typedef VertexIHalfedgeCWIter VIHICWter; + typedef VertexIHalfedgeCCWIter VIHICCWter; + typedef VertexEdgeIter VEIter; + typedef VertexEdgeCWIter VECWIter; + typedef VertexEdgeCCWIter VECCWIter; + typedef VertexFaceIter VFIter; + typedef VertexFaceCWIter VFCWIter; + typedef VertexFaceCCWIter VFCCWIter; + typedef FaceVertexIter FVIter; + typedef FaceVertexCWIter FVCWIter; + typedef FaceVertexCCWIter FVCCWIter; + typedef FaceHalfedgeIter FHIter; + typedef FaceHalfedgeCWIter FHCWIter; + typedef FaceHalfedgeCCWIter FHCWWIter; + typedef FaceEdgeIter FEIter; + typedef FaceEdgeCWIter FECWIter; + typedef FaceEdgeCCWIter FECWWIter; + typedef FaceFaceIter FFIter; + + typedef ConstVertexVertexIter CVVIter; + typedef ConstVertexVertexCWIter CVVCWIter; + typedef ConstVertexVertexCCWIter CVVCCWIter; + typedef ConstVertexOHalfedgeIter CVOHIter; + typedef ConstVertexOHalfedgeCWIter CVOHCWIter; + typedef ConstVertexOHalfedgeCCWIter CVOHCCWIter; + typedef ConstVertexIHalfedgeIter CVIHIter; + typedef ConstVertexIHalfedgeCWIter CVIHCWIter; + typedef ConstVertexIHalfedgeCCWIter CVIHCCWIter; + typedef ConstVertexEdgeIter CVEIter; + typedef ConstVertexEdgeCWIter CVECWIter; + typedef ConstVertexEdgeCCWIter CVECCWIter; + typedef ConstVertexFaceIter CVFIter; + typedef ConstVertexFaceCWIter CVFCWIter; + typedef ConstVertexFaceCCWIter CVFCCWIter; + typedef ConstFaceVertexIter CFVIter; + typedef ConstFaceVertexCWIter CFVCWIter; + typedef ConstFaceVertexCCWIter CFVCCWIter; + typedef ConstFaceHalfedgeIter CFHIter; + typedef ConstFaceHalfedgeCWIter CFHCWIter; + typedef ConstFaceHalfedgeCCWIter CFHCCWIter; + typedef ConstFaceEdgeIter CFEIter; + typedef ConstFaceEdgeCWIter CFECWIter; + typedef ConstFaceEdgeCCWIter CFECCWIter; + typedef ConstFaceFaceIter CFFIter; + typedef ConstFaceFaceCWIter CFFCWIter; + typedef ConstFaceFaceCCWIter CFFCCWIter; + //@} + +public: + + PolyConnectivity() {} + virtual ~PolyConnectivity() {} + + inline static bool is_triangles() + { return false; } + + /** assign_connectivity() method. See ArrayKernel::assign_connectivity() + for more details. */ + inline void assign_connectivity(const PolyConnectivity& _other) + { ArrayKernel::assign_connectivity(_other); } + + /** \name Adding items to a mesh + */ + //@{ + + /// Add a new vertex + inline VertexHandle add_vertex() + { return new_vertex(); } + + /** \brief Add and connect a new face + * + * Create a new face consisting of the vertices provided by the vertex handle vector. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles sorted list of vertex handles (also defines order in which the vertices are added to the face) + */ + FaceHandle add_face(const std::vector& _vhandles); + + + /** \brief Add and connect a new face + * + * Create a new face consisting of three vertices provided by the handles. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vh0 First vertex handle + * @param _vh1 Second vertex handle + * @param _vh2 Third vertex handle + */ + FaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2); + + /** \brief Add and connect a new face + * + * Create a new face consisting of four vertices provided by the handles. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vh0 First vertex handle + * @param _vh1 Second vertex handle + * @param _vh2 Third vertex handle + * @param _vh3 Fourth vertex handle + */ + FaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, VertexHandle _vh3); + + /** \brief Add and connect a new face + * + * Create a new face consisting of vertices provided by a handle array. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles pointer to a sorted list of vertex handles (also defines order in which the vertices are added to the face) + * @param _vhs_size number of vertex handles in the array + */ + FaceHandle add_face(const VertexHandle* _vhandles, size_t _vhs_size); + + //@} + + /// \name Deleting mesh items and other connectivity/topology modifications + //@{ + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _he); + + + /** Mark vertex and all incident edges and faces deleted. + Items marked deleted will be removed by garbageCollection(). + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices = true); + + /** Mark edge (two opposite halfedges) and incident faces deleted. + Resulting isolated vertices are marked deleted if + _delete_isolated_vertices is true. Items marked deleted will be + removed by garbageCollection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices=true); + + /** Delete face _fh and resulting degenerated empty halfedges as + well. Resulting isolated vertices will be deleted if + _delete_isolated_vertices is true. + + \attention All item will only be marked to be deleted. They will + actually be removed by calling garbage_collection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_face(FaceHandle _fh, bool _delete_isolated_vertices=true); + + //@} + + /** \name Begin and end iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_begin(); + /// Const begin iterator for vertices + ConstVertexIter vertices_begin() const; + /// End iterator for vertices + VertexIter vertices_end(); + /// Const end iterator for vertices + ConstVertexIter vertices_end() const; + + /// Begin iterator for halfedges + HalfedgeIter halfedges_begin(); + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_begin() const; + /// End iterator for halfedges + HalfedgeIter halfedges_end(); + /// Const end iterator for halfedges + ConstHalfedgeIter halfedges_end() const; + + /// Begin iterator for edges + EdgeIter edges_begin(); + /// Const begin iterator for edges + ConstEdgeIter edges_begin() const; + /// End iterator for edges + EdgeIter edges_end(); + /// Const end iterator for edges + ConstEdgeIter edges_end() const; + + /// Begin iterator for faces + FaceIter faces_begin(); + /// Const begin iterator for faces + ConstFaceIter faces_begin() const; + /// End iterator for faces + FaceIter faces_end(); + /// Const end iterator for faces + ConstFaceIter faces_end() const; + //@} + + + /** \name Begin for skipping iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_sbegin() + { return VertexIter(*this, VertexHandle(0), true); } + /// Const begin iterator for vertices + ConstVertexIter vertices_sbegin() const + { return ConstVertexIter(*this, VertexHandle(0), true); } + + /// Begin iterator for halfedges + HalfedgeIter halfedges_sbegin() + { return HalfedgeIter(*this, HalfedgeHandle(0), true); } + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_sbegin() const + { return ConstHalfedgeIter(*this, HalfedgeHandle(0), true); } + + /// Begin iterator for edges + EdgeIter edges_sbegin() + { return EdgeIter(*this, EdgeHandle(0), true); } + /// Const begin iterator for edges + ConstEdgeIter edges_sbegin() const + { return ConstEdgeIter(*this, EdgeHandle(0), true); } + + /// Begin iterator for faces + FaceIter faces_sbegin() + { return FaceIter(*this, FaceHandle(0), true); } + /// Const begin iterator for faces + ConstFaceIter faces_sbegin() const + { return ConstFaceIter(*this, FaceHandle(0), true); } + + //@} + + //--- circulators --- + + /** \name Vertex and Face circulators + */ + //@{ + + /// vertex - vertex circulator + VertexVertexIter vv_iter(VertexHandle _vh) + { return VertexVertexIter(*this, _vh); } + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwiter(VertexHandle _vh) + { return VertexVertexCWIter(*this, _vh); } + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwiter(VertexHandle _vh) + { return VertexVertexCCWIter(*this, _vh); } + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_iter(VertexHandle _vh) + { return VertexIHalfedgeIter(*this, _vh); } + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwiter(VertexHandle _vh) + { return VertexIHalfedgeCWIter(*this, _vh); } + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwiter(VertexHandle _vh) + { return VertexIHalfedgeCCWIter(*this, _vh); } + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_iter(VertexHandle _vh) + { return VertexOHalfedgeIter(*this, _vh); } + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwiter(VertexHandle _vh) + { return VertexOHalfedgeCWIter(*this, _vh); } + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwiter(VertexHandle _vh) + { return VertexOHalfedgeCCWIter(*this, _vh); } + /// vertex - edge circulator + VertexEdgeIter ve_iter(VertexHandle _vh) + { return VertexEdgeIter(*this, _vh); } + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwiter(VertexHandle _vh) + { return VertexEdgeCWIter(*this, _vh); } + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwiter(VertexHandle _vh) + { return VertexEdgeCCWIter(*this, _vh); } + /// vertex - face circulator + VertexFaceIter vf_iter(VertexHandle _vh) + { return VertexFaceIter(*this, _vh); } + /// vertex - face circulator cw + VertexFaceCWIter vf_cwiter(VertexHandle _vh) + { return VertexFaceCWIter(*this, _vh); } + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwiter(VertexHandle _vh) + { return VertexFaceCCWIter(*this, _vh); } + + /// const vertex circulator + ConstVertexVertexIter cvv_iter(VertexHandle _vh) const + { return ConstVertexVertexIter(*this, _vh); } + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwiter(VertexHandle _vh) const + { return ConstVertexVertexCWIter(*this, _vh); } + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwiter(VertexHandle _vh) const + { return ConstVertexVertexCCWIter(*this, _vh); } + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_iter(VertexHandle _vh) const + { return ConstVertexIHalfedgeIter(*this, _vh); } + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwiter(VertexHandle _vh) const + { return ConstVertexIHalfedgeCWIter(*this, _vh); } + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwiter(VertexHandle _vh) const + { return ConstVertexIHalfedgeCCWIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_iter(VertexHandle _vh) const + { return ConstVertexOHalfedgeIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwiter(VertexHandle _vh) const + { return ConstVertexOHalfedgeCWIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwiter(VertexHandle _vh) const + { return ConstVertexOHalfedgeCCWIter(*this, _vh); } + /// const vertex - edge circulator + ConstVertexEdgeIter cve_iter(VertexHandle _vh) const + { return ConstVertexEdgeIter(*this, _vh); } + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwiter(VertexHandle _vh) const + { return ConstVertexEdgeCWIter(*this, _vh); } + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwiter(VertexHandle _vh) const + { return ConstVertexEdgeCCWIter(*this, _vh); } + /// const vertex - face circulator + ConstVertexFaceIter cvf_iter(VertexHandle _vh) const + { return ConstVertexFaceIter(*this, _vh); } + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwiter(VertexHandle _vh) const + { return ConstVertexFaceCWIter(*this, _vh); } + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwiter(VertexHandle _vh) const + { return ConstVertexFaceCCWIter(*this, _vh); } + + /// face - vertex circulator + FaceVertexIter fv_iter(FaceHandle _fh) + { return FaceVertexIter(*this, _fh); } + /// face - vertex circulator cw + FaceVertexCWIter fv_cwiter(FaceHandle _fh) + { return FaceVertexCWIter(*this, _fh); } + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwiter(FaceHandle _fh) + { return FaceVertexCCWIter(*this, _fh); } + /// face - halfedge circulator + FaceHalfedgeIter fh_iter(FaceHandle _fh) + { return FaceHalfedgeIter(*this, _fh); } + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwiter(FaceHandle _fh) + { return FaceHalfedgeCWIter(*this, _fh); } + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwiter(FaceHandle _fh) + { return FaceHalfedgeCCWIter(*this, _fh); } + /// face - edge circulator + FaceEdgeIter fe_iter(FaceHandle _fh) + { return FaceEdgeIter(*this, _fh); } + /// face - edge circulator cw + FaceEdgeCWIter fe_cwiter(FaceHandle _fh) + { return FaceEdgeCWIter(*this, _fh); } + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwiter(FaceHandle _fh) + { return FaceEdgeCCWIter(*this, _fh); } + /// face - face circulator + FaceFaceIter ff_iter(FaceHandle _fh) + { return FaceFaceIter(*this, _fh); } + /// face - face circulator cw + FaceFaceCWIter ff_cwiter(FaceHandle _fh) + { return FaceFaceCWIter(*this, _fh); } + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwiter(FaceHandle _fh) + { return FaceFaceCCWIter(*this, _fh); } + + /// const face - vertex circulator + ConstFaceVertexIter cfv_iter(FaceHandle _fh) const + { return ConstFaceVertexIter(*this, _fh); } + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwiter(FaceHandle _fh) const + { return ConstFaceVertexCWIter(*this, _fh); } + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwiter(FaceHandle _fh) const + { return ConstFaceVertexCCWIter(*this, _fh); } + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_iter(FaceHandle _fh) const + { return ConstFaceHalfedgeIter(*this, _fh); } + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwiter(FaceHandle _fh) const + { return ConstFaceHalfedgeCWIter(*this, _fh); } + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwiter(FaceHandle _fh) const + { return ConstFaceHalfedgeCCWIter(*this, _fh); } + /// const face - edge circulator + ConstFaceEdgeIter cfe_iter(FaceHandle _fh) const + { return ConstFaceEdgeIter(*this, _fh); } + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwiter(FaceHandle _fh) const + { return ConstFaceEdgeCWIter(*this, _fh); } + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwiter(FaceHandle _fh) const + { return ConstFaceEdgeCCWIter(*this, _fh); } + /// const face - face circulator + ConstFaceFaceIter cff_iter(FaceHandle _fh) const + { return ConstFaceFaceIter(*this, _fh); } + /// const face - face circulator cw + ConstFaceFaceCWIter cff_cwiter(FaceHandle _fh) const + { return ConstFaceFaceCWIter(*this, _fh); } + /// const face - face circulator + ConstFaceFaceCCWIter cff_ccwiter(FaceHandle _fh) const + { return ConstFaceFaceCCWIter(*this, _fh); } + + // 'begin' circulators + + /// vertex - vertex circulator + VertexVertexIter vv_begin(VertexHandle _vh) + { return VertexVertexIter(*this, _vh); } + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwbegin(VertexHandle _vh) + { return VertexVertexCWIter(*this, _vh); } + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwbegin(VertexHandle _vh) + { return VertexVertexCCWIter(*this, _vh); } + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_begin(VertexHandle _vh) + { return VertexIHalfedgeIter(*this, _vh); } + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwbegin(VertexHandle _vh) + { return VertexIHalfedgeCWIter(*this, _vh); } + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwbegin(VertexHandle _vh) + { return VertexIHalfedgeCCWIter(*this, _vh); } + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_begin(VertexHandle _vh) + { return VertexOHalfedgeIter(*this, _vh); } + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwbegin(VertexHandle _vh) + { return VertexOHalfedgeCWIter(*this, _vh); } + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwbegin(VertexHandle _vh) + { return VertexOHalfedgeCCWIter(*this, _vh); } + /// vertex - edge circulator + VertexEdgeIter ve_begin(VertexHandle _vh) + { return VertexEdgeIter(*this, _vh); } + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwbegin(VertexHandle _vh) + { return VertexEdgeCWIter(*this, _vh); } + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwbegin(VertexHandle _vh) + { return VertexEdgeCCWIter(*this, _vh); } + /// vertex - face circulator + VertexFaceIter vf_begin(VertexHandle _vh) + { return VertexFaceIter(*this, _vh); } + /// vertex - face circulator cw + VertexFaceCWIter vf_cwbegin(VertexHandle _vh) + { return VertexFaceCWIter(*this, _vh); } + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwbegin(VertexHandle _vh) + { return VertexFaceCCWIter(*this, _vh); } + + + /// const vertex circulator + ConstVertexVertexIter cvv_begin(VertexHandle _vh) const + { return ConstVertexVertexIter(*this, _vh); } + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwbegin(VertexHandle _vh) const + { return ConstVertexVertexCWIter(*this, _vh); } + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwbegin(VertexHandle _vh) const + { return ConstVertexVertexCCWIter(*this, _vh); } + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_begin(VertexHandle _vh) const + { return ConstVertexIHalfedgeIter(*this, _vh); } + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwbegin(VertexHandle _vh) const + { return ConstVertexIHalfedgeCWIter(*this, _vh); } + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwbegin(VertexHandle _vh) const + { return ConstVertexIHalfedgeCCWIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_begin(VertexHandle _vh) const + { return ConstVertexOHalfedgeIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwbegin(VertexHandle _vh) const + { return ConstVertexOHalfedgeCWIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwbegin(VertexHandle _vh) const + { return ConstVertexOHalfedgeCCWIter(*this, _vh); } + /// const vertex - edge circulator + ConstVertexEdgeIter cve_begin(VertexHandle _vh) const + { return ConstVertexEdgeIter(*this, _vh); } + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwbegin(VertexHandle _vh) const + { return ConstVertexEdgeCWIter(*this, _vh); } + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwbegin(VertexHandle _vh) const + { return ConstVertexEdgeCCWIter(*this, _vh); } + /// const vertex - face circulator + ConstVertexFaceIter cvf_begin(VertexHandle _vh) const + { return ConstVertexFaceIter(*this, _vh); } + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwbegin(VertexHandle _vh) const + { return ConstVertexFaceCWIter(*this, _vh); } + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwbegin(VertexHandle _vh) const + { return ConstVertexFaceCCWIter(*this, _vh); } + + /// face - vertex circulator + FaceVertexIter fv_begin(FaceHandle _fh) + { return FaceVertexIter(*this, _fh); } + /// face - vertex circulator cw + FaceVertexCWIter fv_cwbegin(FaceHandle _fh) + { return FaceVertexCWIter(*this, _fh); } + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwbegin(FaceHandle _fh) + { return FaceVertexCCWIter(*this, _fh); } + /// face - halfedge circulator + FaceHalfedgeIter fh_begin(FaceHandle _fh) + { return FaceHalfedgeIter(*this, _fh); } + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwbegin(FaceHandle _fh) + { return FaceHalfedgeCWIter(*this, _fh); } + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwbegin(FaceHandle _fh) + { return FaceHalfedgeCCWIter(*this, _fh); } + /// face - edge circulator + FaceEdgeIter fe_begin(FaceHandle _fh) + { return FaceEdgeIter(*this, _fh); } + /// face - edge circulator cw + FaceEdgeCWIter fe_cwbegin(FaceHandle _fh) + { return FaceEdgeCWIter(*this, _fh); } + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwbegin(FaceHandle _fh) + { return FaceEdgeCCWIter(*this, _fh); } + /// face - face circulator + FaceFaceIter ff_begin(FaceHandle _fh) + { return FaceFaceIter(*this, _fh); } + /// face - face circulator cw + FaceFaceCWIter ff_cwbegin(FaceHandle _fh) + { return FaceFaceCWIter(*this, _fh); } + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwbegin(FaceHandle _fh) + { return FaceFaceCCWIter(*this, _fh); } + /// halfedge circulator + HalfedgeLoopIter hl_begin(HalfedgeHandle _heh) + { return HalfedgeLoopIter(*this, _heh); } + /// halfedge circulator + HalfedgeLoopCWIter hl_cwbegin(HalfedgeHandle _heh) + { return HalfedgeLoopCWIter(*this, _heh); } + /// halfedge circulator ccw + HalfedgeLoopCCWIter hl_ccwbegin(HalfedgeHandle _heh) + { return HalfedgeLoopCCWIter(*this, _heh); } + + /// const face - vertex circulator + ConstFaceVertexIter cfv_begin(FaceHandle _fh) const + { return ConstFaceVertexIter(*this, _fh); } + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwbegin(FaceHandle _fh) const + { return ConstFaceVertexCWIter(*this, _fh); } + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwbegin(FaceHandle _fh) const + { return ConstFaceVertexCCWIter(*this, _fh); } + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_begin(FaceHandle _fh) const + { return ConstFaceHalfedgeIter(*this, _fh); } + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwbegin(FaceHandle _fh) const + { return ConstFaceHalfedgeCWIter(*this, _fh); } + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwbegin(FaceHandle _fh) const + { return ConstFaceHalfedgeCCWIter(*this, _fh); } + /// const face - edge circulator + ConstFaceEdgeIter cfe_begin(FaceHandle _fh) const + { return ConstFaceEdgeIter(*this, _fh); } + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwbegin(FaceHandle _fh) const + { return ConstFaceEdgeCWIter(*this, _fh); } + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwbegin(FaceHandle _fh) const + { return ConstFaceEdgeCCWIter(*this, _fh); } + /// const face - face circulator + ConstFaceFaceIter cff_begin(FaceHandle _fh) const + { return ConstFaceFaceIter(*this, _fh); } + /// const face - face circulator cw + ConstFaceFaceCWIter cff_cwbegin(FaceHandle _fh) const + { return ConstFaceFaceCWIter(*this, _fh); } + /// const face - face circulator ccw + ConstFaceFaceCCWIter cff_ccwbegin(FaceHandle _fh) const + { return ConstFaceFaceCCWIter(*this, _fh); } + /// const halfedge circulator + ConstHalfedgeLoopIter chl_begin(HalfedgeHandle _heh) const + { return ConstHalfedgeLoopIter(*this, _heh); } + /// const halfedge circulator cw + ConstHalfedgeLoopCWIter chl_cwbegin(HalfedgeHandle _heh) const + { return ConstHalfedgeLoopCWIter(*this, _heh); } + /// const halfedge circulator ccw + ConstHalfedgeLoopCCWIter chl_ccwbegin(HalfedgeHandle _heh) const + { return ConstHalfedgeLoopCCWIter(*this, _heh); } + + // 'end' circulators + + /// vertex - vertex circulator + VertexVertexIter vv_end(VertexHandle _vh) + { return VertexVertexIter(*this, _vh, true); } + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwend(VertexHandle _vh) + { return VertexVertexCWIter(*this, _vh, true); } + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwend(VertexHandle _vh) + { return VertexVertexCCWIter(*this, _vh, true); } + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_end(VertexHandle _vh) + { return VertexIHalfedgeIter(*this, _vh, true); } + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwend(VertexHandle _vh) + { return VertexIHalfedgeCWIter(*this, _vh, true); } + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwend(VertexHandle _vh) + { return VertexIHalfedgeCCWIter(*this, _vh, true); } + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_end(VertexHandle _vh) + { return VertexOHalfedgeIter(*this, _vh, true); } + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwend(VertexHandle _vh) + { return VertexOHalfedgeCWIter(*this, _vh, true); } + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwend(VertexHandle _vh) + { return VertexOHalfedgeCCWIter(*this, _vh, true); } + /// vertex - edge circulator + VertexEdgeIter ve_end(VertexHandle _vh) + { return VertexEdgeIter(*this, _vh, true); } + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwend(VertexHandle _vh) + { return VertexEdgeCWIter(*this, _vh, true); } + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwend(VertexHandle _vh) + { return VertexEdgeCCWIter(*this, _vh, true); } + /// vertex - face circulator + VertexFaceIter vf_end(VertexHandle _vh) + { return VertexFaceIter(*this, _vh, true); } + /// vertex - face circulator cw + VertexFaceCWIter vf_cwend(VertexHandle _vh) + { return VertexFaceCWIter(*this, _vh, true); } + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwend(VertexHandle _vh) + { return VertexFaceCCWIter(*this, _vh, true); } + + /// const vertex circulator + ConstVertexVertexIter cvv_end(VertexHandle _vh) const + { return ConstVertexVertexIter(*this, _vh, true); } + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwend(VertexHandle _vh) const + { return ConstVertexVertexCWIter(*this, _vh, true); } + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwend(VertexHandle _vh) const + { return ConstVertexVertexCCWIter(*this, _vh, true); } + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_end(VertexHandle _vh) const + { return ConstVertexIHalfedgeIter(*this, _vh, true); } + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwend(VertexHandle _vh) const + { return ConstVertexIHalfedgeCWIter(*this, _vh, true); } + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwend(VertexHandle _vh) const + { return ConstVertexIHalfedgeCCWIter(*this, _vh, true); } + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_end(VertexHandle _vh) const + { return ConstVertexOHalfedgeIter(*this, _vh, true); } + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwend(VertexHandle _vh) const + { return ConstVertexOHalfedgeCWIter(*this, _vh, true); } + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwend(VertexHandle _vh) const + { return ConstVertexOHalfedgeCCWIter(*this, _vh, true); } + /// const vertex - edge circulator + ConstVertexEdgeIter cve_end(VertexHandle _vh) const + { return ConstVertexEdgeIter(*this, _vh, true); } + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwend(VertexHandle _vh) const + { return ConstVertexEdgeCWIter(*this, _vh, true); } + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwend(VertexHandle _vh) const + { return ConstVertexEdgeCCWIter(*this, _vh, true); } + /// const vertex - face circulator + ConstVertexFaceIter cvf_end(VertexHandle _vh) const + { return ConstVertexFaceIter(*this, _vh, true); } + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwend(VertexHandle _vh) const + { return ConstVertexFaceCWIter(*this, _vh, true); } + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwend(VertexHandle _vh) const + { return ConstVertexFaceCCWIter(*this, _vh, true); } + + /// face - vertex circulator + FaceVertexIter fv_end(FaceHandle _fh) + { return FaceVertexIter(*this, _fh, true); } + /// face - vertex circulator cw + FaceVertexCWIter fv_cwend(FaceHandle _fh) + { return FaceVertexCWIter(*this, _fh, true); } + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwend(FaceHandle _fh) + { return FaceVertexCCWIter(*this, _fh, true); } + /// face - halfedge circulator + FaceHalfedgeIter fh_end(FaceHandle _fh) + { return FaceHalfedgeIter(*this, _fh, true); } + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwend(FaceHandle _fh) + { return FaceHalfedgeCWIter(*this, _fh, true); } + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwend(FaceHandle _fh) + { return FaceHalfedgeCCWIter(*this, _fh, true); } + /// face - edge circulator + FaceEdgeIter fe_end(FaceHandle _fh) + { return FaceEdgeIter(*this, _fh, true); } + /// face - edge circulator cw + FaceEdgeCWIter fe_cwend(FaceHandle _fh) + { return FaceEdgeCWIter(*this, _fh, true); } + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwend(FaceHandle _fh) + { return FaceEdgeCCWIter(*this, _fh, true); } + /// face - face circulator + FaceFaceIter ff_end(FaceHandle _fh) + { return FaceFaceIter(*this, _fh, true); } + /// face - face circulator cw + FaceFaceCWIter ff_cwend(FaceHandle _fh) + { return FaceFaceCWIter(*this, _fh, true); } + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwend(FaceHandle _fh) + { return FaceFaceCCWIter(*this, _fh, true); } + /// face - face circulator + HalfedgeLoopIter hl_end(HalfedgeHandle _heh) + { return HalfedgeLoopIter(*this, _heh, true); } + /// face - face circulator cw + HalfedgeLoopCWIter hl_cwend(HalfedgeHandle _heh) + { return HalfedgeLoopCWIter(*this, _heh, true); } + /// face - face circulator ccw + HalfedgeLoopCCWIter hl_ccwend(HalfedgeHandle _heh) + { return HalfedgeLoopCCWIter(*this, _heh, true); } + + /// const face - vertex circulator + ConstFaceVertexIter cfv_end(FaceHandle _fh) const + { return ConstFaceVertexIter(*this, _fh, true); } + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwend(FaceHandle _fh) const + { return ConstFaceVertexCWIter(*this, _fh, true); } + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwend(FaceHandle _fh) const + { return ConstFaceVertexCCWIter(*this, _fh, true); } + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_end(FaceHandle _fh) const + { return ConstFaceHalfedgeIter(*this, _fh, true); } + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwend(FaceHandle _fh) const + { return ConstFaceHalfedgeCWIter(*this, _fh, true); } + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwend(FaceHandle _fh) const + { return ConstFaceHalfedgeCCWIter(*this, _fh, true); } + /// const face - edge circulator + ConstFaceEdgeIter cfe_end(FaceHandle _fh) const + { return ConstFaceEdgeIter(*this, _fh, true); } + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwend(FaceHandle _fh) const + { return ConstFaceEdgeCWIter(*this, _fh, true); } + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwend(FaceHandle _fh) const + { return ConstFaceEdgeCCWIter(*this, _fh, true); } + /// const face - face circulator + ConstFaceFaceIter cff_end(FaceHandle _fh) const + { return ConstFaceFaceIter(*this, _fh, true); } + /// const face - face circulator + ConstFaceFaceCWIter cff_cwend(FaceHandle _fh) const + { return ConstFaceFaceCWIter(*this, _fh, true); } + /// const face - face circulator + ConstFaceFaceCCWIter cff_ccwend(FaceHandle _fh) const + { return ConstFaceFaceCCWIter(*this, _fh, true); } + /// const face - face circulator + ConstHalfedgeLoopIter chl_end(HalfedgeHandle _heh) const + { return ConstHalfedgeLoopIter(*this, _heh, true); } + /// const face - face circulator cw + ConstHalfedgeLoopCWIter chl_cwend(HalfedgeHandle _heh) const + { return ConstHalfedgeLoopCWIter(*this, _heh, true); } + /// const face - face circulator ccw + ConstHalfedgeLoopCCWIter chl_ccwend(HalfedgeHandle _heh) const + { return ConstHalfedgeLoopCCWIter(*this, _heh, true); } + //@} + + /** @name Range based iterators and circulators */ + //@{ + + /// Generic class for vertex/halfedge/edge/face ranges. + template< + typename CONTAINER_TYPE, + typename ITER_TYPE, + ITER_TYPE (CONTAINER_TYPE::*begin_fn)() const, + ITER_TYPE (CONTAINER_TYPE::*end_fn)() const> + class EntityRange { + public: + typedef ITER_TYPE iterator; + typedef ITER_TYPE const_iterator; + + EntityRange(CONTAINER_TYPE &container) : container_(container) {} + ITER_TYPE begin() const { return (container_.*begin_fn)(); } + ITER_TYPE end() const { return (container_.*end_fn)(); } + + private: + CONTAINER_TYPE &container_; + }; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstVertexIter, + &PolyConnectivity::vertices_begin, + &PolyConnectivity::vertices_end> ConstVertexRange; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstVertexIter, + &PolyConnectivity::vertices_sbegin, + &PolyConnectivity::vertices_end> ConstVertexRangeSkipping; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstHalfedgeIter, + &PolyConnectivity::halfedges_begin, + &PolyConnectivity::halfedges_end> ConstHalfedgeRange; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstHalfedgeIter, + &PolyConnectivity::halfedges_sbegin, + &PolyConnectivity::halfedges_end> ConstHalfedgeRangeSkipping; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstEdgeIter, + &PolyConnectivity::edges_begin, + &PolyConnectivity::edges_end> ConstEdgeRange; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstEdgeIter, + &PolyConnectivity::edges_sbegin, + &PolyConnectivity::edges_end> ConstEdgeRangeSkipping; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstFaceIter, + &PolyConnectivity::faces_begin, + &PolyConnectivity::faces_end> ConstFaceRange; + typedef EntityRange< + const PolyConnectivity, + PolyConnectivity::ConstFaceIter, + &PolyConnectivity::faces_sbegin, + &PolyConnectivity::faces_end> ConstFaceRangeSkipping; + + /** + * @return The vertices as a range object suitable + * for C++11 range based for loops. Will skip deleted vertices. + */ + ConstVertexRangeSkipping vertices() const { return ConstVertexRangeSkipping(*this); } + + /** + * @return The vertices as a range object suitable + * for C++11 range based for loops. Will include deleted vertices. + */ + ConstVertexRange all_vertices() const { return ConstVertexRange(*this); } + + /** + * @return The halfedges as a range object suitable + * for C++11 range based for loops. Will skip deleted halfedges. + */ + ConstHalfedgeRangeSkipping halfedges() const { return ConstHalfedgeRangeSkipping(*this); } + + /** + * @return The halfedges as a range object suitable + * for C++11 range based for loops. Will include deleted halfedges. + */ + ConstHalfedgeRange all_halfedges() const { return ConstHalfedgeRange(*this); } + + /** + * @return The edges as a range object suitable + * for C++11 range based for loops. Will skip deleted edges. + */ + ConstEdgeRangeSkipping edges() const { return ConstEdgeRangeSkipping(*this); } + + /** + * @return The edges as a range object suitable + * for C++11 range based for loops. Will include deleted edges. + */ + ConstEdgeRange all_edges() const { return ConstEdgeRange(*this); } + + /** + * @return The faces as a range object suitable + * for C++11 range based for loops. Will skip deleted faces. + */ + ConstFaceRangeSkipping faces() const { return ConstFaceRangeSkipping(*this); } + + /** + * @return The faces as a range object suitable + * for C++11 range based for loops. Will include deleted faces. + */ + ConstFaceRange all_faces() const { return ConstFaceRange(*this); } + + /// Generic class for iterator ranges. + template< + typename CONTAINER_TYPE, + typename ITER_TYPE, + typename CENTER_ENTITY_TYPE, + ITER_TYPE (CONTAINER_TYPE::*begin_fn)(CENTER_ENTITY_TYPE) const, + ITER_TYPE (CONTAINER_TYPE::*end_fn)(CENTER_ENTITY_TYPE) const> + class CirculatorRange { + public: + typedef ITER_TYPE iterator; + typedef ITER_TYPE const_iterator; + + CirculatorRange( + const CONTAINER_TYPE &container, + CENTER_ENTITY_TYPE center) : + container_(container), center_(center) {} + ITER_TYPE begin() const { return (container_.*begin_fn)(center_); } + ITER_TYPE end() const { return (container_.*end_fn)(center_); } + + private: + const CONTAINER_TYPE &container_; + CENTER_ENTITY_TYPE center_; + }; + + typedef CirculatorRange< + PolyConnectivity, + ConstVertexVertexCWIter, + VertexHandle, + &PolyConnectivity::cvv_cwbegin, + &PolyConnectivity::cvv_cwend> ConstVertexVertexRange; + typedef CirculatorRange< + PolyConnectivity, + ConstVertexIHalfedgeIter, + VertexHandle, + &PolyConnectivity::cvih_begin, + &PolyConnectivity::cvih_end> ConstVertexIHalfedgeRange; + typedef CirculatorRange< + PolyConnectivity, + ConstVertexOHalfedgeIter, VertexHandle, + &PolyConnectivity::cvoh_begin, + &PolyConnectivity::cvoh_end> ConstVertexOHalfedgeRange; + typedef CirculatorRange< + PolyConnectivity, + ConstVertexEdgeIter, + VertexHandle, + &PolyConnectivity::cve_begin, + &PolyConnectivity::cve_end> ConstVertexEdgeRange; + typedef CirculatorRange< + PolyConnectivity, + ConstVertexFaceIter, + VertexHandle, + &PolyConnectivity::cvf_begin, + &PolyConnectivity::cvf_end> ConstVertexFaceRange; + typedef CirculatorRange< + PolyConnectivity, + ConstFaceVertexIter, + FaceHandle, + &PolyConnectivity::cfv_begin, + &PolyConnectivity::cfv_end> ConstFaceVertexRange; + typedef CirculatorRange< + PolyConnectivity, + ConstFaceHalfedgeIter, + FaceHandle, + &PolyConnectivity::cfh_begin, + &PolyConnectivity::cfh_end> ConstFaceHalfedgeRange; + typedef CirculatorRange< + PolyConnectivity, + ConstFaceEdgeIter, + FaceHandle, + &PolyConnectivity::cfe_begin, + &PolyConnectivity::cfe_end> ConstFaceEdgeRange; + typedef CirculatorRange< + PolyConnectivity, + ConstFaceFaceIter, + FaceHandle, + &PolyConnectivity::cff_begin, + &PolyConnectivity::cff_end> ConstFaceFaceRange; + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexRange vv_range(VertexHandle _vh) const { + return ConstVertexVertexRange(*this, _vh); + } + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeRange vih_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeRange(*this, _vh); + } + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeRange voh_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeRange(*this, _vh); + } + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeRange ve_range(VertexHandle _vh) const { + return ConstVertexEdgeRange(*this, _vh); + } + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceRange vf_range(VertexHandle _vh) const { + return ConstVertexFaceRange(*this, _vh); + } + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexRange fv_range(FaceHandle _fh) const { + return ConstFaceVertexRange(*this, _fh); + } + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeRange fh_range(FaceHandle _fh) const { + return ConstFaceHalfedgeRange(*this, _fh); + } + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeRange fe_range(FaceHandle _fh) const { + return ConstFaceEdgeRange(*this, _fh); + } + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceRange ff_range(FaceHandle _fh) const { + return ConstFaceFaceRange(*this, _fh); + } + + //@} + + //=========================================================================== + /** @name Boundary and manifold tests + * @{ */ + //=========================================================================== + + /** \brief Check if the halfedge is at the boundary + * + * The halfedge is at the boundary, if no face is incident to it. + * + * @param _heh HalfedgeHandle to test + * @return boundary? + */ + bool is_boundary(HalfedgeHandle _heh) const + { return ArrayKernel::is_boundary(_heh); } + + /** \brief Is the edge a boundary edge? + * + * Checks it the edge _eh is a boundary edge, i.e. is one of its halfedges + * a boundary halfedge. + * + * @param _eh Edge handle to test + * @return boundary? + */ + bool is_boundary(EdgeHandle _eh) const + { + return (is_boundary(halfedge_handle(_eh, 0)) || + is_boundary(halfedge_handle(_eh, 1))); + } + + /** \brief Is vertex _vh a boundary vertex ? + * + * Checks if the associated halfedge (which would on a boundary be the outside + * halfedge), is connected to a face. Which is equivalent, if the vertex is + * at the boundary of the mesh, as OpenMesh will make sure, that if there is a + * boundary halfedge at the vertex, the halfedge will be the one which is associated + * to the vertex. + * + * @param _vh VertexHandle to test + * @return boundary? + */ + bool is_boundary(VertexHandle _vh) const + { + HalfedgeHandle heh(halfedge_handle(_vh)); + return (!(heh.is_valid() && face_handle(heh).is_valid())); + } + + /** \brief Check if face is at the boundary + * + * Is face _fh at boundary, i.e. is one of its edges (or vertices) + * a boundary edge? + * + * @param _fh Check this face + * @param _check_vertex If \c true, check the corner vertices of the face, too. + * @return boundary? + */ + bool is_boundary(FaceHandle _fh, bool _check_vertex=false) const; + + /** \brief Is (the mesh at) vertex _vh two-manifold ? + * + * The vertex is non-manifold if more than one gap exists, i.e. + * more than one outgoing boundary halfedge. If (at least) one + * boundary halfedge exists, the vertex' halfedge must be a + * boundary halfedge. + * + * @param _vh VertexHandle to test + * @return manifold? + */ + bool is_manifold(VertexHandle _vh) const; + + /** @} */ + + // --- shortcuts --- + + /// returns the face handle of the opposite halfedge + inline FaceHandle opposite_face_handle(HalfedgeHandle _heh) const + { return face_handle(opposite_halfedge_handle(_heh)); } + + // --- misc --- + + /** Adjust outgoing halfedge handle for vertices, so that it is a + boundary halfedge whenever possible. + */ + void adjust_outgoing_halfedge(VertexHandle _vh); + + /// Find halfedge from _vh0 to _vh1. Returns invalid handle if not found. + HalfedgeHandle find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh) const; + /// Vertex valence + uint valence(VertexHandle _vh) const; + /// Face valence + uint valence(FaceHandle _fh) const; + + // --- connectivity operattions + + /** Halfedge collapse: collapse the from-vertex of halfedge _heh + into its to-vertex. + + \attention Needs vertex/edge/face status attribute in order to + delete the items that degenerate. + + \note The from vertex is marked as deleted while the to vertex will still exist. + + \note This function does not perform a garbage collection. It + only marks degenerate items as deleted. + + \attention A halfedge collapse may lead to topological inconsistencies. + Therefore you should check this using is_collapse_ok(). + */ + void collapse(HalfedgeHandle _heh); + /** return true if the this the only link between the faces adjacent to _eh. + _eh is allowed to be boundary, in which case true is returned iff _eh is + the only boundary edge of its ajdacent face. + */ + bool is_simple_link(EdgeHandle _eh) const; + /** return true if _fh shares only one edge with all of its adjacent faces. + Boundary is treated as one face, i.e., the function false if _fh has more + than one boundary edge. + */ + bool is_simply_connected(FaceHandle _fh) const; + /** Removes the edge _eh. Its adjacent faces are merged. _eh and one of the + adjacent faces are set deleted. The handle of the remaining face is + returned (InvalidFaceHandle is returned if _eh is a boundary edge). + + \pre is_simple_link(_eh). This ensures that there are no hole faces + or isolated vertices appearing in result of the operation. + + \attention Needs the Attributes::Status attribute for edges and faces. + + \note This function does not perform a garbage collection. It + only marks items as deleted. + */ + FaceHandle remove_edge(EdgeHandle _eh); + /** Inverse of remove_edge. _eh should be the handle of the edge and the + vertex and halfedge handles pointed by edge(_eh) should be valid. + */ + void reinsert_edge(EdgeHandle _eh); + /** Inserts an edge between to_vh(_prev_heh) and from_vh(_next_heh). + A new face is created started at heh0 of the inserted edge and + its halfedges loop includes both _prev_heh and _next_heh. If an + old face existed which includes the argument halfedges, it is + split at the new edge. heh0 is returned. + + \note assumes _prev_heh and _next_heh are either boundary or pointed + to the same face + */ + HalfedgeHandle insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh); + + /** \brief Face split (= 1-to-n split). + * + * Split an arbitrary face into triangles by connecting each vertex of fh to vh. + * + * \note fh will remain valid (it will become one of the triangles) + * \note the halfedge handles of the new triangles will point to the old halfeges + * + * \note The properties of the new faces and all other new primitives will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle of the new vertex that will be inserted in the face + */ + void split(FaceHandle _fh, VertexHandle _vh); + + /** \brief Face split (= 1-to-n split). + * + * Split an arbitrary face into triangles by connecting each vertex of fh to vh. + * + * \note fh will remain valid (it will become one of the triangles) + * \note the halfedge handles of the new triangles will point to the old halfeges + * + * \note The properties of the new faces will be adjusted to the properties of the original faces + * \note Properties of the new edges and halfedges will be undefined + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle of the new vertex that will be inserted in the face + */ + void split_copy(FaceHandle _fh, VertexHandle _vh); + + /** \brief Triangulate the face _fh + + Split an arbitrary face into triangles by connecting + each vertex of fh after its second to vh. + + \note _fh will remain valid (it will become one of the + triangles) + + \note The halfedge handles of the new triangles will + point to the old halfedges + + @param _fh Handle of the face that should be triangulated + */ + void triangulate(FaceHandle _fh); + + /** \brief triangulate the entire mesh + */ + void triangulate(); + + /** Edge split (inserts a vertex on the edge only) + * + * This edge split only splits the edge without introducing new faces! + * As this is for polygonal meshes, we can have valence 2 vertices here. + * + * \note The properties of the new edges and halfedges will be undefined! + * + * @param _eh Handle of the edge, that will be splitted + * @param _vh Handle of the vertex that will be inserted at the edge + */ + void split_edge(EdgeHandle _eh, VertexHandle _vh); + + /** Edge split (inserts a vertex on the edge only) + * + * This edge split only splits the edge without introducing new faces! + * As this is for polygonal meshes, we can have valence 2 vertices here. + * + * \note The properties of the new edge will be copied from the splitted edge + * \note Properties of the new halfedges will be undefined + * + * @param _eh Handle of the edge, that will be splitted + * @param _vh Handle of the vertex that will be inserted at the edge + */ + void split_edge_copy(EdgeHandle _eh, VertexHandle _vh); + + + /** \name Generic handle derefertiation. + Calls the respective vertex(), halfedge(), edge(), face() + method of the mesh kernel. + */ + //@{ + /// Get item from handle + const Vertex& deref(VertexHandle _h) const { return vertex(_h); } + Vertex& deref(VertexHandle _h) { return vertex(_h); } + const Halfedge& deref(HalfedgeHandle _h) const { return halfedge(_h); } + Halfedge& deref(HalfedgeHandle _h) { return halfedge(_h); } + const Edge& deref(EdgeHandle _h) const { return edge(_h); } + Edge& deref(EdgeHandle _h) { return edge(_h); } + const Face& deref(FaceHandle _h) const { return face(_h); } + Face& deref(FaceHandle _h) { return face(_h); } + //@} + +protected: + /// Helper for halfedge collapse + void collapse_edge(HalfedgeHandle _hh); + /// Helper for halfedge collapse + void collapse_loop(HalfedgeHandle _hh); + + + +private: // Working storage for add_face() + struct AddFaceEdgeInfo + { + HalfedgeHandle halfedge_handle; + bool is_new; + bool needs_adjust; + }; + std::vector edgeData_; // + std::vector > next_cache_; // cache for set_next_halfedge and vertex' set_halfedge + +}; + +}//namespace OpenMesh + +#endif//OPENMESH_POLYCONNECTIVITY_HH diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMeshT.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMeshT.cc new file mode 100644 index 0000000..64fc991 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMeshT.cc @@ -0,0 +1,463 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS PolyMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_POLYMESH_C + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== IMPLEMENTATION ========================================================== + +template +uint PolyMeshT::find_feature_edges(Scalar _angle_tresh) +{ + assert(Kernel::has_edge_status());//this function needs edge status property + uint n_feature_edges = 0; + for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it) + { + if (fabs(calc_dihedral_angle(*e_it)) > _angle_tresh) + {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh) + this->status(*e_it).set_feature(true); + n_feature_edges++; + } + else + { + this->status(*e_it).set_feature(false); + } + } + return n_feature_edges; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal(FaceHandle _fh) const +{ + return calc_face_normal_impl(_fh, typename GenProg::IF< + vector_traits::Point>::size_ == 3, + PointIs3DTag, + PointIsNot3DTag + >::Result()); +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(FaceHandle _fh, PointIs3DTag) const +{ + assert(this->halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(this->cfv_iter(_fh)); + + // Safeguard for 1-gons + if (!(++fv_it).is_valid()) return Normal(0, 0, 0); + + // Safeguard for 2-gons + if (!(++fv_it).is_valid()) return Normal(0, 0, 0); + + // use Newell's Method to compute the surface normal + Normal n(0,0,0); + for(fv_it = this->cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + // next vertex + ConstFaceVertexIter fv_itn = fv_it; + ++fv_itn; + + if (!fv_itn.is_valid()) + fv_itn = this->cfv_iter(_fh); + + // http://www.opengl.org/wiki/Calculating_a_Surface_Normal + const Point a = this->point(*fv_it) - this->point(*fv_itn); + const Point b = this->point(*fv_it) + this->point(*fv_itn); + + + // Due to traits, the value types of normals and points can be different. + // Therefore we cast them here. + n[0] += static_cast::value_type>(a[1] * b[2]); + n[1] += static_cast::value_type>(a[2] * b[0]); + n[2] += static_cast::value_type>(a[0] * b[1]); + } + + const typename vector_traits::value_type length = norm(n); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (length != typename vector_traits::value_type(0)) + ? ((n *= (typename vector_traits::value_type(1)/length)), n) + : Normal(0, 0, 0); +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(FaceHandle, PointIsNot3DTag) const +{ + // Dummy fallback implementation + return Normal(typename Normal::value_type(0)); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal(const Point& _p0, + const Point& _p1, + const Point& _p2) const +{ + return calc_face_normal_impl(_p0, _p1, _p2, typename GenProg::IF< + vector_traits::Point>::size_ == 3, + PointIs3DTag, + PointIsNot3DTag + >::Result()); +} + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal_impl(const Point& _p0, + const Point& _p1, + const Point& _p2, + PointIs3DTag) const +{ +#if 1 + // The OpenSG ::operator -= () does not support the type Point + // as rhs. Therefore use vector_cast at this point!!! + // Note! OpenSG distinguishes between Normal and Point!!! + Normal p1p0(vector_cast(_p0)); p1p0 -= vector_cast(_p1); + Normal p1p2(vector_cast(_p2)); p1p2 -= vector_cast(_p1); + + Normal n = cross(p1p2, p1p0); + typename vector_traits::value_type length = norm(n); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (length != typename vector_traits::value_type(0)) + ? ((n *= (typename vector_traits::value_type(1)/length)),n) + : Normal(0,0,0); +#else + Point p1p0 = _p0; p1p0 -= _p1; + Point p1p2 = _p2; p1p2 -= _p1; + + Normal n = vector_cast(cross(p1p2, p1p0)); + typename vector_traits::value_type length = norm(n); + + return (length != 0.0) ? n *= (1.0/length) : Normal(0,0,0); +#endif +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(const Point&, const Point&, const Point&, PointIsNot3DTag) const +{ + return Normal(typename Normal::value_type(0)); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_face_centroid(FaceHandle _fh) const +{ + Point _pt; + vectorize(_pt, 0); + Scalar valence = 0.0; + for (ConstFaceVertexIter cfv_it = this->cfv_iter(_fh); cfv_it.is_valid(); ++cfv_it, valence += 1.0) + { + _pt += this->point(*cfv_it); + } + _pt /= valence; + return _pt; +} +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_normals() +{ + // Face normals are required to compute the vertex and the halfedge normals + if (Kernel::has_face_normals() ) { + update_face_normals(); + + if (Kernel::has_vertex_normals() ) update_vertex_normals(); + if (Kernel::has_halfedge_normals()) update_halfedge_normals(); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_face_normals() +{ + FaceIter f_it(Kernel::faces_sbegin()), f_end(Kernel::faces_end()); + + for (; f_it != f_end; ++f_it) + this->set_normal(*f_it, calc_face_normal(*f_it)); +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_halfedge_normals(const double _feature_angle) +{ + HalfedgeIter h_it(Kernel::halfedges_begin()), h_end(Kernel::halfedges_end()); + + for (; h_it != h_end; ++h_it) + this->set_normal(*h_it, calc_halfedge_normal(*h_it, _feature_angle)); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle) const +{ + if(Kernel::is_boundary(_heh)) + return Normal(0,0,0); + else + { + std::vector fhs; fhs.reserve(10); + + HalfedgeHandle heh = _heh; + + // collect CW face-handles + do + { + fhs.push_back(Kernel::face_handle(heh)); + + heh = Kernel::next_halfedge_handle(heh); + heh = Kernel::opposite_halfedge_handle(heh); + } + while(heh != _heh && !Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle)); + + // collect CCW face-handles + if(heh != _heh && !is_estimated_feature_edge(_heh, _feature_angle)) + { + heh = Kernel::opposite_halfedge_handle(_heh); + + if ( !Kernel::is_boundary(heh) ) { + do + { + + fhs.push_back(Kernel::face_handle(heh)); + + heh = Kernel::prev_halfedge_handle(heh); + heh = Kernel::opposite_halfedge_handle(heh); + } + while(!Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle)); + } + } + + Normal n(0,0,0); + for(unsigned int i=0; i +bool +PolyMeshT:: +is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const +{ + EdgeHandle eh = Kernel::edge_handle(_heh); + + if(Kernel::has_edge_status()) + { + if(Kernel::status(eh).feature()) + return true; + } + + if(Kernel::is_boundary(eh)) + return false; + + // compute angle between faces + FaceHandle fh0 = Kernel::face_handle(_heh); + FaceHandle fh1 = Kernel::face_handle(Kernel::opposite_halfedge_handle(_heh)); + + Normal fn0 = Kernel::normal(fh0); + Normal fn1 = Kernel::normal(fh1); + + // dihedral angle above angle threshold + return ( dot(fn0,fn1) < cos(_feature_angle) ); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_vertex_normal(VertexHandle _vh) const +{ + Normal n; + calc_vertex_normal_fast(_vh,n); + + Scalar length = norm(n); + if (length != 0.0) n *= (Scalar(1.0)/length); + + return n; +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const +{ + vectorize(_n, 0.0); + for (ConstVertexFaceIter vf_it = this->cvf_iter(_vh); vf_it.is_valid(); ++vf_it) + _n += this->normal(*vf_it); +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const +{ + vectorize(_n, 0.0); + ConstVertexIHalfedgeIter cvih_it = this->cvih_iter(_vh); + if (! cvih_it.is_valid() ) + {//don't crash on isolated vertices + return; + } + Normal in_he_vec; + calc_edge_vector(*cvih_it, in_he_vec); + for ( ; cvih_it.is_valid(); ++cvih_it) + {//calculates the sector normal defined by cvih_it and adds it to _n + if (this->is_boundary(*cvih_it)) + { + continue; + } + HalfedgeHandle out_heh(this->next_halfedge_handle(*cvih_it)); + Normal out_he_vec; + calc_edge_vector(out_heh, out_he_vec); + _n += cross(in_he_vec, out_he_vec);//sector area is taken into account + in_he_vec = out_he_vec; + in_he_vec *= -1;//change the orientation + } +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const +{ + static const LoopSchemeMaskDouble& loop_scheme_mask__ = + LoopSchemeMaskDoubleSingleton::Instance(); + + Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0); + unsigned int vh_val = this->valence(_vh); + unsigned int i = 0; + for (ConstVertexOHalfedgeIter cvoh_it = this->cvoh_iter(_vh); cvoh_it.is_valid(); ++cvoh_it, ++i) + { + VertexHandle r1_v( this->to_vertex_handle(*cvoh_it) ); + t_v += (typename vector_traits::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*this->point(r1_v); + t_w += (typename vector_traits::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*this->point(r1_v); + } + _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed? +} + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_vertex_normals() +{ + VertexIter v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end()); + + for (; v_it!=v_end; ++v_it) + this->set_normal(*v_it, calc_vertex_normal(*v_it)); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMeshT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMeshT.hh new file mode 100644 index 0000000..31796fb --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMeshT.hh @@ -0,0 +1,638 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS PolyMeshT +// +//============================================================================= + + +#ifndef OPENMESH_POLYMESHT_HH +#define OPENMESH_POLYMESHT_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/** \class PolyMeshT PolyMeshT.hh + + Base type for a polygonal mesh. + + This is the base class for a polygonal mesh. It is parameterized + by a mesh kernel that is given as a template argument. This class + inherits all methods from its mesh kernel. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type +*/ + +template +class PolyMeshT : public Kernel +{ +public: + + /// Self type. Used to specify iterators/circulators. + typedef PolyMeshT This; + //--- item types --- + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT ( This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT ) + enum { IsPolyMesh = 1 }; + enum { IsTriMesh = 0 }; + static bool is_polymesh() { return true; } + static bool is_trimesh() { return false; } + //@} + + /// \name Mesh Items + //@{ + /// Scalar type + typedef typename Kernel::Scalar Scalar; + /// Coordinate type + typedef typename Kernel::Point Point; + /// Normal type + typedef typename Kernel::Normal Normal; + /// Color type + typedef typename Kernel::Color Color; + /// TexCoord1D type + typedef typename Kernel::TexCoord1D TexCoord1D; + /// TexCoord2D type + typedef typename Kernel::TexCoord2D TexCoord2D; + /// TexCoord3D type + typedef typename Kernel::TexCoord3D TexCoord3D; + /// Vertex type + typedef typename Kernel::Vertex Vertex; + /// Halfedge type + typedef typename Kernel::Halfedge Halfedge; + /// Edge type + typedef typename Kernel::Edge Edge; + /// Face type + typedef typename Kernel::Face Face; + //@} + + //--- handle types --- + + /// Handle for referencing the corresponding item + typedef typename Kernel::VertexHandle VertexHandle; + typedef typename Kernel::HalfedgeHandle HalfedgeHandle; + typedef typename Kernel::EdgeHandle EdgeHandle; + typedef typename Kernel::FaceHandle FaceHandle; + + + + typedef typename Kernel::VertexIter VertexIter; + typedef typename Kernel::HalfedgeIter HalfedgeIter; + typedef typename Kernel::EdgeIter EdgeIter; + typedef typename Kernel::FaceIter FaceIter; + + typedef typename Kernel::ConstVertexIter ConstVertexIter; + typedef typename Kernel::ConstHalfedgeIter ConstHalfedgeIter; + typedef typename Kernel::ConstEdgeIter ConstEdgeIter; + typedef typename Kernel::ConstFaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + /// Circulator + typedef typename Kernel::VertexVertexIter VertexVertexIter; + typedef typename Kernel::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename Kernel::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename Kernel::VertexEdgeIter VertexEdgeIter; + typedef typename Kernel::VertexFaceIter VertexFaceIter; + typedef typename Kernel::FaceVertexIter FaceVertexIter; + typedef typename Kernel::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename Kernel::FaceEdgeIter FaceEdgeIter; + typedef typename Kernel::FaceFaceIter FaceFaceIter; + + typedef typename Kernel::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename Kernel::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename Kernel::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename Kernel::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename Kernel::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename Kernel::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename Kernel::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename Kernel::ConstFaceFaceIter ConstFaceFaceIter; + //@} + + + // --- constructor/destructor + PolyMeshT() {} + template + explicit PolyMeshT(const T& t) : Kernel(t) {} + virtual ~PolyMeshT() {} + + /** Uses default copy and assignment operator. + Use them to assign two meshes of \b equal type. + If the mesh types vary, use PolyMeshT::assign() instead. */ + + // --- creation --- + + /** + * \brief Adds a new default-initialized vertex. + * + * \sa new_vertex(const Point&), new_vertex_dirty() + */ + inline VertexHandle new_vertex() + { return Kernel::new_vertex(); } + + /** + * \brief Adds a new vertex initialized to a custom position. + * + * \sa new_vertex(), new_vertex_dirty() + */ + inline VertexHandle new_vertex(const Point& _p) + { + VertexHandle vh(Kernel::new_vertex()); + this->set_point(vh, _p); + return vh; + } + + /** + * Same as new_vertex(const Point&) but never shrinks, only enlarges the + * vertex property vectors. + * + * If you are rebuilding a mesh that you erased with ArrayKernel::clean() or + * ArrayKernel::clean_keep_reservation() using this method instead of + * new_vertex(const Point &) saves reallocation and reinitialization of + * property memory. + * + * \sa new_vertex(const Point &) + */ + inline VertexHandle new_vertex_dirty(const Point& _p) + { + VertexHandle vh(Kernel::new_vertex_dirty()); + this->set_point(vh, _p); + return vh; + } + + /// Alias for new_vertex(const Point&). + inline VertexHandle add_vertex(const Point& _p) + { return new_vertex(_p); } + + /// Alias for new_vertex_dirty(). + inline VertexHandle add_vertex_dirty(const Point& _p) + { return new_vertex_dirty(_p); } + + // --- normal vectors --- + + /** \name Normal vector computation + */ + //@{ + + /** \brief Compute normals for all primitives + * + * Calls update_face_normals() , update_halfedge_normals() and update_vertex_normals() if + * the normals (i.e. the properties) exist. + * + * \note Face normals are required to compute vertex and halfedge normals! + */ + void update_normals(); + + /// Update normal for face _fh + void update_normal(FaceHandle _fh) + { this->set_normal(_fh, calc_face_normal(_fh)); } + + /** \brief Update normal vectors for all faces. + * + * \attention Needs the Attributes::Normal attribute for faces. + * Call request_face_normals() before using it! + */ + void update_face_normals(); + + /** Calculate normal vector for face _fh. */ + virtual Normal calc_face_normal(FaceHandle _fh) const; + + /** Calculate normal vector for face (_p0, _p1, _p2). */ + Normal calc_face_normal(const Point& _p0, const Point& _p1, + const Point& _p2) const; + /// calculates the average of the vertices defining _fh + void calc_face_centroid(FaceHandle _fh, Point& _pt) const { + _pt = calc_face_centroid(_fh); + } + + /// Computes and returns the average of the vertices defining _gh + Point calc_face_centroid(FaceHandle _fh) const; + + /// Update normal for halfedge _heh + void update_normal(HalfedgeHandle _heh, const double _feature_angle = 0.8) + { this->set_normal(_heh, calc_halfedge_normal(_heh,_feature_angle)); } + + /** \brief Update normal vectors for all halfedges. + * + * Uses the existing face normals to compute halfedge normals + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and halfedges. + * Call request_face_normals() and request_halfedge_normals() before using it! + */ + void update_halfedge_normals(const double _feature_angle = 0.8); + + /** \brief Calculate halfedge normal for one specific halfedge + * + * Calculate normal vector for halfedge _heh. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_halfedge_normals() before using it! + * + * @param _heh Handle of the halfedge + * @param _feature_angle If the dihedral angle across this edge is greater than this value, the edge is considered as a feature edge (angle in radians) + */ + virtual Normal calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle = 0.8) const; + + + /** identifies feature edges w.r.t. the minimal dihedral angle for feature edges (in radians) */ + /** and the status feature tag */ + bool is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const; + + /// Update normal for vertex _vh + void update_normal(VertexHandle _vh) + { this->set_normal(_vh, calc_vertex_normal(_vh)); } + + /** \brief Update normal vectors for all vertices. + * + * Uses existing face normals to calculate new vertex normals. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_vertex_normals() before using it! + */ + void update_vertex_normals(); + + /** \brief Calculate vertex normal for one specific vertex + * + * Calculate normal vector for vertex _vh by averaging normals + * of adjacent faces. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_vertex_normals() before using it! + * + * @param _vh Handle of the vertex + */ + Normal calc_vertex_normal(VertexHandle _vh) const; + + /** Different methods for calculation of the normal at _vh: + - ..._fast - the default one - the same as calc vertex_normal() + - needs the Attributes::Normal attribute for faces + - ..._correct - works properly for non-triangular meshes + - does not need any attributes + - ..._loop - calculates loop surface normals + - does not need any attributes */ + void calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const; + + + //@} + + // --- Geometry API - still in development --- + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + void calc_edge_vector(EdgeHandle _eh, Normal& _edge_vec) const + { + _edge_vec = calc_edge_vector(_eh); + } + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + Normal calc_edge_vector(EdgeHandle _eh) const + { + return calc_edge_vector(this->halfedge_handle(_eh,0)); + } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + void calc_edge_vector(HalfedgeHandle _heh, Normal& _edge_vec) const + { + _edge_vec = calc_edge_vector(_heh); + } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + Normal calc_edge_vector(HalfedgeHandle _heh) const + { + return this->point(this->to_vertex_handle(_heh)) - + this->point(this->from_vertex_handle(_heh)); + } + + // Calculates the length of the edge _eh + Scalar calc_edge_length(EdgeHandle _eh) const + { return calc_edge_length(this->halfedge_handle(_eh,0)); } + + /** Calculates the length of the edge _heh + */ + Scalar calc_edge_length(HalfedgeHandle _heh) const + { return (Scalar)sqrt(calc_edge_sqr_length(_heh)); } + + Scalar calc_edge_sqr_length(EdgeHandle _eh) const + { return calc_edge_sqr_length(this->halfedge_handle(_eh,0)); } + + Scalar calc_edge_sqr_length(HalfedgeHandle _heh) const + { + Normal edge_vec; + calc_edge_vector(_heh, edge_vec); + return sqrnorm(edge_vec); + } + + /** Calculates the midpoint of the halfedge _heh, defined by the positions of + the two incident vertices */ + Point calc_edge_midpoint(HalfedgeHandle _heh) const + { + VertexHandle vh0 = this->from_vertex_handle(_heh); + VertexHandle vh1 = this->to_vertex_handle(_heh); + return 0.5 * (this->point(vh0) + this->point(vh1)); + } + + /** Calculates the midpoint of the edge _eh, defined by the positions of the + two incident vertices */ + Point calc_edge_midpoint(EdgeHandle _eh) const + { + return calc_edge_midpoint(this->halfedge_handle(_eh, 0)); + } + + /** defines a consistent representation of a sector geometry: + the halfedge _in_heh defines the sector orientation + the vertex pointed by _in_heh defines the sector center + _vec0 and _vec1 are resp. the first and the second vectors defining the sector */ + void calc_sector_vectors(HalfedgeHandle _in_heh, Normal& _vec0, Normal& _vec1) const + { + calc_edge_vector(this->next_halfedge_handle(_in_heh), _vec0);//p2 - p1 + calc_edge_vector(this->opposite_halfedge_handle(_in_heh), _vec1);//p0 - p1 + } + + /** calculates the sector angle.\n + * The vertex pointed by _in_heh defines the sector center + * The angle will be calculated between the given halfedge and the next halfedge.\n + * Seen from the center vertex this will be the next halfedge in clockwise direction.\n + NOTE: only boundary concave sectors are treated correctly */ + Scalar calc_sector_angle(HalfedgeHandle _in_heh) const + { + Normal v0, v1; + calc_sector_vectors(_in_heh, v0, v1); + Scalar denom = norm(v0)*norm(v1); + if ( denom == Scalar(0)) + { + return 0; + } + Scalar cos_a = dot(v0 , v1) / denom; + if (this->is_boundary(_in_heh)) + {//determine if the boundary sector is concave or convex + FaceHandle fh(this->face_handle(this->opposite_halfedge_handle(_in_heh))); + Normal f_n(calc_face_normal(fh));//this normal is (for convex fh) OK + Scalar sign_a = dot(cross(v0, v1), f_n); + return angle(cos_a, sign_a); + } + else + { + return acos(sane_aarg(cos_a)); + } + } + + // calculate the cos and the sin of angle <(_in_heh,next_halfedge(_in_heh)) + /* + void calc_sector_angle_cos_sin(HalfedgeHandle _in_heh, Scalar& _cos_a, Scalar& _sin_a) const + { + Normal in_vec, out_vec; + calc_edge_vector(_in_heh, in_vec); + calc_edge_vector(next_halfedge_handle(_in_heh), out_vec); + Scalar denom = norm(in_vec)*norm(out_vec); + if (is_zero(denom)) + { + _cos_a = 1; + _sin_a = 0; + } + else + { + _cos_a = dot(in_vec, out_vec)/denom; + _sin_a = norm(cross(in_vec, out_vec))/denom; + } + } + */ + /** calculates the normal (non-normalized) of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) */ + void calc_sector_normal(HalfedgeHandle _in_heh, Normal& _sector_normal) const + { + Normal vec0, vec1; + calc_sector_vectors(_in_heh, vec0, vec1); + _sector_normal = cross(vec0, vec1);//(p2-p1)^(p0-p1) + } + + /** calculates the area of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) + NOTE: special cases (e.g. concave sectors) are not handled correctly */ + Scalar calc_sector_area(HalfedgeHandle _in_heh) const + { + Normal sector_normal; + calc_sector_normal(_in_heh, sector_normal); + return norm(sector_normal)/2; + } + + /** calculates the dihedral angle on the halfedge _heh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(HalfedgeHandle _heh) const + { + // Make sure that we have face normals on the mesh + assert(Kernel::has_face_normals()); + + if (this->is_boundary(this->edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + const Normal& n0 = this->normal(this->face_handle(_heh)); + const Normal& n1 = this->normal(this->face_handle(this->opposite_halfedge_handle(_heh))); + Normal he; + calc_edge_vector(_heh, he); + Scalar da_cos = dot(n0, n1); + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + /** calculates the dihedral angle on the edge _eh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(EdgeHandle _eh) const + { return calc_dihedral_angle_fast(this->halfedge_handle(_eh,0)); } + + // calculates the dihedral angle on the halfedge _heh + Scalar calc_dihedral_angle(HalfedgeHandle _heh) const + { + if (this->is_boundary(this->edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + Normal n0, n1, he; + calc_sector_normal(_heh, n0); + calc_sector_normal(this->opposite_halfedge_handle(_heh), n1); + calc_edge_vector(_heh, he); + Scalar denom = norm(n0)*norm(n1); + if (denom == Scalar(0)) + { + return 0; + } + Scalar da_cos = dot(n0, n1)/denom; + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + // calculates the dihedral angle on the edge _eh + Scalar calc_dihedral_angle(EdgeHandle _eh) const + { return calc_dihedral_angle(this->halfedge_handle(_eh,0)); } + + /** tags an edge as a feature if its dihedral angle is larger than _angle_tresh + returns the number of the found feature edges, requires edge_status property*/ + unsigned int find_feature_edges(Scalar _angle_tresh = OpenMesh::deg_to_rad(44.0)); + // --- misc --- + + /// Face split (= 1-to-n split) + inline void split(FaceHandle _fh, const Point& _p) + { Kernel::split(_fh, add_vertex(_p)); } + + inline void split(FaceHandle _fh, VertexHandle _vh) + { Kernel::split(_fh, _vh); } + + inline void split(EdgeHandle _eh, const Point& _p) + { Kernel::split_edge(_eh, add_vertex(_p)); } + + inline void split(EdgeHandle _eh, VertexHandle _vh) + { Kernel::split_edge(_eh, _vh); } + +private: + struct PointIs3DTag {}; + struct PointIsNot3DTag {}; + Normal calc_face_normal_impl(FaceHandle, PointIs3DTag) const; + Normal calc_face_normal_impl(FaceHandle, PointIsNot3DTag) const; + Normal calc_face_normal_impl(const Point&, const Point&, const Point&, PointIs3DTag) const; + Normal calc_face_normal_impl(const Point&, const Point&, const Point&, PointIsNot3DTag) const; +}; + +/** + * @brief Cast a mesh with different but identical traits into each other. + * + * Example: + * @code{.cpp} + * struct TriTraits1 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits2 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits3 : public OpenMesh::DefaultTraits { + * typedef Vec3f Point; + * }; + * + * TriMesh_ArrayKernelT a; + * TriMesh_ArrayKernelT &b = mesh_cast&>(a); // OK + * TriMesh_ArrayKernelT &c = mesh_cast&>(a); // ERROR + * @endcode + * + * @see MeshCast + * + * @param rhs + * @return + */ +template +LHS mesh_cast(PolyMeshT &rhs) { + return MeshCast&>::cast(rhs); +} + +template +LHS mesh_cast(PolyMeshT *rhs) { + return MeshCast*>::cast(rhs); +} + +template +const LHS mesh_cast(const PolyMeshT &rhs) { + return MeshCast&>::cast(rhs); +} + +template +const LHS mesh_cast(const PolyMeshT *rhs) { + return MeshCast*>::cast(rhs); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_POLYMESH_C) +# define OPENMESH_POLYMESH_TEMPLATES +# include "PolyMeshT.cc" +#endif +//============================================================================= +#endif // OPENMESH_POLYMESHT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh new file mode 100644 index 0000000..d884ae0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh @@ -0,0 +1,118 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS PolyMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +#define OPENMESH_POLY_MESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +template +class TriMesh_ArrayKernelT; +//== CLASS DEFINITION ========================================================= + +/// Helper class to build a PolyMesh-type +template +struct PolyMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef PolyMeshT Mesh; +}; + + +/** \class PolyMesh_ArrayKernelT PolyMesh_ArrayKernelT.hh + + \ingroup mesh_types_group + Polygonal mesh based on the ArrayKernel. + \see OpenMesh::PolyMeshT + \see OpenMesh::ArrayKernel +*/ +template +class PolyMesh_ArrayKernelT + : public PolyMesh_ArrayKernel_GeneratorT::Mesh +{ +public: + PolyMesh_ArrayKernelT() {} + template + PolyMesh_ArrayKernelT( const TriMesh_ArrayKernelT & t) + { + //assign the connectivity and standard properties + this->assign(t, true); + + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Status.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Status.hh new file mode 100644 index 0000000..19e474d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Status.hh @@ -0,0 +1,183 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS Status +// +//============================================================================= + + +#ifndef OPENMESH_ATTRIBUTE_STATUS_HH +#define OPENMESH_ATTRIBUTE_STATUS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + + +/** Status bits used by the Status class. + * \see OpenMesh::Attributes::StatusInfo + */ +enum StatusBits { + + DELETED = 1, ///< Item has been deleted + LOCKED = 2, ///< Item is locked. + SELECTED = 4, ///< Item is selected. + HIDDEN = 8, ///< Item is hidden. + FEATURE = 16, ///< Item is a feature or belongs to a feature. + TAGGED = 32, ///< Item is tagged. + TAGGED2 = 64, ///< Alternate bit for tagging an item. + FIXEDNONMANIFOLD = 128, ///< Item was non-two-manifold and had to be fixed + UNUSED = 256 ///< Unused +}; + + +/** \class StatusInfo Status.hh + * + * Add status information to a base class. + * + * \see StatusBits + */ +class StatusInfo +{ +public: + + typedef unsigned int value_type; + + StatusInfo() : status_(0) {} + + /// is deleted ? + bool deleted() const { return is_bit_set(DELETED); } + /// set deleted + void set_deleted(bool _b) { change_bit(DELETED, _b); } + + + /// is locked ? + bool locked() const { return is_bit_set(LOCKED); } + /// set locked + void set_locked(bool _b) { change_bit(LOCKED, _b); } + + + /// is selected ? + bool selected() const { return is_bit_set(SELECTED); } + /// set selected + void set_selected(bool _b) { change_bit(SELECTED, _b); } + + + /// is hidden ? + bool hidden() const { return is_bit_set(HIDDEN); } + /// set hidden + void set_hidden(bool _b) { change_bit(HIDDEN, _b); } + + + /// is feature ? + bool feature() const { return is_bit_set(FEATURE); } + /// set feature + void set_feature(bool _b) { change_bit(FEATURE, _b); } + + + /// is tagged ? + bool tagged() const { return is_bit_set(TAGGED); } + /// set tagged + void set_tagged(bool _b) { change_bit(TAGGED, _b); } + + + /// is tagged2 ? This is just one more tag info. + bool tagged2() const { return is_bit_set(TAGGED2); } + /// set tagged + void set_tagged2(bool _b) { change_bit(TAGGED2, _b); } + + + /// is fixed non-manifold ? + bool fixed_nonmanifold() const { return is_bit_set(FIXEDNONMANIFOLD); } + /// set fixed non-manifold + void set_fixed_nonmanifold(bool _b) { change_bit(FIXEDNONMANIFOLD, _b); } + + + /// return whole status + unsigned int bits() const { return status_; } + /// set whole status at once + void set_bits(unsigned int _bits) { status_ = _bits; } + + + /// is a certain bit set ? + bool is_bit_set(unsigned int _s) const { return (status_ & _s) > 0; } + /// set a certain bit + void set_bit(unsigned int _s) { status_ |= _s; } + /// unset a certain bit + void unset_bit(unsigned int _s) { status_ &= ~_s; } + /// set or unset a certain bit + void change_bit(unsigned int _s, bool _b) { + if (_b) status_ |= _s; else status_ &= ~_s; } + + +private: + + value_type status_; +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTE_STATUS_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Traits.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Traits.hh new file mode 100644 index 0000000..a0fbe01 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/Traits.hh @@ -0,0 +1,245 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +/** \file Core/Mesh/Traits.hh + This file defines the default traits and some convenience macros. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_TRAITS_HH +#define OPENMESH_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Macro for defining the vertex attributes. See \ref mesh_type. +#define VertexAttributes(_i) enum { VertexAttributes = _i } + +/// Macro for defining the halfedge attributes. See \ref mesh_type. +#define HalfedgeAttributes(_i) enum { HalfedgeAttributes = _i } + +/// Macro for defining the edge attributes. See \ref mesh_type. +#define EdgeAttributes(_i) enum { EdgeAttributes = _i } + +/// Macro for defining the face attributes. See \ref mesh_type. +#define FaceAttributes(_i) enum { FaceAttributes = _i } + +/// Macro for defining the vertex traits. See \ref mesh_type. +#define VertexTraits \ + template struct VertexT : public Base + +/// Macro for defining the halfedge traits. See \ref mesh_type. +#define HalfedgeTraits \ + template struct HalfedgeT : public Base + +/// Macro for defining the edge traits. See \ref mesh_type. +#define EdgeTraits \ + template struct EdgeT : public Base + +/// Macro for defining the face traits. See \ref mesh_type. +#define FaceTraits \ + template struct FaceT : public Base + + + +//== CLASS DEFINITION ========================================================= + + +/** \class DefaultTraits Traits.hh + + Base class for all traits. All user traits should be derived from + this class. You may enrich all basic items by additional + properties or define one or more of the types \c Point, \c Normal, + \c TexCoord, or \c Color. + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraits +{ + /// The default coordinate type is OpenMesh::Vec3f. + typedef Vec3f Point; + + /// The default normal type is OpenMesh::Vec3f. + typedef Vec3f Normal; + + /// The default 1D texture coordinate type is float. + typedef float TexCoord1D; + /// The default 2D texture coordinate type is OpenMesh::Vec2f. + typedef Vec2f TexCoord2D; + /// The default 3D texture coordinate type is OpenMesh::Vec3f. + typedef Vec3f TexCoord3D; + + /// The default texture index type + typedef int TextureIndex; + + /// The default color type is OpenMesh::Vec3uc. + typedef Vec3uc Color; + +#ifndef DOXY_IGNORE_THIS + VertexTraits {}; + HalfedgeTraits {}; + EdgeTraits {}; + FaceTraits {}; +#endif + + VertexAttributes(0); + HalfedgeAttributes(Attributes::PrevHalfedge); + EdgeAttributes(0); + FaceAttributes(0); +}; + + +//== CLASS DEFINITION ========================================================= + + +/** Helper class to merge two mesh traits. + * \internal + * + * With the help of this class it's possible to merge two mesh traits. + * Whereby \c _Traits1 overrides equally named symbols of \c _Traits2. + * + * For your convenience use the provided defines \c OM_Merge_Traits + * and \c OM_Merge_Traits_In_Template instead. + * + * \see OM_Merge_Traits, OM_Merge_Traits_In_Template + */ +template struct MergeTraits +{ +#ifndef DOXY_IGNORE_THIS + struct Result + { + // Mipspro needs this (strange) typedef + typedef _Traits1 T1; + typedef _Traits2 T2; + + + VertexAttributes ( T1::VertexAttributes | T2::VertexAttributes ); + HalfedgeAttributes ( T1::HalfedgeAttributes | T2::HalfedgeAttributes ); + EdgeAttributes ( T1::EdgeAttributes | T2::EdgeAttributes ); + FaceAttributes ( T1::FaceAttributes | T2::FaceAttributes ); + + + typedef typename T1::Point Point; + typedef typename T1::Normal Normal; + typedef typename T1::Color Color; + typedef typename T1::TexCoord TexCoord; + + template class VertexT : + public T1::template VertexT< + typename T2::template VertexT, Refs> + {}; + + template class HalfedgeT : + public T1::template HalfedgeT< + typename T2::template HalfedgeT, Refs> + {}; + + + template class EdgeT : + public T1::template EdgeT< + typename T2::template EdgeT, Refs> + {}; + + + template class FaceT : + public T1::template FaceT< + typename T2::template FaceT, Refs> + {}; + }; +#endif +}; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Note that in case of ambiguities class _S1 overrides _S2, especially + the point/normal/color/texcoord type to be used is taken from _S1::Point / + _S1::Normal / _S1::Color / _S1::TexCoord +*/ +#define OM_Merge_Traits(_S1, _S2, _D) \ + typedef OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Same as OM_Merge_Traits, but this can be used inside template classes. +*/ +#define OM_Merge_Traits_In_Template(_S1, _S2, _D) \ + typedef typename OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRAITS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriConnectivity.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriConnectivity.cc new file mode 100644 index 0000000..fb77f87 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriConnectivity.cc @@ -0,0 +1,521 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +// CLASS TriMeshT - IMPLEMENTATION + +#include + +namespace OpenMesh +{ + +TriConnectivity::FaceHandle +TriConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size) +{ + // need at least 3 vertices + if (_vhs_size < 3) return InvalidFaceHandle; + + /// face is triangle -> ok + if (_vhs_size == 3) + return PolyConnectivity::add_face(_vertex_handles, _vhs_size); + + /// face is not a triangle -> triangulate + else + { + //omlog() << "triangulating " << _vhs_size << "_gon\n"; + + VertexHandle vhandles[3]; + vhandles[0] = _vertex_handles[0]; + + FaceHandle fh; + unsigned int i(1); + --_vhs_size; + + while (i < _vhs_size) + { + vhandles[1] = _vertex_handles[i]; + vhandles[2] = _vertex_handles[++i]; + fh = PolyConnectivity::add_face(vhandles, 3); + } + + return fh; + } +} + +//----------------------------------------------------------------------------- + +FaceHandle TriConnectivity::add_face(const std::vector& _vhandles) +{ + return add_face(&_vhandles.front(), _vhandles.size()); +} + +//----------------------------------------------------------------------------- + + +FaceHandle TriConnectivity::add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2) +{ + VertexHandle vhs[3] = { _vh0, _vh1, _vh2 }; + return PolyConnectivity::add_face(vhs, 3); +} + +//----------------------------------------------------------------------------- + +bool TriConnectivity::is_collapse_ok(HalfedgeHandle v0v1) +{ + // is the edge already deleted? + if ( status(edge_handle(v0v1)).deleted() ) + return false; + + HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1)); + VertexHandle v0(to_vertex_handle(v1v0)); + VertexHandle v1(to_vertex_handle(v0v1)); + + // are vertices already deleted ? + if (status(v0).deleted() || status(v1).deleted()) + return false; + + VertexHandle vl, vr; + HalfedgeHandle h1, h2; + + // the edges v1-vl and vl-v0 must not be both boundary edges + if (!is_boundary(v0v1)) + { + + h1 = next_halfedge_handle(v0v1); + h2 = next_halfedge_handle(h1); + + vl = to_vertex_handle(h1); + + if (is_boundary(opposite_halfedge_handle(h1)) && + is_boundary(opposite_halfedge_handle(h2))) + { + return false; + } + } + + + // the edges v0-vr and vr-v1 must not be both boundary edges + if (!is_boundary(v1v0)) + { + + h1 = next_halfedge_handle(v1v0); + h2 = next_halfedge_handle(h1); + + vr = to_vertex_handle(h1); + + if (is_boundary(opposite_halfedge_handle(h1)) && + is_boundary(opposite_halfedge_handle(h2))) + return false; + } + + // if vl and vr are equal or both invalid -> fail + if (vl == vr) return false; + + VertexVertexIter vv_it; + + // test intersection of the one-rings of v0 and v1 + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + status(*vv_it).set_tagged(false); + + for (vv_it = vv_iter(v1); vv_it.is_valid(); ++vv_it) + status(*vv_it).set_tagged(true); + + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + if (status(*vv_it).tagged() && *vv_it != vl && *vv_it != vr) + return false; + + + // edge between two boundary vertices should be a boundary edge + if ( is_boundary(v0) && is_boundary(v1) && + !is_boundary(v0v1) && !is_boundary(v1v0)) + return false; + + // passed all tests + return true; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr) +{ + HalfedgeHandle v1vl, vlv1, vrv1, v0v1; + + // build loop from halfedge v1->vl + if (vl.is_valid()) + { + v1vl = find_halfedge(v1, vl); + assert(v1vl.is_valid()); + vlv1 = insert_loop(v1vl); + } + + // build loop from halfedge vr->v1 + if (vr.is_valid()) + { + vrv1 = find_halfedge(vr, v1); + assert(vrv1.is_valid()); + insert_loop(vrv1); + } + + // handle boundary cases + if (!vl.is_valid()) + vlv1 = prev_halfedge_handle(halfedge_handle(v1)); + if (!vr.is_valid()) + vrv1 = prev_halfedge_handle(halfedge_handle(v1)); + + + // split vertex v1 into edge v0v1 + v0v1 = insert_edge(v0, vlv1, vrv1); + + + return v0v1; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::insert_loop(HalfedgeHandle _hh) +{ + HalfedgeHandle h0(_hh); + HalfedgeHandle o0(opposite_halfedge_handle(h0)); + + VertexHandle v0(to_vertex_handle(o0)); + VertexHandle v1(to_vertex_handle(h0)); + + HalfedgeHandle h1 = new_edge(v1, v0); + HalfedgeHandle o1 = opposite_halfedge_handle(h1); + + FaceHandle f0 = face_handle(h0); + FaceHandle f1 = new_face(); + + // halfedge -> halfedge + set_next_halfedge_handle(prev_halfedge_handle(h0), o1); + set_next_halfedge_handle(o1, next_halfedge_handle(h0)); + set_next_halfedge_handle(h1, h0); + set_next_halfedge_handle(h0, h1); + + // halfedge -> face + set_face_handle(o1, f0); + set_face_handle(h0, f1); + set_face_handle(h1, f1); + + // face -> halfedge + set_halfedge_handle(f1, h0); + if (f0.is_valid()) + set_halfedge_handle(f0, o1); + + + // vertex -> halfedge + adjust_outgoing_halfedge(v0); + adjust_outgoing_halfedge(v1); + + return h1; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::insert_edge(VertexHandle _vh, HalfedgeHandle _h0, HalfedgeHandle _h1) +{ + assert(_h0.is_valid() && _h1.is_valid()); + + VertexHandle v0 = _vh; + VertexHandle v1 = to_vertex_handle(_h0); + + assert( v1 == to_vertex_handle(_h1)); + + HalfedgeHandle v0v1 = new_edge(v0, v1); + HalfedgeHandle v1v0 = opposite_halfedge_handle(v0v1); + + + + // vertex -> halfedge + set_halfedge_handle(v0, v0v1); + set_halfedge_handle(v1, v1v0); + + + // halfedge -> halfedge + set_next_halfedge_handle(v0v1, next_halfedge_handle(_h0)); + set_next_halfedge_handle(_h0, v0v1); + set_next_halfedge_handle(v1v0, next_halfedge_handle(_h1)); + set_next_halfedge_handle(_h1, v1v0); + + + // halfedge -> vertex + for (VertexIHalfedgeIter vih_it(vih_iter(v0)); vih_it.is_valid(); ++vih_it) + set_vertex_handle(*vih_it, v0); + + + // halfedge -> face + set_face_handle(v0v1, face_handle(_h0)); + set_face_handle(v1v0, face_handle(_h1)); + + + // face -> halfedge + if (face_handle(v0v1).is_valid()) + set_halfedge_handle(face_handle(v0v1), v0v1); + if (face_handle(v1v0).is_valid()) + set_halfedge_handle(face_handle(v1v0), v1v0); + + + // vertex -> halfedge + adjust_outgoing_halfedge(v0); + adjust_outgoing_halfedge(v1); + + + return v0v1; +} + +//----------------------------------------------------------------------------- +bool TriConnectivity::is_flip_ok(EdgeHandle _eh) const +{ + // boundary edges cannot be flipped + if (is_boundary(_eh)) return false; + + + HalfedgeHandle hh = halfedge_handle(_eh, 0); + HalfedgeHandle oh = halfedge_handle(_eh, 1); + + + // check if the flipped edge is already present + // in the mesh + + VertexHandle ah = to_vertex_handle(next_halfedge_handle(hh)); + VertexHandle bh = to_vertex_handle(next_halfedge_handle(oh)); + + if (ah == bh) // this is generally a bad sign !!! + return false; + + for (ConstVertexVertexIter vvi(*this, ah); vvi.is_valid(); ++vvi) + if (*vvi == bh) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +void TriConnectivity::flip(EdgeHandle _eh) +{ + // CAUTION : Flipping a halfedge may result in + // a non-manifold mesh, hence check for yourself + // whether this operation is allowed or not! + assert(is_flip_ok(_eh));//let's make it sure it is actually checked + assert(!is_boundary(_eh)); + + HalfedgeHandle a0 = halfedge_handle(_eh, 0); + HalfedgeHandle b0 = halfedge_handle(_eh, 1); + + HalfedgeHandle a1 = next_halfedge_handle(a0); + HalfedgeHandle a2 = next_halfedge_handle(a1); + + HalfedgeHandle b1 = next_halfedge_handle(b0); + HalfedgeHandle b2 = next_halfedge_handle(b1); + + VertexHandle va0 = to_vertex_handle(a0); + VertexHandle va1 = to_vertex_handle(a1); + + VertexHandle vb0 = to_vertex_handle(b0); + VertexHandle vb1 = to_vertex_handle(b1); + + FaceHandle fa = face_handle(a0); + FaceHandle fb = face_handle(b0); + + set_vertex_handle(a0, va1); + set_vertex_handle(b0, vb1); + + set_next_halfedge_handle(a0, a2); + set_next_halfedge_handle(a2, b1); + set_next_halfedge_handle(b1, a0); + + set_next_halfedge_handle(b0, b2); + set_next_halfedge_handle(b2, a1); + set_next_halfedge_handle(a1, b0); + + set_face_handle(a1, fb); + set_face_handle(b1, fa); + + set_halfedge_handle(fa, a0); + set_halfedge_handle(fb, b0); + + if (halfedge_handle(va0) == b0) + set_halfedge_handle(va0, a1); + if (halfedge_handle(vb0) == a0) + set_halfedge_handle(vb0, b1); +} + + +//----------------------------------------------------------------------------- + +void TriConnectivity::split(EdgeHandle _eh, VertexHandle _vh) +{ + HalfedgeHandle h0 = halfedge_handle(_eh, 0); + HalfedgeHandle o0 = halfedge_handle(_eh, 1); + + VertexHandle v2 = to_vertex_handle(o0); + + HalfedgeHandle e1 = new_edge(_vh, v2); + HalfedgeHandle t1 = opposite_halfedge_handle(e1); + + FaceHandle f0 = face_handle(h0); + FaceHandle f3 = face_handle(o0); + + set_halfedge_handle(_vh, h0); + set_vertex_handle(o0, _vh); + + if (!is_boundary(h0)) + { + HalfedgeHandle h1 = next_halfedge_handle(h0); + HalfedgeHandle h2 = next_halfedge_handle(h1); + + VertexHandle v1 = to_vertex_handle(h1); + + HalfedgeHandle e0 = new_edge(_vh, v1); + HalfedgeHandle t0 = opposite_halfedge_handle(e0); + + FaceHandle f1 = new_face(); + set_halfedge_handle(f0, h0); + set_halfedge_handle(f1, h2); + + set_face_handle(h1, f0); + set_face_handle(t0, f0); + set_face_handle(h0, f0); + + set_face_handle(h2, f1); + set_face_handle(t1, f1); + set_face_handle(e0, f1); + + set_next_halfedge_handle(h0, h1); + set_next_halfedge_handle(h1, t0); + set_next_halfedge_handle(t0, h0); + + set_next_halfedge_handle(e0, h2); + set_next_halfedge_handle(h2, t1); + set_next_halfedge_handle(t1, e0); + } + else + { + set_next_halfedge_handle(prev_halfedge_handle(h0), t1); + set_next_halfedge_handle(t1, h0); + // halfedge handle of _vh already is h0 + } + + + if (!is_boundary(o0)) + { + HalfedgeHandle o1 = next_halfedge_handle(o0); + HalfedgeHandle o2 = next_halfedge_handle(o1); + + VertexHandle v3 = to_vertex_handle(o1); + + HalfedgeHandle e2 = new_edge(_vh, v3); + HalfedgeHandle t2 = opposite_halfedge_handle(e2); + + FaceHandle f2 = new_face(); + set_halfedge_handle(f2, o1); + set_halfedge_handle(f3, o0); + + set_face_handle(o1, f2); + set_face_handle(t2, f2); + set_face_handle(e1, f2); + + set_face_handle(o2, f3); + set_face_handle(o0, f3); + set_face_handle(e2, f3); + + set_next_halfedge_handle(e1, o1); + set_next_halfedge_handle(o1, t2); + set_next_halfedge_handle(t2, e1); + + set_next_halfedge_handle(o0, e2); + set_next_halfedge_handle(e2, o2); + set_next_halfedge_handle(o2, o0); + } + else + { + set_next_halfedge_handle(e1, next_halfedge_handle(o0)); + set_next_halfedge_handle(o0, e1); + set_halfedge_handle(_vh, e1); + } + + if (halfedge_handle(v2) == h0) + set_halfedge_handle(v2, t1); +} + +//----------------------------------------------------------------------------- + +void TriConnectivity::split_copy(EdgeHandle _eh, VertexHandle _vh) +{ + const VertexHandle v0 = to_vertex_handle(halfedge_handle(_eh, 0)); + const VertexHandle v1 = to_vertex_handle(halfedge_handle(_eh, 1)); + + const int nf = n_faces(); + + // Split the halfedge ( handle will be preserved) + split(_eh, _vh); + + // Copy the properties of the original edge to all neighbor edges that + // have been created + for(VEIter ve_it = ve_iter(_vh); ve_it.is_valid(); ++ve_it) + copy_all_properties(_eh, *ve_it, true); + + for (auto vh : {v0, v1}) + { + // get the halfedge pointing from new vertex to old vertex + const HalfedgeHandle h = find_halfedge(_vh, vh); + if (!is_boundary(h)) // for boundaries there are no faces whose properties need to be copied + { + FaceHandle fh0 = face_handle(h); + FaceHandle fh1 = face_handle(opposite_halfedge_handle(prev_halfedge_handle(h))); + if (fh0.idx() >= nf) // is fh0 the new face? + std::swap(fh0, fh1); + + // copy properties from old face to new face + copy_all_properties(fh0, fh1, true); + } + } +} + +}// namespace OpenMesh diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriConnectivity.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriConnectivity.hh new file mode 100644 index 0000000..197420d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriConnectivity.hh @@ -0,0 +1,211 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_TRICONNECTIVITY_HH +#define OPENMESH_TRICONNECTIVITY_HH + +#include + +namespace OpenMesh { + +/** \brief Connectivity Class for Triangle Meshes +*/ +class OPENMESHDLLEXPORT TriConnectivity : public PolyConnectivity +{ +public: + + TriConnectivity() {} + virtual ~TriConnectivity() {} + + inline static bool is_triangles() + { return true; } + + /** assign_connectivity() methods. See ArrayKernel::assign_connectivity() + for more details. When the source connectivity is not triangles, in + addition "fan" connectivity triangulation is performed*/ + inline void assign_connectivity(const TriConnectivity& _other) + { PolyConnectivity::assign_connectivity(_other); } + + inline void assign_connectivity(const PolyConnectivity& _other) + { + PolyConnectivity::assign_connectivity(_other); + triangulate(); + } + + /** \name Addding items to a mesh + */ + + //@{ + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + FaceHandle add_face(const VertexHandle* _vhandles, size_t _vhs_size); + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + FaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add a face to the mesh (triangle) + * + * This function adds a triangle to the mesh. The triangle is passed directly + * to the underlying PolyConnectivity as we don't explicitly need to triangulate something. + * + * @param _vh0 VertexHandle 1 + * @param _vh1 VertexHandle 2 + * @param _vh2 VertexHandle 3 + * @return FaceHandle of the added face (invalid, if the operation failed) + */ + FaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2); + + //@} + + /** Returns the opposite vertex to the halfedge _heh in the face + referenced by _heh returns InvalidVertexHandle if the _heh is + boundary */ + inline VertexHandle opposite_vh(HalfedgeHandle _heh) const + { + return is_boundary(_heh) ? InvalidVertexHandle : + to_vertex_handle(next_halfedge_handle(_heh)); + } + + /** Returns the opposite vertex to the opposite halfedge of _heh in + the face referenced by it returns InvalidVertexHandle if the + opposite halfedge is boundary */ + VertexHandle opposite_he_opposite_vh(HalfedgeHandle _heh) const + { return opposite_vh(opposite_halfedge_handle(_heh)); } + + /** \name Topology modifying operators + */ + //@{ + + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _heh); + + /// Vertex Split: inverse operation to collapse(). + HalfedgeHandle vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr); + + /// Check whether flipping _eh is topologically correct. + bool is_flip_ok(EdgeHandle _eh) const; + + /** Flip edge _eh. + Check for topological correctness first using is_flip_ok(). */ + void flip(EdgeHandle _eh); + + + /** \brief Edge split (= 2-to-4 split) + * + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges, halfedges, and faces will be undefined! + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + void split(EdgeHandle _eh, VertexHandle _vh); + + /** \brief Edge split (= 2-to-4 split) + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges will be adjusted to the properties of the original edge + * \note The properties of the new faces and halfedges will be undefined + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + void split_copy(EdgeHandle _eh, VertexHandle _vh); + + /** \brief Face split (= 1-to-3) split, calls corresponding PolyMeshT function). + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split(_fh, _vh); } + + /** \brief Face split (= 1-to-3) split, calls corresponding PolyMeshT function). + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split_copy(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split_copy(_fh, _vh); } + + //@} + +private: + /// Helper for vertex split + HalfedgeHandle insert_loop(HalfedgeHandle _hh); + /// Helper for vertex split + HalfedgeHandle insert_edge(VertexHandle _vh, + HalfedgeHandle _h0, HalfedgeHandle _h1); +}; + +} + +#endif//OPENMESH_TRICONNECTIVITY_HH diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMeshT.cc b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMeshT.cc new file mode 100644 index 0000000..c225cd5 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMeshT.cc @@ -0,0 +1,93 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS TriMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_TRIMESH_C + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +template +typename TriMeshT::Normal +TriMeshT:: +calc_face_normal(FaceHandle _fh) const +{ + assert(this->halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(this->cfv_iter(_fh)); + + const Point& p0(this->point(*fv_it)); ++fv_it; + const Point& p1(this->point(*fv_it)); ++fv_it; + const Point& p2(this->point(*fv_it)); + + return PolyMesh::calc_face_normal(p0, p1, p2); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMeshT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMeshT.hh new file mode 100644 index 0000000..1865f30 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMeshT.hh @@ -0,0 +1,438 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS TriMeshT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_HH +#define OPENMESH_TRIMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class TriMeshT TriMeshT.hh + + Base type for a triangle mesh. + + Base type for a triangle mesh, parameterized by a mesh kernel. The + mesh inherits all methods from the kernel class and the + more general polygonal mesh PolyMeshT. Therefore it provides + the same types for items, handles, iterators and so on. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type + \see OpenMesh::PolyMeshT +*/ + +template +class TriMeshT : public PolyMeshT +{ + +public: + + + // self + typedef TriMeshT This; + typedef PolyMeshT PolyMesh; + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT ( This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT ) + enum { IsPolyMesh = 0 }; + enum { IsTriMesh = 1 }; + static bool is_polymesh() { return false; } + static bool is_trimesh() { return true; } + //@} + + //--- items --- + + typedef typename PolyMesh::Scalar Scalar; + typedef typename PolyMesh::Point Point; + typedef typename PolyMesh::Normal Normal; + typedef typename PolyMesh::Color Color; + typedef typename PolyMesh::TexCoord1D TexCoord1D; + typedef typename PolyMesh::TexCoord2D TexCoord2D; + typedef typename PolyMesh::TexCoord3D TexCoord3D; + typedef typename PolyMesh::Vertex Vertex; + typedef typename PolyMesh::Halfedge Halfedge; + typedef typename PolyMesh::Edge Edge; + typedef typename PolyMesh::Face Face; + + + //--- handles --- + + typedef typename PolyMesh::VertexHandle VertexHandle; + typedef typename PolyMesh::HalfedgeHandle HalfedgeHandle; + typedef typename PolyMesh::EdgeHandle EdgeHandle; + typedef typename PolyMesh::FaceHandle FaceHandle; + + + //--- iterators --- + + typedef typename PolyMesh::VertexIter VertexIter; + typedef typename PolyMesh::ConstVertexIter ConstVertexIter; + typedef typename PolyMesh::EdgeIter EdgeIter; + typedef typename PolyMesh::ConstEdgeIter ConstEdgeIter; + typedef typename PolyMesh::FaceIter FaceIter; + typedef typename PolyMesh::ConstFaceIter ConstFaceIter; + + + + //--- circulators --- + + typedef typename PolyMesh::VertexVertexIter VertexVertexIter; + typedef typename PolyMesh::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename PolyMesh::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename PolyMesh::VertexEdgeIter VertexEdgeIter; + typedef typename PolyMesh::VertexFaceIter VertexFaceIter; + typedef typename PolyMesh::FaceVertexIter FaceVertexIter; + typedef typename PolyMesh::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename PolyMesh::FaceEdgeIter FaceEdgeIter; + typedef typename PolyMesh::FaceFaceIter FaceFaceIter; + typedef typename PolyMesh::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename PolyMesh::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename PolyMesh::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename PolyMesh::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename PolyMesh::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename PolyMesh::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename PolyMesh::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename PolyMesh::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename PolyMesh::ConstFaceFaceIter ConstFaceFaceIter; + + // --- constructor/destructor + + /// Default constructor + TriMeshT() : PolyMesh() {} + explicit TriMeshT(PolyMesh rhs) : PolyMesh((rhs.triangulate(), rhs)) + { + } + + /// Destructor + virtual ~TriMeshT() {} + + //--- halfedge collapse / vertex split --- + + /** \brief Vertex Split: inverse operation to collapse(). + * + * Insert the new vertex at position v0. The vertex will be added + * as the inverse of the vertex split. The faces above the split + * will be correctly attached to the two new edges + * + * Before: + * v_l v0 v_r + * x x x + * \ / + * \ / + * \ / + * \ / + * \ / + * \ / + * x + * v1 + * + * After: + * v_l v0 v_r + * x------x------x + * \ | / + * \ | / + * \ | / + * \ | / + * \ | / + * \|/ + * x + * v1 + * + * @param _v0_point Point position for the new point + * @param _v1 Vertex that will be split + * @param _vl Left vertex handle + * @param _vr Right vertex handle + * @return Newly inserted halfedge + */ + inline HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(this->add_vertex(_v0_point), _v1, _vl, _vr); } + + /** \brief Vertex Split: inverse operation to collapse(). + * + * Insert the new vertex at position v0. The vertex will be added + * as the inverse of the vertex split. The faces above the split + * will be correctly attached to the two new edges + * + * Before: + * v_l v0 v_r + * x x x + * \ / + * \ / + * \ / + * \ / + * \ / + * \ / + * x + * v1 + * + * After: + * v_l v0 v_r + * x------x------x + * \ | / + * \ | / + * \ | / + * \ | / + * \ | / + * \|/ + * x + * v1 + * + * @param _v0 Vertex handle for the newly inserted point (Input has to be unconnected!) + * @param _v1 Vertex that will be split + * @param _vl Left vertex handle + * @param _vr Right vertex handle + * @return Newly inserted halfedge + */ + inline HalfedgeHandle vertex_split(VertexHandle _v0, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(_v0, _v1, _vl, _vr); } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be undefined! + * + * + * @param _eh Edge handle that should be splitted + * @param _p New point position that will be inserted at the edge + * @return Vertex handle of the newly added vertex + */ + inline VertexHandle split(EdgeHandle _eh, const Point& _p) + { + //Do not call PolyMeshT function below as this does the wrong operation + const VertexHandle vh = this->add_vertex(_p); Kernel::split(_eh, vh); return vh; + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be adjusted to the properties of the original edge + * + * @param _eh Edge handle that should be splitted + * @param _p New point position that will be inserted at the edge + * @return Vertex handle of the newly added vertex + */ + inline VertexHandle split_copy(EdgeHandle _eh, const Point& _p) + { + //Do not call PolyMeshT function below as this does the wrong operation + const VertexHandle vh = this->add_vertex(_p); Kernel::split_copy(_eh, vh); return vh; + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be undefined! + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split(EdgeHandle _eh, VertexHandle _vh) + { + //Do not call PolyMeshT function below as this does the wrong operation + Kernel::split(_eh, _vh); + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be adjusted to the properties of the original edge + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_copy(EdgeHandle _eh, VertexHandle _vh) + { + //Do not call PolyMeshT function below as this does the wrong operation + Kernel::split_copy(_eh, _vh); + } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _p New point position that will be inserted in the face + * + * @return Vertex handle of the new vertex + */ + inline VertexHandle split(FaceHandle _fh, const Point& _p) + { const VertexHandle vh = this->add_vertex(_p); PolyMesh::split(_fh, vh); return vh; } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be adjusted to the properties of the original face + * + * @param _fh Face handle that should be splitted + * @param _p New point position that will be inserted in the face + * + * @return Vertex handle of the new vertex + */ + inline VertexHandle split_copy(FaceHandle _fh, const Point& _p) + { const VertexHandle vh = this->add_vertex(_p); PolyMesh::split_copy(_fh, vh); return vh; } + + + /** \brief Face split (= 1-to-4) split, splits edges at midpoints and adds 4 new faces in the interior). + * + * @param _fh Face handle that should be splitted + */ + inline void split(FaceHandle _fh) + { + // Collect halfedges of face + HalfedgeHandle he0 = this->halfedge_handle(_fh); + HalfedgeHandle he1 = this->next_halfedge_handle(he0); + HalfedgeHandle he2 = this->next_halfedge_handle(he1); + + EdgeHandle eh0 = this->edge_handle(he0); + EdgeHandle eh1 = this->edge_handle(he1); + EdgeHandle eh2 = this->edge_handle(he2); + + // Collect points of face + VertexHandle p0 = this->to_vertex_handle(he0); + VertexHandle p1 = this->to_vertex_handle(he1); + VertexHandle p2 = this->to_vertex_handle(he2); + + // Calculate midpoint coordinates + const Point new0 = (this->point(p0) + this->point(p2)) * static_cast::value_type >(0.5); + const Point new1 = (this->point(p0) + this->point(p1)) * static_cast::value_type >(0.5); + const Point new2 = (this->point(p1) + this->point(p2)) * static_cast::value_type >(0.5); + + // Add vertices at midpoint coordinates + VertexHandle v0 = this->add_vertex(new0); + VertexHandle v1 = this->add_vertex(new1); + VertexHandle v2 = this->add_vertex(new2); + + const bool split0 = !this->is_boundary(eh0); + const bool split1 = !this->is_boundary(eh1); + const bool split2 = !this->is_boundary(eh2); + + // delete original face + this->delete_face(_fh); + + // split boundary edges of deleted face ( if not boundary ) + if ( split0 ) { + this->split(eh0,v0); + } + + if ( split1 ) { + this->split(eh1,v1); + } + + if ( split2 ) { + this->split(eh2,v2); + } + + // Retriangulate + this->add_face(v0 , p0, v1); + this->add_face(p2, v0 , v2); + this->add_face(v2,v1,p1); + this->add_face(v2 , v0, v1); + } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split(_fh, _vh); } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be adjusted to the properties of the original face + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split_copy(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split_copy(_fh, _vh); } + + /** \name Normal vector computation + */ + //@{ + + /** Calculate normal vector for face _fh (specialized for TriMesh). */ + Normal calc_face_normal(FaceHandle _fh) const; + + //@} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_TRIMESH_C) +#define OPENMESH_TRIMESH_TEMPLATES +#include "TriMeshT.cc" +#endif +//============================================================================= +#endif // OPENMESH_TRIMESH_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh new file mode 100644 index 0000000..0c648bf --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh @@ -0,0 +1,117 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS TriMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_ARRAY_KERNEL_HH +#define OPENMESH_TRIMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +template +class PolyMesh_ArrayKernelT; +//== CLASS DEFINITION ========================================================= + + +/// Helper class to create a TriMesh-type based on ArrayKernelT +template +struct TriMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef TriMeshT Mesh; +}; + + + +/** \ingroup mesh_types_group + Triangle mesh based on the ArrayKernel. + \see OpenMesh::TriMeshT + \see OpenMesh::ArrayKernelT +*/ +template +class TriMesh_ArrayKernelT + : public TriMesh_ArrayKernel_GeneratorT::Mesh +{ +public: + TriMesh_ArrayKernelT() {} + template + TriMesh_ArrayKernelT( const PolyMesh_ArrayKernelT & t) + { + //assign the connectivity and standard properties + this->assign(t,true); + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRIMESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/circulators_header.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/circulators_header.hh new file mode 100644 index 0000000..72bab07 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/circulators_header.hh @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_CIRCULATORS_HH +#define OPENMESH_CIRCULATORS_HH + +//============================================================================= +// +// Vertex and Face circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexVertexIterT; +template class VertexIHalfedgeIterT; +template class VertexOHalfedgeIterT; +template class VertexEdgeIterT; +template class VertexFaceIterT; + +template class ConstVertexVertexIterT; +template class ConstVertexIHalfedgeIterT; +template class ConstVertexOHalfedgeIterT; +template class ConstVertexEdgeIterT; +template class ConstVertexFaceIterT; + +template class FaceVertexIterT; +template class FaceHalfedgeIterT; +template class FaceEdgeIterT; +template class FaceFaceIterT; + +template class ConstFaceVertexIterT; +template class ConstFaceHalfedgeIterT; +template class ConstFaceEdgeIterT; +template class ConstFaceFaceIterT; + + + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/circulators_template.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/circulators_template.hh new file mode 100644 index 0000000..97a2171 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/circulators_template.hh @@ -0,0 +1,190 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class CirculatorT CirculatorsT.hh + Circulator. +*/ + +template +class CirculatorT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const TargetType& reference; + typedef const TargetType* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef TargetType& reference; + typedef TargetType* pointer; +#endif + + + + /// Default constructor + CirculatorT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a SourceHandle + CirculatorT(mesh_ref _mesh, SourceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { post_init; } + + + /// Construct with mesh and start halfedge + CirculatorT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { post_init; } + + + /// Copy constructor + CirculatorT(const CirculatorT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// Assignment operator + CirculatorT& operator=(const CirculatorT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if IsConst + /// construct from non-const circulator type + CirculatorT(const NonConstCircT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// assign from non-const circulator + CirculatorT& operator=(const NonConstCircT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstCircT; +#endif + + + /// Equal ? + bool operator==(const CirculatorT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const CirculatorT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + CirculatorT& operator++() { + assert(mesh_); + active_ = true; + increment; + return *this; + } + + + /// Pre-Decrement (next ccw target) + CirculatorT& operator--() { + assert(mesh_); + active_ = true; + decrement; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + TargetHandle handle() const { + assert(mesh_); + return get_handle; + } + + + /// Cast to the handle of the current target. + operator TargetHandle() const { + assert(mesh_); + return get_handle; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +private: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/footer.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/footer.hh new file mode 100644 index 0000000..8e2a9c1 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/footer.hh @@ -0,0 +1,6 @@ +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/generate.sh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/generate.sh new file mode 100644 index 0000000..3bcaffd --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/generate.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +#------------------------------------------------------------------------------ + + +# generate_iterator( TargetType, n_elements, has_element_status ) +function generate_iterator +{ + NonConstIter=$1"IterT" + ConstIter="Const"$NonConstIter + TargetType="typename Mesh::"$1 + TargetHandle="typename Mesh::"$1"Handle" + + + cat iterators_template.hh \ + | sed -e "s/IteratorT/$NonConstIter/; s/IteratorT/$NonConstIter/; + s/NonConstIterT/$NonConstIter/; + s/ConstIterT/$ConstIter/; + s/TargetType/$TargetType/; + s/TargetHandle/$TargetHandle/; + s/IsConst/0/; + s/n_elements/$2/; + s/has_element_status/$3/;" + + + cat iterators_template.hh \ + | sed -e "s/IteratorT/$ConstIter/; s/IteratorT/$ConstIter/; + s/NonConstIterT/$NonConstIter/; + s/ConstIterT/$ConstIter/; + s/TargetType/$TargetType/; + s/TargetHandle/$TargetHandle/; + s/IsConst/1/; + s/n_elements/$2/; + s/has_element_status/$3/;" +} + + +#------------------------------------------------------------------------------ + + +# generate_circulator( NonConstName, SourceType, TargetType, +# post_init, +# increment, decrement, +# get_handle, +# [Name] ) +function generate_circulator +{ + NonConstCirc=$1 + ConstCirc="Const"$NonConstCirc + SourceHandle="typename Mesh::"$2"Handle" + TargetHandle="typename Mesh::"$3"Handle" + TargetType="typename Mesh::"$3 + + + cat circulators_template.hh \ + | sed -e "s/CirculatorT/$NonConstCirc/; s/CirculatorT/$NonConstCirc/; + s/NonConstCircT/$NonConstCirc/; + s/ConstCircT/$ConstCirc/; + s/SourceHandle/$SourceHandle/; + s/TargetHandle/$TargetHandle/; + s/TargetType/$TargetType/; + s/IsConst/0/; + s/post_init/$4/; + s/increment/$5/; + s/decrement/$6/; + s/get_handle/$7/;" + + + cat circulators_template.hh \ + | sed -e "s/CirculatorT/$ConstCirc/; s/CirculatorT/$ConstCirc/; + s/NonConstCircT/$NonConstCirc/; + s/ConstCircT/$ConstCirc/; + s/SourceHandle/$SourceHandle/; + s/TargetHandle/$TargetHandle/; + s/TargetType/$TargetType/; + s/IsConst/1/; + s/post_init/$4/; + s/increment/$5/; + s/decrement/$6/; + s/get_handle/$7/;" +} + + +#------------------------------------------------------------------------------ + + +### Generate IteratorsT.hh + +cat iterators_header.hh > IteratorsT.hh + +generate_iterator Vertex n_vertices has_vertex_status >> IteratorsT.hh +generate_iterator Halfedge n_halfedges has_halfedge_status >> IteratorsT.hh +generate_iterator Edge n_edges has_edge_status >> IteratorsT.hh +generate_iterator Face n_faces has_face_status >> IteratorsT.hh + +cat footer.hh >> IteratorsT.hh + + +#------------------------------------------------------------------------------ + + +### Generate CirculatorsT.hh + +cat circulators_header.hh > CirculatorsT.hh + + +generate_circulator VertexVertexIterT Vertex Vertex \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->to_vertex_handle(heh_);" \ + >> CirculatorsT.hh + +generate_circulator VertexOHalfedgeIterT Vertex Halfedge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "heh_" \ + >> CirculatorsT.hh + +generate_circulator VertexIHalfedgeIterT Vertex Halfedge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->opposite_halfedge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator VertexEdgeIterT Vertex Edge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->edge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator VertexFaceIterT Vertex Face \ + "if (heh_.is_valid() \&\& !handle().is_valid()) operator++();" \ + "do heh_=mesh_->cw_rotated_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "do heh_=mesh_->ccw_rotated_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "mesh_->face_handle(heh_)" \ + >> CirculatorsT.hh + + +generate_circulator FaceVertexIterT Face Vertex \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "mesh_->to_vertex_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator FaceHalfedgeIterT Face Halfedge \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "heh_" \ + >> CirculatorsT.hh + +generate_circulator FaceEdgeIterT Face Edge \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "mesh_->edge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator FaceFaceIterT Face Face \ + "if (heh_.is_valid() \&\& !handle().is_valid()) operator++();" \ + "do heh_=mesh_->next_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "do heh_=mesh_->prev_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_))" \ + >> CirculatorsT.hh + + +cat footer.hh >> CirculatorsT.hh + + +#------------------------------------------------------------------------------ diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/iterators_header.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/iterators_header.hh new file mode 100644 index 0000000..22f6d8b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/iterators_header.hh @@ -0,0 +1,87 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_ITERATORS_HH +#define OPENMESH_ITERATORS_HH + +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexIterT; +template class ConstVertexIterT; +template class HalfedgeIterT; +template class ConstHalfedgeIterT; +template class EdgeIterT; +template class ConstEdgeIterT; +template class FaceIterT; +template class ConstFaceIterT; + + + + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/iterators_template.hh b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/iterators_template.hh new file mode 100644 index 0000000..99f54e0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Mesh/gen/iterators_template.hh @@ -0,0 +1,162 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class IteratorT IteratorsT.hh + Linear iterator. +*/ + +template +class IteratorT +{ +public: + + + //--- Typedefs --- + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + IteratorT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + IteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + IteratorT(const IteratorT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + IteratorT& operator=(const IteratorT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if IsConst + + /// Construct from a non-const iterator + IteratorT(const NonConstIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + IteratorT& operator=(const NonConstIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const IteratorT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const IteratorT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + IteratorT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + IteratorT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_element_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_elements()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/OpenMeshDLLMacros.hh b/libs/OpenMesh/inc/OpenMesh/Core/System/OpenMeshDLLMacros.hh new file mode 100644 index 0000000..c4d6a29 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/OpenMeshDLLMacros.hh @@ -0,0 +1,72 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 566 $ * + * $Date: 2012-03-23 18:00:57 +0100 (Fr, 23 Mär 2012) $ * + * * +\*===========================================================================*/ + +// Disable the warnings about needs to have DLL interface as we have tons of vector templates +#ifdef _MSC_VER + #pragma warning( disable: 4251 ) +#endif + +#ifndef OPENMESHDLLEXPORT + #ifdef WIN32 + #ifdef OPENMESHDLL + #ifdef BUILDOPENMESHDLL + #define OPENMESHDLLEXPORT __declspec(dllexport) + #define OPENMESHDLLEXPORTONLY __declspec(dllexport) + #else + #define OPENMESHDLLEXPORT __declspec(dllimport) + #define OPENMESHDLLEXPORTONLY + #endif + #else + #define OPENMESHDLLEXPORT + #define OPENMESHDLLEXPORTONLY + #endif + #else + #define OPENMESHDLLEXPORT + #define OPENMESHDLLEXPORTONLY + #endif +#endif diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/compiler.hh b/libs/OpenMesh/inc/OpenMesh/Core/System/compiler.hh new file mode 100644 index 0000000..412b090 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/compiler.hh @@ -0,0 +1,178 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_COMPILER_H +#define OPENMESH_COMPILER_H + +//============================================================================= + +#if defined(ACGMAKE_STATIC_BUILD) +# define OM_STATIC_BUILD 1 +#endif + +//============================================================================= + +#if defined(_DEBUG) || defined(DEBUG) +# define OM_DEBUG +#endif + +//============================================================================= + +// Workaround for Intel Compiler with MS VC++ 6 +#if defined(_MSC_VER) && \ + ( defined(__ICL) || defined(__INTEL_COMPILER) || defined(__ICC) ) +# if !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +# endif +# define OM_USE_INTEL_COMPILER 1 +#endif + +// --------------------------------------------------------- MS Visual C++ ---- +// Compiler _MSC_VER +// .NET 2002 1300 +// .NET 2003 1310 +// .NET 2005 1400 +#if defined(_MSC_VER) && !defined(OM_USE_INTEL_COMPILER) +# if (_MSC_VER == 1300) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 0 +# define OM_PARTIAL_SPECIALIZATION 0 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER == 1310) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER >= 1400) // settings for .NET 2005 (NOTE: not fully tested) +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 7 (.NET 2002) or higher of the MS VC++ is required!" +# endif +// currently no windows dll supported +# define OM_STATIC_BUILD 1 +# if defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "MSVC++" +# define OM_CC_VERSION _MSC_VER +// Does not work stable because the define _CPPRTTI sometimes does not exist, +// though the option /GR is set!? +# if defined(__cplusplus) && !defined(_CPPRTTI) +# error "Enable Runtime Type Information (Compiler Option /GR)!" +# endif +# if !defined(_USE_MATH_DEFINES) +# error "You have to define _USE_MATH_DEFINES in the compiler settings!" +# endif +// ------------------------------------------------------------- Borland C ---- +#elif defined(__BORLANDC__) +# error "Borland Compiler are not supported yet!" +// ------------------------------------------------------------- GNU C/C++ ---- +#elif defined(__GNUC__) && !defined(__ICC) +# define OM_CC_GCC +# define OM_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 ) +# define OM_GCC_MAJOR __GNUC__ +# define OM_GCC_MINOR __GNUC_MINOR__ +# if (OM_GCC_VERSION >= 30200) +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 3.2.0 or better of the GNU Compiler is required!" +# endif +# if defined(_REENTRANT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "GCC" +# define OM_CC_VERSION OM_GCC_VERSION +// ------------------------------------------------------------- Intel icc ---- +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# define OM_CC_ICC +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# if defined(_REENTRANT) || defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "ICC" +# define OM_CC_VERSION __INTEL_COMPILER +// currently no windows dll supported +# if defined(_MSC_VER) || defined(WIN32) +# define OM_STATIC_BUILD 1 +# endif +// ------------------------------------------------------ MIPSpro Compiler ---- +#elif defined(__MIPS_ISA) || defined(__mips) +// _MIPS_ISA +// _COMPILER_VERSION e.g. 730, 7 major, 3 minor +// _MIPS_FPSET 32|64 +// _MIPS_SZINT 32|64 +// _MIPS_SZLONG 32|64 +// _MIPS_SZPTR 32|64 +# define OM_CC_MIPS +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 0 +# define OM_CC "MIPS" +# define OM_CC_VERSION _COMPILER_VERSION +// ------------------------------------------------------------------ ???? ---- +#else +# error "You're using an unsupported compiler!" +#endif + +//============================================================================= +#endif // OPENMESH_COMPILER_H defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/config.h b/libs/OpenMesh/inc/OpenMesh/Core/System/config.h new file mode 100644 index 0000000..65c0b3e --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/config.h @@ -0,0 +1,107 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file config.h + * \todo Move content to config.hh and include it to be compatible with old + * source. + */ + +//============================================================================= + +#ifndef OPENMESH_CONFIG_H +#define OPENMESH_CONFIG_H + +//============================================================================= + +#include +#include +#include + +// ---------------------------------------------------------------------------- + + +#define OM_VERSION 0x70100 + +#define OM_GET_VER ((OM_VERSION & 0xf0000) >> 16) +#define OM_GET_MAJ ((OM_VERSION & 0x0ff00) >> 8) +#define OM_GET_MIN (OM_VERSION & 0x000ff) + +#ifdef WIN32 +# ifdef min +# pragma message("Detected min macro! OpenMesh does not compile with min/max macros active! Please add a define NOMINMAX to your compiler flags or add #undef min before including OpenMesh headers !") +# error min macro active +# endif +# ifdef max +# pragma message("Detected max macro! OpenMesh does not compile with min/max macros active! Please add a define NOMINMAX to your compiler flags or add #undef max before including OpenMesh headers !") +# error max macro active +# endif +#endif + +#if defined(_MSC_VER) +# define DEPRECATED(msg) __declspec(deprecated(msg)) +#elif defined(__GNUC__) +# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40500 /* Test for GCC >= 4.5.0 */ +# define DEPRECATED(msg) __attribute__ ((deprecated(msg))) +# else +# define DEPRECATED(msg) __attribute__ ((deprecated)) +# endif +#elif defined(__clang__) +# define DEPRECATED(msg) __attribute__ ((deprecated(msg))) +#else +# define DEPRECATED(msg) +#endif + +typedef unsigned int uint; + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define OM_HAS_HASH +#endif + +//============================================================================= +#endif // OPENMESH_CONFIG_H defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/config.hh b/libs/OpenMesh/inc/OpenMesh/Core/System/config.hh new file mode 100644 index 0000000..6c23e27 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/config.hh @@ -0,0 +1,49 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#include diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/mostream.hh b/libs/OpenMesh/inc/OpenMesh/Core/System/mostream.hh new file mode 100644 index 0000000..4dabf51 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/mostream.hh @@ -0,0 +1,330 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// multiplex streams & ultilities +// +//============================================================================= + +#ifndef OPENMESH_MOSTREAM_HH +#define OPENMESH_MOSTREAM_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# include +#else +# include +#endif +#include +#include +#include +#include + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + #include +#endif + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +#ifndef DOXY_IGNORE_THIS + + +//== CLASS DEFINITION ========================================================= + + +class basic_multiplex_target +{ +public: + virtual ~basic_multiplex_target() {} + virtual void operator<<(const std::string& _s) = 0; +}; + + +template +class multiplex_target : public basic_multiplex_target +{ +public: + explicit multiplex_target(T& _t) : target_(_t) {} + virtual void operator<<(const std::string& _s) { target_ << _s; } +private: + T& target_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# define STREAMBUF streambuf +# define INT_TYPE int +# define TRAITS_TYPE +#else +# define STREAMBUF std::basic_streambuf +#endif + +class multiplex_streambuf : public STREAMBUF +{ +public: + + typedef STREAMBUF base_type; +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + typedef int int_type; + struct traits_type + { + static int_type eof() { return -1; } + static char to_char_type(int_type c) { return char(c); } + }; +#else + typedef base_type::int_type int_type; + typedef base_type::traits_type traits_type; +#endif + + // Constructor + multiplex_streambuf() : enabled_(true) { buffer_.reserve(100); } + + // Destructor + ~multiplex_streambuf() + { + tmap_iter t_it(target_map_.begin()), t_end(target_map_.end()); + for (; t_it!=t_end; ++t_it) + delete t_it->second; + } + + + // buffer enable/disable + bool is_enabled() const { return enabled_; } + void enable() { enabled_ = true; } + void disable() { enabled_ = false; } + + + // construct multiplex_target and add it to targets + template bool connect(T& _target) + { + void* key = (void*) &_target; + + if (target_map_.find(key) != target_map_.end()) + return false; + + target_type* mtarget = new multiplex_target(_target); + target_map_[key] = mtarget; + + __connect(mtarget); + return true; + } + + + // disconnect target from multiplexer + template bool disconnect(T& _target) + { + void* key = (void*) &_target; + tmap_iter t_it = target_map_.find(key); + + if (t_it != target_map_.end()) + { + __disconnect(t_it->second); + target_map_.erase(t_it); + return true; + } + + return false; + } + + +protected: + + // output what's in buffer_ + virtual int sync() + { + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::lock_guard lck (serializer_); + #endif + + if (!buffer_.empty()) + { + if (enabled_) multiplex(); +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + buffer_ = ""; // member clear() not available! +#else + buffer_.clear(); +#endif + } + return base_type::sync(); + } + + + // take on char and add it to buffer_ + // if '\n' is encountered, trigger a sync() + virtual + int_type overflow(int_type _c = multiplex_streambuf::traits_type::eof()) + { + char c = traits_type::to_char_type(_c); + + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + { + std::lock_guard lck (serializer_); + buffer_.push_back(c); + } + #else + buffer_.push_back(c); + #endif + + if (c == '\n') sync(); + return 0; + } + + +private: + + typedef basic_multiplex_target target_type; + typedef std::vector target_list; + typedef target_list::iterator tlist_iter; + typedef std::map target_map; + typedef target_map::iterator tmap_iter; + + + // add _target to list of multiplex targets + void __connect(target_type* _target) { targets_.push_back(_target); } + + + // remove _target from list of multiplex targets + void __disconnect(target_type* _target) { + targets_.erase(std::find(targets_.begin(), targets_.end(), _target)); + } + + + // multiplex output of buffer_ to all targets + void multiplex() + { + tlist_iter t_it(targets_.begin()), t_end(targets_.end()); + for (; t_it!=t_end; ++t_it) + **t_it << buffer_; + } + + +private: + + target_list targets_; + target_map target_map_; + std::string buffer_; + bool enabled_; + + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::mutex serializer_; + #endif + +}; + +#undef STREAMBUF + + +//== CLASS DEFINITION ========================================================= + + +/** \class mostream mostream.hh + + This class provides streams that can easily be multiplexed (using + the connect() method) and toggled on/off (using enable() / + disable()). + + \see omlog, omout, omerr +*/ + +class mostream : public std::ostream +{ +public: + + /// Explicit constructor + explicit mostream() : std::ostream(NULL) { init(&streambuffer_); } + + + /// Connect target to multiplexer + template bool connect(T& _target) + { + return streambuffer_.connect(_target); + } + + + /// Disconnect target from multiplexer + template bool disconnect(T& _target) + { + return streambuffer_.disconnect(_target); + } + + + /// is buffer enabled + bool is_enabled() const { return streambuffer_.is_enabled(); } + + /// enable this buffer + void enable() { streambuffer_.enable(); } + + /// disable this buffer + void disable() { streambuffer_.disable(); } + + +private: + multiplex_streambuf streambuffer_; +}; + + +//============================================================================= +#endif +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MOSTREAM_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/omstream.cc b/libs/OpenMesh/inc/OpenMesh/Core/System/omstream.cc new file mode 100644 index 0000000..79554c1 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/omstream.cc @@ -0,0 +1,107 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS mostream - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include +#include + + +//== IMPLEMENTATION ========================================================== + + +OpenMesh::mostream& omlog() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::clog); +#ifdef NDEBUG + mystream.disable(); +#endif + initialized = true; + } + return mystream; +} + + +OpenMesh::mostream& omout() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::cout); + initialized = true; + } + return mystream; +} + + +OpenMesh::mostream& omerr() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::cerr); + initialized = true; + } + return mystream; +} + + +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/System/omstream.hh b/libs/OpenMesh/inc/OpenMesh/Core/System/omstream.hh new file mode 100644 index 0000000..01fdfb0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/System/omstream.hh @@ -0,0 +1,83 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// OpenMesh streams: omlog, omout, omerr +// +//============================================================================= + +#ifndef OPENMESH_OMSTREAMS_HH +#define OPENMESH_OMSTREAMS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== CLASS DEFINITION ========================================================= + +/** \file omstream.hh + This file provides the streams omlog, omout, and omerr. +*/ + +/** \name stream replacements + These stream provide replacements for clog, cout, and cerr. They have + the advantage that they can easily be multiplexed. + \see OpenMesh::mostream +*/ +//@{ +OPENMESHDLLEXPORT OpenMesh::mostream& omlog(); +OPENMESHDLLEXPORT OpenMesh::mostream& omout(); +OPENMESHDLLEXPORT OpenMesh::mostream& omerr(); +//@} + +//============================================================================= +#endif // OPENMESH_OMSTREAMS_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.cc b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.cc new file mode 100644 index 0000000..a0f5aba --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.cc @@ -0,0 +1,76 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +//----------------------------------------------------------------------------- + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.hh b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.hh new file mode 100644 index 0000000..31a2fd2 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.hh @@ -0,0 +1,108 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= +#ifndef DOXY_IGNORE_THIS +#ifndef OPENMESH_NEWCLASS_HH +#define OPENMESH_NEWCLASS_HH + + +//== INCLUDES ================================================================= + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class newClass newClass.hh + + Brief Description. + + A more elaborate description follows. +*/ + +class newClass +{ +public: + + /// Default constructor + newClass() {} + + /// Destructor + ~newClass() {} + + +private: + + /// Copy constructor (not used) + newClass(const newClass& _rhs); + + /// Assignment operator (not used) + newClass& operator=(const newClass& _rhs); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_NEWCLASS_HH defined +#endif // DOXY_IGNORE_THIS +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.sh b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.sh new file mode 100644 index 0000000..7ea19a7 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClass.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +A=`echo $1_ | tr '[:lower:]' '[:upper:]'` + +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClass.cc > tmp_newClass.cc +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClass.hh > tmp_newClass.hh + +mv -i tmp_newClass.cc $1.cc && echo $1.cc - ok +mv -i tmp_newClass.hh $1.hh && echo $1.hh - ok diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.cc b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.cc new file mode 100644 index 0000000..e89b6da --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.cc @@ -0,0 +1,77 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_NEWCLASS_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +//----------------------------------------------------------------------------- + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.hh new file mode 100644 index 0000000..00b5f14 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.hh @@ -0,0 +1,115 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= +#ifndef DOXY_IGNORE_THIS +#ifndef OPENMESH_NEWCLASST_HH +#define OPENMESH_NEWCLASST_HH + + +//== INCLUDES ================================================================= + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + + +/** \class newClassT newClassT.hh + + Brief Description. + + A more elaborate description follows. +*/ + +template <> +class newClassT +{ +public: + + /// Default constructor + newClassT() {} + + /// Destructor + ~newClassT() {} + + +private: + + /// Copy constructor (not used) + newClassT(const newClassT& _rhs); + + /// Assignment operator (not used) + newClassT& operator=(const newClassT& _rhs); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_NEWCLASS_C) +#define OPENMESH_NEWCLASS_TEMPLATES +#include "newClass.cc" +#endif +//============================================================================= +#endif // OPENMESH_NEWCLASST_HH defined +#endif // DOXY_IGNORE_THIS +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.sh b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.sh new file mode 100644 index 0000000..7023244 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Templates/newClassT.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +A=`echo $1_ | tr '[:lower:]' '[:upper:]'` + +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClassT.cc > tmp_newClass.cc +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClassT.hh > tmp_newClass.hh + +mv -i tmp_newClass.cc $1.cc && echo $1.cc - ok +mv -i tmp_newClass.hh $1.hh && echo $1.hh - ok diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/AutoPropertyHandleT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/AutoPropertyHandleT.hh new file mode 100644 index 0000000..fae37a9 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/AutoPropertyHandleT.hh @@ -0,0 +1,138 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_AutoPropertyHandleT_HH +#define OPENMESH_AutoPropertyHandleT_HH + +//== INCLUDES ================================================================= +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +template +class AutoPropertyHandleT : public PropertyHandle_ +{ +public: + typedef Mesh_ Mesh; + typedef PropertyHandle_ PropertyHandle; + typedef PropertyHandle Base; + typedef typename PropertyHandle::Value Value; + typedef AutoPropertyHandleT + Self; +protected: + Mesh* m_; + bool own_property_;//ref counting? + +public: + AutoPropertyHandleT() + : m_(NULL), own_property_(false) + {} + + AutoPropertyHandleT(const Self& _other) + : Base(_other.idx()), m_(_other.m_), own_property_(false) + {} + + explicit AutoPropertyHandleT(Mesh& _m, const std::string& _pp_name = std::string()) + { add_property(_m, _pp_name); } + + AutoPropertyHandleT(Mesh& _m, PropertyHandle _pph) + : Base(_pph.idx()), m_(&_m), own_property_(false) + {} + + ~AutoPropertyHandleT() + { + if (own_property_) + { + m_->remove_property(*this); + } + } + + inline void add_property(Mesh& _m, const std::string& _pp_name = std::string()) + { + assert(!is_valid()); + m_ = &_m; + own_property_ = _pp_name.empty() || !m_->get_property_handle(*this, _pp_name); + if (own_property_) + { + m_->add_property(*this, _pp_name); + } + } + + inline void remove_property() + { + assert(own_property_);//only the owner can delete the property + m_->remove_property(*this); + own_property_ = false; + invalidate(); + } + + template + inline Value& operator [] (_Handle _hnd) + { return m_->property(*this, _hnd); } + + template + inline const Value& operator [] (_Handle _hnd) const + { return m_->property(*this, _hnd); } + + inline bool own_property() const + { return own_property_; } + + inline void free_property() + { own_property_ = false; } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_AutoPropertyHandleT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/BaseProperty.cc b/libs/OpenMesh/inc/OpenMesh/Core/Utils/BaseProperty.cc new file mode 100644 index 0000000..92de7b6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/BaseProperty.cc @@ -0,0 +1,59 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#include + +namespace OpenMesh +{ + +void BaseProperty::stats(std::ostream& _ostr) const +{ + _ostr << " " << name() << (persistent() ? ", persistent " : "") << "\n"; +} + +} diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/BaseProperty.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/BaseProperty.hh new file mode 100644 index 0000000..3abcfe2 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/BaseProperty.hh @@ -0,0 +1,188 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_BASEPROPERTY_HH +#define OPENMESH_BASEPROPERTY_HH + +#include +#include +#include + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class BaseProperty Property.hh + + Abstract class defining the basic interface of a dynamic property. +**/ + +class OPENMESHDLLEXPORT BaseProperty +{ +public: + + /// Indicates an error when a size is returned by a member. + static const size_t UnknownSize = size_t(-1); + +public: + + /// \brief Default constructor. + /// + /// In %OpenMesh all mesh data is stored in so-called properties. + /// We distinuish between standard properties, which can be defined at + /// compile time using the Attributes in the traits definition and + /// at runtime using the request property functions defined in one of + /// the kernels. + /// + /// If the property should be stored along with the default properties + /// in the OM-format one must name the property and enable the persistant + /// flag with set_persistent(). + /// + /// \param _name Optional textual name for the property. + /// + BaseProperty(const std::string& _name = "") + : name_(_name), persistent_(false) + {} + + /// \brief Copy constructor + BaseProperty(const BaseProperty & _rhs) + : name_( _rhs.name_ ), persistent_( _rhs.persistent_ ) {} + + /// Destructor. + virtual ~BaseProperty() {} + +public: // synchronized array interface + + /// Reserve memory for n elements. + virtual void reserve(size_t _n) = 0; + + /// Resize storage to hold n elements. + virtual void resize(size_t _n) = 0; + + /// Clear all elements and free memory. + virtual void clear() = 0; + + /// Extend the number of elements by one. + virtual void push_back() = 0; + + /// Let two elements swap their storage place. + virtual void swap(size_t _i0, size_t _i1) = 0; + + /// Copy one element to another + virtual void copy(size_t _io, size_t _i1) = 0; + + /// Return a deep copy of self. + virtual BaseProperty* clone () const = 0; + +public: // named property interface + + /// Return the name of the property + const std::string& name() const { return name_; } + + virtual void stats(std::ostream& _ostr) const; + +public: // I/O support + + /// Returns true if the persistent flag is enabled else false. + bool persistent(void) const { return persistent_; } + + /// Enable or disable persistency. Self must be a named property to enable + /// persistency. + virtual void set_persistent( bool _yn ) = 0; + + /// Number of elements in property + virtual size_t n_elements() const = 0; + + /// Size of one element in bytes or UnknownSize if not known. + virtual size_t element_size() const = 0; + + /// Return size of property in bytes + virtual size_t size_of() const + { + return size_of( n_elements() ); + } + + /// Estimated size of property if it has _n_elem elements. + /// The member returns UnknownSize if the size cannot be estimated. + virtual size_t size_of(size_t _n_elem) const + { + return (element_size()!=UnknownSize) + ? (_n_elem*element_size()) + : UnknownSize; + } + + /// Store self as one binary block + virtual size_t store( std::ostream& _ostr, bool _swap ) const = 0; + + /** Restore self from a binary block. Uses reserve() to set the + size of self before restoring. + **/ + virtual size_t restore( std::istream& _istr, bool _swap ) = 0; + +protected: + + // To be used in a derived class, when overloading set_persistent() + template < typename T > + void check_and_set_persistent( bool _yn ) + { + if ( _yn && !IO::is_streamable() ) + omerr() << "Warning! Type of property value is not binary storable!\n"; + persistent_ = IO::is_streamable() && _yn; + } + +private: + + std::string name_; + bool persistent_; +}; + +}//namespace OpenMesh + +#endif //OPENMESH_BASEPROPERTY_HH + + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/Endian.cc b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Endian.cc new file mode 100644 index 0000000..c4fb314 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Endian.cc @@ -0,0 +1,86 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION =========================================================== + +//----------------------------------------------------------------------------- + +int Endian::one_ = 1; + +const Endian::Type Endian::local_ = *((unsigned char*)&Endian::one_) + ? Endian::LSB + : Endian::MSB; + +const char * Endian::as_string(Type _t) +{ + return _t == LSB ? "LSB" : "MSB"; +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/Endian.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Endian.hh new file mode 100644 index 0000000..e511c00 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Endian.hh @@ -0,0 +1,103 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_ENDIAN_HH +#define OPENMESH_UTILS_ENDIAN_HH + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Determine byte order of host system. + */ +class OPENMESHDLLEXPORT Endian +{ +public: + + enum Type { + LSB = 1, ///< Little endian (Intel family and clones) + MSB ///< big endian (Motorola's 68x family, DEC Alpha, MIPS) + }; + + /// Return endian type of host system. + static Type local() { return local_; } + + /// Return type _t as string. + static const char * as_string(Type _t); + +private: + static int one_; + static const Type local_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/GenProg.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/GenProg.hh new file mode 100644 index 0000000..bf0b20a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/GenProg.hh @@ -0,0 +1,165 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Utils for generic/generative programming +// +//============================================================================= + +#ifndef OPENMESH_GENPROG_HH +#define OPENMESH_GENPROG_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +namespace GenProg { +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + + +/// This type maps \c true or \c false to different types. +template struct Bool2Type { enum { my_bool = b }; }; + +/// This class generates different types from different \c int 's. +template struct Int2Type { enum { my_int = i }; }; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type TrueType; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type FalseType; + +//----------------------------------------------------------------------------- +/// compile time assertions +template struct AssertCompile; +template <> struct AssertCompile {}; + + + +//--- Template "if" w/ partial specialization --------------------------------- +#if OM_PARTIAL_SPECIALIZATION + + +template +struct IF { typedef Then Result; }; + +/** Template \c IF w/ partial specialization +\code +typedef IF::Result ResultType; +\endcode +*/ +template +struct IF { typedef Else Result; }; + + + + + +//--- Template "if" w/o partial specialization -------------------------------- +#else + + +struct SelectThen +{ + template struct Select { + typedef Then Result; + }; +}; + +struct SelectElse +{ + template struct Select { + typedef Else Result; + }; +}; + +template struct ChooseSelector { + typedef SelectThen Result; +}; + +template <> struct ChooseSelector { + typedef SelectElse Result; +}; + + +/** Template \c IF w/o partial specialization. Use it like +\code +typedef IF::Result ResultType; +\endcode +*/ + +template +class IF +{ + typedef typename ChooseSelector::Result Selector; +public: + typedef typename Selector::template Select::Result Result; +}; + +#endif + +//============================================================================= +#endif +} // namespace GenProg +} // namespace OpenMesh + +#define assert_compile(EXPR) GenProg::AssertCompile<(EXPR)>(); + +//============================================================================= +#endif // OPENMESH_GENPROG_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/Noncopyable.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Noncopyable.hh new file mode 100644 index 0000000..ddbfb3e --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Noncopyable.hh @@ -0,0 +1,94 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the Non-Copyable metapher +// +//============================================================================= + +#ifndef OPENMESH_NONCOPYABLE_HH +#define OPENMESH_NONCOPYABLE_HH + + +//----------------------------------------------------------------------------- + +#include + +//----------------------------------------------------------------------------- + +namespace OpenMesh { +namespace Utils { + +//----------------------------------------------------------------------------- + +/** This class demonstrates the non copyable idiom. In some cases it is + important an object can't be copied. Deriving from Noncopyable makes sure + all relevant constructor and operators are made inaccessable, for public + AND derived classes. +**/ +class Noncopyable +{ +public: + Noncopyable() { } + +private: + /// Prevent access to copy constructor + Noncopyable( const Noncopyable& ); + + /// Prevent access to assignment operator + const Noncopyable& operator=( const Noncopyable& ); +}; + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_NONCOPYABLE_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/Property.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Property.hh new file mode 100644 index 0000000..ab26d9d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/Property.hh @@ -0,0 +1,555 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_PROPERTY_HH +#define OPENMESH_PROPERTY_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class PropertyT Property.hh + * + * \brief Default property class for any type T. + * + * The default property class for any type T. + * + * The property supports persistency if T is a "fundamental" type: + * - integer fundamental types except bool: + * char, short, int, long, long long (__int64 for MS VC++) and + * their unsigned companions. + * - float fundamentals except long double: + * float, double + * - %OpenMesh vector types + * + * Persistency of non-fundamental types is supported if and only if a + * specialization of struct IO::binary<> exists for the wanted type. + */ + +// TODO: it might be possible to define Property using kind of a runtime info +// structure holding the size of T. Then reserve, swap, resize, etc can be written +// in pure malloc() style w/o virtual overhead. Template member function proved per +// element access to the properties, asserting dynamic_casts in debug + +template +class PropertyT : public BaseProperty +{ +public: + + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + +public: + + /// Default constructor + PropertyT(const std::string& _name = "") + : BaseProperty(_name) + {} + + /// Copy constructor + PropertyT(const PropertyT & _rhs) + : BaseProperty( _rhs ), data_( _rhs.data_ ) {} + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) { data_.reserve(_n); } + virtual void resize(size_t _n) { data_.resize(_n); } + virtual void clear() { data_.clear(); vector_type().swap(data_); } + virtual void push_back() { data_.push_back(T()); } + virtual void swap(size_t _i0, size_t _i1) + { std::swap(data_[_i0], data_[_i1]); } + virtual void copy(size_t _i0, size_t _i1) + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) + { check_and_set_persistent( _yn ); } + + virtual size_t n_elements() const { return data_.size(); } + virtual size_t element_size() const { return IO::size_of(); } + +#ifndef DOXY_IGNORE_THIS + struct plus { + size_t operator () ( size_t _b, const T& _v ) + { return _b + IO::size_of(_v); } + }; +#endif + + virtual size_t size_of(void) const + { + if (element_size() != IO::UnknownSize) + return this->BaseProperty::size_of(n_elements()); + return std::accumulate(data_.begin(), data_.end(), size_t(0), plus()); + } + + virtual size_t size_of(size_t _n_elem) const + { return this->BaseProperty::size_of(_n_elem); } + + virtual size_t store( std::ostream& _ostr, bool _swap ) const + { + if ( IO::is_streamable() ) + return IO::store(_ostr, data_, _swap ); + size_t bytes = 0; + for (size_t i=0; i() ) + return IO::restore(_istr, data_, _swap ); + size_t bytes = 0; + for (size_t i=0; i* clone() const + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + +private: + + vector_type data_; +}; + +//----------------------------------------------------------------------------- + + +/** Property specialization for bool type. + + The data will be stored as a bitset. + */ +template <> +class PropertyT : public BaseProperty +{ +public: + + typedef std::vector vector_type; + typedef bool value_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + +public: + + PropertyT(const std::string& _name = "") + : BaseProperty(_name) + { } + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) { data_.reserve(_n); } + virtual void resize(size_t _n) { data_.resize(_n); } + virtual void clear() { data_.clear(); vector_type().swap(data_); } + virtual void push_back() { data_.push_back(bool()); } + virtual void swap(size_t _i0, size_t _i1) + { bool t(data_[_i0]); data_[_i0]=data_[_i1]; data_[_i1]=t; } + virtual void copy(size_t _i0, size_t _i1) + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) + { + check_and_set_persistent( _yn ); + } + + virtual size_t n_elements() const { return data_.size(); } + virtual size_t element_size() const { return UnknownSize; } + virtual size_t size_of() const { return size_of( n_elements() ); } + virtual size_t size_of(size_t _n_elem) const + { + return _n_elem / 8 + ((_n_elem % 8)!=0); + } + + size_t store( std::ostream& _ostr, bool /* _swap */ ) const + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + bits = static_cast(data_[bidx]) + | (static_cast(data_[bidx+1]) << 1) + | (static_cast(data_[bidx+2]) << 2) + | (static_cast(data_[bidx+3]) << 3) + | (static_cast(data_[bidx+4]) << 4) + | (static_cast(data_[bidx+5]) << 5) + | (static_cast(data_[bidx+6]) << 6) + | (static_cast(data_[bidx+7]) << 7); + _ostr << bits; + } + bytes = N; + + if (R) + { + bits = 0; + for (idx=0; idx < R; ++idx) + bits |= static_cast(data_[bidx+idx]) << idx; + _ostr << bits; + ++bytes; + } + + assert( bytes == size_of() ); + + return bytes; + } + + size_t restore( std::istream& _istr, bool /* _swap */ ) + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; // + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + _istr >> bits; + data_[bidx+0] = (bits & 0x01) != 0; + data_[bidx+1] = (bits & 0x02) != 0; + data_[bidx+2] = (bits & 0x04) != 0; + data_[bidx+3] = (bits & 0x08) != 0; + data_[bidx+4] = (bits & 0x10) != 0; + data_[bidx+5] = (bits & 0x20) != 0; + data_[bidx+6] = (bits & 0x40) != 0; + data_[bidx+7] = (bits & 0x80) != 0; + } + bytes = N; + + if (R) + { + _istr >> bits; + for (idx=0; idx < R; ++idx) + data_[bidx+idx] = (bits & (1<* clone() const + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + +private: + + vector_type data_; +}; + + +//----------------------------------------------------------------------------- + + +/** Property specialization for std::string type. +*/ +template <> +class PropertyT : public BaseProperty +{ +public: + + typedef std::string Value; + typedef std::vector vector_type; + typedef std::string value_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + +public: + + PropertyT(const std::string& _name = "") + : BaseProperty(_name) + { } + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) { data_.reserve(_n); } + virtual void resize(size_t _n) { data_.resize(_n); } + virtual void clear() { data_.clear(); vector_type().swap(data_); } + virtual void push_back() { data_.push_back(std::string()); } + virtual void swap(size_t _i0, size_t _i1) { + std::swap(data_[_i0], data_[_i1]); + } + virtual void copy(size_t _i0, size_t _i1) + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) + { check_and_set_persistent( _yn ); } + + virtual size_t n_elements() const { return data_.size(); } + virtual size_t element_size() const { return UnknownSize; } + virtual size_t size_of() const + { return IO::size_of( data_ ); } + + virtual size_t size_of(size_t /* _n_elem */) const + { return UnknownSize; } + + /// Store self as one binary block. Max. length of a string is 65535 bytes. + size_t store( std::ostream& _ostr, bool _swap ) const + { return IO::store( _ostr, data_, _swap ); } + + size_t restore( std::istream& _istr, bool _swap ) + { return IO::restore( _istr, data_, _swap ); } + +public: + + const value_type* data() const { + if( data_.empty() ) + return 0; + + return (value_type*) &data_[0]; + } + + /// Access the i'th element. No range check is performed! + reference operator[](int _idx) { + assert( size_t(_idx) < data_.size()); + return ((value_type*) &data_[0])[_idx]; + } + + /// Const access the i'th element. No range check is performed! + const_reference operator[](int _idx) const { + assert( size_t(_idx) < data_.size()); + return ((value_type*) &data_[0])[_idx]; + } + + PropertyT* clone() const { + PropertyT* p = new PropertyT( *this ); + return p; + } +private: + + vector_type data_; + +}; + +/// Base property handle. +template +struct BasePropHandleT : public BaseHandle +{ + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + + explicit BasePropHandleT(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a vertex property + */ +template +struct VPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit VPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit VPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a halfedge property + */ +template +struct HPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit HPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit HPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing an edge property + */ +template +struct EPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit EPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit EPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a face property + */ +template +struct FPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit FPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit FPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a mesh property + */ +template +struct MPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit MPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit MPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PROPERTY_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/PropertyContainer.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/PropertyContainer.hh new file mode 100644 index 0000000..d8d7393 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/PropertyContainer.hh @@ -0,0 +1,375 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_PROPERTYCONTAINER +#define OPENMESH_PROPERTYCONTAINER + +// Use static casts when not debugging +#ifdef NDEBUG +#define OM_FORCE_STATIC_CAST +#endif + +#include + +//----------------------------------------------------------------------------- +namespace OpenMesh +{ +//== FORWARDDECLARATIONS ====================================================== + class BaseKernel; + +//== CLASS DEFINITION ========================================================= +/// A a container for properties. +class PropertyContainer +{ +public: + + //-------------------------------------------------- constructor / destructor + + PropertyContainer() {} + virtual ~PropertyContainer() { std::for_each(properties_.begin(), properties_.end(), Delete()); } + + + //------------------------------------------------------------- info / access + + typedef std::vector Properties; + const Properties& properties() const { return properties_; } + size_t size() const { return properties_.size(); } + + + + //--------------------------------------------------------- copy / assignment + + PropertyContainer(const PropertyContainer& _rhs) { operator=(_rhs); } + + PropertyContainer& operator=(const PropertyContainer& _rhs) + { + // The assignment below relies on all previous BaseProperty* elements having been deleted + std::for_each(properties_.begin(), properties_.end(), Delete()); + properties_ = _rhs.properties_; + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + for (; p_it!=p_end; ++p_it) + if (*p_it) + *p_it = (*p_it)->clone(); + return *this; + } + + + + //--------------------------------------------------------- manage properties + + template + BasePropHandleT add(const T&, const std::string& _name="") + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + int idx=0; + for ( ; p_it!=p_end && *p_it!=NULL; ++p_it, ++idx ) {}; + if (p_it==p_end) properties_.push_back(NULL); + properties_[idx] = new PropertyT(_name); + return BasePropHandleT(idx); + } + + + template + BasePropHandleT handle(const T&, const std::string& _name) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != NULL && + (*p_it)->name() == _name //skip deleted properties +// Skip type check +#ifndef OM_FORCE_STATIC_CAST + && dynamic_cast*>(properties_[idx]) != NULL //check type +#endif + ) + { + return BasePropHandleT(idx); + } + } + return BasePropHandleT(); + } + + BaseProperty* property( const std::string& _name ) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != NULL && (*p_it)->name() == _name) //skip deleted properties + { + return *p_it; + } + } + return NULL; + } + + template PropertyT& property(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != NULL); +#ifdef OM_FORCE_STATIC_CAST + return *static_cast *> (properties_[_h.idx()]); +#else + PropertyT* p = dynamic_cast*>(properties_[_h.idx()]); + assert(p != NULL); + return *p; +#endif + } + + + template const PropertyT& property(BasePropHandleT _h) const + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != NULL); +#ifdef OM_FORCE_STATIC_CAST + return *static_cast*>(properties_[_h.idx()]); +#else + PropertyT* p = dynamic_cast*>(properties_[_h.idx()]); + assert(p != NULL); + return *p; +#endif + } + + + template void remove(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + delete properties_[_h.idx()]; + properties_[_h.idx()] = NULL; + } + + + void clear() + { + // Clear properties vector: + // Replaced the old version with new one + // which performs a swap to clear values and + // deallocate memory. + + // Old version (changed 22.07.09) { + // std::for_each(properties_.begin(), properties_.end(), Delete()); + // } + + std::for_each(properties_.begin(), properties_.end(), ClearAll()); + } + + + //---------------------------------------------------- synchronize properties + +/* + * In C++11 an beyond we can introduce more efficient and more legible + * implementations of the following methods. + */ +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + /** + * Reserves space for \p _n elements in all property vectors. + */ + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->reserve(_n); }); + } + + /** + * Resizes all property vectors to the specified size. + */ + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->resize(_n); }); + } + + /** + * Same as resize() but ignores property vectors that have a size larger + * than \p _n. + * + * Use this method instead of resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p && p->n_elements() < _n) p->resize(_n); }); + } + + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), + [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); }); + } +#else + /** + * Reserves space for \p _n elements in all property vectors. + */ + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Reserve(_n)); + } + + /** + * Resizes all property vectors to the specified size. + */ + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Resize(_n)); + } + + /** + * Same as \sa resize() but ignores property vectors that have a size + * larger than \p _n. + * + * Use this method instead of \sa resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n)); + } + + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); + } +#endif + + + +protected: // generic add/get + + size_t _add( BaseProperty* _bp ) + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + size_t idx=0; + for (; p_it!=p_end && *p_it!=NULL; ++p_it, ++idx) {}; + if (p_it==p_end) properties_.push_back(NULL); + properties_[idx] = _bp; + return idx; + } + + BaseProperty& _property( size_t _idx ) + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != NULL); + BaseProperty *p = properties_[_idx]; + assert( p != NULL ); + return *p; + } + + const BaseProperty& _property( size_t _idx ) const + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != NULL); + BaseProperty *p = properties_[_idx]; + assert( p != NULL ); + return *p; + } + + + typedef Properties::iterator iterator; + typedef Properties::const_iterator const_iterator; + iterator begin() { return properties_.begin(); } + iterator end() { return properties_.end(); } + const_iterator begin() const { return properties_.begin(); } + const_iterator end() const { return properties_.end(); } + + friend class BaseKernel; + +private: + + //-------------------------------------------------- synchronization functors + +#ifndef DOXY_IGNORE_THIS + struct Reserve + { + Reserve(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->reserve(n_); } + size_t n_; + }; + + struct Resize + { + Resize(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->resize(n_); } + size_t n_; + }; + + struct ResizeIfSmaller + { + ResizeIfSmaller(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p && _p->n_elements() < n_) _p->resize(n_); } + size_t n_; + }; + + struct ClearAll + { + ClearAll() {} + void operator()(BaseProperty* _p) const { if (_p) _p->clear(); } + }; + + struct Swap + { + Swap(size_t _i0, size_t _i1) : i0_(_i0), i1_(_i1) {} + void operator()(BaseProperty* _p) const { if (_p) _p->swap(i0_, i1_); } + size_t i0_, i1_; + }; + + struct Delete + { + Delete() {} + void operator()(BaseProperty* _p) const { if (_p) delete _p; _p=NULL; } + }; +#endif + + Properties properties_; +}; + +}//namespace OpenMesh + +#endif//OPENMESH_PROPERTYCONTAINER + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/PropertyManager.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/PropertyManager.hh new file mode 100644 index 0000000..ae8ad18 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/PropertyManager.hh @@ -0,0 +1,577 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef PROPERTYMANAGER_HH_ +#define PROPERTYMANAGER_HH_ + +#include +#include +#include + +namespace OpenMesh { + +/** + * This class is intended to manage the lifecycle of properties. + * It also defines convenience operators to access the encapsulated + * property's value. + * + * For C++11, it is recommended to use the factory functions + * makePropertyManagerFromNew, makePropertyManagerFromExisting, + * makePropertyManagerFromExistingOrNew to construct a PropertyManager, e.g. + * + * \code + * TriMesh mesh; + * auto visited = makePropertyManagerFromNew>(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de"); + * + * for (auto vh : mesh.vertices()) { + * if (!visited[vh]) { + * visitComponent(mesh, vh, visited); + * } + * } + * \endcode + * + * For C++98, it is usually more convenient to use the constructor explicitly, + * i.e. + * + * \code + * TriMesh mesh; + * PropertyManager, TriMesh> visited(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de"); + * + * for (TriMesh::VertexIter vh_it = mesh.begin(); ... ; ...) { + * if (!visited[*vh_it]) { + * visitComponent(mesh, *vh_it, visited); + * } + * } + * \endcode + * + */ +template +class PropertyManager { +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) + public: + PropertyManager(const PropertyManager&) = delete; + PropertyManager& operator=(const PropertyManager&) = delete; +#else + private: + /** + * Noncopyable because there aren't no straightforward copy semantics. + */ + PropertyManager(const PropertyManager&); + + /** + * Noncopyable because there aren't no straightforward copy semantics. + */ + PropertyManager& operator=(const PropertyManager&); +#endif + + public: + /** + * Constructor. + * + * Throws an \p std::runtime_error if \p existing is true and + * no property named \p propname of the appropriate property type + * exists. + * + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + * @param existing If false, a new property is created and its lifecycle is managed (i.e. + * the property is deleted upon destruction of the PropertyManager instance). If true, + * the instance merely acts as a convenience wrapper around an existing property with no + * lifecycle management whatsoever. + * + * @see PropertyManager::createIfNotExists, makePropertyManagerFromNew, + * makePropertyManagerFromExisting, makePropertyManagerFromExistingOrNew + */ + PropertyManager(MeshT &mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) { + if (existing) { + if (!mesh_->get_property_handle(prop_, propname)) { + std::ostringstream oss; + oss << "Requested property handle \"" << propname << "\" does not exist."; + throw std::runtime_error(oss.str()); + } + } else { + mesh_->add_property(prop_, propname); + } + } + + PropertyManager() : mesh_(0), retain_(false) { + } + + ~PropertyManager() { + deleteProperty(); + } + + void swap(PropertyManager &rhs) { + std::swap(mesh_, rhs.mesh_); + std::swap(prop_, rhs.prop_); + std::swap(retain_, rhs.retain_); + std::swap(name_, rhs.name_); + } + + static bool propertyExists(MeshT &mesh, const char *propname) { + PROPTYPE dummy; + return mesh.get_property_handle(dummy, propname); + } + + bool isValid() const { return mesh_ != 0; } + operator bool() const { return isValid(); } + + const PROPTYPE &getRawProperty() const { return prop_; } + + const std::string &getName() const { return name_; } + + MeshT &getMesh() const { return *mesh_; } + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) + /// Only for pre C++11 compatibility. + + typedef PropertyManager Proxy; + + /** + * Move constructor. Transfers ownership (delete responsibility). + */ + PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) { + rhs.retain_ = true; + } + + /** + * Move assignment. Transfers ownership (delete responsibility). + */ + PropertyManager &operator=(PropertyManager &&rhs) { + if (&rhs != this) { + deleteProperty(); + mesh_ = rhs.mesh_; + prop_ = rhs.prop_; + retain_ = rhs.retain_; + name_ = rhs.name_; + rhs.retain_ = true; + } + return *this; + } + + /** + * Create a property manager for the supplied property and mesh. + * If the property doesn't exist, it is created. In any case, + * lifecycle management is disabled. + * + * @see makePropertyManagerFromExistingOrNew + */ + static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) { + PROPTYPE dummy_prop; + PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname)); + pm.retain(); + return std::move(pm); + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static PropertyManager createIfNotExists(MeshT &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + const bool exists = propertyExists(mesh, propname); + PropertyManager pm(mesh, propname, exists); + pm.retain(); + if (!exists) + pm.set_range(begin, end, init_value); + return std::move(pm); + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static PropertyManager createIfNotExists(MeshT &mesh, const char *propname, + const ITERATOR_RANGE &range, const PROP_VALUE &init_value) { + return createIfNotExists( + mesh, propname, range.begin(), range.end(), init_value); + } + + PropertyManager duplicate(const char *clone_name) { + PropertyManager pm(*mesh_, clone_name, false); + pm.mesh_->property(pm.prop_) = mesh_->property(prop_); + return pm; + } + + /** + * Included for backwards compatibility with non-C++11 version. + */ + PropertyManager move() { + return std::move(*this); + } + +#else + class Proxy { + private: + Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) : + mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {} + MeshT *mesh_; + PROPTYPE prop_; + bool retain_; + std::string name_; + + friend class PropertyManager; + }; + + operator Proxy() { + Proxy p(mesh_, prop_, retain_, name_); + mesh_ = 0; + retain_ = true; + return p; + } + + Proxy move() { + return (Proxy)*this; + } + + PropertyManager(Proxy p) : mesh_(p.mesh_), prop_(p.prop_), retain_(p.retain_), name_(p.name_) {} + + PropertyManager &operator=(Proxy p) { + PropertyManager(p).swap(*this); + return *this; + } + + /** + * Create a property manager for the supplied property and mesh. + * If the property doesn't exist, it is created. In any case, + * lifecycle management is disabled. + * + * @see makePropertyManagerFromExistingOrNew + */ + static Proxy createIfNotExists(MeshT &mesh, const char *propname) { + PROPTYPE dummy_prop; + PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname)); + pm.retain(); + return (Proxy)pm; + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static Proxy createIfNotExists(MeshT &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + const bool exists = propertyExists(mesh, propname); + PropertyManager pm(mesh, propname, exists); + pm.retain(); + if (!exists) + pm.set_range(begin, end, init_value); + return (Proxy)pm; + } + + Proxy duplicate(const char *clone_name) { + PropertyManager pm(*mesh_, clone_name, false); + pm.mesh_->property(pm.prop_) = mesh_->property(prop_); + return (Proxy)pm; + } +#endif + + /** + * \brief Disable lifecycle management for this property. + * + * If this method is called, the encapsulated property will not be deleted + * upon destruction of the PropertyManager instance. + */ + inline void retain(bool doRetain = true) { + retain_ = doRetain; + } + + /** + * Access the encapsulated property. + */ + inline PROPTYPE &operator* () { + return prop_; + } + + /** + * Access the encapsulated property. + */ + inline const PROPTYPE &operator* () const { + return prop_; + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + template + inline typename PROPTYPE::reference operator[] (const HandleType &handle) { + return mesh_->property(prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + template + inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const { + return mesh_->property(prop_, handle); + } + + /** + * Conveniently set the property for an entire range of values. + * + * Examples: + * \code + * MeshT mesh; + * PropertyManager, MeshT> distance( + * mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de"); + * distance.set_range( + * mesh.vertices_begin(), mesh.vertices_end(), + * std::numeric_limits::infinity()); + * \endcode + * or + * \code + * MeshT::VertexHandle vh; + * distance.set_range( + * mesh.vv_begin(vh), mesh.vv_end(vh), + * std::numeric_limits::infinity()); + * \endcode + * + * @param begin Start iterator. Needs to dereference to HandleType. + * @param end End iterator. (Exclusive.) + * @param value The value the range will be set to. + */ + template + void set_range(HandleTypeIterator begin, HandleTypeIterator end, + const PROP_VALUE &value) { + for (; begin != end; ++begin) + (*this)[*begin] = value; + } + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) + template + void set_range(const HandleTypeIteratorRange &range, + const PROP_VALUE &value) { + set_range(range.begin(), range.end(), value); + } +#endif + + /** + * Conveniently transfer the values managed by one property manager + * onto the values managed by a different property manager. + * + * @param begin Start iterator. Needs to dereference to HandleType. Will + * be used with this property manager. + * @param end End iterator. (Exclusive.) Will be used with this property + * manager. + * @param dst_propmanager The destination property manager. + * @param dst_begin Start iterator. Needs to dereference to the + * HandleType of dst_propmanager. Will be used with dst_propmanager. + * @param dst_end End iterator. (Exclusive.) + * Will be used with dst_propmanager. Used to double check the bounds. + */ + template + void copy_to(HandleTypeIterator begin, HandleTypeIterator end, + PropertyManager &dst_propmanager, + HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const { + + for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) { + dst_propmanager[*dst_begin] = (*this)[*begin]; + } + } + + template + void copy_to(const RangeType &range, + PropertyManager &dst_propmanager, + const RangeType_2 &dst_range) const { + copy_to(range.begin(), range.end(), dst_propmanager, + dst_range.begin(), dst_range.end()); + } + + /** + * Copy the values of a property from a source range to + * a target range. The source range must not be smaller than the + * target range. + * + * @param prop_name Name of the property to copy. Must exist on the + * source mesh. Will be created on the target mesh if it doesn't exist. + * + * @param src_mesh Source mesh from which to copy. + * @param src_range Source range which to copy. Must not be smaller than + * dst_range. + * @param dst_mesh Destination mesh on which to copy. + * @param dst_range Destination range. + */ + template + static void copy(const char *prop_name, + MeshT &src_mesh, const RangeType &src_range, + MeshT_2 &dst_mesh, const RangeType_2 &dst_range) { + + typedef OpenMesh::PropertyManager DstPM; + DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name)); + + typedef OpenMesh::PropertyManager SrcPM; + SrcPM src(src_mesh, prop_name, true); + + src.copy_to(src_range, dst, dst_range); + } + + private: + void deleteProperty() { + if (!retain_) + mesh_->remove_property(prop_); + } + + private: + MeshT *mesh_; + PROPTYPE prop_; + bool retain_; + std::string name_; +}; + +/** \relates PropertyManager + * Creates a new property whose lifecycle is managed by the returned + * PropertyManager. + * + * Intended for temporary properties. Shadows any existsing properties of + * matching name and type. + */ +template +PropertyManager makePropertyManagerFromNew(MeshT &mesh, const char *propname) { + return PropertyManager(mesh, propname, false); +} + +/** \relates PropertyManager + * Creates a non-owning wrapper for an existing mesh property (no lifecycle + * management). + * + * Intended for convenient access. + * + * @pre Property with the name \p propname of matching type exists. + * @throws std::runtime_error if no property with the name \p propname of + * matching type exists. + */ +template +PropertyManager makePropertyManagerFromExisting(MeshT &mesh, const char *propname) { + return PropertyManager(mesh, propname, true); +} + +/** \relates PropertyManager + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +PropertyManager makePropertyManagerFromExistingOrNew(MeshT &mesh, const char *propname) { + return PropertyManager::createIfNotExists(mesh, propname); +} + +/** \relates PropertyManager + * Like the two parameter version of makePropertyManagerFromExistingOrNew() + * except it initializes the property with the specified value over the + * specified range if it needs to be created. If the property already exists, + * this function has the exact same effect as the two parameter version. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +PropertyManager makePropertyManagerFromExistingOrNew( + MeshT &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + return PropertyManager::createIfNotExists( + mesh, propname, begin, end, init_value); +} + +/** \relates PropertyManager + * Like the two parameter version of makePropertyManagerFromExistingOrNew() + * except it initializes the property with the specified value over the + * specified range if it needs to be created. If the property already exists, + * this function has the exact same effect as the two parameter version. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +PropertyManager makePropertyManagerFromExistingOrNew( + MeshT &mesh, const char *propname, + const ITERATOR_RANGE &range, + const PROP_VALUE &init_value) { + return makePropertyManagerFromExistingOrNew( + mesh, propname, range.begin(), range.end(), init_value); +} + +} /* namespace OpenMesh */ +#endif /* PROPERTYMANAGER_HH_ */ diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/RandomNumberGenerator.cc b/libs/OpenMesh/inc/OpenMesh/Core/Utils/RandomNumberGenerator.cc new file mode 100644 index 0000000..83222b6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/RandomNumberGenerator.cc @@ -0,0 +1,106 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 362 $ * + * $Date: 2011-01-26 10:21:12 +0100 (Mi, 26 Jan 2011) $ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for generating a random number between 0.0 and 1.0 with +// a garantueed resolution +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION =========================================================== + +RandomNumberGenerator::RandomNumberGenerator(const size_t _resolution) : + resolution_(_resolution), + iterations_(1), + maxNum_(RAND_MAX + 1.0) +{ + double tmp = double(resolution_); + while (tmp > (double(RAND_MAX) + 1.0) ) { + iterations_++; + tmp /= (double(RAND_MAX) + 1.0); + } + + for ( unsigned int i = 0 ; i < iterations_ - 1; ++i ) { + maxNum_ *= (RAND_MAX + 1.0); + } +} + +//----------------------------------------------------------------------------- + +double RandomNumberGenerator::getRand() const { + double randNum = 0.0; + for ( unsigned int i = 0 ; i < iterations_; ++i ) { + randNum *= (RAND_MAX + 1.0); + randNum += rand(); + } + + return randNum / maxNum_; +} + +double RandomNumberGenerator::resolution() const { + return maxNum_; +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/RandomNumberGenerator.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/RandomNumberGenerator.hh new file mode 100644 index 0000000..aaedfcd --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/RandomNumberGenerator.hh @@ -0,0 +1,117 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 693 $ * + * $Date: 2012-09-23 16:25:16 +0200 (So, 23 Sep 2012) $ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for generating a random number between 0.0 and 1.0 with +// a garantueed resolution +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH +#define OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Generate a random number between 0.0 and 1.0 with a guaranteed resolution + * ( Number of possible values ) + * + * Especially useful on windows, as there MAX_RAND is often only 32k which is + * not enough resolution for a lot of applications + */ +class OPENMESHDLLEXPORT RandomNumberGenerator +{ +public: + + /** \brief Constructor + * + * @param _resolution specifies the desired resolution for the random number generated + */ + explicit RandomNumberGenerator(const size_t _resolution); + + /// returns a random double between 0.0 and 1.0 with a guaranteed resolution + double getRand() const; + + double resolution() const; + +private: + + /// desired resolution + const size_t resolution_; + + /// number of "blocks" of RAND_MAX that make up the desired _resolution + size_t iterations_; + + /// maximum random number generated, which is used for normalization + double maxNum_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/SingletonT.cc b/libs/OpenMesh/inc/OpenMesh/Core/Utils/SingletonT.cc new file mode 100644 index 0000000..abc189a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/SingletonT.cc @@ -0,0 +1,85 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + + +#define OPENMESH_SINGLETON_C + + +//== INCLUDES ================================================================= + + +// header +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== SINGLETON'S DATA ========================================================= + + +template +T* SingletonT::pInstance__ = 0; + +template +bool SingletonT::destroyed__ = false; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/SingletonT.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/SingletonT.hh new file mode 100644 index 0000000..b0745c4 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/SingletonT.hh @@ -0,0 +1,154 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + + +#ifndef __SINGLETON_HH__ +#define __SINGLETON_HH__ + + +//=== INCLUDES ================================================================ + +// OpenMesh +#include + +// STL +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//=== IMPLEMENTATION ========================================================== + + +/** A simple singleton template. + Encapsulates an arbitrary class and enforces its uniqueness. +*/ + +template +class SingletonT +{ +public: + + /** Singleton access function. + Use this function to obtain a reference to the instance of the + encapsulated class. Note that this instance is unique and created + on the first call to Instance(). + */ + + static T& Instance() + { + if (!pInstance__) + { + // check if singleton alive + if (destroyed__) + { + OnDeadReference(); + } + // first time request -> initialize + else + { + Create(); + } + } + return *pInstance__; + } + + +private: + + // Disable constructors/assignment to enforce uniqueness + SingletonT(); + SingletonT(const SingletonT&); + SingletonT& operator=(const SingletonT&); + + // Create a new singleton and store its pointer + static void Create() + { + static T theInstance; + pInstance__ = &theInstance; + } + + // Will be called if instance is accessed after its lifetime has expired + static void OnDeadReference() + { + throw std::runtime_error("[Singelton error] - Dead reference detected!\n"); + } + + virtual ~SingletonT() + { + pInstance__ = 0; + destroyed__ = true; + } + + static T* pInstance__; + static bool destroyed__; +}; + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SINGLETON_C) +# define OPENMESH_SINGLETON_TEMPLATES +# include "SingletonT.cc" +#endif +//============================================================================= +#endif // __SINGLETON_HH__ +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/color_cast.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/color_cast.hh new file mode 100644 index 0000000..0dd9901 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/color_cast.hh @@ -0,0 +1,385 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_COLOR_CAST_HH +#define OPENMESH_COLOR_CAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +/// Cast one color vector to another. +template +struct color_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_cast(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3i return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3i return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4i return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f), + (int)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3ui return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3ui return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f), + (unsigned int)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(255) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4f( _src[0], + _src[1], + _src[2], + 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4ui(_src[0], + _src[1], + _src[2], + 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3i& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0]*f, _src[1]*f, _src[2]*f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4i& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f( _src[0] * f, _src[1] * f, _src[2] * f , _src[3] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4uc( _src[0], _src[1], _src[2], 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, _src[3] * f ); + } +}; + +// ---------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +#if !defined(OM_CC_MSVC) +template +struct color_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif + +//----------------------------------------------------------------------------- + + +template +inline +typename color_caster::return_type +color_cast(const src_t& _src ) +{ + return color_caster::cast(_src); +} + +#endif +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_COLOR_CAST_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/vector_cast.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/vector_cast.hh new file mode 100644 index 0000000..39fca19 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/vector_cast.hh @@ -0,0 +1,163 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTORCAST_HH +#define OPENMESH_VECTORCAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +template +inline void vector_cast( const src_t &_src, dst_t &_dst, GenProg::Int2Type ) +{ + assert_compile(vector_traits::size_ <= vector_traits::size_) + vector_cast(_src,_dst, GenProg::Int2Type()); + _dst[n-1] = static_cast::value_type >(_src[n-1]); +} + +template +inline void vector_cast( const src_t & /*_src*/, dst_t & /*_dst*/, GenProg::Int2Type<0> ) +{ +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type ) +{ + assert_compile(vector_traits::size_ <= vector_traits::size_) + vector_copy(_src,_dst, GenProg::Int2Type()); + _dst[n-1] = _src[n-1]; +} + +template +inline void vector_copy( const src_t & /*_src*/, dst_t & /*_dst*/ , GenProg::Int2Type<0> ) +{ +} + + + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +template +struct vector_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_cast(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + +#if !defined(OM_CC_MSVC) +template +struct vector_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif +//----------------------------------------------------------------------------- + + +/// Cast vector type to another vector type by copying the vector elements +template +inline +typename vector_caster::return_type +vector_cast(const src_t& _src ) +{ + return vector_caster::cast(_src); +} + + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Core/Utils/vector_traits.hh b/libs/OpenMesh/inc/OpenMesh/Core/Utils/vector_traits.hh new file mode 100644 index 0000000..fb78b3c --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Core/Utils/vector_traits.hh @@ -0,0 +1,115 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTOR_TRAITS_HH +#define OPENMESH_VECTOR_TRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Provide a standardized access to relevant information about a + vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +/** Helper class providing information about a vector type. + * + * If want to use a different vector type than the one provided %OpenMesh + * you need to supply a specialization of this class for the new vector type. + */ +template +struct vector_traits +{ + /// Type of the vector class + typedef typename T::vector_type vector_type; + + /// Type of the scalar value + typedef typename T::value_type value_type; + + /// size/dimension of the vector + static const size_t size_ = T::size_; + + /// size/dimension of the vector + static size_t size() { return size_; } +}; + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/BaseDecimaterT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/BaseDecimaterT.cc new file mode 100644 index 0000000..b36778f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/BaseDecimaterT.cc @@ -0,0 +1,310 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file DecimaterT.cc + */ + +//============================================================================= +// +// CLASS DecimaterT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_BASE_DECIMATER_DECIMATERT_CC + +//== INCLUDES ================================================================= + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +BaseDecimaterT::BaseDecimaterT(Mesh& _mesh) : + mesh_(_mesh), cmodule_(NULL), initialized_(false), observer_(NULL) { + // default properties + mesh_.request_vertex_status(); + mesh_.request_edge_status(); + mesh_.request_face_status(); + +} + +//----------------------------------------------------------------------------- + +template +BaseDecimaterT::~BaseDecimaterT() { + // default properties + mesh_.release_vertex_status(); + mesh_.release_edge_status(); + mesh_.release_face_status(); + + // dispose of modules + { + set_uninitialized(); + typename ModuleList::iterator m_it, m_end = all_modules_.end(); + for (m_it = all_modules_.begin(); m_it != m_end; ++m_it) + delete *m_it; + all_modules_.clear(); + } +} + +//----------------------------------------------------------------------------- + +template +bool BaseDecimaterT::is_collapse_legal(const CollapseInfo& _ci) { + // std::clog << "McDecimaterT<>::is_collapse_legal()\n"; + + // locked ? + if (mesh_.status(_ci.v0).locked()) + return false; + + // this test checks: + // is v0v1 deleted? + // is v0 deleted? + // is v1 deleted? + // are both vlv0 and v1vl boundary edges? + // are both v0vr and vrv1 boundary edges? + // are vl and vr equal or both invalid? + // one ring intersection test + // edge between two boundary vertices should be a boundary edge + if (!mesh_.is_collapse_ok(_ci.v0v1)) + return false; + + if (_ci.vl.is_valid() && _ci.vr.is_valid() + && mesh_.find_halfedge(_ci.vl, _ci.vr).is_valid() + && mesh_.valence(_ci.vl) == 3 && mesh_.valence(_ci.vr) == 3) { + return false; + } + //--- feature test --- + + if (mesh_.status(_ci.v0).feature() + && !mesh_.status(mesh_.edge_handle(_ci.v0v1)).feature()) + return false; + + //--- test boundary cases --- + if (mesh_.is_boundary(_ci.v0)) { + + // don't collapse a boundary vertex to an inner one + if (!mesh_.is_boundary(_ci.v1)) + return false; + + // only one one ring intersection + if (_ci.vl.is_valid() && _ci.vr.is_valid()) + return false; + } + + // there have to be at least 2 incident faces at v0 + if (mesh_.cw_rotated_halfedge_handle( + mesh_.cw_rotated_halfedge_handle(_ci.v0v1)) == _ci.v0v1) + return false; + + // collapse passed all tests -> ok + return true; +} + +//----------------------------------------------------------------------------- + +template +float BaseDecimaterT::collapse_priority(const CollapseInfo& _ci) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) { + if ((*m_it)->collapse_priority(_ci) < 0.0) + return ModBaseT< Mesh >::ILLEGAL_COLLAPSE; + } + return cmodule_->collapse_priority(_ci); +} + +//----------------------------------------------------------------------------- + +template +void BaseDecimaterT::postprocess_collapse(CollapseInfo& _ci) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->postprocess_collapse(_ci); + + cmodule_->postprocess_collapse(_ci); +} + +//----------------------------------------------------------------------------- + +template +void BaseDecimaterT::preprocess_collapse(CollapseInfo& _ci) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->preprocess_collapse(_ci); + + cmodule_->preprocess_collapse(_ci); +} + +//----------------------------------------------------------------------------- + +template +void BaseDecimaterT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->set_error_tolerance_factor(_factor); + + cmodule_->set_error_tolerance_factor(_factor); + } +} + +//----------------------------------------------------------------------------- + +template +void BaseDecimaterT::info(std::ostream& _os) { + if (initialized_) { + _os << "initialized : yes" << std::endl; + _os << "binary modules: " << bmodules_.size() << std::endl; + for (ModuleListIterator m_it = bmodules_.begin(); m_it != bmodules_.end(); + ++m_it) { + _os << " " << (*m_it)->name() << std::endl; + } + _os << "priority module: " << cmodule_->name().c_str() << std::endl; + } else { + _os << "initialized : no" << std::endl; + _os << "available modules: " << all_modules_.size() << std::endl; + for (ModuleListIterator m_it = all_modules_.begin(); + m_it != all_modules_.end(); ++m_it) { + _os << " " << (*m_it)->name() << " : "; + if ((*m_it)->is_binary()) { + _os << "binary"; + if ((*m_it)->name() == "Quadric") { + _os << " and priority (special treatment)"; + } + } else { + _os << "priority"; + } + _os << std::endl; + } + } +} + +//----------------------------------------------------------------------------- + +template +bool BaseDecimaterT::initialize() { + if (initialized_) { + return true; + } + + // FIXME: quadric module shouldn't be treated specially. + // Q: Why? + // A: It isn't generic and breaks encapsulation. Also, using string + // name comparison is not reliable, since you can't guarantee that + // no one else will name their custom module "Quadric". + // Q: What should be done instead? + // A: ModBaseT API should support modules that can be both binary + // and priority, or BETTER YET, let the DecimaterT API specify the + // priority module explicitly. + + // find the priority module: either the only non-binary module in the list, or "Quadric" + Module *quadric = NULL; + Module *pmodule = NULL; + for (ModuleListIterator m_it = all_modules_.begin(), m_end = + all_modules_.end(); m_it != m_end; ++m_it) { + if ((*m_it)->name() == "Quadric") + quadric = *m_it; + + if (!(*m_it)->is_binary()) { + if (pmodule) { + // only one priority module allowed! + set_uninitialized(); + return false; + } + pmodule = *m_it; + } + } + + // Quadric is used as default priority module (even if it is set to be binary) + if (!pmodule && quadric) { + pmodule = quadric; + } + + if (!pmodule) { + // At least one priority module required + set_uninitialized(); + return false; + } + + // set pmodule as the current priority module + cmodule_ = pmodule; + + for (ModuleListIterator m_it = all_modules_.begin(), m_end = + all_modules_.end(); m_it != m_end; ++m_it) { + // every module gets initialized + (*m_it)->initialize(); + + if (*m_it != pmodule) { + // all other modules are binary, and go into bmodules_ list + bmodules_.push_back(*m_it); + } + } + + return initialized_ = true; +} + + + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/BaseDecimaterT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/BaseDecimaterT.hh new file mode 100644 index 0000000..3006f6a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/BaseDecimaterT.hh @@ -0,0 +1,289 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file BaseDecimaterT.hh + */ + +//============================================================================= +// +// CLASS McDecimaterT +// +//============================================================================= + +#ifndef OPENMESH_BASE_DECIMATER_DECIMATERT_HH +#define OPENMESH_BASE_DECIMATER_DECIMATERT_HH + + +//== INCLUDES ================================================================= + +#include + +#include +#include +#include +#include + + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** base class decimater framework + \see BaseDecimaterT, \ref decimater_docu +*/ +class BaseDecimaterModule +{ +}; + +template < typename MeshT > +class BaseDecimaterT : private Utils::Noncopyable +{ +public: //-------------------------------------------------------- public types + + typedef BaseDecimaterT< MeshT > Self; + typedef MeshT Mesh; + typedef CollapseInfoT CollapseInfo; + typedef ModBaseT Module; + typedef std::vector< Module* > ModuleList; + typedef typename ModuleList::iterator ModuleListIterator; + +public: //------------------------------------------------------ public methods + BaseDecimaterT(Mesh& _mesh); + virtual ~BaseDecimaterT(); + + /** Initialize decimater and decimating modules. + + Return values: + true ok + false No ore more than one non-binary module exist. In that case + the decimater is uninitialized! + */ + bool initialize(); + + + /// Returns whether decimater has been successfully initialized. + bool is_initialized() const { return initialized_; } + + + /// Print information about modules to _os + void info( std::ostream& _os ); + +public: //--------------------------------------------------- module management + + /** \brief Add observer + * + * You can set an observer which is used as a callback to check the decimators progress and to + * abort it if necessary. + * + * @param _o Observer to be used + */ + void set_observer(Observer* _o) + { + observer_ = _o; + } + + /// Get current observer of a decimater + Observer* observer() + { + return observer_; + } + + /// access mesh. used in modules. + Mesh& mesh() { return mesh_; } + + /// add module to decimater + template < typename _Module > + bool add( ModHandleT<_Module>& _mh ) + { + if (_mh.is_valid()) + return false; + + _mh.init( new _Module(mesh()) ); + all_modules_.push_back( _mh.module() ); + + set_uninitialized(); + + return true; + } + + + /// remove module + template < typename _Module > + bool remove( ModHandleT<_Module>& _mh ) + { + if (!_mh.is_valid()) + return false; + + typename ModuleList::iterator it = std::find(all_modules_.begin(), + all_modules_.end(), + _mh.module() ); + + if ( it == all_modules_.end() ) // module not found + return false; + + delete *it; + all_modules_.erase( it ); // finally remove from list + _mh.clear(); + + set_uninitialized(); + return true; + } + + + /// get module referenced by handle _mh + template < typename Module > + Module& module( ModHandleT& _mh ) + { + assert( _mh.is_valid() ); + return *_mh.module(); + } + + +protected: + + /// returns false, if abort requested by observer + bool notify_observer(size_t _n_collapses) + { + if (observer() && _n_collapses % observer()->get_interval() == 0) + { + observer()->notify(_n_collapses); + return !observer()->abort(); + } + return true; + } + + /// Reset the initialized flag, and clear the bmodules_ and cmodule_ + void set_uninitialized() { + initialized_ = false; + cmodule_ = 0; + bmodules_.clear(); + } + + void update_modules(CollapseInfo& _ci) + { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->postprocess_collapse(_ci); + cmodule_->postprocess_collapse(_ci); + } + + +protected: //---------------------------------------------------- private methods + + /// Is an edge collapse legal? Performs topological test only. + /// The method evaluates the status bit Locked, Deleted, and Feature. + /// \attention The method temporarily sets the bit Tagged. After usage + /// the bit will be disabled! + bool is_collapse_legal(const CollapseInfo& _ci); + + /// Calculate priority of an halfedge collapse (using the modules) + float collapse_priority(const CollapseInfo& _ci); + + /// Pre-process a collapse + void preprocess_collapse(CollapseInfo& _ci); + + /// Post-process a collapse + void postprocess_collapse(CollapseInfo& _ci); + + /** + * This provides a function that allows the setting of a percentage + * of the original constraint of the modules + * + * Note that some modules might re-initialize in their + * set_error_tolerance_factor function as necessary + * @param _factor has to be in the closed interval between 0.0 and 1.0 + */ + void set_error_tolerance_factor(double _factor); + + /** Reset the status of this class + * + * You have to call initialize again!! + */ + void reset(){ initialized_ = false; }; + + +private: //------------------------------------------------------- private data + + + /// reference to mesh + Mesh& mesh_; + + /// list of binary modules + ModuleList bmodules_; + + /// the current priority module + Module* cmodule_; + + /// list of all allocated modules (including cmodule_ and all of bmodules_) + ModuleList all_modules_; + + /// Flag if all modules were initialized + bool initialized_; + + /// observer + Observer* observer_; + +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_BASE_DECIMATER_DECIMATERT_CC) +#define OPENMESH_BASE_DECIMATER_TEMPLATES +#include "BaseDecimaterT.cc" +#endif +//============================================================================= +#endif // OPENMESH_BASE_DECIMATER_DECIMATERT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/CollapseInfoT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/CollapseInfoT.hh new file mode 100644 index 0000000..4212e82 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/CollapseInfoT.hh @@ -0,0 +1,168 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file CollapseInfoT.hh + Provides data class CollapseInfoT for storing all information + about a halfedge collapse. + */ + +//============================================================================= +// +// STRUCT CollpaseInfoT +// +//============================================================================= +#ifndef OPENMESH_DECIMATER_COLLAPSEINFOT_HH +#define OPENMESH_DECIMATER_COLLAPSEINFOT_HH + +//== INCLUDES ================================================================= + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + +//== CLASS DEFINITION ========================================================= + +/** Stores information about a halfedge collapse. + + The class stores information about a halfedge collapse. The most + important information is \c v0v1, \c v1v0, \c v0, \c v1, \c vl, + \c vr, which you can lookup in the following image: + \image html collapse_info.png + \see ModProgMeshT::Info + */ +template +struct CollapseInfoT { + public: + /** Initializing constructor. + * + * Given a mesh and a halfedge handle of the halfedge to be collapsed + * all important information of a halfedge collapse will be stored. + * \param _mesh Mesh source + * \param _heh Halfedge to collapse. The direction of the halfedge + * defines the direction of the collapse, i.e. the from-vertex + * will be removed and the to-vertex remains. + */ + CollapseInfoT(Mesh& _mesh, typename Mesh::HalfedgeHandle _heh); + + Mesh& mesh; + + typename Mesh::HalfedgeHandle v0v1; ///< Halfedge to be collapsed + typename Mesh::HalfedgeHandle v1v0; ///< Reverse halfedge + typename Mesh::VertexHandle v0; ///< Vertex to be removed + typename Mesh::VertexHandle v1; ///< Remaining vertex + typename Mesh::Point p0; ///< Position of removed vertex + typename Mesh::Point p1; ///< Positions of remaining vertex + typename Mesh::FaceHandle fl; ///< Left face + typename Mesh::FaceHandle fr; ///< Right face + typename Mesh::VertexHandle vl; ///< Left vertex + typename Mesh::VertexHandle vr; ///< Right vertex + //@{ + /** Outer remaining halfedge of diamond spanned by \c v0, \c v1, + * \c vl, and \c vr + */ + typename Mesh::HalfedgeHandle vlv1, v0vl, vrv0, v1vr; + //@} +}; + +//----------------------------------------------------------------------------- + +/** +* Local configuration of halfedge collapse to be stored in CollapseInfoT: +* +* vl +* * +* / \ +* / \ +* / fl \ +* v0 *------>* v1 +* \ fr / +* \ / +* \ / +* * +* vr +* +* +* @param _mesh Reference to mesh +* @param _heh The halfedge (v0 -> v1) defining the collapse +*/ +template +inline CollapseInfoT::CollapseInfoT(Mesh& _mesh, + typename Mesh::HalfedgeHandle _heh) : + mesh(_mesh), v0v1(_heh), v1v0(_mesh.opposite_halfedge_handle(v0v1)), v0( + _mesh.to_vertex_handle(v1v0)), v1(_mesh.to_vertex_handle(v0v1)), p0( + _mesh.point(v0)), p1(_mesh.point(v1)), fl(_mesh.face_handle(v0v1)), fr( + _mesh.face_handle(v1v0)) + +{ + // get vl + if (fl.is_valid()) { + vlv1 = mesh.next_halfedge_handle(v0v1); + v0vl = mesh.next_halfedge_handle(vlv1); + vl = mesh.to_vertex_handle(vlv1); + vlv1 = mesh.opposite_halfedge_handle(vlv1); + v0vl = mesh.opposite_halfedge_handle(v0vl); + } + + // get vr + if (fr.is_valid()) { + vrv0 = mesh.next_halfedge_handle(v1v0); + v1vr = mesh.next_halfedge_handle(vrv0); + vr = mesh.to_vertex_handle(vrv0); + vrv0 = mesh.opposite_halfedge_handle(vrv0); + v1vr = mesh.opposite_halfedge_handle(v1vr); + } +} + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_DECIMATER_COLLAPSEINFOT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/DecimaterT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/DecimaterT.cc new file mode 100644 index 0000000..2ca41a7 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/DecimaterT.cc @@ -0,0 +1,369 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file DecimaterT.cc + */ + +//============================================================================= +// +// CLASS DecimaterT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_DECIMATER_DECIMATERT_CC + +//== INCLUDES ================================================================= + +#include + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +DecimaterT::DecimaterT(Mesh& _mesh) : + BaseDecimaterT(_mesh), + mesh_(_mesh), +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + heap_(nullptr) +#else + heap_(NULL) +#endif + +{ + + // private vertex properties + mesh_.add_property(collapse_target_); + mesh_.add_property(priority_); + mesh_.add_property(heap_position_); +} + +//----------------------------------------------------------------------------- + +template +DecimaterT::~DecimaterT() { + + // private vertex properties + mesh_.remove_property(collapse_target_); + mesh_.remove_property(priority_); + mesh_.remove_property(heap_position_); + +} + +//----------------------------------------------------------------------------- + +template +void DecimaterT::heap_vertex(VertexHandle _vh) { + // std::clog << "heap_vertex: " << _vh << std::endl; + + float prio, best_prio(FLT_MAX); + typename Mesh::HalfedgeHandle heh, collapse_target; + + // find best target in one ring + typename Mesh::VertexOHalfedgeIter voh_it(mesh_, _vh); + for (; voh_it.is_valid(); ++voh_it) { + heh = *voh_it; + CollapseInfo ci(mesh_, heh); + + if (this->is_collapse_legal(ci)) { + prio = this->collapse_priority(ci); + if (prio >= 0.0 && prio < best_prio) { + best_prio = prio; + collapse_target = heh; + } + } + } + + // target found -> put vertex on heap + if (collapse_target.is_valid()) { + // std::clog << " added|updated" << std::endl; + mesh_.property(collapse_target_, _vh) = collapse_target; + mesh_.property(priority_, _vh) = best_prio; + + if (heap_->is_stored(_vh)) + heap_->update(_vh); + else + heap_->insert(_vh); + } + + // not valid -> remove from heap + else { + // std::clog << " n/a|removed" << std::endl; + if (heap_->is_stored(_vh)) + heap_->remove(_vh); + + mesh_.property(collapse_target_, _vh) = collapse_target; + mesh_.property(priority_, _vh) = -1; + } +} + +//----------------------------------------------------------------------------- +template +size_t DecimaterT::decimate(size_t _n_collapses) { + + if (!this->is_initialized()) + return 0; + + typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); + typename Mesh::VertexHandle vp; + typename Mesh::HalfedgeHandle v0v1; + typename Mesh::VertexVertexIter vv_it; + typename Mesh::VertexFaceIter vf_it; + unsigned int n_collapses(0); + + typedef std::vector Support; + typedef typename Support::iterator SupportIterator; + + Support support(15); + SupportIterator s_it, s_end; + + // check _n_collapses + if (!_n_collapses) + _n_collapses = mesh_.n_vertices(); + + // initialize heap + HeapInterface HI(mesh_, priority_, heap_position_); + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + heap_ = std::unique_ptr(new DeciHeap(HI)); +#else + heap_ = std::auto_ptr(new DeciHeap(HI)); +#endif + + + heap_->reserve(mesh_.n_vertices()); + + for (v_it = mesh_.vertices_begin(); v_it != v_end; ++v_it) { + heap_->reset_heap_position(*v_it); + if (!mesh_.status(*v_it).deleted()) + heap_vertex(*v_it); + } + + const bool update_normals = mesh_.has_face_normals(); + + // process heap + while ((!heap_->empty()) && (n_collapses < _n_collapses)) { + // get 1st heap entry + vp = heap_->front(); + v0v1 = mesh_.property(collapse_target_, vp); + heap_->pop_front(); + + // setup collapse info + CollapseInfo ci(mesh_, v0v1); + + // check topological correctness AGAIN ! + if (!this->is_collapse_legal(ci)) + continue; + + // store support (= one ring of *vp) + vv_it = mesh_.vv_iter(ci.v0); + support.clear(); + for (; vv_it.is_valid(); ++vv_it) + support.push_back(*vv_it); + + // pre-processing + this->preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(v0v1); + ++n_collapses; + + if (update_normals) + { + // update triangle normals + vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it.is_valid(); ++vf_it) + if (!mesh_.status(*vf_it).deleted()) + mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it)); + } + + // post-process collapse + this->postprocess_collapse(ci); + + // update heap (former one ring of decimated vertex) + for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) { + assert(!mesh_.status(*s_it).deleted()); + heap_vertex(*s_it); + } + + // notify observer and stop if the observer requests it + if (!this->notify_observer(n_collapses)) + return n_collapses; + } + + // delete heap + heap_.reset(); + + + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; +} + +//----------------------------------------------------------------------------- + +template +size_t DecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { + + if (!this->is_initialized()) + return 0; + + if (_nv >= mesh_.n_vertices() || _nf >= mesh_.n_faces()) + return 0; + + typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); + typename Mesh::VertexHandle vp; + typename Mesh::HalfedgeHandle v0v1; + typename Mesh::VertexVertexIter vv_it; + typename Mesh::VertexFaceIter vf_it; + size_t nv = mesh_.n_vertices(); + size_t nf = mesh_.n_faces(); + unsigned int n_collapses = 0; + + typedef std::vector Support; + typedef typename Support::iterator SupportIterator; + + Support support(15); + SupportIterator s_it, s_end; + + // initialize heap + HeapInterface HI(mesh_, priority_, heap_position_); + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + heap_ = std::unique_ptr(new DeciHeap(HI)); + #else + heap_ = std::auto_ptr(new DeciHeap(HI)); + #endif + heap_->reserve(mesh_.n_vertices()); + + for (v_it = mesh_.vertices_begin(); v_it != v_end; ++v_it) { + heap_->reset_heap_position(*v_it); + if (!mesh_.status(*v_it).deleted()) + heap_vertex(*v_it); + } + + const bool update_normals = mesh_.has_face_normals(); + + // process heap + while ((!heap_->empty()) && (_nv < nv) && (_nf < nf)) { + // get 1st heap entry + vp = heap_->front(); + v0v1 = mesh_.property(collapse_target_, vp); + heap_->pop_front(); + + // setup collapse info + CollapseInfo ci(mesh_, v0v1); + + // check topological correctness AGAIN ! + if (!this->is_collapse_legal(ci)) + continue; + + // store support (= one ring of *vp) + vv_it = mesh_.vv_iter(ci.v0); + support.clear(); + for (; vv_it.is_valid(); ++vv_it) + support.push_back(*vv_it); + + // adjust complexity in advance (need boundary status) + ++n_collapses; + --nv; + if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0)) + --nf; + else + nf -= 2; + + // pre-processing + this->preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(v0v1); + + // update triangle normals + if (update_normals) + { + vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it.is_valid(); ++vf_it) + if (!mesh_.status(*vf_it).deleted()) + mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it)); + } + + // post-process collapse + this->postprocess_collapse(ci); + + // update heap (former one ring of decimated vertex) + for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) { + assert(!mesh_.status(*s_it).deleted()); + heap_vertex(*s_it); + } + + // notify observer and stop if the observer requests it + if (!this->notify_observer(n_collapses)) + return n_collapses; + } + + // delete heap + heap_.reset(); + + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; +} + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/DecimaterT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/DecimaterT.hh new file mode 100644 index 0000000..55cf080 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/DecimaterT.hh @@ -0,0 +1,222 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file DecimaterT.hh + */ + +//============================================================================= +// +// CLASS DecimaterT +// +//============================================================================= + +#ifndef OPENMESH_DECIMATER_DECIMATERT_HH +#define OPENMESH_DECIMATER_DECIMATERT_HH + + +//== INCLUDES ================================================================= + +#include + +#include +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** Decimater framework. + \see BaseModT, \ref decimater_docu +*/ +template < typename MeshT > +class DecimaterT : virtual public BaseDecimaterT //virtual especially for the mixed decimater +{ +public: //-------------------------------------------------------- public types + + typedef DecimaterT< MeshT > Self; + typedef MeshT Mesh; + typedef CollapseInfoT CollapseInfo; + typedef ModBaseT Module; + typedef std::vector< Module* > ModuleList; + typedef typename ModuleList::iterator ModuleListIterator; + +public: //------------------------------------------------------ public methods + + /// Constructor + DecimaterT( Mesh& _mesh ); + + /// Destructor + ~DecimaterT(); + +public: + + /** + * @brief Perform a number of collapses on the mesh. + * @param _n_collapses Desired number of collapses. If zero (default), attempt + * to do as many collapses as possible. + * @return Number of collapses that were actually performed. + * @note This operation only marks the removed mesh elements for deletion. In + * order to actually remove the decimated elements from the mesh, a + * subsequent call to ArrayKernel::garbage_collection() is required. + */ + size_t decimate( size_t _n_collapses = 0 ); + + /** + * @brief Decimate the mesh to a desired target vertex complexity. + * @param _n_vertices Target complexity, i.e. desired number of remaining + * vertices after decimation. + * @return Number of collapses that were actually performed. + * @note This operation only marks the removed mesh elements for deletion. In + * order to actually remove the decimated elements from the mesh, a + * subsequent call to ArrayKernel::garbage_collection() is required. + */ + size_t decimate_to( size_t _n_vertices ) + { + return ( (_n_vertices < this->mesh().n_vertices()) ? + decimate( this->mesh().n_vertices() - _n_vertices ) : 0 ); + } + + /** + * @brief Attempts to decimate the mesh until a desired vertex or face + * complexity is achieved. + * @param _n_vertices Target vertex complexity. + * @param _n_faces Target face complexity. + * @return Number of collapses that were actually performed. + * @note Decimation stops as soon as either one of the two complexity bounds + * is satisfied. + * @note This operation only marks the removed mesh elements for deletion. In + * order to actually remove the decimated elements from the mesh, a + * subsequent call to ArrayKernel::garbage_collection() is required. + */ + size_t decimate_to_faces( size_t _n_vertices=0, size_t _n_faces=0 ); + +public: + + typedef typename Mesh::VertexHandle VertexHandle; + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + /// Heap interface + class HeapInterface + { + public: + + HeapInterface(Mesh& _mesh, + VPropHandleT _prio, + VPropHandleT _pos) + : mesh_(_mesh), prio_(_prio), pos_(_pos) + { } + + inline bool + less( VertexHandle _vh0, VertexHandle _vh1 ) + { return mesh_.property(prio_, _vh0) < mesh_.property(prio_, _vh1); } + + inline bool + greater( VertexHandle _vh0, VertexHandle _vh1 ) + { return mesh_.property(prio_, _vh0) > mesh_.property(prio_, _vh1); } + + inline int + get_heap_position(VertexHandle _vh) + { return mesh_.property(pos_, _vh); } + + inline void + set_heap_position(VertexHandle _vh, int _pos) + { mesh_.property(pos_, _vh) = _pos; } + + + private: + Mesh& mesh_; + VPropHandleT prio_; + VPropHandleT pos_; + }; + + typedef Utils::HeapT DeciHeap; + + +private: //---------------------------------------------------- private methods + + /// Insert vertex in heap + void heap_vertex(VertexHandle _vh); + +private: //------------------------------------------------------- private data + + + // reference to mesh + Mesh& mesh_; + + // heap + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::unique_ptr heap_; + #else + std::auto_ptr heap_; + #endif + + // vertex properties + VPropHandleT collapse_target_; + VPropHandleT priority_; + VPropHandleT heap_position_; + +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_DECIMATERT_CC) +#define OPENMESH_DECIMATER_TEMPLATES +#include "DecimaterT.cc" +#endif +//============================================================================= +#endif // OPENMESH_DECIMATER_DECIMATERT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/McDecimaterT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/McDecimaterT.cc new file mode 100644 index 0000000..4dc813a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/McDecimaterT.cc @@ -0,0 +1,538 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file McDecimaterT.cc + */ + +//============================================================================= +// +// CLASS McDecimaterT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_MULTIPLE_CHOICE_DECIMATER_DECIMATERT_CC + +//== INCLUDES ================================================================= + +#include + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +#ifdef WIN32 +# include +#endif + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +McDecimaterT::McDecimaterT(Mesh& _mesh) : + BaseDecimaterT(_mesh), + mesh_(_mesh), randomSamples_(10) { + + // default properties + mesh_.request_vertex_status(); + mesh_.request_halfedge_status(); + mesh_.request_edge_status(); + mesh_.request_face_status(); + +} + +//----------------------------------------------------------------------------- + +template +McDecimaterT::~McDecimaterT() { + // default properties + mesh_.release_vertex_status(); + mesh_.release_edge_status(); + mesh_.release_halfedge_status(); + mesh_.release_face_status(); + +} + +//----------------------------------------------------------------------------- +template +size_t McDecimaterT::decimate(size_t _n_collapses) { + + if (!this->is_initialized()) + return 0; + + unsigned int n_collapses(0); + + bool collapsesUnchanged = false; + // old n_collapses in order to check for convergence + unsigned int oldCollapses = 0; + // number of iterations where no new collapses where + // performed in a row + unsigned int noCollapses = 0; + +#ifdef WIN32 + RandomNumberGenerator randGen(mesh_.n_halfedges()); +#endif + + const bool update_normals = mesh_.has_face_normals(); + + while ( n_collapses < _n_collapses) { + + if (noCollapses > 20) { + omlog() << "[McDecimater] : no collapses performed in over 20 iterations in a row\n"; + break; + } + + // Optimal id and value will be collected during the random sampling + typename Mesh::HalfedgeHandle bestHandle(-1); + typename Mesh::HalfedgeHandle tmpHandle(-1); + double bestEnergy = FLT_MAX; + double energy = FLT_MAX; + + // Generate random samples for collapses + for ( int i = 0; i < (int)randomSamples_; ++i) { + + // Random halfedge handle +#ifdef WIN32 + tmpHandle = typename Mesh::HalfedgeHandle(int(randGen.getRand() * double(mesh_.n_halfedges() - 1.0)) ); +#else + tmpHandle = typename Mesh::HalfedgeHandle( (double(rand()) / double(RAND_MAX) ) * double(mesh_.n_halfedges()-1) ); +#endif + + // if it is not deleted, we analyse it + if ( ! mesh_.status(tmpHandle).deleted() ) { + + CollapseInfo ci(mesh_, tmpHandle); + + // Check if legal we analyze the priority of this collapse operation + if (this->is_collapse_legal(ci)) { + energy = this->collapse_priority(ci); + + if (energy != ModBaseT::ILLEGAL_COLLAPSE) { + // Check if the current samples energy is better than any energy before + if ( energy < bestEnergy ) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } + } else { + continue; + } + } + + } + + // Found the best energy? + if ( bestEnergy != FLT_MAX ) { + + // setup collapse info + CollapseInfo ci(mesh_, bestHandle); + + // check topological correctness AGAIN ! + if (!this->is_collapse_legal(ci)) + continue; + + // pre-processing + this->preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(bestHandle); + ++n_collapses; + + // store current collapses state + oldCollapses = n_collapses; + noCollapses = 0; + collapsesUnchanged = false; + + // update triangle normals + if (update_normals) + { + typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it.is_valid(); ++vf_it) + if (!mesh_.status(*vf_it).deleted()) + mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it)); + } + + // post-process collapse + this->postprocess_collapse(ci); + + // notify observer and stop if the observer requests it + if (!this->notify_observer(n_collapses)) + return n_collapses; + + } else { + if (oldCollapses == n_collapses) { + if (collapsesUnchanged == false) { + noCollapses = 1; + collapsesUnchanged = true; + } else { + noCollapses++; + } + } + } + + } + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; +} + +//----------------------------------------------------------------------------- + +template +size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { + + if (!this->is_initialized()) + return 0; + + // check if no vertex or face contraints were set + if ( (_nv == 0) && (_nf == 1) ) + return decimate_constraints_only(1.0); + + size_t nv = mesh_.n_vertices(); + size_t nf = mesh_.n_faces(); + unsigned int n_collapses(0); + + + bool collapsesUnchanged = false; + // old n_collapses in order to check for convergence + unsigned int oldCollapses = 0; + // number of iterations where no new collapses where + // performed in a row + unsigned int noCollapses = 0; + +#ifdef WIN32 + RandomNumberGenerator randGen(mesh_.n_halfedges()); +#endif + + const bool update_normals = mesh_.has_face_normals(); + + while ((_nv < nv) && (_nf < nf)) { + + if (noCollapses > 20) { + omlog() << "[McDecimater] : no collapses performed in over 20 iterations in a row\n"; + break; + } + + // Optimal id and value will be collected during the random sampling + typename Mesh::HalfedgeHandle bestHandle(-1); + typename Mesh::HalfedgeHandle tmpHandle(-1); + double bestEnergy = FLT_MAX; + double energy = FLT_MAX; + + // Generate random samples for collapses + for (int i = 0; i < (int) randomSamples_; ++i) { + + // Random halfedge handle +#ifdef WIN32 + tmpHandle = typename Mesh::HalfedgeHandle(int(randGen.getRand() * double(mesh_.n_halfedges() - 1.0)) ); +#else + tmpHandle = typename Mesh::HalfedgeHandle( ( double(rand()) / double(RAND_MAX) ) * double(mesh_.n_halfedges() - 1)); +#endif + + // if it is not deleted, we analyse it + if (!mesh_.status(tmpHandle).deleted()) { + + CollapseInfo ci(mesh_, tmpHandle); + + // Check if legal we analyze the priority of this collapse operation + if (this->is_collapse_legal(ci)) { + energy = this->collapse_priority(ci); + + if (energy != ModBaseT::ILLEGAL_COLLAPSE) { + // Check if the current samples energy is better than any energy before + if (energy < bestEnergy) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } + } else { + continue; + } + } + + } + + // Found the best energy? + if ( bestEnergy != FLT_MAX ) { + + // setup collapse info + CollapseInfo ci(mesh_, bestHandle); + + // check topological correctness AGAIN ! + if (!this->is_collapse_legal(ci)) + continue; + + // adjust complexity in advance (need boundary status) + + // One vertex is killed by the collapse + --nv; + + // If we are at a boundary, one face is lost, + // otherwise two + if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0)) + --nf; + else + nf -= 2; + + // pre-processing + this->preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(bestHandle); + ++n_collapses; + + // store current collapses state + oldCollapses = n_collapses; + noCollapses = 0; + collapsesUnchanged = false; + + if (update_normals) + { + // update triangle normals + typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it.is_valid(); ++vf_it) + if (!mesh_.status(*vf_it).deleted()) + mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it)); + } + + // post-process collapse + this->postprocess_collapse(ci); + + // notify observer and stop if the observer requests it + if (!this->notify_observer(n_collapses)) + return n_collapses; + + } else { + if (oldCollapses == n_collapses) { + if (collapsesUnchanged == false) { + noCollapses = 1; + collapsesUnchanged = true; + } else { + noCollapses++; + } + } + } + + } + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; +} + +//----------------------------------------------------------------------------- + +template +size_t McDecimaterT::decimate_constraints_only(float _factor) { + + if (!this->is_initialized()) + return 0; + + if (_factor < 1.0) + this->set_error_tolerance_factor(_factor); + + unsigned int n_collapses(0); + size_t nv = mesh_.n_vertices(); + size_t nf = mesh_.n_faces(); + + bool lastCollapseIllegal = false; + // number of illegal collapses that occurred in a row + unsigned int illegalCollapses = 0; + + bool collapsesUnchanged = false; + // old n_collapses in order to check for convergence + unsigned int oldCollapses = 0; + // number of iterations where no new collapses where + // performed in a row + unsigned int noCollapses = 0; + + double energy = FLT_MAX; + double bestEnergy = FLT_MAX; + +#ifdef WIN32 + RandomNumberGenerator randGen(mesh_.n_halfedges()); +#endif + + while ((noCollapses <= 50) && (illegalCollapses <= 50) && (nv > 0) && (nf > 1)) { + + // Optimal id and value will be collected during the random sampling + typename Mesh::HalfedgeHandle bestHandle(-1); + typename Mesh::HalfedgeHandle tmpHandle(-1); + bestEnergy = FLT_MAX; + + +#ifndef WIN32 + const double randomNormalizer = (1.0 / RAND_MAX) * (mesh_.n_halfedges() - 1); +#endif + + // Generate random samples for collapses + for (int i = 0; i < (int) randomSamples_; ++i) { + + // Random halfedge handle +#ifdef WIN32 + tmpHandle = typename Mesh::HalfedgeHandle(int(randGen.getRand() * double(mesh_.n_halfedges() - 1.0)) ); +#else + tmpHandle = typename Mesh::HalfedgeHandle(int(rand() * randomNormalizer ) ); +#endif + + // if it is not deleted, we analyze it + if (!mesh_.status(mesh_.edge_handle(tmpHandle)).deleted()) { + + CollapseInfo ci(mesh_, tmpHandle); + + // Check if legal we analyze the priority of this collapse operation + if (this->is_collapse_legal(ci)) { + + energy = this->collapse_priority(ci); + + if (energy == ModBaseT::ILLEGAL_COLLAPSE) { + if (lastCollapseIllegal) { + illegalCollapses++; + } else { + illegalCollapses = 1; + lastCollapseIllegal = true; + } + } else { + + illegalCollapses = 0; + lastCollapseIllegal = false; + + // Check if the current samples energy is better than any energy before + if (energy < bestEnergy) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } + } else { + + continue; + } + } + + } + + + + // Found the best energy? + if ( bestEnergy != FLT_MAX ) { + + // setup collapse info + CollapseInfo ci(mesh_, bestHandle); + + // check topological correctness AGAIN ! + if (!this->is_collapse_legal(ci)) + continue; + + // adjust complexity in advance (need boundary status) + + // One vertex is killed by the collapse + --nv; + + // If we are at a boundary, one face is lost, + // otherwise two + if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0)) + --nf; + else + nf -= 2; + + // pre-processing + this->preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(bestHandle); + ++n_collapses; + + // store current collapses state + oldCollapses = n_collapses; + noCollapses = 0; + collapsesUnchanged = false; + + + // update triangle normals + typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it.is_valid(); ++vf_it) + if (!mesh_.status(*vf_it).deleted()) + mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it)); + + // post-process collapse + this->postprocess_collapse(ci); + + // notify observer and stop if the observer requests it + if (!this->notify_observer(n_collapses)) + return n_collapses; + + } else { + if (oldCollapses == n_collapses) { + if (collapsesUnchanged == false) { + noCollapses = 1; + collapsesUnchanged = true; + } else { + noCollapses++; + } + } + } + + } + + if (_factor < 1.0) + this->set_error_tolerance_factor(1.0); + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; + +} + +//============================================================================= +}// END_NS_MC_DECIMATER +} // END_NS_OPENMESH +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/McDecimaterT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/McDecimaterT.hh new file mode 100644 index 0000000..82e1fd6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/McDecimaterT.hh @@ -0,0 +1,151 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file McDecimaterT.hh + */ + +//============================================================================= +// +// CLASS McDecimaterT +// +//============================================================================= + +#ifndef OPENMESH_MC_DECIMATER_DECIMATERT_HH +#define OPENMESH_MC_DECIMATER_DECIMATERT_HH + + +//== INCLUDES ================================================================= + +#include +#include + + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** Multiple choice decimater framework + \see BaseModT, \ref decimater_docu +*/ +template < typename MeshT > +class McDecimaterT : virtual public BaseDecimaterT //virtual especially for the mixed decimater +{ +public: //-------------------------------------------------------- public types + + typedef McDecimaterT< MeshT > Self; + typedef MeshT Mesh; + typedef CollapseInfoT CollapseInfo; + typedef ModBaseT Module; + typedef std::vector< Module* > ModuleList; + typedef typename ModuleList::iterator ModuleListIterator; + +public: //------------------------------------------------------ public methods + + /// Constructor + McDecimaterT( Mesh& _mesh ); + + /// Destructor + ~McDecimaterT(); + +public: + + /** Decimate (perform _n_collapses collapses). Return number of + performed collapses. If _n_collapses is not given reduce as + much as possible */ + size_t decimate( size_t _n_collapses ); + + /// Decimate to target complexity, returns number of collapses + size_t decimate_to( size_t _n_vertices ) + { + return ( (_n_vertices < this->mesh().n_vertices()) ? + decimate( this->mesh().n_vertices() - _n_vertices ) : 0 ); + } + + /** Decimate to target complexity (vertices and faces). + * Stops when the number of vertices or the number of faces is reached. + * Returns number of performed collapses. + */ + size_t decimate_to_faces( size_t _n_vertices=0, size_t _n_faces=0 ); + + /** + * Decimate only with constraints, while _factor gives the + * percentage of the constraints that should be used + */ + size_t decimate_constraints_only(float _factor); + + size_t samples(){return randomSamples_;} + void set_samples(const size_t _value){randomSamples_ = _value;} + +private: //------------------------------------------------------- private data + + + // reference to mesh + Mesh& mesh_; + + size_t randomSamples_; + +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MULTIPLE_CHOICE_DECIMATER_DECIMATERT_CC) +#define OPENMESH_MULTIPLE_CHOICE_DECIMATER_TEMPLATES +#include "McDecimaterT.cc" +#endif +//============================================================================= +#endif // OPENMESH_MC_DECIMATER_DECIMATERT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/MixedDecimaterT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/MixedDecimaterT.cc new file mode 100644 index 0000000..bb21f39 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/MixedDecimaterT.cc @@ -0,0 +1,178 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ +* * +* $Revision$ * +* $Date$ * +* * +\*===========================================================================*/ + +/** \file MixedDecimaterT.cc +*/ + +//============================================================================= +// +// CLASS MixedDecimaterT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_MIXED_DECIMATER_DECIMATERT_CC + +//== INCLUDES ================================================================= + +#include + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACE =============================================================== +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +MixedDecimaterT::MixedDecimaterT(Mesh& _mesh) : + BaseDecimaterT(_mesh),McDecimaterT(_mesh), DecimaterT(_mesh) { + +} + +//----------------------------------------------------------------------------- + +template +MixedDecimaterT::~MixedDecimaterT() { + +} + +//----------------------------------------------------------------------------- +template +size_t MixedDecimaterT::decimate(const size_t _n_collapses, const float _mc_factor) { + + if (_mc_factor > 1.0) + return 0; + + size_t n_collapses_mc = static_cast(_mc_factor*_n_collapses); + size_t n_collapses_inc = static_cast(_n_collapses - n_collapses_mc); + + size_t r_collapses = 0; + if (_mc_factor > 0.0) + r_collapses = McDecimaterT::decimate(n_collapses_mc); + + // returns, if the previous steps were aborted by the observer + if (this->observer() && this->observer()->abort()) + return r_collapses; + + if (_mc_factor < 1.0) + r_collapses += DecimaterT::decimate(n_collapses_inc); + + return r_collapses; + +} + +template +size_t MixedDecimaterT::decimate_to_faces(const size_t _n_vertices,const size_t _n_faces, const float _mc_factor ){ + + if (_mc_factor > 1.0) + return 0; + + std::size_t r_collapses = 0; + if (_mc_factor > 0.0) + { + bool constraintsOnly = (_n_vertices == 0) && (_n_faces == 1); + if (!constraintsOnly) { + size_t mesh_faces = this->mesh().n_faces(); + size_t mesh_vertices = this->mesh().n_vertices(); + //reduce the mesh only for _mc_factor + size_t n_vertices_mc = static_cast(mesh_vertices - _mc_factor * (mesh_vertices - _n_vertices)); + size_t n_faces_mc = static_cast(mesh_faces - _mc_factor * (mesh_faces - _n_faces)); + + r_collapses = McDecimaterT::decimate_to_faces(n_vertices_mc, n_faces_mc); + } else { + + const size_t samples = this->samples(); + + // MinimalSample count for the McDecimater + const size_t min = 2; + + // Maximal number of samples for the McDecimater + const size_t max = samples; + + // Number of incremental steps + const size_t steps = 7; + + for ( size_t i = 0; i < steps; ++i ) { + + // Compute number of samples to be used + size_t samples = int (double( min) + double(i)/(double(steps)-1.0) * (max-2) ) ; + + // We won't allow 1 here, as this is the last step in the incremental part + float decimaterLevel = (float(i + 1)) * _mc_factor / (float(steps) ); + + this->set_samples(samples); + r_collapses += McDecimaterT::decimate_constraints_only(decimaterLevel); + } + } + } + + //Update the mesh::n_vertices function, otherwise the next Decimater function will delete too much + this->mesh().garbage_collection(); + + // returns, if the previous steps were aborted by the observer + if (this->observer() && this->observer()->abort()) + return r_collapses; + + //reduce the rest of the mesh + if (_mc_factor < 1.0) { + r_collapses += DecimaterT::decimate_to_faces(_n_vertices,_n_faces); + } + + + return r_collapses; +} + +//============================================================================= +}// END_NS_MC_DECIMATER +} // END_NS_OPENMESH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/MixedDecimaterT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/MixedDecimaterT.hh new file mode 100644 index 0000000..cf52a5a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/MixedDecimaterT.hh @@ -0,0 +1,136 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file MixedDecimaterT.cc + */ + +//============================================================================= +// +// CLASS MixedDecimaterT - IMPLEMENTATION +// +//============================================================================= + +#ifndef OPENMESH_MIXED_DECIMATER_DECIMATERT_HH +#define OPENMESH_MIXED_DECIMATER_DECIMATERT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** Mixed decimater framework + \see BaseModT, \ref decimater_docu +*/ +template < typename MeshT > +class MixedDecimaterT : public McDecimaterT, public DecimaterT +{ +public: //-------------------------------------------------------- public types + + typedef McDecimaterT< MeshT > Self; + typedef MeshT Mesh; + typedef CollapseInfoT CollapseInfo; + typedef ModBaseT Module; + typedef std::vector< Module* > ModuleList; + typedef typename ModuleList::iterator ModuleListIterator; + +public: //------------------------------------------------------ public methods + + /// Constructor + MixedDecimaterT( Mesh& _mesh ); + + /// Destructor + ~MixedDecimaterT(); + +public: + + /** Decimate (perform _n_collapses collapses). Return number of + performed collapses. If _n_collapses is not given reduce as + much as possible */ + size_t decimate( const size_t _n_collapses, const float _mc_factor ); + + /// Decimate to target complexity, returns number of collapses + size_t decimate_to( size_t _n_vertices, const float _mc_factor ) + { + return ( (_n_vertices < this->mesh().n_vertices()) ? + decimate( this->mesh().n_vertices() - _n_vertices, _mc_factor ) : 0 ); + } + + /** Decimate to target complexity (vertices and faces). + * Stops when the number of vertices or the number of faces is reached. + * Returns number of performed collapses. + */ + size_t decimate_to_faces( const size_t _n_vertices=0, const size_t _n_faces=0 , const float _mc_factor = 0.8); + +private: //------------------------------------------------------- private data + +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MIXED_DECIMATER_DECIMATERT_CC) +#define OPENMESH_MIXED_DECIMATER_TEMPLATES +#include "MixedDecimaterT.cc" +#endif +//============================================================================= +#endif // OPENMESH_MIXED_DECIMATER_DECIMATERT_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModAspectRatioT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModAspectRatioT.cc new file mode 100644 index 0000000..ec79f85 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModAspectRatioT.cc @@ -0,0 +1,203 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file ModAspectRatioT.cc + */ + +//============================================================================= +// +// CLASS ModAspectRatioT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_DECIMATER_MODASPECTRATIOT_C + +//== INCLUDES ================================================================= + +#include "ModAspectRatioT.hh" + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +typename ModAspectRatioT::Scalar ModAspectRatioT::aspectRatio( + const Point& _v0, const Point& _v1, const Point& _v2) { + Point d0 = _v0 - _v1; + Point d1 = _v1 - _v2; + + // finds the max squared edge length + Scalar l2, maxl2 = d0.sqrnorm(); + if ((l2 = d1.sqrnorm()) > maxl2) + maxl2 = l2; + // keep searching for the max squared edge length + d1 = _v2 - _v0; + if ((l2 = d1.sqrnorm()) > maxl2) + maxl2 = l2; + + // squared area of the parallelogram spanned by d0 and d1 + Scalar a2 = (d0 % d1).sqrnorm(); + + // the area of the triangle would be + // sqrt(a2)/2 or length * height / 2 + // aspect ratio = length / height + // = length * length / (2*area) + // = length * length / sqrt(a2) + + // returns the length of the longest edge + // divided by its corresponding height + return sqrt((maxl2 * maxl2) / a2); +} + +//----------------------------------------------------------------------------- + +template +void ModAspectRatioT::initialize() { + typename Mesh::FaceIter f_it, f_end(mesh_.faces_end()); + typename Mesh::FVIter fv_it; + + for (f_it = mesh_.faces_begin(); f_it != f_end; ++f_it) { + fv_it = mesh_.fv_iter(*f_it); + typename Mesh::Point& p0 = mesh_.point(*fv_it); + typename Mesh::Point& p1 = mesh_.point(*(++fv_it)); + typename Mesh::Point& p2 = mesh_.point(*(++fv_it)); + + mesh_.property(aspect_, *f_it) = static_cast(1.0) / aspectRatio(p0, p1, p2); + } +} + +//----------------------------------------------------------------------------- + +template +void ModAspectRatioT::preprocess_collapse(const CollapseInfo& _ci) { + typename Mesh::FaceHandle fh; + typename Mesh::FVIter fv_it; + + for (typename Mesh::VFIter vf_it = mesh_.vf_iter(_ci.v0); vf_it.is_valid(); ++vf_it) { + fh = *vf_it; + if (fh != _ci.fl && fh != _ci.fr) { + fv_it = mesh_.fv_iter(fh); + typename Mesh::Point& p0 = mesh_.point(*fv_it); + typename Mesh::Point& p1 = mesh_.point(*(++fv_it)); + typename Mesh::Point& p2 = mesh_.point(*(++fv_it)); + + mesh_.property(aspect_, fh) = static_cast(1.0) / aspectRatio(p0, p1, p2); + } + } +} + +//----------------------------------------------------------------------------- + +template +float ModAspectRatioT::collapse_priority(const CollapseInfo& _ci) { + typename Mesh::VertexHandle v2, v3; + typename Mesh::FaceHandle fh; + const typename Mesh::Point *p1(&_ci.p1), *p2, *p3; + typename Mesh::Scalar r0, r1, r0_min(1.0), r1_min(1.0); + typename Mesh::ConstVertexOHalfedgeIter voh_it(mesh_, _ci.v0); + + v3 = mesh_.to_vertex_handle(*voh_it); + p3 = &mesh_.point(v3); + + while (voh_it.is_valid()) { + v2 = v3; + p2 = p3; + + ++voh_it; + v3 = mesh_.to_vertex_handle(*voh_it); + p3 = &mesh_.point(v3); + + fh = mesh_.face_handle(*voh_it); + + // if not boundary + if (fh.is_valid()) { + // aspect before + if ((r0 = mesh_.property(aspect_, fh)) < r0_min) + r0_min = r0; + + // aspect after + if (!(v2 == _ci.v1 || v3 == _ci.v1)) + if ((r1 = static_cast(1.0) / aspectRatio(*p1, *p2, *p3)) < r1_min) + r1_min = r1; + } + } + + if (Base::is_binary()) { + return + ((r1_min > r0_min) || (r1_min > min_aspect_)) ? float(Base::LEGAL_COLLAPSE) : + float(Base::ILLEGAL_COLLAPSE); + + } else { + if (r1_min > r0_min) + return 1.f - float(r1_min); + else + return + (r1_min > min_aspect_) ? 2.f - float(r1_min) : float(Base::ILLEGAL_COLLAPSE); + } +} + +//----------------------------------------------------------------------------- + +template +void ModAspectRatioT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the larger min_aspect_ gets + // thus creating a stricter constraint + // division by (2.0 - error_tolerance_factor_) is for normalization + float min_aspect = min_aspect_ * (2.f - float(_factor)) / (2.f - float(this->error_tolerance_factor_)); + set_aspect_ratio(1.f/min_aspect); + this->error_tolerance_factor_ = _factor; + } +} + +//============================================================================= +} +} +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModAspectRatioT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModAspectRatioT.hh new file mode 100644 index 0000000..d22325f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModAspectRatioT.hh @@ -0,0 +1,156 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file ModAspectRatioT.hh + */ + +//============================================================================= +// +// CLASS ModAspectRatioT +// +//============================================================================= + +#ifndef OPENMESH_DECIMATER_MODASPECTRATIOT_HH +#define OPENMESH_DECIMATER_MODASPECTRATIOT_HH + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== CLASS DEFINITION ========================================================= + +/** \brief Use aspect ratio to control decimation + * + * This module computes the aspect ratio. + * + * In binary mode, the collapse is legal if: + * - The aspect ratio after the collapse is greater + * - The aspect ratio after the collapse is greater than the given minimum + * + * In continuous mode the collapse is illegal if: + * - The aspect ratio after the collapse is smaller than the given minimum + * + * + */ +template +class ModAspectRatioT: public ModBaseT { + public: + + DECIMATING_MODULE( ModAspectRatioT, MeshT, AspectRatio ) + ; + + typedef typename Mesh::Scalar Scalar; + typedef typename Mesh::Point Point; + + /// constructor + ModAspectRatioT(MeshT& _mesh, float _min_aspect = 5.0, bool _is_binary = + true) : + Base(_mesh, _is_binary), mesh_(Base::mesh()), min_aspect_( + 1.f / _min_aspect) { + mesh_.add_property(aspect_); + } + + /// destructor + ~ModAspectRatioT() { + mesh_.remove_property(aspect_); + } + + /// get aspect ratio + float aspect_ratio() const { + return 1.f / min_aspect_; + } + + /// set aspect ratio + void set_aspect_ratio(float _f) { + min_aspect_ = 1.f / _f; + } + + /// precompute face aspect ratio + void initialize(); + + /// Returns the collapse priority + float collapse_priority(const CollapseInfo& _ci); + + /// update aspect ratio of one-ring + void preprocess_collapse(const CollapseInfo& _ci); + + /// set percentage of aspect ratio + void set_error_tolerance_factor(double _factor); + + private: + + /** \brief return aspect ratio (length/height) of triangle + * + */ + Scalar aspectRatio(const Point& _v0, const Point& _v1, const Point& _v2); + + private: + + Mesh& mesh_; + float min_aspect_; + FPropHandleT aspect_; +}; + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODASPECTRATIOT_C) +#define OPENMESH_DECIMATER_MODASPECTRATIOT_TEMPLATES +#include "ModAspectRatioT.cc" +#endif +//============================================================================= +#endif // OPENMESH_DECIMATER_MODASPECTRATIOT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModBaseT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModBaseT.hh new file mode 100644 index 0000000..034ba5e --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModBaseT.hh @@ -0,0 +1,305 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModBaseT.hh + Base class for all decimation modules. + */ + +//============================================================================= +// +// CLASS ModBaseT +// +//============================================================================= + +#ifndef OPENMESH_DECIMATER_MODBASET_HH +#define OPENMESH_DECIMATER_MODBASET_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== FORWARD DECLARATIONS ===================================================== + +template class BaseDecimaterT; + + +//== CLASS DEFINITION ========================================================= + +/** Handle for mesh decimation modules + \internal + */ + +template +class ModHandleT : private Utils::Noncopyable +{ +public: + + typedef ModHandleT Self; + typedef Module module_type; + +public: + + /// Default constructor + ModHandleT() : mod_(NULL) {} + + /// Destructor + ~ModHandleT() { /* don't delete mod_, since handle is not owner! */ } + + /// Check handle status + /// \return \c true, if handle is valid, else \c false. + bool is_valid() const { return mod_ != NULL; } + +private: + +#if defined(OM_CC_MSVC) + friend class BaseDecimaterT; +#else + template friend class BaseDecimaterT; +#endif + + void clear() { mod_ = NULL; } + void init(Module* _m) { mod_ = _m; } + Module* module() { return mod_; } + + +private: + + Module* mod_; + +}; + + + + +//== CLASS DEFINITION ========================================================= + + + +/// Macro that sets up the name() function +/// \internal +#define DECIMATER_MODNAME(_mod_name) \ + virtual const std::string& name() const { \ + static std::string _s_modname_(#_mod_name); return _s_modname_; \ +} + + +/** Convenience macro, to be used in derived modules + * The macro defines the types + * - \c Handle, type of the module's handle. + * - \c Base, type of ModBaseT<>. + * - \c Mesh, type of the associated mesh passed by the decimater type. + * - \c CollapseInfo, to your convenience + * and uses DECIMATER_MODNAME() to define the name of the module. + * + * \param Classname The name of the derived class. + * \param MeshT Pass here the mesh type, which is the + * template parameter passed to ModBaseT. + * \param Name Give the module a name. + */ +#define DECIMATING_MODULE(Classname, MeshT, Name) \ + typedef Classname < MeshT > Self; \ + typedef OpenMesh::Decimater::ModHandleT< Self > Handle; \ + typedef OpenMesh::Decimater::ModBaseT< MeshT > Base; \ + typedef typename Base::Mesh Mesh; \ + typedef typename Base::CollapseInfo CollapseInfo; \ + DECIMATER_MODNAME( Name ) + + + +//== CLASS DEFINITION ========================================================= + + +/** Base class for all decimation modules. + + Each module has to implement this interface. + To build your own module you have to + -# derive from this class. + -# create the basic settings with DECIMATING_MODULE(). + -# override collapse_priority(), if necessary. + -# override initialize(), if necessary. + -# override postprocess_collapse(), if necessary. + + A module has two major working modes: + -# binary mode + -# non-binary mode + + In the binary mode collapse_priority() checks a constraint and + returns LEGAL_COLLAPSE or ILLEGAL_COLLAPSE. + + In the non-binary mode the module computes a float error value in + the range [0, inf) and returns it. In the case a constraint has + been set, e.g. the error must be lower than a upper bound, and the + constraint is violated, collapse_priority() must return + ILLEGAL_COLLAPSE. + + \see collapse_priority() + + \todo "Tutorial on building a custom decimation module." + +*/ + +template +class ModBaseT +{ +public: + typedef MeshT Mesh; + typedef CollapseInfoT CollapseInfo; + + enum { + ILLEGAL_COLLAPSE = -1, ///< indicates an illegal collapse + LEGAL_COLLAPSE = 0 ///< indicates a legal collapse + }; + +protected: + + /// Default constructor + /// \see \ref decimater_docu + ModBaseT(MeshT& _mesh, bool _is_binary) + : error_tolerance_factor_(1.0), mesh_(_mesh), is_binary_(_is_binary) {} + +public: + + /// Virtual desctructor + virtual ~ModBaseT() { } + + /// Set module's name (using DECIMATER_MODNAME macro) + DECIMATER_MODNAME(ModBase); + + + /// Returns true if criteria returns a binary value. + bool is_binary(void) const { return is_binary_; } + + /// Set whether module is binary or not. + void set_binary(bool _b) { is_binary_ = _b; } + + +public: // common interface + + /// Initialize module-internal stuff + virtual void initialize() { } + + /** Return collapse priority. + * + * In the binary mode collapse_priority() checks a constraint and + * returns LEGAL_COLLAPSE or ILLEGAL_COLLAPSE. + * + * In the non-binary mode the module computes a float error value in + * the range [0, inf) and returns it. In the case a constraint has + * been set, e.g. the error must be lower than a upper bound, and the + * constraint is violated, collapse_priority() must return + * ILLEGAL_COLLAPSE. + * + * \return Collapse priority in the range [0,inf), + * \c LEGAL_COLLAPSE or \c ILLEGAL_COLLAPSE. + */ + virtual float collapse_priority(const CollapseInfoT& /* _ci */) + { return LEGAL_COLLAPSE; } + + /** Before _from_vh has been collapsed into _to_vh, this method + will be called. + */ + virtual void preprocess_collapse(const CollapseInfoT& /* _ci */) + {} + + /** After _from_vh has been collapsed into _to_vh, this method + will be called. + */ + virtual void postprocess_collapse(const CollapseInfoT& /* _ci */) + {} + + /** + * This provides a function that allows the setting of a percentage + * of the original contraint. + * + * Note that the module might need to be re-initialized again after + * setting the percentage + * @param _factor has to be in the closed interval between 0.0 and 1.0 + */ + virtual void set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) + error_tolerance_factor_ = _factor; + } + + +protected: + + /// Access the mesh associated with the decimater. + MeshT& mesh() { return mesh_; } + + // current percentage of the original constraint + double error_tolerance_factor_; + +private: + + // hide copy constructor & assignemnt + ModBaseT(const ModBaseT& _cpy); + ModBaseT& operator=(const ModBaseT& ); + + MeshT& mesh_; + + bool is_binary_; +}; + + +//============================================================================= +} // namespace Decimater +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_DECIMATER_MODBASE_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc new file mode 100644 index 0000000..bfd45e5 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc @@ -0,0 +1,103 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file ModEdgeLengthT.cc + */ + +//============================================================================= +// +// CLASS ModEdgeLengthT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_DECIMATER_MODEDGELENGTHT_C + +//== INCLUDES ================================================================= + +#include "ModEdgeLengthT.hh" + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +ModEdgeLengthT::ModEdgeLengthT(MeshT &_mesh, float _edge_length, + bool _is_binary) : + Base(_mesh, _is_binary), mesh_(Base::mesh()) { + set_edge_length(_edge_length); +} + +//----------------------------------------------------------------------------- + +template +float ModEdgeLengthT::collapse_priority(const CollapseInfo& _ci) { + typename Mesh::Scalar sqr_length = (_ci.p0 - _ci.p1).sqrnorm(); + + return ( (sqr_length <= sqr_edge_length_) ? sqr_length : float(Base::ILLEGAL_COLLAPSE)); +} + +//----------------------------------------------------------------------------- + +template +void ModEdgeLengthT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller edge_length_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + typename Mesh::Scalar edge_length = edge_length_ * static_cast(_factor / this->error_tolerance_factor_); + set_edge_length(edge_length); + this->error_tolerance_factor_ = _factor; + } +} + +//============================================================================= +} +} +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh new file mode 100644 index 0000000..f50878d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh @@ -0,0 +1,129 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file ModEdgeLengthT.hh + */ + +//============================================================================= +// +// CLASS ModEdgeLengthT +// +//============================================================================= +#ifndef OPENMESH_DECIMATER_MODEDGELENGTHT_HH +#define OPENMESH_DECIMATER_MODEDGELENGTHT_HH + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== CLASS DEFINITION ========================================================= + +/** \brief Use edge length to control decimation + * + * This module computes the edge length. + * + * In binary and continuous mode, the collapse is legal if: + * - The length after the collapse is lower than the given tolerance + * + */ +template +class ModEdgeLengthT: public ModBaseT { + public: + + DECIMATING_MODULE( ModEdgeLengthT, MeshT, EdgeLength ) + ; + + /// Constructor + ModEdgeLengthT(MeshT& _mesh, float _edge_length = FLT_MAX, + bool _is_binary = true); + + /// get edge_length + float edge_length() const { + return edge_length_; + } + + /// set edge_length + void set_edge_length(typename Mesh::Scalar _f) { + edge_length_ = _f; + sqr_edge_length_ = _f * _f; + } + + /** Compute priority: + Binary mode: Don't collapse edges longer then edge_length_ + Cont. mode: Collapse smallest edge first, but + don't collapse edges longer as edge_length_ + */ + float collapse_priority(const CollapseInfo& _ci); + + /// set the percentage of edge length + void set_error_tolerance_factor(double _factor); + + private: + + Mesh& mesh_; + typename Mesh::Scalar edge_length_, sqr_edge_length_; +}; + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODEDGELENGTHT_C) +#define MODEDGELENGTHT_TEMPLATES +#include "ModEdgeLengthT.cc" +#endif +//============================================================================= +#endif // OPENMESH_DECIMATER_MODEDGELENGTHT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModHausdorffT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModHausdorffT.cc new file mode 100644 index 0000000..3701a46 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModHausdorffT.cc @@ -0,0 +1,393 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModHausdorffT.cc + */ + + +//============================================================================= +// +// CLASS ModHausdorffT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_DECIMATER_MODHAUSDORFFT_C + + +//== INCLUDES ================================================================= + +#include "ModHausdorffT.hh" + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +typename ModHausdorffT::Scalar +ModHausdorffT:: +distPointTriangleSquared( const Point& _p, + const Point& _v0, + const Point& _v1, + const Point& _v2 ) +{ + const Point v0v1 = _v1 - _v0; + const Point v0v2 = _v2 - _v0; + const Point n = v0v1 % v0v2; // not normalized ! + const Scalar d = n.sqrnorm(); + + + // Check if the triangle is degenerated + if (d < FLT_MIN && d > -FLT_MIN) { + return -1.0; + } + const Scalar invD = static_cast(1.0) / d; + + // these are not needed for every point, should still perform + // better with many points against one triangle + const Point v1v2 = _v2 - _v1; + const Scalar inv_v0v2_2 = static_cast(1.0) / v0v2.sqrnorm(); + const Scalar inv_v0v1_2 = static_cast(1.0) / v0v1.sqrnorm(); + const Scalar inv_v1v2_2 = static_cast(1.0) / v1v2.sqrnorm(); + + + Point v0p = _p - _v0; + Point t = v0p % n; + typename Point::value_type s01, s02, s12; + const Scalar a = (t | v0v2) * -invD; + const Scalar b = (t | v0v1) * invD; + + if (a < 0) + { + // Calculate the distance to an edge or a corner vertex + s02 = ( v0v2 | v0p ) * inv_v0v2_2; + if (s02 < 0.0) + { + s01 = ( v0v1 | v0p ) * inv_v0v1_2; + if (s01 <= 0.0) { + v0p = _v0; + } else if (s01 >= 1.0) { + v0p = _v1; + } else { + v0p = _v0 + v0v1 * s01; + } + } else if (s02 > 1.0) { + s12 = ( v1v2 | ( _p - _v1 )) * inv_v1v2_2; + if (s12 >= 1.0) { + v0p = _v2; + } else if (s12 <= 0.0) { + v0p = _v1; + } else { + v0p = _v1 + v1v2 * s12; + } + } else { + v0p = _v0 + v0v2 * s02; + } + } else if (b < 0.0) { + // Calculate the distance to an edge or a corner vertex + s01 = ( v0v1 | v0p ) * inv_v0v1_2; + if (s01 < 0.0) + { + // const Point n = v0v1 % v0v2; // not normalized ! + s02 = ( v0v2 | v0p ) * inv_v0v2_2; + if (s02 <= 0.0) { + v0p = _v0; + } else if (s02 >= 1.0) { + v0p = _v2; + } else { + v0p = _v0 + v0v2 * s02; + } + } else if (s01 > 1.0) { + s12 = ( v1v2 | ( _p - _v1 )) * inv_v1v2_2; + if (s12 >= 1.0) { + v0p = _v2; + } else if (s12 <= 0.0) { + v0p = _v1; + } else { + v0p = _v1 + v1v2 * s12; + } + } else { + v0p = _v0 + v0v1 * s01; + } + } else if (a+b > 1.0) { + // Calculate the distance to an edge or a corner vertex + s12 = ( v1v2 | ( _p - _v1 )) * inv_v1v2_2; + if (s12 >= 1.0) { + s02 = ( v0v2 | v0p ) * inv_v0v2_2; + if (s02 <= 0.0) { + v0p = _v0; + } else if (s02 >= 1.0) { + v0p = _v2; + } else { + v0p = _v0 + v0v2*s02; + } + } else if (s12 <= 0.0) { + s01 = ( v0v1 | v0p ) * inv_v0v1_2; + if (s01 <= 0.0) { + v0p = _v0; + } else if (s01 >= 1.0) { + v0p = _v1; + } else { + v0p = _v0 + v0v1 * s01; + } + } else { + v0p = _v1 + v1v2 * s12; + } + } else { + // Calculate the distance to an interior point of the triangle + return ( (_p - n*((n|v0p) * invD)) - _p).sqrnorm(); + } + + return (v0p - _p).sqrnorm(); +} + + +template +void +ModHausdorffT:: +initialize() +{ + typename Mesh::FIter f_it(mesh_.faces_begin()), f_end(mesh_.faces_end()); + + for (; f_it!=f_end; ++f_it) + mesh_.property(points_, *f_it).clear(); +} + + +//----------------------------------------------------------------------------- + + +template +float +ModHausdorffT:: +collapse_priority(const CollapseInfo& _ci) +{ + std::vector faces; faces.reserve(20); + typename Mesh::VertexFaceIter vf_it; + typename Mesh::FaceHandle fh; + const typename Mesh::Scalar sqr_tolerace = tolerance_*tolerance_; + typename Mesh::CFVIter fv_it; + bool ok; + + // Clear the temporary point storage + tmp_points_.clear(); + + // collect all points to be tested + // collect all faces to be tested against + for (vf_it=mesh_.vf_iter(_ci.v0); vf_it.is_valid(); ++vf_it) { + fh = *vf_it; + + if (fh != _ci.fl && fh != _ci.fr) + faces.push_back(fh); + + Points& pts = mesh_.property(points_, fh); + std::copy(pts.begin(), pts.end(), std::back_inserter(tmp_points_)); + } + + // add point to be removed + tmp_points_.push_back(_ci.p0); + + // setup iterators + typename std::vector::iterator fh_it, fh_end(faces.end()); + typename Points::const_iterator p_it, p_end(tmp_points_.end()); + + // simulate collapse + mesh_.set_point(_ci.v0, _ci.p1); + + // for each point: try to find a face such that error is < tolerance + ok = true; + + for (p_it=tmp_points_.begin(); ok && p_it!=p_end; ++p_it) { + ok = false; + + for (fh_it=faces.begin(); !ok && fh_it!=fh_end; ++fh_it) { + fv_it=mesh_.cfv_iter(*fh_it); + const Point& p0 = mesh_.point(*fv_it); + const Point& p1 = mesh_.point(*(++fv_it)); + const Point& p2 = mesh_.point(*(++fv_it)); + + if ( distPointTriangleSquared(*p_it, p0, p1, p2) <= sqr_tolerace) + ok = true; + } + } + + // undo simulation changes + mesh_.set_point(_ci.v0, _ci.p0); + + return ( ok ? Base::LEGAL_COLLAPSE : Base::ILLEGAL_COLLAPSE ); +} + +//----------------------------------------------------------------------------- + +template +void ModHausdorffT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller tolerance gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + Scalar tolerance = tolerance_ * Scalar(_factor / this->error_tolerance_factor_); + set_tolerance(tolerance); + this->error_tolerance_factor_ = _factor; + } +} + +//----------------------------------------------------------------------------- + +template +void +ModHausdorffT:: +postprocess_collapse(const CollapseInfo& _ci) +{ + typename Mesh::VertexFaceIter vf_it; + FaceHandle fh; + std::vector faces; + + + // collect points & neighboring triangles + + tmp_points_.clear(); + faces.reserve(20); + + // collect active faces and their points + for (vf_it=mesh_.vf_iter(_ci.v1); vf_it.is_valid(); ++vf_it) { + fh = *vf_it; + faces.push_back(fh); + + Points& pts = mesh_.property(points_, fh); + std::copy(pts.begin(), pts.end(), std::back_inserter(tmp_points_)); + pts.clear(); + } + if (faces.empty()) return; // should not happen anyway... + + + // collect points of the 2 deleted faces + if ((fh=_ci.fl).is_valid()) { + Points& pts = mesh_.property(points_, fh); + std::copy(pts.begin(), pts.end(), std::back_inserter(tmp_points_)); + pts.clear(); + } + if ((fh=_ci.fr).is_valid()) { + Points& pts = mesh_.property(points_, fh); + std::copy(pts.begin(), pts.end(), std::back_inserter(tmp_points_)); + pts.clear(); + } + + // add the deleted point + tmp_points_.push_back(_ci.p0); + + + // setup iterators + typename std::vector::iterator fh_it, fh_end(faces.end()); + typename Points::const_iterator p_it, p_end(tmp_points_.end()); + + // re-distribute points + Scalar emin, e; + typename Mesh::CFVIter fv_it; + + for (p_it=tmp_points_.begin(); p_it!=p_end; ++p_it) { + emin = FLT_MAX; + + for (fh_it=faces.begin(); fh_it!=fh_end; ++fh_it) { + fv_it=mesh_.cfv_iter(*fh_it); + const Point& p0 = mesh_.point(*fv_it); + const Point& p1 = mesh_.point(*(++fv_it)); + const Point& p2 = mesh_.point(*(++fv_it)); + + e = distPointTriangleSquared(*p_it, p0, p1, p2); + if (e < emin) { + emin = e; + fh = *fh_it; + } + + } + + mesh_.property(points_, fh).push_back(*p_it); + } +} + + +//----------------------------------------------------------------------------- + + +template +typename ModHausdorffT::Scalar +ModHausdorffT:: +compute_sqr_error(FaceHandle _fh, const Point& _p) const +{ + typename Mesh::CFVIter fv_it = mesh_.cfv_iter(_fh); + const Point& p0 = mesh_.point(fv_it); + const Point& p1 = mesh_.point(++fv_it); + const Point& p2 = mesh_.point(++fv_it); + + const Points& points = mesh_.property(points_, _fh); + typename Points::const_iterator p_it = points.begin(); + typename Points::const_iterator p_end = points.end(); + + Point dummy; + Scalar e; + Scalar emax = distPointTriangleSquared(_p, p0, p1, p2); + + + + for (; p_it!=p_end; ++p_it) { + e = distPointTriangleSquared(*p_it, p0, p1, p2); + if (e > emax) + emax = e; + } + + return emax; +} + + +//============================================================================= +} +} +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModHausdorffT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModHausdorffT.hh new file mode 100644 index 0000000..caad8c5 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModHausdorffT.hh @@ -0,0 +1,167 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file ModHausdorffT.hh + */ + +//============================================================================= +// +// CLASS ModHausdorffT +// +//============================================================================= + +#ifndef OPENMESH_DECIMATER_MODHAUSDORFFT_HH +#define OPENMESH_DECIMATER_MODHAUSDORFFT_HH + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== CLASS DEFINITION ========================================================= + +/** \brief Use Hausdorff distance to control decimation + * + * This module computes the aspect ratio. + * + * In binary mode, the collapse is legal if: + * - The distance after the collapse is lower than the given tolerance + * + * No continuous mode + */ +template +class ModHausdorffT: public ModBaseT { + public: + + DECIMATING_MODULE( ModHausdorffT, MeshT, Hausdorff ); + + typedef typename Mesh::Scalar Scalar; + typedef typename Mesh::Point Point; + typedef typename Mesh::FaceHandle FaceHandle; + typedef std::vector Points; + + /// Constructor + ModHausdorffT(MeshT& _mesh, Scalar _error_tolerance = FLT_MAX) : + Base(_mesh, true), mesh_(Base::mesh()), tolerance_(_error_tolerance) { + mesh_.add_property(points_); + } + + /// Destructor + ~ModHausdorffT() { + mesh_.remove_property(points_); + } + + /// get max error tolerance + Scalar tolerance() const { + return tolerance_; + } + + /// set max error tolerance + void set_tolerance(Scalar _e) { + tolerance_ = _e; + } + + /// reset per-face point lists + virtual void initialize(); + + /** \brief compute Hausdorff error for one-ring + * + * This mod only allows collapses if the Hausdorff distance + * after a collapse is lower than the given tolerance. + * + * + * @param _ci Collapse info data + * @return Binary return, if collapse is legal or illegal + */ + + virtual float collapse_priority(const CollapseInfo& _ci); + + /// re-distribute points + virtual void postprocess_collapse(const CollapseInfo& _ci); + + /// set the percentage of tolerance + void set_error_tolerance_factor(double _factor); + + private: + + /// squared distance from point _p to triangle (_v0, _v1, _v2) + Scalar distPointTriangleSquared(const Point& _p, const Point& _v0, const Point& _v1, const Point& _v2); + + /// compute max error for face _fh w.r.t. its point list and _p + Scalar compute_sqr_error(FaceHandle _fh, const Point& _p) const; + + private: + + /// Temporary point storage + Points tmp_points_; + + Mesh& mesh_; + Scalar tolerance_; + + OpenMesh::FPropHandleT points_; +}; + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODHAUSDORFFT_C) +#define OPENMESH_DECIMATER_MODHAUSDORFFT_TEMPLATES +#include "ModHausdorffT.cc" +#endif +//============================================================================= +#endif // OPENMESH_DECIMATER_MODHAUSDORFFT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModIndependentSetsT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModIndependentSetsT.hh new file mode 100644 index 0000000..e4d79f6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModIndependentSetsT.hh @@ -0,0 +1,108 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * + \*===========================================================================*/ + +/** \file ModQuadricT.hh + + */ + +//============================================================================= +// +// CLASS ModQuadricT +// +//============================================================================= +#ifndef OPENMESH_TOOLS_MODINDEPENDENTSETST_HH +#define OPENMESH_TOOLS_MODINDEPENDENTSETST_HH + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Decimater { // BEGIN_NS_DECIMATER + +//== CLASS DEFINITION ========================================================= + +/** Lock one-ring around remaining vertex after a collapse to prevent + * further collapses of halfedges incident to the one-ring vertices. + */ +template +class ModIndependentSetsT: public ModBaseT { + public: + DECIMATING_MODULE( ModIndependentSetsT, MeshT, IndependentSets ) + ; + + /// Constructor + ModIndependentSetsT(MeshT &_mesh) : + Base(_mesh, true) { + } + + /// override + void postprocess_collapse(const CollapseInfo& _ci) { + typename Mesh::VertexVertexIter vv_it; + + Base::mesh().status(_ci.v1).set_locked(true); + vv_it = Base::mesh().vv_iter(_ci.v1); + for (; vv_it.is_valid(); ++vv_it) + Base::mesh().status(*vv_it).set_locked(true); + } + + private: + + /// hide this method + void set_binary(bool _b) { } +}; + +//============================================================================= +}// END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_TOOLS_MODINDEPENDENTSETST_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh new file mode 100644 index 0000000..0415b04 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh @@ -0,0 +1,267 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModNormalDeviationT.hh + */ + +//============================================================================= +// +// CLASS ModNormalDeviationT +// +//============================================================================= + + +#ifndef OPENMESH_DECIMATER_MODNORMALDEVIATIONT_HH +#define OPENMESH_DECIMATER_MODNORMALDEVIATIONT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** \brief Use Normal deviation to control decimation + * + * The module tracks the normals while decimating + * a normal cone consisting of all normals of the + * faces collapsed together is computed and if + * a collapse would increase the size of + * the cone to a value greater than the given value + * the collapse will be illegal. + * + * In binary and mode, the collapse is legal if: + * - The normal deviation after the collapse is lower than the given value + * + * In continuous mode the maximal deviation is returned + */ +template +class ModNormalDeviationT : public ModBaseT< MeshT > +{ +public: + + DECIMATING_MODULE( ModNormalDeviationT, MeshT, NormalDeviation ); + + typedef typename Mesh::Scalar Scalar; + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal Normal; + typedef typename Mesh::VertexHandle VertexHandle; + typedef typename Mesh::FaceHandle FaceHandle; + typedef typename Mesh::EdgeHandle EdgeHandle; + typedef NormalConeT NormalCone; + + + +public: + + /// Constructor + ModNormalDeviationT(MeshT& _mesh, float _max_dev = 180.0) + : Base(_mesh, true), mesh_(Base::mesh()) + { + set_normal_deviation(_max_dev); + mesh_.add_property(normal_cones_); + + const bool mesh_has_normals = _mesh.has_face_normals(); + _mesh.request_face_normals(); + + if (!mesh_has_normals) + { + omerr() << "Mesh has no face normals. Compute them automatically." << std::endl; + _mesh.update_face_normals(); + } + } + + + /// Destructor + ~ModNormalDeviationT() { + mesh_.remove_property(normal_cones_); + mesh_.release_face_normals(); + } + + + /// Get normal deviation ( 0 .. 360 ) + Scalar normal_deviation() const { + return normal_deviation_ / M_PI * 180.0; + } + + /// Set normal deviation ( 0 .. 360 ) + void set_normal_deviation(Scalar _s) { + normal_deviation_ = _s / static_cast(180.0) * static_cast(M_PI); + } + + + /// Allocate and init normal cones + void initialize() { + if (!normal_cones_.is_valid()) + mesh_.add_property(normal_cones_); + + typename Mesh::FaceIter f_it = mesh_.faces_begin(), + f_end = mesh_.faces_end(); + + for (; f_it != f_end; ++f_it) + mesh_.property(normal_cones_, *f_it) = NormalCone(mesh_.normal(*f_it)); + } + + /** \brief Control normals when Decimating + * + * Binary and Cont. mode. + * + * The module tracks the normals while decimating + * a normal cone consisting of all normals of the + * faces collapsed together is computed and if + * a collapse would increase the size of + * the cone to a value greater than the given value + * the collapse will be illegal. + * + * @param _ci Collapse info data + * @return Half of the normal cones size (radius in radians) + */ + float collapse_priority(const CollapseInfo& _ci) { + // simulate collapse + mesh_.set_point(_ci.v0, _ci.p1); + + + typename Mesh::Scalar max_angle(0.0); + typename Mesh::ConstVertexFaceIter vf_it(mesh_, _ci.v0); + typename Mesh::FaceHandle fh, fhl, fhr; + + if (_ci.v0vl.is_valid()) fhl = mesh_.face_handle(_ci.v0vl); + if (_ci.vrv0.is_valid()) fhr = mesh_.face_handle(_ci.vrv0); + + for (; vf_it.is_valid(); ++vf_it) { + fh = *vf_it; + if (fh != _ci.fl && fh != _ci.fr) { + NormalCone nc = mesh_.property(normal_cones_, fh); + + nc.merge(NormalCone(mesh_.calc_face_normal(fh))); + if (fh == fhl) nc.merge(mesh_.property(normal_cones_, _ci.fl)); + if (fh == fhr) nc.merge(mesh_.property(normal_cones_, _ci.fr)); + + if (nc.angle() > max_angle) { + max_angle = nc.angle(); + if (max_angle > 0.5 * normal_deviation_) + break; + } + } + } + + + // undo simulation changes + mesh_.set_point(_ci.v0, _ci.p0); + + + return (max_angle < 0.5 * normal_deviation_ ? max_angle : float( Base::ILLEGAL_COLLAPSE )); + } + + /// set the percentage of normal deviation + void set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller normal_deviation_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + Scalar normal_deviation = normal_deviation_ * static_cast( 180.0 / M_PI * _factor / this->error_tolerance_factor_); + + set_normal_deviation(normal_deviation); + this->error_tolerance_factor_ = _factor; + } + } + + + void postprocess_collapse(const CollapseInfo& _ci) { + // account for changed normals + typename Mesh::VertexFaceIter vf_it(mesh_, _ci.v1); + for (; vf_it.is_valid(); ++vf_it) + mesh_.property(normal_cones_, *vf_it). + merge(NormalCone(mesh_.normal(*vf_it))); + + + // normal cones of deleted triangles + typename Mesh::FaceHandle fh; + + if (_ci.vlv1.is_valid()) { + fh = mesh_.face_handle(mesh_.opposite_halfedge_handle(_ci.vlv1)); + if (fh.is_valid()) + mesh_.property(normal_cones_, fh). + merge(mesh_.property(normal_cones_, _ci.fl)); + } + + if (_ci.v1vr.is_valid()) { + fh = mesh_.face_handle(mesh_.opposite_halfedge_handle(_ci.v1vr)); + if (fh.is_valid()) + mesh_.property(normal_cones_, fh). + merge(mesh_.property(normal_cones_, _ci.fr)); + } + } + + + +private: + + Mesh& mesh_; + Scalar normal_deviation_; + OpenMesh::FPropHandleT normal_cones_; +}; + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_DECIMATER_MODNORMALDEVIATIONT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh new file mode 100644 index 0000000..2fd3a18 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh @@ -0,0 +1,207 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModNormalFlippingT.hh + + */ + +//============================================================================= +// +// CLASS ModNormalFlipping +// +//============================================================================= + + +#ifndef OPENMESH_DECIMATER_MODNORMALFLIPPING_HH +#define OPENMESH_DECIMATER_MODNORMALFLIPPING_HH + + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Decimater { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + +/** Decimating module to avoid flipping of faces. + * + * This module can be used only as a binary module. The criterion + * of allowing/disallowing the collapse is the angular deviation between + * the face normal of the original faces and normals of the faces after the + * collapse. The collapse will pass the test, if the deviation is below + * a given threshold. + */ +template +class ModNormalFlippingT : public ModBaseT< MeshT > +{ +public: + + DECIMATING_MODULE( ModNormalFlippingT, MeshT, NormalFlipping ); + +public: + + /// Constructor + ModNormalFlippingT( MeshT &_mesh) : Base(_mesh, true) + { + set_max_normal_deviation( 90.0f ); + const bool mesh_has_normals = _mesh.has_face_normals(); + _mesh.request_face_normals(); + + if (!mesh_has_normals) + { + omerr() << "Mesh has no face normals. Compute them automatically." << std::endl; + _mesh.update_face_normals(); + } + } + + + ~ModNormalFlippingT() + { + Base::mesh().release_face_normals(); + } + + +public: + + /** Compute collapse priority due to angular deviation of face normals + * before and after a collapse. + * + * -# Compute for each adjacent face of \c _ci.v0 the face + * normal if the collpase would be executed. + * + * -# Prevent the collapse, if the cosine of the angle between the + * original and the new normal is below a given threshold. + * + * \param _ci The collapse description + * \return LEGAL_COLLAPSE or ILLEGAL_COLLAPSE + * + * \see set_max_normal_deviation() + */ + float collapse_priority(const CollapseInfo& _ci) + { + // simulate collapse + Base::mesh().set_point(_ci.v0, _ci.p1); + + // check for flipping normals + typename Mesh::ConstVertexFaceIter vf_it(Base::mesh(), _ci.v0); + typename Mesh::FaceHandle fh; + typename Mesh::Scalar c(1.0); + + for (; vf_it.is_valid(); ++vf_it) + { + fh = *vf_it; + if (fh != _ci.fl && fh != _ci.fr) + { + typename Mesh::Normal n1 = Base::mesh().normal(fh); + typename Mesh::Normal n2 = Base::mesh().calc_face_normal(fh); + + c = dot(n1, n2); + + if (c < min_cos_) + break; + } + } + + // undo simulation changes + Base::mesh().set_point(_ci.v0, _ci.p0); + + return float( (c < min_cos_) ? Base::ILLEGAL_COLLAPSE : Base::LEGAL_COLLAPSE ); + } + + /// set the percentage of maximum normal deviation + void set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller max_deviation_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + double max_normal_deviation = (max_deviation_ * 180.0/M_PI) * _factor / this->error_tolerance_factor_; + set_max_normal_deviation(max_normal_deviation); + this->error_tolerance_factor_ = _factor; + } + } + + +public: + + /// get normal deviation + double max_normal_deviation() const { return max_deviation_ / M_PI * 180.0; } + + /** Set normal deviation + * + * Set the maximum angular deviation of the orignal normal and the new + * normal in degrees. + */ + void set_max_normal_deviation(double _d) { + max_deviation_ = _d / 180.0 * M_PI; + min_cos_ = cos(max_deviation_); + } + +private: + + // hide this method + void set_binary(bool _b) {} + +private: + + // maximum normal deviation + double max_deviation_, min_cos_; +}; + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENACG_MODNORMALFLIPPING_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModProgMeshT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModProgMeshT.cc new file mode 100644 index 0000000..04af1e9 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModProgMeshT.cc @@ -0,0 +1,191 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModProgMeshT.cc + */ + + +//============================================================================= +// +// CLASS ModProgMeshT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_DECIMATER_MODPROGMESH_CC + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + + + +//== IMPLEMENTATION ========================================================== + + +template +bool +ModProgMeshT:: +write( const std::string& _ofname ) +{ + // sort vertices + size_t i=0, N=Base::mesh().n_vertices(), n_base_vertices(0), n_base_faces(0); + std::vector vhandles(N); + + + // base vertices + typename Mesh::VertexIter + v_it=Base::mesh().vertices_begin(), + v_end=Base::mesh().vertices_end(); + + for (; v_it != v_end; ++v_it) + if (!Base::mesh().status(*v_it).deleted()) + { + vhandles[i] = *v_it; + Base::mesh().property( idx_, *v_it ) = i; + ++i; + } + n_base_vertices = i; + + + // deleted vertices + typename InfoList::reverse_iterator + r_it=pmi_.rbegin(), r_end=pmi_.rend(); + + for (; r_it!=r_end; ++r_it) + { + vhandles[i] = r_it->v0; + Base::mesh().property( idx_, r_it->v0) = i; + ++i; + } + + + // base faces + typename Mesh::ConstFaceIter f_it = Base::mesh().faces_begin(), + f_end = Base::mesh().faces_end(); + for (; f_it != f_end; ++f_it) + if (!Base::mesh().status(*f_it).deleted()) + ++n_base_faces; + + // ---------------------------------------- write progressive mesh + + std::ofstream out( _ofname.c_str(), std::ios::binary ); + + if (!out) + return false; + + // always use little endian byte ordering + bool swap = Endian::local() != Endian::LSB; + + // write header + out << "ProgMesh"; + IO::store( out, static_cast(n_base_vertices), swap );//store in 32-bit + IO::store( out, static_cast(n_base_faces) , swap ); + IO::store( out, static_cast(pmi_.size()) , swap ); + + Vec3f p; + + // write base vertices + for (i=0; i( Base::mesh().point(vhandles[i]) ); + + IO::store( out, p, swap ); + } + + + // write base faces + for (f_it=Base::mesh().faces_begin(); f_it != f_end; ++f_it) + { + if (!Base::mesh().status(*f_it).deleted()) + { + typename Mesh::ConstFaceVertexIter fv_it(Base::mesh(), *f_it); + + IO::store( out, static_cast(Base::mesh().property( idx_, *fv_it )) ); + IO::store( out, static_cast(Base::mesh().property( idx_, *(++fv_it ))) ); + IO::store( out, static_cast(Base::mesh().property( idx_, *(++fv_it ))) ); + } + } + + + // write detail info + for (r_it=pmi_.rbegin(); r_it!=r_end; ++r_it) + { + // store v0.pos, v1.idx, vl.idx, vr.idx + IO::store( out, vector_cast(Base::mesh().point(r_it->v0))); + IO::store(out, static_cast(Base::mesh().property(idx_, r_it->v1))); + IO::store( out, + r_it->vl.is_valid() ? static_cast(Base::mesh().property(idx_, r_it->vl)) : -1); + IO::store( out, + r_it->vr.is_valid() ? static_cast(Base::mesh().property(idx_, r_it->vr)) : -1); + } + + return true; +} + + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModProgMeshT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModProgMeshT.hh new file mode 100644 index 0000000..55325b4 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModProgMeshT.hh @@ -0,0 +1,198 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModProgMeshT.hh + + */ + +//============================================================================= +// +// CLASS ModProgMeshT +// +//============================================================================= + +#ifndef OPENMESH_TOOLS_MODPROGMESHT_HH +#define OPENMESH_TOOLS_MODPROGMESHT_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** Collect progressive mesh information while decimating. + * + * The progressive mesh data is stored in an internal structure, which + * can be evaluated after the decimation process and (!) before calling + * the garbage collection of the decimated mesh. + */ +template +class ModProgMeshT : public ModBaseT +{ +public: + + DECIMATING_MODULE( ModProgMeshT, MeshT, ProgMesh ); + + /** Struct storing progressive mesh information + * \see CollapseInfoT, ModProgMeshT + */ + struct Info + { + /// Initializing constructor copies appropriate handles from + /// collapse information \c _ci. + Info( const CollapseInfo& _ci ) + : v0(_ci.v0), v1(_ci.v1), vl(_ci.vl),vr(_ci.vr) + {} + + typename Mesh::VertexHandle v0; ///< See CollapseInfoT::v0 + typename Mesh::VertexHandle v1; ///< See CollapseInfoT::v1 + typename Mesh::VertexHandle vl; ///< See CollapseInfoT::vl + typename Mesh::VertexHandle vr; ///< See CollapseInfoT::vr + + }; + + /// Type of the list storing the progressive mesh info Info. + typedef std::vector InfoList; + + +public: + + /// Constructor + ModProgMeshT( MeshT &_mesh ) : Base(_mesh, true) + { + Base::mesh().add_property( idx_ ); + } + + + /// Destructor + ~ModProgMeshT() + { + Base::mesh().remove_property( idx_ ); + } + + const InfoList& pmi() const + { + return pmi_; + } + +public: // inherited + + + /// Stores collapse information in a queue. + /// \see infolist() + void postprocess_collapse(const CollapseInfo& _ci) + { + pmi_.push_back( Info( _ci ) ); + } + + + bool is_binary(void) const { return true; } + + +public: // specific methods + + /** Write progressive mesh data to a file in proprietary binary format .pm. + * + * The methods uses the collected data to write a progressive mesh + * file. It's a binary format with little endian byte ordering: + * + * - The first 8 bytes contain the word "ProgMesh". + * - 32-bit int for the number of vertices \c NV in the base mesh. + * - 32-bit int for the number of faces in the base mesh. + * - 32-bit int for the number of halfedge collapses (now vertex splits) + * - Positions of vertices of the base mesh (32-bit float triplets).
+ * \c [x,y,z][x,y,z]... + * - Triplets of indices (32-bit int) for each triangle (index in the + * list of vertices of the base mesh defined by the positions.
+ * \c [v0,v1,v2][v0,v1,v2]... + * - For each collapse/split a detail information package made of + * 3 32-bit floats for the positions of vertex \c v0, and 3 32-bit + * int indices for \c v1, \c vl, and \c vr. + * The index for \c vl or \c vr might be -1, if the face on this side + * of the edge does not exists. + * + * \remark Write file before calling the garbage collection of the mesh. + * \param _ofname Name of the file, where to write the progressive mesh + * \return \c true on success of the operation, else \c false. + */ + bool write( const std::string& _ofname ); + /// Reference to collected information + const InfoList& infolist() const { return pmi_; } + +private: + + // hide this method form user + void set_binary(bool _b) {} + + InfoList pmi_; + VPropHandleT idx_; +}; + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODPROGMESH_CC) +#define OSG_MODPROGMESH_TEMPLATES +#include "ModProgMeshT.cc" +#endif +//============================================================================= +#endif // OPENMESH_TOOLS_PROGMESHT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModQuadricT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModQuadricT.cc new file mode 100644 index 0000000..0b46147 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModQuadricT.cc @@ -0,0 +1,159 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModQuadricT.cc + Bodies of template member function. + */ + +//============================================================================= +// +// CLASS ModQuadric - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_DECIMATER_MODQUADRIC_CC + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACE =============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Decimater { // BEGIN_NS_DECIMATER + + +//== IMPLEMENTATION ========================================================== + + +template +void +ModQuadricT:: +initialize() +{ + using Geometry::Quadricd; + // alloc quadrics + if (!quadrics_.is_valid()) + Base::mesh().add_property( quadrics_ ); + + // clear quadrics + typename Mesh::VertexIter v_it = Base::mesh().vertices_begin(), + v_end = Base::mesh().vertices_end(); + + for (; v_it != v_end; ++v_it) + Base::mesh().property(quadrics_, *v_it).clear(); + + // calc (normal weighted) quadric + typename Mesh::FaceIter f_it = Base::mesh().faces_begin(), + f_end = Base::mesh().faces_end(); + + typename Mesh::FaceVertexIter fv_it; + typename Mesh::VertexHandle vh0, vh1, vh2; + typedef Vec3d Vec3; + + for (; f_it != f_end; ++f_it) + { + fv_it = Base::mesh().fv_iter(*f_it); + vh0 = *fv_it; ++fv_it; + vh1 = *fv_it; ++fv_it; + vh2 = *fv_it; + + Vec3 v0, v1, v2; + { + using namespace OpenMesh; + + v0 = vector_cast(Base::mesh().point(vh0)); + v1 = vector_cast(Base::mesh().point(vh1)); + v2 = vector_cast(Base::mesh().point(vh2)); + } + + Vec3 n = (v1-v0) % (v2-v0); + double area = n.norm(); + if (area > FLT_MIN) + { + n /= area; + area *= 0.5; + } + + const double a = n[0]; + const double b = n[1]; + const double c = n[2]; + const double d = -(vector_cast(Base::mesh().point(vh0))|n); + + Quadricd q(a, b, c, d); + q *= area; + + Base::mesh().property(quadrics_, vh0) += q; + Base::mesh().property(quadrics_, vh1) += q; + Base::mesh().property(quadrics_, vh2) += q; + } +} + +//----------------------------------------------------------------------------- + +template +void ModQuadricT::set_error_tolerance_factor(double _factor) { + if (this->is_binary()) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller max_err_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + double max_err = max_err_ * _factor / this->error_tolerance_factor_; + set_max_err(max_err); + this->error_tolerance_factor_ = _factor; + + initialize(); + } + } +} + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModQuadricT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModQuadricT.hh new file mode 100644 index 0000000..41835a8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModQuadricT.hh @@ -0,0 +1,199 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS ModQuadricT +// +//============================================================================= + +#ifndef OSG_MODQUADRIC_HH +#define OSG_MODQUADRIC_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** \brief Mesh decimation module computing collapse priority based on error quadrics. + * + * This module can be used as a binary and non-binary module. + */ +template +class ModQuadricT : public ModBaseT +{ +public: + + // Defines the types Self, Handle, Base, Mesh, and CollapseInfo + // and the memberfunction name() + DECIMATING_MODULE( ModQuadricT, MeshT, Quadric ); + +public: + + /** Constructor + * \internal + */ + ModQuadricT( MeshT &_mesh ) + : Base(_mesh, false) + { + unset_max_err(); + Base::mesh().add_property( quadrics_ ); + } + + + /// Destructor + virtual ~ModQuadricT() + { + Base::mesh().remove_property(quadrics_); + } + + +public: // inherited + + /// Initalize the module and prepare the mesh for decimation. + virtual void initialize(void); + + /** Compute collapse priority based on error quadrics. + * + * \see ModBaseT::collapse_priority() for return values + * \see set_max_err() + */ + virtual float collapse_priority(const CollapseInfo& _ci) + { + using namespace OpenMesh; + + typedef Geometry::QuadricT Q; + + Q q = Base::mesh().property(quadrics_, _ci.v0); + q += Base::mesh().property(quadrics_, _ci.v1); + + double err = q(_ci.p1); + + //min_ = std::min(err, min_); + //max_ = std::max(err, max_); + + //double err = q( p ); + + return float( (err < max_err_) ? err : float( Base::ILLEGAL_COLLAPSE ) ); + } + + + /// Post-process halfedge collapse (accumulate quadrics) + virtual void postprocess_collapse(const CollapseInfo& _ci) + { + Base::mesh().property(quadrics_, _ci.v1) += + Base::mesh().property(quadrics_, _ci.v0); + } + + /// set the percentage of maximum quadric error + void set_error_tolerance_factor(double _factor); + + + +public: // specific methods + + /** Set maximum quadric error constraint and enable binary mode. + * \param _err Maximum error allowed + * \param _binary Let the module work in non-binary mode in spite of the + * enabled constraint. + * \see unset_max_err() + */ + void set_max_err(double _err, bool _binary=true) + { + max_err_ = _err; + Base::set_binary(_binary); + } + + /// Unset maximum quadric error constraint and restore non-binary mode. + /// \see set_max_err() + void unset_max_err(void) + { + max_err_ = DBL_MAX; + Base::set_binary(false); + } + + /// Return value of max. allowed error. + double max_err() const { return max_err_; } + + +private: + + // maximum quadric error + double max_err_; + + // this vertex property stores a quadric for each vertex + VPropHandleT< Geometry::QuadricT > quadrics_; +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODQUADRIC_CC) +#define OSG_MODQUADRIC_TEMPLATES +#include "ModQuadricT.cc" +#endif +//============================================================================= +#endif // OSG_MODQUADRIC_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModRoundnessT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModRoundnessT.hh new file mode 100644 index 0000000..622947b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/ModRoundnessT.hh @@ -0,0 +1,327 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file ModRoundnessT.hh + + */ + +//============================================================================= +// +// CLASS ModRoundnessT +// +//============================================================================= + +#ifndef OPENMESH_DECIMATER_MODROUNDNESST_HH +#define OPENMESH_DECIMATER_MODROUNDNESST_HH + + +//== INCLUDES ================================================================= + +#include +#include + +#if defined(OM_CC_MSVC) +# define OM_ENABLE_WARNINGS 4244 +# pragma warning(disable : OM_ENABLE_WARNINGS ) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Decimater { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + + +/** \brief Use Roundness of triangles to control decimation + * + * + * In binary and mode, the collapse is legal if: + * - The roundness after the collapse is greater than the given value + * + * In continuous mode the roundness after the collapse is returned + */ +template +class ModRoundnessT : public ModBaseT +{ + public: + DECIMATING_MODULE( ModRoundnessT, MeshT, Roundness ); + + public: + + // typedefs + typedef typename MeshT::Point Point; + typedef typename vector_traits::value_type value_type; + + public: + + /// Constructor + ModRoundnessT( MeshT &_dec ) : + Base(_dec, false), + min_r_(-1.0) + { } + + /// Destructor + ~ModRoundnessT() { } + + public: // inherited + + /** Compute collapse priority due to roundness of triangle. + * + * The roundness is computed by dividing the radius of the + * circumference by the length of the shortest edge. The result is + * normalized. + * + * \return [0:1] or ILLEGAL_COLLAPSE in non-binary mode + * \return LEGAL_COLLAPSE or ILLEGAL_COLLAPSE in binary mode + * \see set_min_roundness() + */ + float collapse_priority(const CollapseInfo& _ci) + { + // using namespace OpenMesh; + + typename Mesh::ConstVertexOHalfedgeIter voh_it(Base::mesh(), _ci.v0); + double r; + double priority = 0.0; //==LEGAL_COLLAPSE + typename Mesh::FaceHandle fhC, fhB; + Vec3f B,C; + + if ( min_r_ < 0.0f ) // continues mode + { + C = vector_cast(Base::mesh().point( Base::mesh().to_vertex_handle(*voh_it))); + fhC = Base::mesh().face_handle( *voh_it ); + + for (++voh_it; voh_it.is_valid(); ++voh_it) + { + B = C; + fhB = fhC; + C = vector_cast(Base::mesh().point(Base::mesh().to_vertex_handle(*voh_it))); + fhC = Base::mesh().face_handle( *voh_it ); + + if ( fhB == _ci.fl || fhB == _ci.fr ) + continue; + + // simulate collapse using position of v1 + r = roundness( vector_cast(_ci.p1), B, C ); + + // return the maximum non-roundness + priority = std::max( priority, (1.0-r) ); + + } + } + else // binary mode + { + C = vector_cast(Base::mesh().point( Base::mesh().to_vertex_handle(*voh_it))); + fhC = Base::mesh().face_handle( *voh_it ); + + for (++voh_it; voh_it.is_valid() && (priority==Base::LEGAL_COLLAPSE); ++voh_it) + { + B = C; + fhB = fhC; + C = vector_cast(Base::mesh().point(Base::mesh().to_vertex_handle(*voh_it))); + fhC = Base::mesh().face_handle( *voh_it ); + + if ( fhB == _ci.fl || fhB == _ci.fr ) + continue; + + priority = ( (r=roundness( vector_cast(_ci.p1), B, C )) < min_r_) + ? Base::ILLEGAL_COLLAPSE : Base::LEGAL_COLLAPSE; + } + } + + return (float) priority; + } + + /// set the percentage of minimum roundness + void set_error_tolerance_factor(double _factor) { + if (this->is_binary()) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller min_r_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + value_type min_roundness = min_r_ * static_cast(_factor / this->error_tolerance_factor_); + set_min_roundness(min_roundness); + this->error_tolerance_factor_ = _factor; + } +} + } + + +public: // specific methods + + void set_min_angle( float _angle, bool /* _binary=true */ ) + { + assert( _angle > 0 && _angle < 60 ); + + _angle = float(M_PI * _angle /180.0); + + Vec3f A,B,C; + + A = Vec3f( 0.0f, 0.0f, 0.0f); + B = Vec3f( 2.0f * cos(_angle), 0.0f, 0.0f); + C = Vec3f( cos(_angle), sin(_angle), 0.0f); + + double r1 = roundness(A,B,C); + + _angle = float(0.5 * ( M_PI - _angle )); + + A = Vec3f( 0.0f, 0.0f, 0.0f); + B = Vec3f( 2.0f*cos(_angle), 0.0f, 0.0f); + C = Vec3f( cos(_angle), sin(_angle), 0.0f); + + double r2 = roundness(A,B,C); + + set_min_roundness( value_type(std::min(r1,r2)), true ); + } + + /** Set a minimum roundness value. + * \param _min_roundness in range (0,1) + * \param _binary Set true, if the binary mode should be enabled, + * else false. In latter case the collapse_priority() + * returns a float value if the constraint does not apply + * and ILLEGAL_COLLAPSE else. + */ + void set_min_roundness( value_type _min_roundness, bool _binary=true ) + { + assert( 0.0 <= _min_roundness && _min_roundness <= 1.0 ); + min_r_ = _min_roundness; + Base::set_binary(_binary); + } + + /// Unset minimum value constraint and enable non-binary mode. + void unset_min_roundness() + { + min_r_ = -1.0; + Base::set_binary(false); + } + + // Compute a normalized roundness of a triangle ABC + // + // Having + // A,B,C corner points of triangle + // a,b,c the vectors BC,CA,AB + // Area area of triangle + // + // then define + // + // radius of circumference + // R := ----------------------- + // length of shortest edge + // + // ||a|| * ||b|| * ||c|| + // --------------------- + // 4 * Area ||a|| * ||b|| * ||c|| + // = ----------------------- = ----------------------------------- + // min( ||a||,||b||,||c||) 4 * Area * min( ||a||,||b||,||c|| ) + // + // ||a|| * ||b|| * ||c|| + // = ------------------------------------------------------- + // 4 * 1/2 * ||cross(B-A,C-A)|| * min( ||a||,||b||,||c|| ) + // + // a'a * b'b * c'c + // R� = ---------------------------------------------------------- + // 4 * cross(B-A,C-A)'cross(B-A,C-A) * min( a'a, b'b, c'c ) + // + // a'a * b'b * c'c + // R = 1/2 * sqrt(---------------------------) + // AA * min( a'a, b'b, c'c ) + // + // At angle 60� R has it's minimum for all edge lengths = sqrt(1/3) + // + // Define normalized roundness + // + // nR := sqrt(1/3) / R + // + // AA * min( a'a, b'b, c'c ) + // = sqrt(4/3) * sqrt(---------------------------) + // a'a * b'b * c'c + // + double roundness( const Vec3f& A, const Vec3f& B, const Vec3f &C ) + { + const value_type epsilon = value_type(1e-15); + + static const value_type sqrt43 = value_type(sqrt(4.0/3.0)); // 60�,a=b=c, **) + + Vec3f vecAC = C-A; + Vec3f vecAB = B-A; + + // compute squared values to avoid sqrt-computations + value_type aa = (B-C).sqrnorm(); + value_type bb = vecAC.sqrnorm(); + value_type cc = vecAB.sqrnorm(); + value_type AA = cross(vecAC,vecAB).sqrnorm(); // without factor 1/4 **) + + if ( AA < epsilon ) + return 0.0; + + double nom = AA * std::min( std::min(aa,bb),cc ); + double denom = aa * bb * cc; + double nR = sqrt43 * sqrt(nom/denom); + + return nR; + } + + private: + + value_type min_r_; +}; + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_CC_MSVC) && defined(OM_ENABLE_WARNINGS) +# pragma warning(default : OM_ENABLE_WARNINGS) +# undef OM_ENABLE_WARNINGS +#endif +//============================================================================= +#endif // OPENMESH_DECIMATER_MODROUNDNESST_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/Observer.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/Observer.cc new file mode 100644 index 0000000..6a39e9c --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/Observer.cc @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 1197 $ * + * $Date: 2015-01-15 11:19:39 +0100 (Do, 15 Jan 2015) $ * + * * + \*===========================================================================*/ + +/** \file Observer.cc + */ + +//============================================================================= +// +// CLASS Observer - IMPLEMENTATION +// +//============================================================================= + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +Observer::Observer(size_t _notificationInterval) : + notificationInterval_(_notificationInterval) +{ +} + +Observer::~Observer() +{ +} + +size_t Observer::get_interval() const +{ + return Observer::notificationInterval_; +} + +void Observer::set_interval(size_t _notificationInterval) +{ + notificationInterval_ = _notificationInterval; +} + +bool Observer::abort() const +{ + return false; +}; + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/Observer.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/Observer.hh new file mode 100644 index 0000000..f42b300 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Decimater/Observer.hh @@ -0,0 +1,128 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 1199 $ * + * $Date: 2015-01-16 08:47:33 +0100 (Fr, 16 Jan 2015) $ * + * * +\*===========================================================================*/ + +/** \file Observer.hh + * + * This file contains an observer class which is used to monitor the progress + * of an decimater. + * + */ + +//============================================================================= +// +// CLASS Observer +// +//============================================================================= + +#pragma once + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + +/** \brief Observer class + * + * Observers can be used to monitor the progress of the decimation and to + * abort it in between. + */ +class OPENMESHDLLEXPORT Observer +{ +public: + + /** Create an observer + * + * @param _notificationInterval Interval of decimation steps between notifications. + */ + explicit Observer(size_t _notificationInterval); + + /// Destructor + virtual ~Observer(); + + /// Get the interval between notification steps + size_t get_interval() const; + + /// Set the interval between notification steps + void set_interval(size_t _notificationInterval); + + /** \brief callback + * + * This function has to be overloaded. It will be called regularly during + * the decimation process and will return the current step. + * + * @param _step Current step of the decimater + */ + virtual void notify(size_t _step) = 0; + + /** \brief Abort callback + * + * After each notification, this function is called by the decimater. If the + * function returns true, the decimater will stop at a consistent state. Otherwise + * it will continue. + * + * @return abort Yes or No + */ + virtual bool abort() const; + +private: + size_t notificationInterval_; +}; + + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Dualizer/meshDualT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Dualizer/meshDualT.hh new file mode 100644 index 0000000..ab006f0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Dualizer/meshDualT.hh @@ -0,0 +1,145 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/* + Compute the dual of a mesh: + - each face of the original mesh is replaced by a vertex at the center of gravity of the vertices of the face + - each vertex of the original mesh is replaced by a face containing the dual vertices of its primal adjacent faces + + Changelog: + - 29 mar 2010: initial work + + Programmer: + Clement Courbet - clement.courbet@ecp.fr + + (c) Clement Courbet 2010 +*/ + +#ifndef OPENMESH_MESH_DUAL_H +#define OPENMESH_MESH_DUAL_H + +//== INCLUDES ================================================================= + +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Util { + +//== Function DEFINITION ========================================================= + +/** \brief create a dual mesh +* +* This function takes a mesh and computes the dual mesh of it. Each face of the original mesh is replaced by a vertex at the center of gravity of the vertices of the face. +* Each vertex of the original mesh is replaced by a face containing the dual vertices of its primal adjacent faces. +*/ +template +PolyMesh_ArrayKernelT* MeshDual (PolyMesh_ArrayKernelT &primal) +{ + PolyMesh_ArrayKernelT* dual = new PolyMesh_ArrayKernelT(); + + //we will need to reference which vertex in the dual is attached to each face in the primal + //and which face of the dual is attached to each vertex in the primal. + + FPropHandleT< typename PolyMesh_ArrayKernelT::VertexHandle > primalToDual; + primal.add_property(primalToDual); + + //for each face in the primal mesh, add a vertex at the center of gravity of the face + for(typename PolyMesh_ArrayKernelT::ConstFaceIter fit=primal.faces_begin(); fit!=primal.faces_end(); ++fit) + { + typename PolyMesh_ArrayKernelT::Point centerPoint(0,0,0); + typename PolyMesh_ArrayKernelT::Scalar degree= 0.0; + for(typename PolyMesh_ArrayKernelT::ConstFaceVertexIter vit=primal.cfv_iter(*fit); vit.is_valid(); ++vit, ++degree) + centerPoint += primal.point(*vit); + assert(degree!=0); + centerPoint /= degree; + primal.property(primalToDual, *fit) = dual->add_vertex(centerPoint); + } + + //for each vertex in the primal, add a face in the dual + std::vector< typename PolyMesh_ArrayKernelT::VertexHandle > face_vhandles; + for(typename PolyMesh_ArrayKernelT::ConstVertexIter vit=primal.vertices_begin(); vit!=primal.vertices_end(); ++vit) + { + if(!primal.is_boundary(*vit)) + { + face_vhandles.clear(); + for(typename PolyMesh_ArrayKernelT::ConstVertexFaceIter fit=primal.cvf_iter(*vit); fit.is_valid(); ++fit) + face_vhandles.push_back(primal.property(primalToDual, *fit)); + dual->add_face(face_vhandles); + } + } + + primal.remove_property(primalToDual); + + return dual; + +} + +//============================================================================= +} // namespace Util +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_MESH_DUAL_H defined +//============================================================================= + + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/ArrayKernelT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/ArrayKernelT.hh new file mode 100644 index 0000000..774faf9 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/ArrayKernelT.hh @@ -0,0 +1,227 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS OSGArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_KERNELOSG_ARRAY_KERNEL_HH +#define OPENMEHS_KERNELOSG_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + +/** \ingroup mesh_kernels_group + * + * Mesh kernel using arrays for mesh item storage. + * + * This mesh kernel uses the OpenSG GeoProperties as container + * to store the mesh items. + * + * \note You do not have to use this class directly, use the predefined + * mesh-kernel combinations in \ref mesh_types_group. + */ +// \see OpenMesh::ArrayHandleT +// \see \ref mesh_type + + +template +class ArrayKernelT + : public OpenMesh::ArrayKernelT +{ +public: + + typedef ArrayKernelT This; + typedef OpenMesh::ArrayKernelT Base; + + // attributes +// typedef typename Base::HasVertexNormals HasVertexNormals; +// typedef typename Base::HasVertexColors HasVertexColors; +// typedef typename Base::HasVertexTexCoords HasVertexTexCoords; +// typedef typename Base::HasVertexStatus HasVertexStatus; + typedef typename Base::HasPrevHalfedge HasPrevHalfedge; +// typedef typename Base::HasEdgeStatus HasEdgeStatus; +// typedef typename Base::HasFaceNormals HasFaceNormals; +// typedef typename Base::HasFaceColors HasFaceColors; +// typedef typename Base::HasFaceStatus HasFaceStatus; + + // item types + typedef typename FinalMeshItems::Vertex Vertex; + typedef typename FinalMeshItems::Halfedge Halfedge; + typedef typename FinalMeshItems::Edge Edge; + typedef typename FinalMeshItems::Face Face; + typedef typename FinalMeshItems::Point Point; + typedef typename FinalMeshItems::Normal Normal; + typedef typename FinalMeshItems::Color Color; + typedef typename FinalMeshItems::TexCoord TexCoord; + typedef typename FinalMeshItems::Scalar Scalar; + +// // handles +// typedef typename OpenMesh::VertexHandle VertexHandle; +// typedef typename FinalMeshItems::HalfedgeHandle HalfedgeHandle; +// typedef typename FinalMeshItems::EdgeHandle EdgeHandle; +// typedef typename FinalMeshItems::FaceHandle FaceHandle; + + // iterators + typedef std::vector VertexContainer; + typedef std::vector EdgeContainer; + typedef std::vector FaceContainer; + typedef typename VertexContainer::iterator KernelVertexIter; + typedef typename VertexContainer::const_iterator KernelConstVertexIter; + typedef typename EdgeContainer::iterator KernelEdgeIter; + typedef typename EdgeContainer::const_iterator KernelConstEdgeIter; + typedef typename FaceContainer::iterator KernelFaceIter; + typedef typename FaceContainer::const_iterator KernelConstFaceIter; + +public: + + ArrayKernelT() : Base() + { } + + virtual ~ArrayKernelT() + { } + +public: // replacements + + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh) { + Base::set_halfedge_handle( _vh, _heh ); + } + + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh) { + Base::set_halfedge_handle( _fh, _heh ); + osg_sync( _fh ); + } + + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh) { + Base::set_next_halfedge_handle( _heh, _nheh ); + osg_sync( face_handle( _heh ) ); // ##Changed + } + + void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + +protected: + + bool osg_sync( FaceHandle _fh ) + { + return _fh.is_valid() + ? osg_sync( _fh, typename Face::IsTriangle() ) + : false; + } + +private: + + bool osg_sync( FaceHandle _fh, GenProg::Bool2Type ) + { + HalfedgeHandle hh( halfedge_handle(_fh) ); + if ( !hh.is_valid() ) return false; + FaceHandle f1( _fh.idx() * 3 ); + set_face_indices( f1, to_vertex_handle(hh).idx() ); + + hh = next_halfedge_handle(hh); + if ( !hh.is_valid() ) return false; + FaceHandle f2( f1.idx()+1 ); + set_face_indices( f2, to_vertex_handle(hh).idx() ); + + hh = next_halfedge_handle(hh); + if ( !hh.is_valid() ) return false; + FaceHandle f3( f1.idx()+2 ); + set_face_indices( f3, to_vertex_handle(hh).idx() ); + + set_face_types ( _fh, GL_TRIANGLES ); + set_face_lengths( _fh, 3 ); + + return true; + } + + bool osg_sync( FaceHandle _fh, GenProg::Bool2Type ) + { + return false; + } + +}; + + +template +void +ArrayKernelT:: +garbage_collection(bool _v, bool _e, bool _f) +{ + Base::garbage_collection(_v, _e, _f); + for (size_t fidx=0; fidx < n_faces(); ++fidx) + osg_sync( FaceHandle(fidx) ); +} + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ARRAY_KERNEL_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/AttribKernelT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/AttribKernelT.hh new file mode 100644 index 0000000..6849905 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/AttribKernelT.hh @@ -0,0 +1,704 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_ATTRIBKERNEL_HH +#define OPENMESH_KENREL_OSG_ATTRIBKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + + +/// This class adds the standard properties to the mesh type. +template +class AttribKernelT + : public PropertyKernel< typename MeshItems::Face::IsTriangle > +{ +protected: + + typedef typename MeshItems::Face::IsTriangle IsTriMesh; + typedef PropertyKernel< IsTriMesh > Base; + + typedef typename Base::FPTypesHandle FPTypesHandle; + typedef typename Base::FPLengthsHandle FPLengthsHandle; + typedef typename Base::FIndicesHandle FIndicesHandle; + +public: + + //---------------------------------------------------------------- item types + + typedef typename MeshItems::Vertex Vertex; + typedef typename MeshItems::Halfedge Halfedge; + typedef typename MeshItems::Edge Edge; + typedef typename MeshItems::Face Face; + + typedef typename MeshItems::Point Point; + typedef typename MeshItems::Normal Normal; + typedef typename MeshItems::Color Color; + typedef typename MeshItems::TexCoord TexCoord; + + typedef typename MeshItems::Scalar Scalar; + + typedef Attributes::StatusInfo StatusInfo; + + + enum Attribs { + VAttribs = MeshItems::VAttribs, + HAttribs = MeshItems::HAttribs, + EAttribs = MeshItems::EAttribs, + FAttribs = MeshItems::FAttribs, + }; + + typedef GenProg::Bool2Type<(bool)(HAttribs & Attributes::PrevHalfedge)> + HasPrevHalfedge; + + // + + typedef typename _t2vp< Point >::prop GeoPositions; + typedef typename _t2vn< Normal >::prop GeoNormals; + typedef typename _t2vc< Color >::prop GeoColors; + typedef typename _t2vtc< TexCoord >::prop GeoTexCoords; + +// typedef typename Base::GeoPTypes GeoPTypes; +// typedef typename Base::GeoPLengths GeoPLengths; +// typedef typename Base::GeoIndices GeoIndices; + + //-------------------------------------------------- constructor / destructor + + AttribKernelT() : + + refcount_vnormals_(0), + refcount_vcolors_(0), + refcount_vtexcoords_(0), + refcount_vstatus_(0), + refcount_estatus_(0), + refcount_ecolors_(0), + refcount_hstatus_(0), + refcount_fnormals_(0), + refcount_fcolors_(0), + refcount_fstatus_(0) + + { + points_ = add_vpositions( Point(), "v:points" ); + + face_types_ = add_fptypes(); + face_lengths_ = add_fplengths(); + face_indices_ = add_findices( face_types_, face_lengths_); + + if (VAttribs & Attributes::Normal) + request_vertex_normals(); + + if (VAttribs & Attributes::Color) + request_vertex_colors(); + + if (VAttribs & Attributes::TexCoord) + request_vertex_texcoords(); + + if (VAttribs & Attributes::Status) + request_vertex_status(); + + if (EAttribs & Attributes::Status) + request_edge_status(); + + if (EAttribs & Attributes::Color) + request_edge_colors(); + + if (FAttribs & Attributes::Normal) + request_face_normals(); + + if (FAttribs & Attributes::Color) + request_face_colors(); + + if (FAttribs & Attributes::Status) + request_face_status(); + } + + ~AttribKernelT() + { + // should remove properties, but this will be done in + // BaseKernel's destructor anyway... + } + + + // ------------------------------------------------------- copy & assignement + + AttribKernelT( const AttribKernelT& _rhs ) + : Base( _rhs ) + { + operator=(_rhs); + } + + AttribKernelT& operator = ( const AttribKernelT& _rhs ) + { + // remove old properties + remove_property(points_); + remove_property(vertex_normals_); + remove_property(vertex_colors_); + remove_property(vertex_texcoords_); + remove_property(vertex_status_); + remove_property(halfedge_status_); + remove_property(edge_status_); + remove_property(edge_colors_); + remove_property(face_normals_); + remove_property(face_colors_); + remove_property(face_status_); + + // parent deep-copies properties + BaseKernel::operator=(_rhs); + + // copy property handles + points_ = _rhs.points_; + vertex_normals_ = _rhs.vertex_normals_; + vertex_colors_ = _rhs.vertex_colors_; + vertex_texcoords_ = _rhs.vertex_texcoords_; + vertex_status_ = _rhs.vertex_status_; + halfedge_status_ = _rhs.halfedge_status_; + edge_status_ = _rhs.edge_status_; + edge_colors_ = _rhs.edge_colors_; + face_normals_ = _rhs.face_normals_; + face_colors_ = _rhs.face_colors_; + face_status_ = _rhs.face_status_; + + // copy ref-counts + refcount_vnormals_ = _rhs.refcount_vnormals_; + refcount_vcolors_ = _rhs.refcount_vcolors_; + refcount_vtexcoords_ = _rhs.refcount_vtexcoords_; + refcount_vstatus_ = _rhs.refcount_vstatus_; + refcount_hstatus_ = _rhs.refcount_hstatus_; + refcount_estatus_ = _rhs.refcount_estatus_; + refcount_ecolors_ = _rhs.refcount_ecolors_; + refcount_fnormals_ = _rhs.refcount_fnormals_; + refcount_fcolors_ = _rhs.refcount_fcolors_; + refcount_fstatus_ = _rhs.refcount_fstatus_; + + return *this; + } + + //------------------------------------------------------------ osg properties + + //------------------------------ vertex property + + typename GeoPositions::property_ptr_t osg_vpositions() + { return vpositions(points_).osg_ptr(); } + + typename GeoNormals::property_ptr_t osg_vnormals() + { return vnormals(vertex_normals_).osg_ptr(); } + + typename GeoColors::property_ptr_t osg_vcolors() + { return vcolors(vertex_colors_).osg_ptr(); } + + typename GeoTexCoords::property_ptr_t osg_vtexcoords() + { return vtexcoords(vertex_texcoords_).osg_ptr(); } + + //------------------------------ edge property + + typename GeoColors::property_ptr_t osg_ecolors() + { return ecolors(edge_colors_).osg_ptr(); } + + //------------------------------ face property + + GeoPTypes::property_ptr_t osg_ptypes() + { return fptypes( face_types_ ).osg_ptr(); } + + GeoPLengths::property_ptr_t osg_plengths() + { return fplengths( face_lengths_ ).osg_ptr(); } + + typename GeoIndices::property_ptr_t osg_indices() + { return findices( face_indices_ ).osg_ptr(); } + + + //---------------------------------------- set osg geo property + + //------------------------------ face property + + void set_face_types( FaceHandle _fh, GeoPTypes::value_type _t) + { fptypes( face_types_, _fh ) = _t; } + + void set_face_lengths( FaceHandle _fh, GeoPLengths::value_type _l) + { fplengths( face_lengths_, _fh ) = _l; } + + void set_face_indices( FaceHandle _fh, + typename GeoIndices::value_type _i) + { findices( face_indices_, _fh ) = _i; } + + //--------------------------------------------------------- set/get properties + + //---------------------------------------- points + + const Point* points() const + { return vpositions( points_ ).data(); } + + const Point& point(VertexHandle _vh) const + { return vpositions( points_, _vh); } + + void set_point(VertexHandle _vh, const Point& _p) + { vpositions( points_, _vh ) = _p; } + + + //---------------------------------------- vertex normals + + const Normal* vertex_normals() const { + return vnormals(vertex_normals_).data(); + } + + const Normal& normal(VertexHandle _vh) const { + return vnormals(vertex_normals_, _vh); + } + + void set_normal(VertexHandle _vh, const Normal& _n) { + vnormals(vertex_normals_, _vh) = _n; + } + + + //---------------------------------------- vertex colors + + const Color* vertex_colors() const { + return vcolors(vertex_colors_).data(); + } + + const Color& color(VertexHandle _vh) const { + return vcolors(vertex_colors_, _vh); + } + + void set_color(VertexHandle _vh, const Color& _c) { + vcolors(vertex_colors_, _vh) = _c; + } + + + //---------------------------------------- vertex texcoords + + const TexCoord* texcoords() const { + return vtexcoords(vertex_texcoords_).data(); + } + + const TexCoord& texcoord(VertexHandle _vh) const { + return vtexcoords(vertex_texcoords_, _vh); + } + + void set_texcoord(VertexHandle _vh, const TexCoord& _t) { + vtexcoords(vertex_texcoords_, _vh) = _t; + } + + + //---------------------------------------- vertex status + + const StatusInfo& status(VertexHandle _vh) const { + return property(vertex_status_, _vh); + } + + StatusInfo& status(VertexHandle _vh) { + return property(vertex_status_, _vh); + } + + + //---------------------------------------- halfedge status + + const StatusInfo& status(HalfedgeHandle _eh) const { + return property(halfedge_status_, _eh); + } + + StatusInfo& status(HalfedgeHandle _eh) { + return property(halfedge_status_, _eh); + } + + + //---------------------------------------- edge status + + const StatusInfo& status(EdgeHandle _eh) const { + return property(edge_status_, _eh); + } + + StatusInfo& status(EdgeHandle _eh) { + return property(edge_status_, _eh); + } + + //---------------------------------------- edge colors + + const Color* edge_colors() const { + return ecolors(edge_colors_).data(); + } + + const Color& color(EdgeHandle _eh) const { + return ecolors(edge_colors_, _eh); + } + + void set_color(EdgeHandle _eh, const Color& _c) { + ecolors(edge_colors_, _eh) = _c; + } + + + //---------------------------------------- face status + + const StatusInfo& status(FaceHandle _fh) const { + return property(face_status_, _fh); + } + + StatusInfo& status(FaceHandle _fh) { + return property(face_status_, _fh); + } + + + //---------------------------------------- face normals + + const Normal& normal(FaceHandle _fh) const { + return property(face_normals_, _fh); + } + + void set_normal(FaceHandle _fh, const Normal& _n) { + property(face_normals_, _fh) = _n; + } + + + //---------------------------------------- face colors + + const Color& color(FaceHandle _fh) const { + return property(face_colors_, _fh); + } + + void set_color(FaceHandle _fh, const Color& _c) { + property(face_colors_, _fh) = _c; + } + + + + //------------------------------------------------ request / alloc properties + + void request_vertex_normals() { + if (!refcount_vnormals_++) + vertex_normals_ = add_vnormals( Normal(), "v:normals" ); + } + + void request_vertex_colors() { + if (!refcount_vcolors_++) + vertex_colors_ = add_vcolors( Color(), "v:colors" ); + } + + void request_vertex_texcoords() { + if (!refcount_vtexcoords_++) + vertex_texcoords_ = add_vtexcoords( TexCoord(), "v:texcoords" ); + } + + void request_vertex_status() { + if (!refcount_vstatus_++) + add_property( vertex_status_, "v:status" ); + } + + void request_halfedge_status() { + if (!refcount_hstatus_++) + add_property( halfedge_status_, "h:status" ); + } + + void request_edge_status() { + if (!refcount_estatus_++) + add_property( edge_status_, "e:status" ); + } + + void request_edge_colors() { + if (!refcount_ecolors_++) + edge_colors_ = add_ecolors( Color(), "e:colors" ); + } + + void request_face_normals() { + if (!refcount_fnormals_++) + add_property( face_normals_, "f:normals" ); + } + + void request_face_colors() { + if (!refcount_fcolors_++) + add_property( face_colors_, "f:colors" ); + } + + void request_face_status() { + if (!refcount_fstatus_++) + add_property( face_status_, "f:status" ); + } + + + + //------------------------------------------------- release / free properties + + void release_vertex_normals() { + if ((refcount_vnormals_ > 0) && (! --refcount_vnormals_)) + remove_property(vertex_normals_); + } + + void release_vertex_colors() { + if ((refcount_vcolors_ > 0) && (! --refcount_vcolors_)) + remove_property(vertex_colors_); + } + + void release_vertex_texcoords() { + if ((refcount_vtexcoords_ > 0) && (! --refcount_vtexcoords_)) + remove_property(vertex_texcoords_); + } + + void release_vertex_status() { + if ((refcount_vstatus_ > 0) && (! --refcount_vstatus_)) + remove_property(vertex_status_); + } + + void release_halfedge_status() { + if ((refcount_hstatus_ > 0) && (! --refcount_hstatus_)) + remove_property(halfedge_status_); + } + + void release_edge_status() { + if ((refcount_estatus_ > 0) && (! --refcount_estatus_)) + remove_property(edge_status_); + } + + void release_edge_colors() { + if ((refcount_ecolors_ > 0) && (! --refcount_ecolors_)) + remove_property(edge_colors_); + } + + void release_face_normals() { + if ((refcount_fnormals_ > 0) && (! --refcount_fnormals_)) + remove_property(face_normals_); + } + + void release_face_colors() { + if ((refcount_fcolors_ > 0) && (! --refcount_fcolors_)) + remove_property(face_colors_); + } + + void release_face_status() { + if ((refcount_fstatus_ > 0) && (! --refcount_fstatus_)) + remove_property(face_status_); + } + + + //----------------------------------------------- static check for properties + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::Normal)> + HasVertexNormals; + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::Color)> + HasVertexColors; + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::TexCoord)> + HasVertexTexCoords; + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::Status)> + HasVertexStatus; + + + typedef + GenProg::Bool2Type<(bool)(HAttribs & Attributes::PrevHalfedge)> + HasPrevHalfedge; + + typedef + GenProg::Bool2Type<(bool)(HAttribs & Attributes::Status)> + HasHalfedgeStatus; + + + typedef + GenProg::Bool2Type<(bool)(EAttribs & Attributes::Status)> + HasEdgeStatus; + + typedef + GenProg::Bool2Type<(bool)(EAttribs & Attributes::Color)> + HasEdgeColors; + + + typedef + GenProg::Bool2Type<(bool)(FAttribs & Attributes::Normal)> + HasFaceNormals; + + typedef + GenProg::Bool2Type<(bool)(FAttribs & Attributes::Color)> + HasFaceColors; + + typedef + GenProg::Bool2Type<(bool)(FAttribs & Attributes::Status)> + HasFaceStatus; + + + //---------------------------------------------- dynamic check for properties + + bool has_vertex_normals() const { return vertex_normals_.is_valid(); } + bool has_vertex_colors() const { return vertex_colors_.is_valid(); } + bool has_vertex_texcoords() const { return vertex_texcoords_.is_valid(); } + bool has_vertex_status() const { return vertex_status_.is_valid(); } + bool has_edge_status() const { return edge_status_.is_valid(); } + bool has_halfedge_status() const { return halfedge_status_.is_valid(); } + bool has_edge_colors() const { return edge_colors_.is_valid(); } + bool has_face_normals() const { return face_normals_.is_valid(); } + bool has_face_colors() const { return face_colors_.is_valid(); } + bool has_face_status() const { return face_status_.is_valid(); } + + static bool has_prev_halfedge() { + return (HAttribs & Attributes::PrevHalfedge); + } + + +public: + + osg::GeometryPtr createGeometryPtr() + { + using namespace osg; + GeometryPtr geo=Geometry::create(); + return bind(geo) ? geo : NullFC; + } + + // create new geometry core from mesh + bool bind( osg::GeometryPtr& _geo ) + { + using namespace osg; + + int Mask = + Geometry::TypesFieldMask | + Geometry::LengthsFieldMask | + Geometry::IndicesFieldMask | + Geometry::PositionsFieldMask; + + if ( has_vertex_colors() ) + Mask |= Geometry::ColorsFieldMask; + if ( has_vertex_normals() ) + Mask |= Geometry::NormalsFieldMask; + if ( has_vertex_texcoords() ) + Mask |= Geometry::TexCoordsFieldMask; + +// std::clog << "#ptypes : " << osg_ptypes()->getSize() << std::endl; +// std::clog << "#plengths : " << osg_plengths()->getSize() << std::endl; +// std::clog << "#indices : " << osg_indices()->getSize() << std::endl; +// std::clog << "#points : " << osg_vpositions()->getSize() << std::endl; + + beginEditCP( _geo, Mask ); + { + addRefCP( osg_ptypes() ); + _geo->setTypes ( osg_ptypes() ); + addRefCP( osg_plengths() ); + _geo->setLengths ( osg_plengths() ); + addRefCP( osg_indices() ); + _geo->setIndices ( osg_indices() ); + addRefCP( osg_vpositions() ); + _geo->setPositions( osg_vpositions() ); + + if ( has_vertex_colors() ) + { + addRefCP( osg_vcolors() ); + _geo->setColors ( osg_vcolors() ); + } + if ( has_vertex_normals() ) + { + addRefCP( osg_vnormals() ); + _geo->setNormals ( osg_vnormals() ); + } + if ( has_vertex_texcoords() ) + { + addRefCP( osg_vtexcoords() ); + _geo->setTexCoords( osg_vtexcoords() ); + } + } + endEditCP (_geo, Mask); + + return true; + } + +private: + + VPropHandleT points_; + VPropHandleT vertex_normals_; + VPropHandleT vertex_colors_; + VPropHandleT vertex_texcoords_; + VPropHandleT vertex_status_; + + FPTypesHandle face_types_; + FPLengthsHandle face_lengths_; + FIndicesHandle face_indices_; + + EPropHandleT edge_status_; + EPropHandleT edge_colors_; + HPropHandleT halfedge_status_; + + FPropHandleT face_normals_; + FPropHandleT face_colors_; + FPropHandleT face_status_; + + unsigned int refcount_vnormals_; + unsigned int refcount_vcolors_; + unsigned int refcount_vtexcoords_; + unsigned int refcount_vstatus_; + unsigned int refcount_estatus_; + unsigned int refcount_ecolors_; + unsigned int refcount_hstatus_; + unsigned int refcount_fnormals_; + unsigned int refcount_fcolors_; + unsigned int refcount_fstatus_; + +}; + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_ATTRIBKERNEL_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/PropertyKernel.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/PropertyKernel.hh new file mode 100644 index 0000000..b2ec6a3 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/PropertyKernel.hh @@ -0,0 +1,272 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_PROPERTYKERNEL_HH +#define OPENMESH_KENREL_OSG_PROPERTYKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + +/** Helper class, extending functionaliy of OpenMesh::BaseKernel to OpenSG + * specific property adaptors. + * \internal + * \todo Follow coding convention and rename class to PropertyKernelT + */ +template < typename IsTriMesh > +class PropertyKernel : public OpenMesh::BaseKernel +{ +public: + + // --------------------------------------------------------------- item types + + typedef FPropHandleT FPTypesHandle; + typedef FPropHandleT FPLengthsHandle; + typedef FPropHandleT FIndicesHandle; + + typedef FP::GeoPTypesUI8 GeoPTypes; + typedef FP::GeoPLengthsUI32 GeoPLengths; + typedef FP::GeoIndicesUI32 GeoIndices; + + // ------------------------------------------------- constructor / destructor + + PropertyKernel() {} + virtual ~PropertyKernel() { } + + +protected: // ---------------------------------------------- add osg properties + + // -------------------- vertex properties + + template < typename T > + VPropHandleT add_vpositions( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vp::prop(_n))); } + + template < typename T > + VPropHandleT add_vnormals( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vn::prop(_n) )); } + + template < typename T > + VPropHandleT add_vcolors( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vc::prop(_n) )); } + + template < typename T > + VPropHandleT add_vtexcoords( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vtc::prop(_n) )); } + + + // -------------------- face properties + + FPTypesHandle add_fptypes( ) + { return FPTypesHandle(_add_fprop(new GeoPTypes)); } + + FPLengthsHandle add_fplengths( ) + { return FPLengthsHandle(_add_fprop(new GeoPLengths)); } + + FIndicesHandle add_findices( FPTypesHandle _pht, FPLengthsHandle _phl ) + { + GeoIndices *bp = new GeoIndices( fptypes(_pht), fplengths(_phl ) ); + return FIndicesHandle(_add_fprop( bp ) ); + } + +protected: // ------------------------------------------- access osg properties + + template < typename T > + typename _t2vp::prop& vpositions( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vp::prop& vpositions( VPropHandleT _ph) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + template < typename T > + typename _t2vn::prop& vnormals( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vn::prop& vnormals( VPropHandleT _ph) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + template < typename T > + typename _t2vc::prop& vcolors( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vc::prop& vcolors( VPropHandleT _ph ) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + template < typename T > + typename _t2vtc::prop& vtexcoords( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vtc::prop& vtexcoords( VPropHandleT _ph ) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + // + GeoPTypes& fptypes( FPTypesHandle _ph ) + { return static_cast( _fprop(_ph) ); } + + const GeoPTypes& fptypes( FPTypesHandle _ph ) const + { return static_cast( _fprop(_ph) ); } + + + GeoPLengths& fplengths( FPLengthsHandle _ph ) + { return static_cast( _fprop(_ph) ); } + + const GeoPLengths& fplengths( FPLengthsHandle _ph ) const + { return static_cast( _fprop(_ph) ); } + + + GeoIndices& findices( FIndicesHandle _ph ) + { return static_cast( _fprop(_ph) ); } + + const GeoIndices& findices( FIndicesHandle _ph ) const + { return static_cast( _fprop(_ph) ); } + + +protected: // ------------------------------------ access osg property elements + + template + T& vpositions( VPropHandleT _ph, VertexHandle _vh ) + { return vpositions(_ph)[_vh.idx()]; } + + template + const T& vpositions( VPropHandleT _ph, VertexHandle _vh ) const + { return vpositions(_ph)[_vh.idx()]; } + + + template < typename T> + T& vnormals( VPropHandleT _ph, VertexHandle _vh ) + { return vnormals(_ph)[_vh.idx()]; } + + template + const T& vnormals( VPropHandleT _ph, VertexHandle _vh ) const + { return vnormals(_ph)[_vh.idx()]; } + + + template < typename T> + T& vcolors( VPropHandleT _ph, VertexHandle _vh ) + { return vcolors(_ph)[_vh.idx()]; } + + template + const T& vcolors( VPropHandleT _ph, VertexHandle _vh ) const + { return vcolors(_ph)[_vh.idx()]; } + + + template < typename T> + T& vtexcoords( VPropHandleT _ph, VertexHandle _vh ) + { return vtexcoords(_ph)[_vh.idx()]; } + + template + const T& vtexcoords( VPropHandleT _ph, VertexHandle _vh ) const + { return vtexcoords(_ph)[_vh.idx()]; } + + + // -------------------- access face property elements + + FPTypesHandle::value_type& + fptypes( FPTypesHandle _ph, FaceHandle _fh ) + { return fptypes( _ph )[ _fh.idx()]; } + + const FPTypesHandle::value_type& + fptypes( FPTypesHandle _ph, FaceHandle _fh ) const + { return fptypes( _ph )[ _fh.idx()]; } + + + FPLengthsHandle::value_type& + fplengths( FPLengthsHandle _ph, FaceHandle _fh ) + { return fplengths( _ph )[ _fh.idx()]; } + + const FPLengthsHandle::value_type& + fplengths( FPLengthsHandle _ph, FaceHandle _fh ) const + { return fplengths( _ph )[ _fh.idx()]; } + + + FIndicesHandle::value_type& + findices( FIndicesHandle _ph, FaceHandle _fh ) + { return findices( _ph )[ _fh.idx()]; } + + const FIndicesHandle::value_type& + findices( FIndicesHandle _ph, FaceHandle _fh ) const + { return findices( _ph )[ _fh.idx()]; } + +public: + + void stats(void) + { + std::cout << "#V : " << n_vertices() << std::endl; + std::cout << "#E : " << n_edges() << std::endl; + std::cout << "#F : " << n_faces() << std::endl; + property_stats(); + } +}; + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_PROPERTYKERNEL_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/PropertyT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/PropertyT.hh new file mode 100644 index 0000000..2530217 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/PropertyT.hh @@ -0,0 +1,416 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_PROPERTYT_HH +#define OPENMESH_KERNEL_OSG_PROPERTYT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +// +#include +// +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + + +//== CLASS DEFINITION ========================================================= + + +// ---------------------------------------------------------------------------- + +/** Property adaptor for OpenSG GeoProperties + * + * This class bridges the interfaces of %OpenMesh properties and + * OpenSG GeoProperties. The PropertyKernelT uses these adaptors to + * add all necessary property functions to the kernel, while the + * AttribKernelT extends the kernel with the standard properites. + * Finally the ArrayKernelT completes the kernel build with a specialized + * version of the garbage collections since the GeoIndices require + * special handling. + * + * \attention Data will be shared with a geometry core when linking + * a mesh with a OpenSG geometry node using Kernel_OSG::bind. + * \internal + */ +template +class oPropertyT : public BaseProperty +{ +public: + + // Type of the encapsulated OpenSG Geometry Property + typedef GeoProperty property_t; + typedef typename property_t::PtrType property_ptr_t; + + typedef typename property_t::StoredFieldType field_t; + typedef typename field_t::StoredType element_t; + typedef typename field_t::StoredType value_type; + +public: + + // + oPropertyT( property_ptr_t _geo_prop, + const std::string& _name = "" ) + : BaseProperty(_name), data_( _geo_prop ) + { + osg_init_check(); + } + + // + oPropertyT( const std::string& _name = "" ) + : BaseProperty(_name), data_(NULL) + { + data_ = property_t::create(); + + // make sure data_ is not null. In that case most probably + // osg::osgInit() hasn't been executed! + osg_init_check(); + } + + /// + virtual ~oPropertyT() + { } + +public: + + oPropertyT& operator = (const oPropertyT& _rhs ) + { + // Shallow copy! Remember, data_ is a osg pointer type, and the assign + // operator makes a shallow copy! + data_ = _rhs.data_; + return *this; + + } + + +public: // interface BaseProperty + + virtual void reserve(size_t _n) { data_->getField().reserve( _n ); } + virtual void resize(size_t _n) { data_->resize( _n ); } + virtual void push_back() { data_->resize( data_->size()+1 ); } + virtual void swap(size_t _i0, size_t _i1) + { std::swap( data_->getField()[_i0], data_->getField()[_i1] ); } + + virtual oPropertyT* clone() const + { + oPropertyT *dolly = new oPropertyT(); + if (n_elements() > 0) + { + // OSGGeoProperty does not provide a deep copy + dolly->resize(n_elements()); + element_t *begin = const_cast(data()); + element_t *end = begin+n_elements(); + element_t *dst = const_cast(dolly->data()); + std::copy( begin, end, dst ); + } + return dolly; + } + +public: + + virtual void set_persistent( bool _yn ) + { + check_and_set_persistent(_yn); + } + + virtual size_t n_elements() const + { return data_==osg::NullFC ? UnknownSize : data_->getSize(); } + + virtual size_t element_size() const + { return UnknownSize; } + + virtual size_t store( std::ostream& _ostr, bool _swap ) const + { return 0; } + + virtual size_t restore( std::istream& _istr, bool _swap ) + { return 0; } + + +public: // OpenSG GeoPropertyInterface compatibility + + void clear(void) { data_->clear(); } + + +public: // access to OpenSG GeoProperty + + property_ptr_t& osg_ptr() + { return data_; } + + const property_ptr_t& osg_ptr() const + { return data_; } + + + const element_t *data() const + { return &( (*this)[ 0 ] ); } + + element_t& operator[](size_t idx) + { return data_->getField()[ idx ]; } + + const element_t& operator[](size_t idx) const + { return data_->getField()[ idx ]; } + + +protected: + + property_ptr_t data_; + + +private: + + void osg_init_check(void) + { + // make sure data_ is not null. In that case most probably + // osg::osgInit() hasn't been executed! + if ( data_ == osg::NullFC ) + throw std::logic_error("OpenSG Runtime Environment is not initialized: " \ + "Use osg::osgInit()"); + } + + oPropertyT( const oPropertyT& ); +}; + +// ----------------------------------------------------------------- class ---- + + +// ------------------------------------------------------------ properties ---- + +/// OpenSG Vertex Properties Adaptors. +namespace VP { + + // ---------------------------------------- Positions + /// \name GeoPositions + //@{ + /// Adaptor for osg::GeoPositions + typedef oPropertyT< osg::GeoPositions2d > GeoPositions2d; + typedef oPropertyT< osg::GeoPositions2f > GeoPositions2f; + typedef oPropertyT< osg::GeoPositions3d > GeoPositions3d; + typedef oPropertyT< osg::GeoPositions3f > GeoPositions3f; + typedef oPropertyT< osg::GeoPositions4d > GeoPositions4d; + typedef oPropertyT< osg::GeoPositions4f > GeoPositions4f; + //@} + + // ---------------------------------------- Normals + /// \name GeoNormals + //@{ + /// Adaptor for osg::GeoNormals + typedef oPropertyT< osg::GeoNormals3f > GeoNormals3f; + //@} + + // ---------------------------------------- TexCoords + /// \name GeoTexCoords + //@{ + /// Adaptor for osg::GeoTexCoords + typedef oPropertyT< osg::GeoTexCoords1f > GeoTexCoords1f; + typedef oPropertyT< osg::GeoTexCoords2f > GeoTexCoords2f; + typedef oPropertyT< osg::GeoTexCoords3f > GeoTexCoords3f; + //@} + + // ---------------------------------------- Colors + /// \name GeoColors + //@{ + /// Adaptor for osg::GeoColors + typedef oPropertyT< osg::GeoColors3f > GeoColors3f; + typedef oPropertyT< osg::GeoColors3ub > GeoColors3ub; + typedef oPropertyT< osg::GeoColors4f > GeoColors4f; + typedef oPropertyT< osg::GeoColors4ub > GeoColors4ub; + //@} + +} // namespace VP + + +/// OpenSG Face Properties Adaptors. +namespace FP { + + // ---------------------------------------- Types + /// Adaptor for osg::GeoPTypesUI8 + typedef oPropertyT< osg::GeoPTypesUI8 > GeoPTypesUI8; + + // ---------------------------------------- Lengths + /// Adaptor for osg::GeoPLengthsUI32 + typedef oPropertyT< osg::GeoPLengthsUI32 > GeoPLengthsUI32; + + // ---------------------------------------- Indices + + typedef oPropertyT< osg::GeoIndicesUI32 > _GeoIndicesUI32; + + /// Adaptor for osg::GeoIndicesUI32 + template < typename IsTriMesh > + class GeoIndicesUI32 : public _GeoIndicesUI32 + { + public: // ---------------------------------------- typedefs + + typedef _GeoIndicesUI32 inherited_t; + typedef typename inherited_t::property_ptr_t property_ptr_t; + + public: // ---------------------------------------- ctor/dtor + + GeoIndicesUI32( property_ptr_t _geo_prop, + GeoPTypesUI8& _types, + GeoPLengthsUI32& _lengths) + : inherited_t( _geo_prop ), types_(_types), length_(_lengths) + { } + + GeoIndicesUI32( GeoPTypesUI8& _types, + GeoPLengthsUI32& _lengths) + : inherited_t(), types_(_types), length_(_lengths) + { } + + virtual ~GeoIndicesUI32() + { } + + public: // ---------------------------------------- inherited + + void swap(size_t _i0, size_t _i1) { _swap( _i0, _i1, IsTriMesh() ); } + virtual void reserve(size_t _n) { _reserve( _n, IsTriMesh() ); } + virtual void resize(size_t _n) { _resize( _n, IsTriMesh() ); } + + protected: // ------------------------------------- swap + + void _swap(size_t _i0, size_t _i1, GenProg::False ) + { + omerr() << "Unsupported mesh type!" << std::endl; + assert(0); + } + + void _swap(size_t _i0, size_t _i1, GenProg::True ) + { + size_t j0 = _i0 + _i0 + _i0; + size_t j1 = _i1 + _i1 + _i1; + + inherited_t::swap( j0, j1 ); + inherited_t::swap( ++j0, ++j1 ); + inherited_t::swap( ++j0, ++j1 ); + } + + virtual void _reserve(size_t _n, GenProg::True ) + { inherited_t::reserve( _n + _n + _n ); } + + virtual void _reserve(size_t _n, GenProg::False ) + { assert( false ); } + + virtual void _resize(size_t _n, GenProg::True ) + { inherited_t::resize( _n + _n + _n ); } + + virtual void _resize(size_t _n, GenProg::False ) + { assert( false ); } + + + protected: + + GeoPTypesUI8 &types_; + GeoPLengthsUI32 &length_; + + }; + +} // namespace FP + + +// ---------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +template struct _t2vp; +template <> struct _t2vp< osg::Pnt2f > +{ typedef osg::GeoPositions2f type; typedef VP::GeoPositions2f prop; }; + +template <> struct _t2vp< osg::Pnt3f > +{ typedef osg::GeoPositions3f type; typedef VP::GeoPositions3f prop; }; + +template <> struct _t2vp< osg::Pnt4f > +{ typedef osg::GeoPositions4f type; typedef VP::GeoPositions4f prop; }; + +template <> struct _t2vp< osg::Pnt2d > +{ typedef osg::GeoPositions2d type; typedef VP::GeoPositions2d prop; }; +template <> struct _t2vp< osg::Pnt3d > +{ typedef osg::GeoPositions3d type; typedef VP::GeoPositions3d prop; }; +template <> struct _t2vp< osg::Pnt4d > +{ typedef osg::GeoPositions4d type; typedef VP::GeoPositions4d prop; }; + +template struct _t2vn; +template <> struct _t2vn< osg::Vec3f > +{ typedef osg::GeoNormals3f type; typedef VP::GeoNormals3f prop; }; + +template struct _t2vc; +template <> struct _t2vc< osg::Color3f > +{ typedef osg::GeoColors3f type; typedef VP::GeoColors3f prop; }; + +template <> struct _t2vc< osg::Color4f > +{ typedef osg::GeoColors4f type; typedef VP::GeoColors4f prop; }; + +template <> struct _t2vc< osg::Color3ub > +{ typedef osg::GeoColors3ub type; typedef VP::GeoColors3ub prop; }; + +template <> struct _t2vc< osg::Color4ub > +{ typedef osg::GeoColors4ub type; typedef VP::GeoColors3ub prop; }; + +template struct _t2vtc; +template <> struct _t2vtc< osg::Vec2f > +{ typedef osg::GeoTexCoords2f type; typedef VP::GeoTexCoords2f prop; }; + +template <> struct _t2vtc< osg::Vec3f > +{ typedef osg::GeoTexCoords3f type; typedef VP::GeoTexCoords3f prop; }; + +#endif + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PROPERTYT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/Traits.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/Traits.hh new file mode 100644 index 0000000..bc87c01 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/Traits.hh @@ -0,0 +1,105 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +/** \file Tools/Kernel_OSG/Traits.hh + This file defines the default traits and some convenienve macros. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_KERNEL_OSG_TRAITS_HH +#define OPENMESH_KERNEL_OSG_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +// +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + +//== CLASS DEFINITION ========================================================= + + +/** Base class for all mesh traits using the OSGArrayKernelT. + * + * \see The Mesh docu section on \ref mesh_type. + * \see Traits.hh for a list of macros for traits classes. + */ +struct Traits : DefaultTraits +{ + typedef osg::Pnt3f Point; + typedef osg::Color3ub Color; + typedef osg::Vec3f Normal; + typedef osg::Vec2f TexCoord; + typedef osg::Vec3f::ValueType Scalar; + +}; + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRAITS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh new file mode 100644 index 0000000..ff4bd91 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh @@ -0,0 +1,117 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS TriMesh_OSGArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_KERNEL_OSG_TRIMESH_OSGARRAYKERNEL_HH +#define OPENMESH_KERNEL_OSG_TRIMESH_OSGARRAYKERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +// -------------------- +#include +#include +#include +//#include +#include +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + +/// Helper class to create a TriMesh-type based on Kernel_OSG::ArrayKernelT +template +struct TriMesh_OSGArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef ArrayKernelT MeshKernel; + typedef TriMeshT Mesh; +}; + + + +/** \ingroup mesh_types_group + Triangle mesh based on the Kernel_OSG::ArrayKernelT. + \see OpenMesh::TriMeshT + \see OpenMesh::ArrayKernelT +*/ +template +class TriMesh_OSGArrayKernelT + : public TriMesh_OSGArrayKernel_GeneratorT::Mesh +{}; + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_TRIMESH_OSGARRAYKERNEL_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/VectorAdapter.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/VectorAdapter.hh new file mode 100644 index 0000000..bb545d3 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/VectorAdapter.hh @@ -0,0 +1,205 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +// ---------------------------------------------------------------------------- + +#ifndef OPENMESH_KERNEL_OSG_VECTORADAPTER_HH +#define OPENMESH_KERNEL_OSG_VECTORADAPTER_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +// ----------------------------------------------------------------- class ---- + +#define OSG_VECTOR_TRAITS( VecType ) \ + template <> struct vector_traits< VecType > { \ + typedef VecType vector_type; \ + typedef vector_type::ValueType value_type; \ + typedef GenProg::Int2Type< vector_type::_iSize > typed_size; \ + \ + static const size_t size_ = vector_type::_iSize; \ + static size_t size() { return size_; } \ + } + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt4f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt3f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt2f ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec4f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec3f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec2f ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt4d ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt3d ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt2d ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec4d ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec3d ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec4ub ); + + +// ---------------------------------------------------------------------------- + + +#define OSG_COLOR_TRAITS( VecType, N ) \ + template <> struct vector_traits< VecType > { \ + typedef VecType vector_type; \ + typedef vector_type::ValueType value_type; \ + typedef GenProg::Int2Type< N > typed_size; \ + \ + static const size_t size_ = N; \ + static size_t size() { return size_; } \ + } + + +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color3ub, 3 ); +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color4ub, 4 ); +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color3f, 3 ); +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color4f, 4 ); + +#undef OSG_VECTOR_TRAITS + + +// ---------------------------------------- +#if 1 +#define PNT2VEC_CASTER( DST, SRC ) \ + template <> struct vector_caster< DST, SRC > { \ + typedef DST dst_t; \ + typedef SRC src_t; \ + typedef const dst_t& return_type; \ + inline static return_type cast( const src_t& _src ) {\ + return _src.subZero(); \ + } \ + } + +/// convert Pnt3f to Vec3f +PNT2VEC_CASTER( osg::Vec3f, osg::Pnt3f ); + +/// convert Pnt4f to Vec4f +PNT2VEC_CASTER( osg::Vec4f, osg::Pnt4f ); + +/// convert Pnt3d to Vec3d +PNT2VEC_CASTER( osg::Vec3d, osg::Pnt3d ); + +/// convert Pnt4d to Vec4d +PNT2VEC_CASTER( osg::Vec4d, osg::Pnt4d ); + +#undef PNT2VEC +#else + + template <> + struct vector_caster< osg::Vec3f, osg::Pnt3f > + { + typedef osg::Vec3f dst_t; + typedef osg::Pnt3f src_t; + + typedef const dst_t& return_type; + inline static return_type cast( const src_t& _src ) + { + std::cout << "casting Pnt3f to Vec3f\n"; + return _src.subZero(); + } + }; + +#endif +// ---------------------------------------- + +//@{ +/// Adapter for osg vector member computing a scalar product +inline +osg::Vec3f::ValueType dot( const osg::Vec3f &_v1, const osg::Vec3f &_v2 ) +{ return _v1.dot(_v2); } + + +inline +osg::Vec3f::ValueType dot( const osg::Vec3f &_v1, const osg::Pnt3f &_v2 ) +{ return _v1.dot(_v2); } + + +inline +osg::Vec2f::ValueType dot( const osg::Vec2f &_v1, const osg::Vec2f &_v2 ) +{ return _v1.dot(_v2); } + + +inline +osg::Vec3f cross( const osg::Vec3f &_v1, const osg::Vec3f &_v2 ) +{ return _v1.cross(_v2); } +//@} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VECTORADAPTER_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/bindT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/bindT.hh new file mode 100644 index 0000000..c93f2c8 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/bindT.hh @@ -0,0 +1,319 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +/** \file bindT.hh + + Bind an OpenMesh to a OpenSG geometry node. Be aware that due to + this link the geometry node maybe modified. For instance triangle + strips are converted to regular triangles. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_KERNEL_OSG_BINDT_HH +#define OPENMESH_KERNEL_OSG_BINDT_HH + + +//== INCLUDES ================================================================= + + +#include +#include +// +#include +#include +#include +#include +// +#include "color_cast.hh" + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + + +//== CLASS DEFINITION ========================================================= + +inline +bool type_is_valid( unsigned char _t ) +{ + return _t == GL_TRIANGLES + || _t == GL_TRIANGLE_STRIP + || _t == GL_QUADS + || _t == GL_POLYGON; +} + + +/** Bind a OpenSG geometry to a mesh. + * + * \param _mesh The mesh object to bind the geometry to. + * \param _geo The geometry object to bind. + * \return true if the connection has been established else false. + */ +template < typename Mesh > inline +bool bind( osg::GeometryPtr& _geo, Mesh& _mesh ) +{ + _geo = _mesh.createGeometryPtr(); +} + +/** Bind a mesh object to geometry. The binder is able to handle + * non-indexed and indexed geometry. Multi-indexed geometry is not + * supported. + * + * \param _mesh The mesh object to bind. + * \param _geo The geometry object to bind to. + * \return true if the connection has been established else false. + */ +template < typename Mesh > inline +bool bind( Mesh& _mesh, osg::GeometryPtr& _geo ) +{ + using namespace OpenMesh; + using namespace osg; + using namespace std; + + bool ok = true; + + // pre-check if types are supported + + GeoPTypesPtr types = _geo->getTypes(); + + if ( (size_t)count_if( types->getData(), types->getData()+types->size(), + ptr_fun(type_is_valid) ) != (size_t)types->size() ) + return false; + + // pre-check if it is a multi-indexed geometry, which is not supported! + + if ( _geo->getIndexMapping().getSize() > 1 ) + { + omerr << "OpenMesh::Kernel_OSG::bind(): Multi-indexed geometry is not supported!\n"; + return false; + } + + + // create shortcuts + + GeoPLengthsPtr lengths = _geo->getLengths(); + GeoIndicesPtr indices = _geo->getIndices(); + GeoPositionsPtr pos = _geo->getPositions(); + GeoNormalsPtr normals = _geo->getNormals(); + GeoColorsPtr colors = _geo->getColors(); + + + // -------------------- now convert everything to polygon/triangles + + size_t tidx, bidx; // types; base index into indices + vector< VertexHandle > vhandles; + + // ---------- initialize geometry + + { + VertexHandle vh; + typedef typename Mesh::Color color_t; + + bool bind_normal = (normals!=NullFC) && _mesh.has_vertex_normals(); + bool bind_color = (colors !=NullFC) && _mesh.has_vertex_colors(); + + for (bidx=0; bidx < pos->size(); ++bidx) + { + vh = _mesh.add_vertex( pos->getValue(bidx) ); + if ( bind_normal ) + _mesh.set_normal(vh, normals->getValue(bidx)); + if ( bind_color ) + _mesh.set_color(vh, color_cast(colors->getValue(bidx))); + } + } + + // ---------- create topology + + FaceHandle fh; + + size_t max_bidx = indices != NullFC ? indices->size() : pos->size(); + + for (bidx=tidx=0; ok && tidxsize() && bidx < max_bidx; ++tidx) + { + switch( types->getValue(tidx) ) + { + case GL_TRIANGLES: + vhandles.resize(3); + for(size_t lidx=0; lidx < lengths->getValue(tidx)-2; lidx+=3) + { + if (indices == NullFC ) { + vhandles[0] = VertexHandle(bidx+lidx); + vhandles[1] = VertexHandle(bidx+lidx+1); + vhandles[2] = VertexHandle(bidx+lidx+2); + } + else { + vhandles[0] = VertexHandle(indices->getValue(bidx+lidx ) ); + vhandles[1] = VertexHandle(indices->getValue(bidx+lidx+1) ); + vhandles[2] = VertexHandle(indices->getValue(bidx+lidx+2) ); + } + + if ( !(fh = _mesh.add_face( vhandles )).is_valid() ) + { + // if fh is complex try swapped order + swap(vhandles[2], vhandles[1]); + fh = _mesh.add_face( vhandles ); + } + ok = fh.is_valid(); + } + break; + + case GL_TRIANGLE_STRIP: + vhandles.resize(3); + for (size_t lidx=0; lidx < lengths->getValue(tidx)-2; ++lidx) + { + if (indices == NullFC ) { + vhandles[0] = VertexHandle(bidx+lidx); + vhandles[1] = VertexHandle(bidx+lidx+1); + vhandles[2] = VertexHandle(bidx+lidx+2); + } + else { + vhandles[0] = VertexHandle(indices->getValue(bidx+lidx ) ); + vhandles[1] = VertexHandle(indices->getValue(bidx+lidx+1) ); + vhandles[2] = VertexHandle(indices->getValue(bidx+lidx+2) ); + } + + if (vhandles[0]!=vhandles[2] && + vhandles[0]!=vhandles[1] && + vhandles[1]!=vhandles[2]) + { + // if fh is complex try swapped order + bool swapped(false); + + if (lidx % 2) // odd numbered triplet must be reordered + swap(vhandles[2], vhandles[1]); + + if ( !(fh = _mesh.add_face( vhandles )).is_valid() ) + { + omlog << "OpenMesh::Kernel_OSG::bind(): complex entity!\n"; + + swap(vhandles[2], vhandles[1]); + fh = _mesh.add_face( vhandles ); + swapped = true; + } + ok = fh.is_valid(); + } + } + break; + + case GL_QUADS: + vhandles.resize(4); + for(size_t nf=_mesh.n_faces(), lidx=0; + lidx < lengths->getValue(tidx)-3; lidx+=4) + { + if (indices == NullFC ) { + vhandles[0] = VertexHandle(bidx+lidx); + vhandles[1] = VertexHandle(bidx+lidx+1); + vhandles[2] = VertexHandle(bidx+lidx+2); + vhandles[3] = VertexHandle(bidx+lidx+3); + } + else { + vhandles[0] = VertexHandle(indices->getValue(bidx+lidx ) ); + vhandles[1] = VertexHandle(indices->getValue(bidx+lidx+1) ); + vhandles[2] = VertexHandle(indices->getValue(bidx+lidx+2) ); + vhandles[3] = VertexHandle(indices->getValue(bidx+lidx+3) ); + } + + fh = _mesh.add_face( vhandles ); + ok = ( Mesh::Face::is_triangle() && (_mesh.n_faces()==(nf+2))) + || fh.is_valid(); + nf = _mesh.n_faces(); + } + break; + + case GL_POLYGON: + { + size_t ne = lengths->getValue(tidx); + size_t nf = _mesh.n_faces(); + + vhandles.resize(ne); + + for(size_t lidx=0; lidx < ne; ++lidx) + vhandles[lidx] = (indices == NullFC) + ? VertexHandle(bidx+lidx) + : VertexHandle(indices->getValue(bidx+lidx) ); + + fh = _mesh.add_face( vhandles ); + ok = ( Mesh::Face::is_triangle() && (_mesh.n_faces()==nf+ne-2) ) + || fh.is_valid(); + + break; + } + default: + cerr << "Warning! Skipping unsupported type " + << types->getValue(tidx) << " '" + << Utils::GLenum_as_string( types->getValue(tidx) ) << "'\n"; + } + + // update base index into indices for next face type + bidx += lengths->getValue(tidx); + } + + if (ok) + ok=_mesh.bind(_geo); + else + _mesh.clear(); + + return ok; +} + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_BINDT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/color_cast.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/color_cast.hh new file mode 100644 index 0000000..df4bb3e --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Kernel_OSG/color_cast.hh @@ -0,0 +1,91 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_COLOR_CAST_HH +#define OPENMESH_KERNEL_OSG_COLOR_CAST_HH + +#include +#include +#include + +namespace OpenMesh { + +/// Helper struct +/// \internal +template <> +struct color_caster +{ + typedef osg::Color3ub return_type; + typedef unsigned char ub; + + inline static return_type cast(const osg::Color3f& _src) + { + return return_type( (ub)std::min((_src[0]* 255.0f + 0.5f),255.0f), + (ub)std::min((_src[1]* 255.0f + 0.5f),255.0f), + (ub)std::min((_src[2]* 255.0f + 0.5f),255.0f) ); + } +}; + +/// Helper struct +/// \internal +template <> +struct color_caster +{ + typedef osg::Color3f return_type; + + inline static return_type cast(const osg::Color3ub& _src) + { + return return_type( (float)(_src[0] / 255.0f ), + (float)(_src[1] / 255.0f ), + (float)(_src[2] / 255.0f ) ); + } +}; + +} // namespace OpenMesh + +#endif // OPENMESH_KERNEL_OSG_COLOR_CAST_HH diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.cc new file mode 100644 index 0000000..f038006 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.cc @@ -0,0 +1,198 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file JacobiLaplaceSmootherT.cc + + */ + +//============================================================================= +// +// CLASS JacobiLaplaceSmootherT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_JACOBI_LAPLACE_SMOOTHERT_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Smoother { + + +//== IMPLEMENTATION ========================================================== + + +template +void +JacobiLaplaceSmootherT:: +smooth(unsigned int _n) +{ + if (Base::continuity() > Base::C0) + { + Base::mesh_.add_property(umbrellas_); + if (Base::continuity() > Base::C1) + Base::mesh_.add_property(squared_umbrellas_); + } + + LaplaceSmootherT::smooth(_n); + + if (Base::continuity() > Base::C0) + { + Base::mesh_.remove_property(umbrellas_); + if (Base::continuity() > Base::C1) + Base::mesh_.remove_property(squared_umbrellas_); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +JacobiLaplaceSmootherT:: +compute_new_positions_C0() +{ + typename Mesh::VertexIter v_it, v_end(Base::mesh_.vertices_end()); + typename Mesh::ConstVertexOHalfedgeIter voh_it; + typename Mesh::Normal u, p, zero(0,0,0); + typename Mesh::Scalar w; + + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + if (this->is_active(*v_it)) + { + // compute umbrella + u = zero; + for (voh_it = Base::mesh_.cvoh_iter(*v_it); voh_it.is_valid(); ++voh_it) { + w = this->weight(Base::mesh_.edge_handle(*voh_it)); + u += vector_cast(Base::mesh_.point(Base::mesh_.to_vertex_handle(*voh_it))) * w; + } + u *= this->weight(*v_it); + u -= vector_cast(Base::mesh_.point(*v_it)); + + // damping + u *= static_cast< typename Mesh::Scalar >(0.5); + + // store new position + p = vector_cast(Base::mesh_.point(*v_it)); + p += u; + this->set_new_position(*v_it, p); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +JacobiLaplaceSmootherT:: +compute_new_positions_C1() +{ + typename Mesh::VertexIter v_it, v_end(Base::mesh_.vertices_end()); + typename Mesh::ConstVertexOHalfedgeIter voh_it; + typename Mesh::Normal u, uu, p, zero(0,0,0); + typename Mesh::Scalar w, diag; + + + // 1st pass: compute umbrellas + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + u = zero; + for (voh_it = Base::mesh_.cvoh_iter(*v_it); voh_it.is_valid(); ++voh_it) { + w = this->weight(Base::mesh_.edge_handle(*voh_it)); + u -= vector_cast(Base::mesh_.point(Base::mesh_.to_vertex_handle(*voh_it)))*w; + } + u *= this->weight(*v_it); + u += vector_cast(Base::mesh_.point(*v_it)); + + Base::mesh_.property(umbrellas_, *v_it) = u; + } + + + // 2nd pass: compute updates + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + if (this->is_active(*v_it)) + { + uu = zero; + diag = 0.0; + for (voh_it = Base::mesh_.cvoh_iter(*v_it); voh_it.is_valid(); ++voh_it) { + w = this->weight(Base::mesh_.edge_handle(*voh_it)); + uu -= Base::mesh_.property(umbrellas_, Base::mesh_.to_vertex_handle(*voh_it)); + diag += (w * this->weight(Base::mesh_.to_vertex_handle(*voh_it)) + static_cast(1.0) ) * w; + } + uu *= this->weight(*v_it); + diag *= this->weight(*v_it); + uu += Base::mesh_.property(umbrellas_, *v_it); + if (diag) uu *= static_cast(1.0) / diag; + + // damping + uu *= static_cast::value_type>(0.25); + + // store new position + p = vector_cast(Base::mesh_.point(*v_it)); + p -= uu; + this->set_new_position(*v_it, p); + } + } +} + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.hh new file mode 100644 index 0000000..1d9ae6b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.hh @@ -0,0 +1,117 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file JacobiLaplaceSmootherT.hh + + */ + + +//============================================================================= +// +// CLASS JacobiLaplaceSmootherT +// +//============================================================================= + +#ifndef OPENMESH_JACOBI_LAPLACE_SMOOTHERT_HH +#define OPENMESH_JACOBI_LAPLACE_SMOOTHERT_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Smoother { + +//== CLASS DEFINITION ========================================================= + +/** Laplacian Smoothing. + * + */ +template +class JacobiLaplaceSmootherT : public LaplaceSmootherT +{ +private: + typedef LaplaceSmootherT Base; + +public: + + JacobiLaplaceSmootherT( Mesh& _mesh ) : LaplaceSmootherT(_mesh) {} + + // override: alloc umbrellas + void smooth(unsigned int _n); + + +protected: + + virtual void compute_new_positions_C0(); + virtual void compute_new_positions_C1(); + + +private: + + OpenMesh::VPropHandleT umbrellas_; + OpenMesh::VPropHandleT squared_umbrellas_; +}; + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_JACOBI_LAPLACE_SMOOTHERT_C) +#define OPENMESH_JACOBI_LAPLACE_SMOOTHERT_TEMPLATES +#include "JacobiLaplaceSmootherT.cc" +#endif +//============================================================================= +#endif // OPENMESH_JACOBI_LAPLACE_SMOOTHERT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/LaplaceSmootherT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/LaplaceSmootherT.cc new file mode 100644 index 0000000..a962322 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/LaplaceSmootherT.cc @@ -0,0 +1,227 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file LaplaceSmootherT.cc + + */ + +//============================================================================= +// +// CLASS LaplaceSmootherT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_LAPLACE_SMOOTHERT_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Smoother { + + +//== IMPLEMENTATION ========================================================== + + +template +LaplaceSmootherT:: +LaplaceSmootherT(Mesh& _mesh) + : SmootherT(_mesh) +{ + // custom properties + Base::mesh_.add_property(vertex_weights_); + Base::mesh_.add_property(edge_weights_); +} + + +//----------------------------------------------------------------------------- + + +template +LaplaceSmootherT:: +~LaplaceSmootherT() +{ + // free custom properties + Base::mesh_.remove_property(vertex_weights_); + Base::mesh_.remove_property(edge_weights_); +} + + +//----------------------------------------------------------------------------- + + +template +void +LaplaceSmootherT:: +initialize(Component _comp, Continuity _cont) +{ + SmootherT::initialize(_comp, _cont); + + // calculate weights + switch (_comp) + { + case Base::Tangential: + compute_weights(UniformWeighting); + break; + + + case Base::Normal: + compute_weights(CotWeighting); + break; + + + case Base::Tangential_and_Normal: + compute_weights(UniformWeighting); + break; + } +} + + +//----------------------------------------------------------------------------- + + +template +void +LaplaceSmootherT:: +compute_weights(LaplaceWeighting _weighting) +{ + typename Mesh::VertexIter v_it, v_end(Base::mesh_.vertices_end()); + typename Mesh::EdgeIter e_it, e_end(Base::mesh_.edges_end()); + typename Mesh::HalfedgeHandle heh0, heh1, heh2; + typename Mesh::VertexHandle v0, v1; + const typename Mesh::Point *p0, *p1, *p2; + typename Mesh::Normal d0, d1; + typename Mesh::Scalar weight, lb(-1.0), ub(1.0); + + + + // init vertex weights + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + Base::mesh_.property(vertex_weights_, *v_it) = 0.0; + + + + switch (_weighting) + { + // Uniform weighting + case UniformWeighting: + { + for (e_it=Base::mesh_.edges_begin(); e_it!=e_end; ++e_it) + { + heh0 = Base::mesh_.halfedge_handle(*e_it, 0); + heh1 = Base::mesh_.halfedge_handle(*e_it, 1); + v0 = Base::mesh_.to_vertex_handle(heh0); + v1 = Base::mesh_.to_vertex_handle(heh1); + + Base::mesh_.property(edge_weights_, *e_it) = 1.0; + Base::mesh_.property(vertex_weights_, v0) += 1.0; + Base::mesh_.property(vertex_weights_, v1) += 1.0; + } + + break; + } + + + // Cotangent weighting + case CotWeighting: + { + for (e_it=Base::mesh_.edges_begin(); e_it!=e_end; ++e_it) + { + weight = 0.0; + + heh0 = Base::mesh_.halfedge_handle(*e_it, 0); + v0 = Base::mesh_.to_vertex_handle(heh0); + p0 = &Base::mesh_.point(v0); + + heh1 = Base::mesh_.halfedge_handle(*e_it, 1); + v1 = Base::mesh_.to_vertex_handle(heh1); + p1 = &Base::mesh_.point(v1); + + heh2 = Base::mesh_.next_halfedge_handle(heh0); + p2 = &Base::mesh_.point(Base::mesh_.to_vertex_handle(heh2)); + d0 = (*p0 - *p2); d0.normalize(); + d1 = (*p1 - *p2); d1.normalize(); + weight += static_cast(1.0) / tan(acos(std::max(lb, std::min(ub, dot(d0,d1) )))); + + heh2 = Base::mesh_.next_halfedge_handle(heh1); + p2 = &Base::mesh_.point(Base::mesh_.to_vertex_handle(heh2)); + d0 = (*p0 - *p2); d0.normalize(); + d1 = (*p1 - *p2); d1.normalize(); + weight += static_cast(1.0) / tan(acos(std::max(lb, std::min(ub, dot(d0,d1) )))); + + Base::mesh_.property(edge_weights_, *e_it) = weight; + Base::mesh_.property(vertex_weights_, v0) += weight; + Base::mesh_.property(vertex_weights_, v1) += weight; + } + break; + } + } + + + // invert vertex weights: + // before: sum of edge weights + // after: one over sum of edge weights + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + weight = Base::mesh_.property(vertex_weights_, *v_it); + if (weight) + Base::mesh_.property(vertex_weights_, *v_it) = static_cast(1.0) / weight; + } +} + + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/LaplaceSmootherT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/LaplaceSmootherT.hh new file mode 100644 index 0000000..98dd5f3 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/LaplaceSmootherT.hh @@ -0,0 +1,131 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file LaplaceSmootherT.hh + + */ + +//============================================================================= +// +// CLASS LaplaceSmootherT +// +//============================================================================= + +#ifndef OPENMESH_LAPLACE_SMOOTHERT_HH +#define OPENMESH_LAPLACE_SMOOTHERT_HH + + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Smoother { + +//== CLASS DEFINITION ========================================================= + +/// Laplacian Smoothing. +template +class LaplaceSmootherT : public SmootherT +{ +private: + typedef SmootherT Base; +public: + + typedef typename SmootherT::Component Component; + typedef typename SmootherT::Continuity Continuity; + typedef typename SmootherT::Scalar Scalar; + typedef typename SmootherT::VertexHandle VertexHandle; + typedef typename SmootherT::EdgeHandle EdgeHandle; + + + LaplaceSmootherT( Mesh& _mesh ); + virtual ~LaplaceSmootherT(); + + + void initialize(Component _comp, Continuity _cont); + + +protected: + + // misc helpers + + Scalar weight(VertexHandle _vh) const + { return Base::mesh_.property(vertex_weights_, _vh); } + + Scalar weight(EdgeHandle _eh) const + { return Base::mesh_.property(edge_weights_, _eh); } + + +private: + + enum LaplaceWeighting { UniformWeighting, CotWeighting }; + void compute_weights(LaplaceWeighting _mode); + + + OpenMesh::VPropHandleT vertex_weights_; + OpenMesh::EPropHandleT edge_weights_; +}; + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_LAPLACE_SMOOTHERT_C) +#define OPENMESH_LAPLACE_SMOOTHERT_TEMPLATES +#include "LaplaceSmootherT.cc" +#endif +//============================================================================= +#endif // OPENMESH_LAPLACE_SMOOTHERT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/SmootherT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/SmootherT.cc new file mode 100644 index 0000000..c727aeb --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/SmootherT.cc @@ -0,0 +1,436 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file SmootherT.cc + + */ + +//============================================================================= +// +// CLASS SmootherT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_SMOOTHERT_C + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Smoother { + + +//== IMPLEMENTATION ========================================================== + + +template +SmootherT:: +SmootherT(Mesh& _mesh) + : mesh_(_mesh), + skip_features_(false) +{ + // request properties + mesh_.request_vertex_status(); + mesh_.request_face_normals(); + mesh_.request_vertex_normals(); + + // custom properties + mesh_.add_property(original_positions_); + mesh_.add_property(original_normals_); + mesh_.add_property(new_positions_); + mesh_.add_property(is_active_); + + + // default settings + component_ = Tangential_and_Normal; + continuity_ = C0; + tolerance_ = -1.0; +} + + +//----------------------------------------------------------------------------- + + +template +SmootherT:: +~SmootherT() +{ + // free properties + mesh_.release_vertex_status(); + mesh_.release_face_normals(); + mesh_.release_vertex_normals(); + + // free custom properties + mesh_.remove_property(original_positions_); + mesh_.remove_property(original_normals_); + mesh_.remove_property(new_positions_); + mesh_.remove_property(is_active_); +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +initialize(Component _comp, Continuity _cont) +{ + typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); + + + // store smoothing settings + component_ = _comp; + continuity_ = _cont; + + + // update normals + mesh_.update_face_normals(); + mesh_.update_vertex_normals(); + + + // store original points & normals + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + mesh_.property(original_positions_, *v_it) = mesh_.point(*v_it); + mesh_.property(original_normals_, *v_it) = mesh_.normal(*v_it); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +set_active_vertices() +{ + typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); + + + // is something selected? + bool nothing_selected(true); + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.status(*v_it).selected()) + { nothing_selected = false; break; } + + + // tagg all active vertices + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + bool active = ((nothing_selected || mesh_.status(*v_it).selected()) + && !mesh_.is_boundary(*v_it) + && !mesh_.status(*v_it).locked()); + + if ( skip_features_ ) { + + active = active && !mesh_.status(*v_it).feature(); + + typename Mesh::VertexOHalfedgeIter voh_it(mesh_,*v_it); + for ( ; voh_it.is_valid() ; ++voh_it ) { + + // If the edge is a feature edge, skip the current vertex while smoothing + if ( mesh_.status(mesh_.edge_handle(*voh_it)).feature() ) + active = false; + + typename Mesh::FaceHandle fh1 = mesh_.face_handle(*voh_it ); + typename Mesh::FaceHandle fh2 = mesh_.face_handle(mesh_.opposite_halfedge_handle(*voh_it ) ); + + // If one of the faces is a feature, lock current vertex + if ( fh1.is_valid() && mesh_.status( fh1 ).feature() ) + active = false; + if ( fh2.is_valid() && mesh_.status( fh2 ).feature() ) + active = false; + + } + } + + mesh_.property(is_active_, *v_it) = active; + } + + + // C1: remove one ring of boundary vertices + if (continuity_ == C1) + { + typename Mesh::VVIter vv_it; + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.is_boundary(*v_it)) + for (vv_it=mesh_.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) + mesh_.property(is_active_, *vv_it) = false; + } + + + // C2: remove two rings of boundary vertices + if (continuity_ == C2) + { + typename Mesh::VVIter vv_it; + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + mesh_.status(*v_it).set_tagged(false); + mesh_.status(*v_it).set_tagged2(false); + } + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.is_boundary(*v_it)) + for (vv_it=mesh_.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) + mesh_.status(*v_it).set_tagged(true); + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.status(*v_it).tagged()) + for (vv_it=mesh_.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) + mesh_.status(*v_it).set_tagged2(true); + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + if (mesh_.status(*v_it).tagged2()) + mesh_.property(is_active_, *vv_it) = false; + mesh_.status(*v_it).set_tagged(false); + mesh_.status(*v_it).set_tagged2(false); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +set_relative_local_error(Scalar _err) +{ + if (!mesh_.vertices_empty()) + { + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + + + // compute bounding box + Point bb_min, bb_max; + bb_min = bb_max = mesh_.point(*v_it); + for (++v_it; v_it!=v_end; ++v_it) + { + minimize(bb_min, mesh_.point(*v_it)); + maximize(bb_max, mesh_.point(*v_it)); + } + + + // abs. error = rel. error * bounding-diagonal + set_absolute_local_error(norm(_err * (bb_max-bb_min))); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +set_absolute_local_error(Scalar _err) +{ + tolerance_ = _err; +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +disable_local_error_check() +{ + tolerance_ = -1.0; +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +smooth(unsigned int _n) +{ + // mark active vertices + set_active_vertices(); + + // smooth _n iterations + while (_n--) + { + compute_new_positions(); + + if (component_ == Tangential) + project_to_tangent_plane(); + + else if (tolerance_ >= 0.0) + local_error_check(); + + move_points(); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +compute_new_positions() +{ + switch (continuity_) + { + case C0: + compute_new_positions_C0(); + break; + + case C1: + compute_new_positions_C1(); + break; + + case C2: + break; + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +project_to_tangent_plane() +{ + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + // Normal should be a vector type. In some environment a vector type + // is different from point type, e.g. OpenSG! + typename Mesh::Normal translation, normal; + + + for (; v_it != v_end; ++v_it) + { + if (is_active(*v_it)) + { + translation = new_position(*v_it)-orig_position(*v_it); + normal = orig_normal(*v_it); + normal *= dot(translation, normal); + translation -= normal; + translation += vector_cast(orig_position(*v_it)); + set_new_position(*v_it, translation); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +local_error_check() +{ + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + + typename Mesh::Normal translation; + typename Mesh::Scalar s; + + + for (; v_it != v_end; ++v_it) + { + if (is_active(*v_it)) + { + translation = new_position(*v_it) - orig_position(*v_it); + + s = fabs(dot(translation, orig_normal(*v_it))); + + if (s > tolerance_) + { + translation *= (tolerance_ / s); + translation += vector_cast(orig_position(*v_it)); + set_new_position(*v_it, translation); + } + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +move_points() +{ + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + + for (; v_it != v_end; ++v_it) + if (is_active(*v_it)) + mesh_.set_point(*v_it, mesh_.property(new_positions_, *v_it)); +} + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/SmootherT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/SmootherT.hh new file mode 100644 index 0000000..65d3764 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/SmootherT.hh @@ -0,0 +1,260 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file SmootherT.hh + + */ + +//============================================================================= +// +// CLASS SmootherT +// +//============================================================================= + +#ifndef OPENMESH_SMOOTHER_SMOOTHERT_HH +#define OPENMESH_SMOOTHER_SMOOTHERT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Smoother { + +//== CLASS DEFINITION ========================================================= + +/** Base class for smoothing algorithms. + */ +template +class SmootherT : private Utils::Noncopyable +{ +public: + + typedef typename Mesh::Scalar Scalar; + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal NormalType; + typedef typename Mesh::VertexHandle VertexHandle; + typedef typename Mesh::EdgeHandle EdgeHandle; + + // initialize smoother + enum Component { + Tangential, ///< Smooth tangential direction + Normal, ///< Smooth normal direction + Tangential_and_Normal ///< Smooth tangential and normal direction + }; + + enum Continuity { + C0, + C1, + C2 + }; + +public: + + /** \brief constructor & destructor + * + * @param _mesh Reference a triangle or poly mesh + */ + SmootherT( Mesh& _mesh ); + virtual ~SmootherT(); + + +public: + + //=========================================================================== + /** @name Initialization and algorithm execution + * @{ */ + //=========================================================================== + + /** Initialize smoother + * \param _comp Determine component to smooth + * \param _cont Determine Continuity + */ + void initialize(Component _comp, Continuity _cont); + + /// Do _n smoothing iterations + virtual void smooth(unsigned int _n); + + /** @} */ + + //=========================================================================== + /** @name Error control functions + * @{ */ + //=========================================================================== + + /** \brief Set local error relative to bounding box + * + * This function sets a maximal error tolerance for the smoother as a fraction + * of the bounding box of the mesh. First the bounding box diagonal is computed. + * Then the error is set as the length of the diagonal multiplied with the + * given factor. + * + * @param _err Factor scaling the bounding box diagonal + */ + void set_relative_local_error(Scalar _err); + + /** \brief Set local error as an absolute value + * + * Set the maximal error tolerance of the smoother to the given value. + * + * @param _err Maximal error + */ + void set_absolute_local_error(Scalar _err); + + /** \brief Disable error control of the smoother + * + * This function disables the error control of the smoother. + */ + void disable_local_error_check(); + + /** \brief enable or disable feature handling + * + * This function can be used to control if features on the mesh should be preserved. + * If enabled, the smoother will keep features and does not modify them. Features + * can be set via OpenMesh status flags (request status and set primitives as features). + * Feature flag can be set for vertices edges and faces. + * + * @param _state true : If features are selected on the mesh, they will be left unmodified\n + * false : Features will be ignored + */ + void skip_features( bool _state ){ skip_features_ = _state; }; + + + /** @} */ + +private: + + /** \brief Find active vertices. Resets tagged status ! + * + * This function recomputes the set of active vertices, which will be touched by the smoother. + * If nothing on the mesh is selected, all vertices which are not locked, feature or boundary will be + * marked as active and moved by the smoother. + * If vertices are selected, than only the selected ones, excluding the locked, feature and boundary vertices will be + * moved. + * + * The function is called first when running the smoother. + */ + void set_active_vertices(); + + // single steps of smoothing + void compute_new_positions(); + void project_to_tangent_plane(); + void local_error_check(); + void move_points(); + + + +protected: + + // override these + virtual void compute_new_positions_C0() = 0; + virtual void compute_new_positions_C1() = 0; + + + +protected: + + // misc helpers + + const Point& orig_position(VertexHandle _vh) const + { return mesh_.property(original_positions_, _vh); } + + const NormalType& orig_normal(VertexHandle _vh) const + { return mesh_.property(original_normals_, _vh); } + + const Point& new_position(VertexHandle _vh) const + { return mesh_.property(new_positions_, _vh); } + + void set_new_position(VertexHandle _vh, const Point& _p) + { mesh_.property(new_positions_, _vh) = _p; } + + bool is_active(VertexHandle _vh) const + { return mesh_.property(is_active_, _vh); } + + Component component() const { return component_; } + Continuity continuity() const { return continuity_; } + +protected: + + Mesh& mesh_; + bool skip_features_; + + +private: + + Scalar tolerance_; + Scalar normal_deviation_; + Component component_; + Continuity continuity_; + + OpenMesh::VPropHandleT original_positions_; + OpenMesh::VPropHandleT original_normals_; + OpenMesh::VPropHandleT new_positions_; + OpenMesh::VPropHandleT is_active_; +}; + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SMOOTHERT_C) +#define OPENMESH_SMOOTHERT_TEMPLATES +#include "SmootherT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SMOOTHER_SMOOTHERT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/smooth_mesh.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/smooth_mesh.hh new file mode 100644 index 0000000..fad9d67 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Smoother/smooth_mesh.hh @@ -0,0 +1,110 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef SMOOTH_MESH_HH +#define SMOOTH_MESH_HH + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { //BEGIN_NS_OPENMESH + +template +void smooth_mesh_property(unsigned int _n_iters, _Mesh& _m, _PropertyHandle _pph) +{ + typedef typename _PropertyHandle::Value Value; + + std::vector temp_values(_m.n_vertices()); + + for (unsigned int i=0; i < _n_iters; ++i) + { + for ( typename _Mesh::ConstVertexIter cv_it = _m.vertices_begin(); + cv_it != _m.vertices_end(); ++cv_it) + { + unsigned int valence = 0; + + Value& temp_value = temp_values[cv_it->idx()]; + + temp_value.vectorize(0); + + for ( typename _Mesh::ConstVertexVertexIter cvv_it = _m.cvv_iter(cv_it); + cvv_it; ++cvv_it) + { + temp_value += _m.property(_pph,cvv_it); + ++valence; + } + if (valence > 0) + {//guard against isolated vertices + temp_value *= (typename Value::value_type)(1.0 / valence); + } + else + { + temp_value = _m.property(_pph, cv_it); + } + } + + for ( typename _Mesh::ConstVertexIter cv_it = _m.vertices_begin(); + cv_it != _m.vertices_end(); ++cv_it) + { + _m.property(_pph,cv_it) = temp_values[cv_it->idx()]; + } + } +} + +template +void smooth_mesh(_Mesh& _m, uint _n_iters) +{ + smooth_mesh_property(_n_iters, _m, _m.points_pph()); +} + +};//namespace OpenMesh + +#endif//SMOOTH_MESH_HH diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeT.cc new file mode 100644 index 0000000..049f568 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeT.cc @@ -0,0 +1,324 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Adaptive/Composite/CompositeT.cc + + */ + +//============================================================================= +// +// CLASS CompositeT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== IMPLEMENTATION ========================================================== + + +template +bool +CompositeT :: +initialize( void ) +{ + typename Mesh::VertexIter v_it; + typename Mesh::FaceIter f_it; + typename Mesh::EdgeIter e_it; + const typename Mesh::Point zero_point(0.0, 0.0, 0.0); + + // ---------------------------------------- Init Vertices + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + mesh_.data(*v_it).set_state(0); + mesh_.data(*v_it).set_final(); + mesh_.data(*v_it).set_position(0, mesh_.point(*v_it)); + } + + // ---------------------------------------- Init Faces + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) + { + mesh_.data(*f_it).set_state(0); + mesh_.data(*f_it).set_final(); + mesh_.data(*f_it).set_position(0, zero_point); + } + + // ---------------------------------------- Init Edges + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) + { + mesh_.data(*e_it).set_state(0); + mesh_.data(*e_it).set_final(); + mesh_.data(*e_it).set_position(0, zero_point); + } + + + // ---------------------------------------- Init Rules + + int n_subdiv_rules_ = 0; + + + // look for subdivision rule(s) + for (size_t i=0; i < n_rules(); ++i) { + + if (rule_sequence_[i]->type()[0] == 'T' || + rule_sequence_[i]->type()[0] == 't') + { + ++n_subdiv_rules_; + subdiv_rule_ = rule_sequence_[i]; + subdiv_type_ = rule_sequence_[i]->subdiv_type(); + } + } + + + // check for correct number of subdivision rules + assert(n_subdiv_rules_ == 1); + + if (n_subdiv_rules_ != 1) + { + ::omerr() << "Error! More than one subdivision rules not allowed!\n"; + return false; + } + + // check for subdivision type + assert(subdiv_type_ == 3 || subdiv_type_ == 4); + + if (subdiv_type_ != 3 && subdiv_type_ != 4) + { + ::omerr() << "Error! Unknown subdivision type in sequence!" << std::endl; + return false; + } + + // set pointer to last rule +// first_rule_ = rule_sequence_.front(); +// last_rule_ = rule_sequence_.back(); //[n_rules() - 1]; + + // set numbers and previous rule + for (size_t i = 0; i < n_rules(); ++i) + { + rule_sequence_[i]->set_subdiv_type(subdiv_type_); + rule_sequence_[i]->set_n_rules(n_rules()); + rule_sequence_[i]->set_number(i); + rule_sequence_[i]->set_prev_rule(rule_sequence_[(i+n_rules()-1)%n_rules()]); + rule_sequence_[i]->set_subdiv_rule(subdiv_rule_); + } + + return true; +} + + +// ---------------------------------------------------------------------------- +#define MOBJ mesh_.deref +#define TVH to_vertex_handle +#define HEH halfedge_handle +#define NHEH next_halfedge_handle +#define PHEH prev_halfedge_handle +#define OHEH opposite_halfedge_handle +// ---------------------------------------------------------------------------- + + +template +void CompositeT::refine(typename M::FaceHandle& _fh) +{ + std::vector hh_vector; + + // -------------------- calculate new level for faces and vertices + int new_face_level = + t_rule()->number() + 1 + + ((int)floor((float)(mesh_.data(_fh).state() - t_rule()->number() - 1)/n_rules()) + 1) * n_rules(); + + int new_vertex_level = + new_face_level + l_rule()->number() - t_rule()->number(); + + // -------------------- store old vertices + // !!! only triangle meshes supported! + typename Mesh::VertexHandle vh[3]; + + vh[0] = mesh_.TVH(mesh_.HEH(_fh)); + vh[1] = mesh_.TVH(mesh_.NHEH(mesh_.HEH(_fh))); + vh[2] = mesh_.TVH(mesh_.PHEH(mesh_.HEH(_fh))); + + // save handles to incoming halfedges for getting the new vertices + // after subdivision (1-4 split) + if (subdiv_type_ == 4) + { + hh_vector.clear(); + + // green face + if (mesh_.data(_fh).final()) + { + typename Mesh::FaceHalfedgeIter fh_it(mesh_.fh_iter(_fh)); + + for (; fh_it.is_valid(); ++fh_it) + { + hh_vector.push_back(mesh_.PHEH(mesh_.OHEH(*fh_it))); + } + } + + // red face + else + { + + typename Mesh::HalfedgeHandle red_hh(mesh_.data(_fh).red_halfedge()); + + hh_vector.push_back(mesh_.PHEH(mesh_.OHEH(mesh_.NHEH(red_hh)))); + hh_vector.push_back(mesh_.PHEH(mesh_.OHEH(mesh_.PHEH(mesh_.OHEH(red_hh))))); + } + } + + + // -------------------- Average rule before topo rule? + if (t_rule()->number() > 0) + t_rule()->prev_rule()->raise(_fh, new_face_level-1); + + // -------------------- Apply topological operator first + t_rule()->raise(_fh, new_face_level); + +#if 0 // original code + assert(MOBJ(_fh).state() >= + subdiv_rule_->number()+1+(int) (MOBJ(_fh).state()/n_rules())*n_rules()); +#else // improved code (use % operation and avoid floating point division) + assert( mesh_.data(_fh).state() >= ( t_rule()->number()+1+generation(_fh) ) ); +#endif + + // raise new vertices to final levels + if (subdiv_type_ == 3) + { + typename Mesh::VertexHandle new_vh(mesh_.TVH(mesh_.NHEH(mesh_.HEH(_fh)))); + + // raise new vertex to final level + l_rule()->raise(new_vh, new_vertex_level); + } + + if (subdiv_type_ == 4) + { + typename Mesh::HalfedgeHandle hh; + typename Mesh::VertexHandle new_vh; + + while (!hh_vector.empty()) { + + hh = hh_vector.back(); + hh_vector.pop_back(); + + // get new vertex + new_vh = mesh_.TVH(mesh_.NHEH(hh)); + + // raise new vertex to final level + l_rule()->raise(new_vh, new_vertex_level); + } + } + + // raise old vertices to final position + l_rule()->raise(vh[0], new_vertex_level); + l_rule()->raise(vh[1], new_vertex_level); + l_rule()->raise(vh[2], new_vertex_level); +} + + +// ---------------------------------------------------------------------------- + + +template +void CompositeT::refine(typename M::VertexHandle& _vh) +{ + // calculate next final level for vertex + int new_vertex_state = generation(_vh) + l_rule()->number() + 1; + + // raise vertex to final position + l_rule()->raise(_vh, new_vertex_state); +} + + +// ---------------------------------------------------------------------------- + + +template +std::string CompositeT::rules_as_string(const std::string& _sep) const +{ + std::string seq; + typename RuleSequence::const_iterator it = rule_sequence_.begin(); + + if ( it != rule_sequence_.end() ) + { + seq = (*it)->type(); + for (++it; it != rule_sequence_.end(); ++it ) + { + seq += _sep; + seq += (*it)->type(); + } + } + return seq; +} + +// ---------------------------------------------------------------------------- +#undef MOBJ +#undef TVH +#undef HEH +#undef NHEH +#undef PHEH +#undef OHEH +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeT.hh new file mode 100644 index 0000000..c6bb4b0 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeT.hh @@ -0,0 +1,316 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Adaptive/Composite/CompositeT.hh + + */ + +//============================================================================= +// +// CLASS CompositeT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBDIVIDER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== CLASS DEFINITION ========================================================= + + +template struct RuleHandleT; +template class RuleInterfaceT; + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. + * + * The adaptive composite subdivision framework is based on the work + * done by P. Oswald and P. Schroeder. This framework elevates the + * uniform case of the composite scheme to the adaptive + * setting. + * + * For details on the composite scheme refer to + * - P. Oswald, + * P. Schroeder "Composite primal/dual sqrt(3)-subdivision schemes", + * CAGD 20, 3, 2003, 135--164 + * + * For details on the transition from uniform to adaptive composite + * subdivision please refer to + * - A. von Studnitz, + * A. Sovakar, L. Kobbelt "API Design for Adaptive Subdivision + * Schemes" OpenSG Symposium 2003 + * + * In the composite scheme a subdivision operator is created by + * combining smaller "atomic" rules. Depending on the selection and + * ordering of the operator many known subdivision schemes can be + * created. + * + * Every rule inherits from RuleInterfaceT and is represented out of + * the subdivider object by a RuleHandleT (as usual within + * %OpenMesh). You can add rules using the CompositeT::add() + * functions. The correct order of adding the rules is very + * important, and furthermore not all rules get along with each other + * very well. (Please read the given literature, especially the + * paper by Oswald and Schr�der.) + * + * To use a composite subdivider first define a rule sequence + * describing the order of execution of the rules. In the order the + * rules habe been added they will be executed. E.g. the rules given + * in operator notation have to added from right to left. + * + * After the rule sequence has been defined the subdivider has to be + * intialized using CompositeT::initialize(). If everything went well, + * use CompositeT::refine() to subdivide locally a face or vertex. + * + * \note Not all (topological) operators have been implemented! + * \note Only triangle meshes are supported. + * \note The rule sequence must begin with a topological operator. + * + * \see RuleInterfaceT, RuleHandleT + * + */ +template class CompositeT +{ +public: + + typedef RuleInterfaceT Rule; + typedef M Mesh; + typedef std::vector RuleSequence; + + typedef typename M::VertexHandle VH; + typedef typename M::FaceHandle FH; + typedef typename M::EdgeHandle EH; + typedef typename M::HalfedgeHandle HH; + +public: + + /// Constructor + CompositeT(Mesh& _mesh) + : subdiv_type_(0), + subdiv_rule_(NULL), /*first_rule_(NULL), last_rule_(NULL),*/ mesh_(_mesh) + { } + + /// + virtual ~CompositeT() + { cleanup(); } + + + /// Reset \c self to state after the default constructor except of + /// the mesh. + void cleanup(void) + { + subdiv_type_ = 0; + subdiv_rule_ = NULL; + + std::for_each(rule_sequence_.begin(), + rule_sequence_.end(), DeleteRule() ); + rule_sequence_.clear(); + } + + + /// Initialize faces, edges, vertices, and rules + bool initialize(void); + + + /// Refine one face. + void refine(typename M::FaceHandle& _fh); + + + /// Raise one vertex to next final level. + void refine(typename M::VertexHandle& _vh); + + + /// Return subdivision split type (3 for 1-to-3 split, 4 for 1-to-4 split). + int subdiv_type() { return subdiv_type_; } + + + // Return subdivision rule. + const Rule& subdiv_rule() const { return *subdiv_rule_; } + +public: + + /// \name Managing composite rules + //*@ + + /** Add new rule to rule sequence by passing the type of the wanted + * rule as template argument to the method. + * \return Valid handle on success. Else it is invalid. + */ + template < typename R > + RuleHandleT add() + { + size_t idx = rule_sequence_.size(); + rule_sequence_.push_back( new R( mesh_ ) ); + return RuleHandleT( (idx < rule_sequence_.size()) ? idx : -1 ); + } + + /** Add new rule to rule sequence by passing an appropriate handle + * to the method. + * \return Valid handle on success. Else it is invalid. + */ + template < typename R > + RuleHandleT& add( RuleHandleT& _rh ) + { + return _rh = add< R >(); + } + + /** Get rule in the rule sequence by a handle. + * + * \return The wanted rule if the handle is valid. The return value + * is undefined if the handle is invalid! + */ + template < typename R > + typename RuleHandleT::Rule& rule( const RuleHandleT& _rh ) + { + typedef typename RuleHandleT::Rule rule_t; + assert( _rh.is_valid() ); + return *dynamic_cast(rule_sequence_[ _rh.idx() ]); + } + + + /** Get rule (interface) by index + * + * \return The wanted rule if the handle is valid. The return value + * is undefined if the handle is invalid! + */ + RuleInterfaceT& rule( size_t _idx ) + { + assert( _idx < n_rules() ); + return *rule_sequence_[ _idx ]; + } + + /// Number of rules in the rule sequence + size_t n_rules() const { return rule_sequence_.size(); } + + /// Return the sequence as string + std::string rules_as_string(const std::string& _sep= " * ") const; + + //@} + +protected: + + /// The rule sequence + const RuleSequence& rules() const { return rule_sequence_; } + +protected: // helper + + // get current generation from state + state_t generation(state_t _s) { return _s-(_s % n_rules()); } + state_t generation( VH _vh ) { return generation(mesh_.data(_vh).state()); } + state_t generation( EH _eh ) { return generation(mesh_.data(_eh).state()); } + state_t generation( FH _fh ) { return generation(mesh_.data(_fh).state()); } + +private: + + // short cuts + Rule* t_rule() { return subdiv_rule_; } + Rule* f_rule() { return rule_sequence_.front(); } + Rule* l_rule() { return rule_sequence_.back(); } + +private: + + // + RuleSequence rule_sequence_; + + // Split type + int subdiv_type_; + + Rule *subdiv_rule_; +// Rule *first_rule_; +// Rule *last_rule_; + + // + Mesh &mesh_; + +private: // helper + +#ifndef DOXY_IGNORE_THIS + struct DeleteRule { void operator()( Rule* _r ) { delete _r; } }; +#endif + +private: + + CompositeT( const CompositeT& ); + CompositeT& operator = ( const CompositeT ); + +}; + + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_CC) +# define OPENMESH_SUBDIVIDER_TEMPLATES +# include "CompositeT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeTraits.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeTraits.hh new file mode 100644 index 0000000..d930d06 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/CompositeTraits.hh @@ -0,0 +1,265 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Subdivider/Adaptive/Composite/CompositeTraits.hh + Mesh traits for adaptive composite subdivider. + */ + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITETRAITS_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITETRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. +*/ + +// typedef unsigned short state_t; +// const state_t mask_final = 1 << ((sizeof(state_t)*8)-1); +// const state_t mask_state = ~mask_final; + +/** Mesh traits for adaptive composite subdivision + */ +struct CompositeTraits : public OpenMesh::DefaultTraits +{ + typedef int state_t; ///< External representation for intermediate state + typedef bool final_t; ///< External representation for final flag + + + /// Storage type for intermediate states and the final flag of a mesh entity. + struct State + { + int state : 31; + unsigned final : 1; + }; + + // ---------------------------------------- attributes + + // add face normals + FaceAttributes( OpenMesh::Attributes::Normal ); + + // add vertex normals + VertexAttributes( OpenMesh::Attributes::Normal ); + + // add previous halfedge handle + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + // ---------------------------------------- items + + FaceTraits + { + + private: + + typedef typename Refs::Point Point; + typedef typename Refs::HalfedgeHandle HalfedgeHandle; + typedef std::map PositionHistory; + + State state_; + HalfedgeHandle red_halfedge_; + + PositionHistory pos_map_; + + public: + + // face state + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // face not final if divided (loop) or edge not flipped (sqrt(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // halfedge of dividing edge (red-green triangulation) + const HalfedgeHandle& red_halfedge() const { return red_halfedge_; } + void set_red_halfedge(const HalfedgeHandle& _h) { red_halfedge_ = _h; } + + // position of face, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + if (pos_map_.find(_i) != pos_map_.end()) + return pos_map_[_i]; + else { + + if (_i <= 0) { + return Point(0.0, 0.0, 0.0); + } + + return position(_i - 1); + } + } + }; // end class FaceTraits + + + EdgeTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + PositionHistory pos_map_; + + public: + + typedef typename Refs::Scalar Scalar; + + // Scalar weight_; + + // state of edge + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // edge not final if dividing face (Loop) or edge not flipped (SQRT(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of edge, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + return pos_map_[_i]; + else + { + if (_i <= 0) + { + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class EdgeTraits + + + VertexTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + PositionHistory pos_map_; + + public: + + // state of vertex + state_t state() const { return state_.state; } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + + // usually not needed by loop or sqrt(3) + final_t final() const { return state_.final; } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of vertex, depending on generation _i. (not for display) + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + + return pos_map_[_i]; + + else { + + if (_i <= 0) { + + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class VertexTraits +}; // end class CompositeTraits + + +// export items to namespace to maintain compatibility +typedef CompositeTraits::state_t state_t; +typedef CompositeTraits::final_t final_t; +typedef CompositeTraits::State State; + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITETRAITS_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh new file mode 100644 index 0000000..33046b5 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh @@ -0,0 +1,407 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS RuleInterfaceT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_RULEINTERFACET_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_RULEINTERFACET_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBDIVIDER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== FORWARDS ================================================================= + +template class CompositeT; +template class RuleInterfaceT; + +//== CLASS DEFINITION ========================================================= + + +// ---------------------------------------------------------------------------- + +/** Handle template for adaptive composite subdividion rules + * \internal + * + * Use typed handle of a rule, e.g. Tvv3::Handle. + */ +template < typename R > +struct RuleHandleT : public BaseHandle +{ + explicit RuleHandleT(int _idx=-1) : BaseHandle(_idx) {} + typedef R Rule; + + operator bool() const { return is_valid(); } + +}; + +/** Defines the method type() (RuleInterfaceT::type()) and the + * typedefs Self and Handle. + */ +#define COMPOSITE_RULE( classname, mesh_type ) \ + protected:\ + friend class CompositeT; \ + public: \ + const char *type() const { return #classname; } \ + typedef classname Self; \ + typedef RuleHandleT< Self > Handle + + +// ---------------------------------------------------------------------------- +/** Base class for adaptive composite subdivision rules + * \see class CompositeT + */ +template class RuleInterfaceT +{ +public: + + typedef M Mesh; + typedef RuleInterfaceT Self; + typedef RuleHandleT< Self > Rule; + + typedef typename M::Scalar scalar_t; + +protected: + + /// Default constructor + RuleInterfaceT(Mesh& _mesh) : mesh_(_mesh) {}; + +public: + + /// Destructor + virtual ~RuleInterfaceT() {}; + + + /// Returns the name of the rule. + /// Use define COMPOSITE_RULE to overload this function in a derived class. + virtual const char *type() const = 0; + +public: + + /// \name Raise item + //@{ + /// Raise item to target state \c _target_state. + virtual void raise(typename M::FaceHandle& _fh, state_t _target_state) + { + if (mesh_.data(_fh).state() < _target_state) { + update(_fh, _target_state); + mesh_.data(_fh).inc_state(); + } + } + + virtual void raise(typename M::EdgeHandle& _eh, state_t _target_state) + { + if (mesh_.data(_eh).state() < _target_state) { + update(_eh, _target_state); + mesh_.data(_eh).inc_state(); + } + } + + virtual void raise(typename M::VertexHandle& _vh, state_t _target_state) + { + if (mesh_.data(_vh).state() < _target_state) { + update(_vh, _target_state); + mesh_.data(_vh).inc_state(); + } + } + //@} + + void update(typename M::FaceHandle& _fh, state_t _target_state) + { + typename M::FaceHandle opp_fh; + + while (mesh_.data(_fh).state() < _target_state - 1) { + prev_rule()->raise(_fh, _target_state - 1); + } + + // Don't use unflipped / unfinal faces!!! + if (subdiv_type() == 3) { + + if (mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.halfedge_handle(_fh))).is_valid()) { + + while (!mesh_.data(_fh).final()) { + + opp_fh = mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.halfedge_handle(_fh))); + + assert (mesh_.data(_fh).state() >= + mesh_.data(opp_fh).state()); + + // different states: raise other face + if (mesh_.data(_fh).state() > mesh_.data(opp_fh).state()){ + + // raise opposite face + prev_rule()->raise(opp_fh, _target_state - 1); + } + + else { + + // equal states + + // flip edge + // typename M::EdgeHandle eh(mesh_.edge_handle(mesh_.halfedge_handle(_fh))); + + // if (mesh_.is_flip_ok(eh)) { + + // std::cout << "Flipping Edge...\n"; + + // mesh_.flip(eh); + + // mesh_.data(_fh).set_final(); + // mesh_.data(opp_fh).set_final(); + // } + + // else { + + // std::cout << "Flip not okay.\n"; + // } + } + } + } + + else { + + // mesh_.data(_fh).set_final(); + } + + // std::cout << "Raising Face to Level " + // << _target_state + // << " with " + // << type() + // << ".\n"; + + } + + assert( subdiv_type() != 4 || + mesh_.data(_fh).final() || + _target_state%n_rules() == (subdiv_rule()->number() + 1)%n_rules() ); + + typename M::FaceEdgeIter fe_it; + typename M::FaceVertexIter fv_it; + typename M::EdgeHandle eh; + typename M::VertexHandle vh; + + std::vector face_vector; + face_vector.clear(); + + if (_target_state > 1) { + + for (fe_it = mesh_.fe_iter(_fh); fe_it.is_valid(); ++fe_it) { + + eh = *fe_it; + prev_rule()->raise(eh, _target_state - 1); + } + + for (fv_it = mesh_.fv_iter(_fh); fv_it.is_valid(); ++fv_it) { + + vh = *fv_it; + prev_rule()->raise(vh, _target_state - 1); + } + } + } + + + void update(typename M::EdgeHandle& _eh, state_t _target_state) + { + state_t state(mesh_.data(_eh).state()); + + // raise edge to correct state + if (state + 1 < _target_state && _target_state > 0) { + + prev_rule()->raise(_eh, _target_state - 1); + } + + typename M::VertexHandle vh; + typename M::FaceHandle fh; + + if (_target_state > 1) + { + vh = mesh_.to_vertex_handle(mesh_.halfedge_handle(_eh, 0)); + prev_rule()->raise(vh, _target_state - 1); + + vh = mesh_.to_vertex_handle(mesh_.halfedge_handle(_eh, 1)); + prev_rule()->raise(vh, _target_state - 1); + + fh = mesh_.face_handle(mesh_.halfedge_handle(_eh, 0)); + if (fh.is_valid()) + prev_rule()->raise(fh, _target_state - 1); + + fh = mesh_.face_handle(mesh_.halfedge_handle(_eh, 1)); + if (fh.is_valid()) + prev_rule()->raise(fh, _target_state - 1); + } + } + + + void update(typename M::VertexHandle& _vh, state_t _target_state) { + + state_t state(mesh_.data(_vh).state()); + + // raise vertex to correct state + if (state + 1 < _target_state) + { + prev_rule()->raise(_vh, _target_state - 1); + } + + std::vector halfedge_vector; + halfedge_vector.clear(); + + typename M::VertexOHalfedgeIter voh_it; + typename M::EdgeHandle eh; + typename M::FaceHandle fh; + + if (_target_state > 1) + { + + for (voh_it = mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + halfedge_vector.push_back(*voh_it); + } + + while ( !halfedge_vector.empty() ) { + eh = mesh_.edge_handle(halfedge_vector.back()); + halfedge_vector.pop_back(); + + prev_rule()->raise(eh, _target_state - 1); + } + + for (voh_it = mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + halfedge_vector.push_back(*voh_it); + } + + while ( !halfedge_vector.empty() ) { + fh = mesh_.face_handle(halfedge_vector.back()); + halfedge_vector.pop_back(); + + if (fh.is_valid()) + prev_rule()->raise(fh, _target_state - 1); + } + } + } + +public: + + + /// Type of split operation, if it is a topological operator + int subdiv_type() const { return subdiv_type_; } + + + /// Position in rule sequence + int number() const { return number_; } + + /// \name Parameterization of rule + //@{ + + /// Set coefficient - ignored by non-parameterized rules. + virtual void set_coeff( scalar_t _coeff ) { coeff_ = _coeff; } + + /// Get coefficient - ignored by non-parameterized rules. + scalar_t coeff() const { return coeff_; } + + //@} + +protected: + + void set_prev_rule(Self*& _p) { prev_rule_ = _p; } + Self* prev_rule() { return prev_rule_; } + + void set_subdiv_rule(Self*& _n) { subdiv_rule_ = _n; } + Self* subdiv_rule() { return subdiv_rule_; } + + void set_number(int _n) { number_ = _n; } + + void set_n_rules(int _n) { n_rules_ = _n; } + int n_rules() { return n_rules_; } + + void set_subdiv_type(int _n) + { assert(_n == 3 || _n == 4); subdiv_type_ = _n; } + + friend class CompositeT; + +protected: + + Mesh& mesh_; + +private: + + Self* prev_rule_; + Self* subdiv_rule_; + + int subdiv_type_; + int number_; + int n_rules_; + + scalar_t coeff_; + +private: // Noncopyable + + RuleInterfaceT(const RuleInterfaceT&); + RuleInterfaceT& operator=(const RuleInterfaceT&); + +}; + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_RULEINTERFACET_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RulesT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RulesT.cc new file mode 100644 index 0000000..1213cab --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RulesT.cc @@ -0,0 +1,2029 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file RulesT.cc + + */ + +//============================================================================= +// +// Rules - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include "RulesT.hh" +// -------------------- +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +#if defined(OM_CC_MSVC) +# pragma warning(disable:4244) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== IMPLEMENTATION ========================================================== + +#define MOBJ Base::mesh_.data +#define FH face_handle +#define VH vertex_handle +#define EH edge_handle +#define HEH halfedge_handle +#define NHEH next_halfedge_handle +#define PHEH prev_halfedge_handle +#define OHEH opposite_halfedge_handle +#define TVH to_vertex_handle +#define FVH from_vertex_handle + +// ------------------------------------------------------------------ Tvv3 ---- + + +template +void +Tvv3::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + if (MOBJ(_fh).state() < _target_state) + { + this->update(_fh, _target_state); + + typename M::VertexVertexIter vv_it; + typename M::FaceVertexIter fv_it; + typename M::VertexHandle vh; + typename M::Point position(0.0, 0.0, 0.0); + typename M::Point face_position; + const typename M::Point zero_point(0.0, 0.0, 0.0); + std::vector vertex_vector; + + + // raise all adjacent vertices to level x-1 + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it.is_valid(); ++fv_it) { + + vertex_vector.push_back(*fv_it); + } + + while(!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + if (_target_state > 1) + Base::prev_rule()->raise(vh, _target_state - 1); + } + + face_position = MOBJ(_fh).position(_target_state - 1); + + typename M::EdgeHandle eh; + std::vector edge_vector; + + // interior face + if (!Base::mesh_.is_boundary(_fh) || MOBJ(_fh).final()) { + + // insert new vertex + vh = Base::mesh_.new_vertex(); + + Base::mesh_.split(_fh, vh); + + typename M::Scalar valence(0.0); + + // calculate display position for new vertex + for (vv_it = Base::mesh_.vv_iter(vh); vv_it.is_valid(); ++vv_it) + { + position += Base::mesh_.point(*vv_it); + valence += 1.0; + } + + position /= valence; + + // set attributes for new vertex + Base::mesh_.set_point(vh, position); + MOBJ(vh).set_position(_target_state, zero_point); + MOBJ(vh).set_state(_target_state); + MOBJ(vh).set_not_final(); + + typename M::VertexOHalfedgeIter voh_it; + // check for edge flipping + for (voh_it = Base::mesh_.voh_iter(vh); voh_it.is_valid(); ++voh_it) { + + if (Base::mesh_.FH(*voh_it).is_valid()) { + + MOBJ(Base::mesh_.FH(*voh_it)).set_state(_target_state); + MOBJ(Base::mesh_.FH(*voh_it)).set_not_final(); + MOBJ(Base::mesh_.FH(*voh_it)).set_position(_target_state - 1, face_position); + + + for (state_t j = 0; j < _target_state; ++j) { + MOBJ(Base::mesh_.FH(*voh_it)).set_position(j, MOBJ(_fh).position(j)); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it))).is_valid()) { + + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it)))).state() == _target_state) { + + if (Base::mesh_.is_flip_ok(Base::mesh_.EH(Base::mesh_.NHEH(*voh_it)))) { + + edge_vector.push_back(Base::mesh_.EH(Base::mesh_.NHEH(*voh_it))); + } + } + } + } + } + } + + // boundary face + else { + + typename M::VertexHandle vh1 = Base::mesh_.new_vertex(), + vh2 = Base::mesh_.new_vertex(); + + typename M::HalfedgeHandle hh2 = Base::mesh_.HEH(_fh), + hh1, hh3; + + while (!Base::mesh_.is_boundary(Base::mesh_.OHEH(hh2))) + hh2 = Base::mesh_.NHEH(hh2); + + eh = Base::mesh_.EH(hh2); + + hh2 = Base::mesh_.NHEH(hh2); + hh1 = Base::mesh_.NHEH(hh2); + + assert(Base::mesh_.is_boundary(eh)); + + Base::mesh_.split(eh, vh1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh2)); + + assert(Base::mesh_.is_boundary(eh)); + + Base::mesh_.split(eh, vh2); + + hh3 = Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(hh1))); + + typename M::VertexHandle vh0(Base::mesh_.TVH(hh1)), + vh3(Base::mesh_.FVH(hh2)); + + // set display position and attributes for new vertices + Base::mesh_.set_point(vh1, (Base::mesh_.point(vh0) * static_cast(2.0) + Base::mesh_.point(vh3)) / static_cast(3.0) ); + + MOBJ(vh1).set_position(_target_state, zero_point); + MOBJ(vh1).set_state(_target_state); + MOBJ(vh1).set_not_final(); + + MOBJ(vh0).set_position(_target_state, MOBJ(vh0).position(_target_state - 1) * static_cast(3.0)); + MOBJ(vh0).set_state(_target_state); + MOBJ(vh0).set_not_final(); + + // set display position and attributes for old vertices + Base::mesh_.set_point(vh2, (Base::mesh_.point(vh3) * static_cast(2.0) + Base::mesh_.point(vh0)) / static_cast(3.0) ); + MOBJ(vh2).set_position(_target_state, zero_point); + MOBJ(vh2).set_state(_target_state); + MOBJ(vh2).set_not_final(); + + MOBJ(vh3).set_position(_target_state, MOBJ(vh3).position(_target_state - 1) * static_cast(3.0) ); + MOBJ(vh3).set_state(_target_state); + MOBJ(vh3).set_not_final(); + + // init 3 faces + MOBJ(Base::mesh_.FH(hh1)).set_state(_target_state); + MOBJ(Base::mesh_.FH(hh1)).set_not_final(); + MOBJ(Base::mesh_.FH(hh1)).set_position(_target_state - 1, face_position); + + MOBJ(Base::mesh_.FH(hh2)).set_state(_target_state); + MOBJ(Base::mesh_.FH(hh2)).set_not_final(); + MOBJ(Base::mesh_.FH(hh2)).set_position(_target_state - 1, face_position); + + MOBJ(Base::mesh_.FH(hh3)).set_state(_target_state); + MOBJ(Base::mesh_.FH(hh3)).set_final(); + MOBJ(Base::mesh_.FH(hh3)).set_position(_target_state - 1, face_position); + + + for (state_t j = 0; j < _target_state; ++j) { + MOBJ(Base::mesh_.FH(hh1)).set_position(j, MOBJ(_fh).position(j)); + } + + for (state_t j = 0; j < _target_state; ++j) { + + MOBJ(Base::mesh_.FH(hh2)).set_position(j, MOBJ(_fh).position(j)); + } + + for (state_t j = 0; j < _target_state; ++j) { + + MOBJ(Base::mesh_.FH(hh3)).set_position(j, MOBJ(_fh).position(j)); + } + + // check for edge flipping + if (Base::mesh_.FH(Base::mesh_.OHEH(hh1)).is_valid()) { + + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(hh1))).state() == _target_state) { + + if (Base::mesh_.is_flip_ok(Base::mesh_.EH(hh1))) { + + edge_vector.push_back(Base::mesh_.EH(hh1)); + } + } + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh2)).is_valid()) { + + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(hh2))).state() == _target_state) { + + if (Base::mesh_.is_flip_ok(Base::mesh_.EH(hh2))) { + + edge_vector.push_back(Base::mesh_.EH(hh2)); + } + } + } + } + + // flip edges + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + assert(Base::mesh_.is_flip_ok(eh)); + + Base::mesh_.flip(eh); + + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 0))).set_final(); + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 1))).set_final(); + + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 0))).set_state(_target_state); + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 1))).set_state(_target_state); + + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 0))).set_position(_target_state, face_position); + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 1))).set_position(_target_state, face_position); + } + } +} + + +template +void Tvv3::raise(typename M::VertexHandle& _vh, state_t _target_state) { + + if (MOBJ(_vh).state() < _target_state) { + + this->update(_vh, _target_state); + + // multiply old position by 3 + MOBJ(_vh).set_position(_target_state, MOBJ(_vh).position(_target_state - 1) * static_cast(3.0) ); + + MOBJ(_vh).inc_state(); + + assert(MOBJ(_vh).state() == _target_state); + } +} + + +// ------------------------------------------------------------------ Tvv4 ---- + + +template +void +Tvv4::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + + if (MOBJ(_fh).state() < _target_state) { + + this->update(_fh, _target_state); + + typename M::FaceVertexIter fv_it; + typename M::VertexHandle temp_vh; + typename M::Point face_position; + const typename M::Point zero_point(0.0, 0.0, 0.0); + std::vector vertex_vector; + std::vector halfedge_vector; + + // raise all adjacent vertices to level x-1 + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it.is_valid(); ++fv_it) { + + vertex_vector.push_back(*fv_it); + } + + while(!vertex_vector.empty()) { + + temp_vh = vertex_vector.back(); + vertex_vector.pop_back(); + + if (_target_state > 1) { + Base::prev_rule()->raise(temp_vh, _target_state - 1); + } + } + + face_position = MOBJ(_fh).position(_target_state - 1); + + typename M::HalfedgeHandle hh[3]; + typename M::VertexHandle vh[3]; + typename M::VertexHandle new_vh[3]; + typename M::FaceHandle fh[4]; + typename M::EdgeHandle eh; + typename M::HalfedgeHandle temp_hh; + + // normal (final) face + if (MOBJ(_fh).final()) { + + // define three halfedge handles around the face + hh[0] = Base::mesh_.HEH(_fh); + hh[1] = Base::mesh_.NHEH(hh[0]); + hh[2] = Base::mesh_.NHEH(hh[1]); + + assert(hh[0] == Base::mesh_.NHEH(hh[2])); + + vh[0] = Base::mesh_.TVH(hh[0]); + vh[1] = Base::mesh_.TVH(hh[1]); + vh[2] = Base::mesh_.TVH(hh[2]); + + new_vh[0] = Base::mesh_.add_vertex(zero_point); + new_vh[1] = Base::mesh_.add_vertex(zero_point); + new_vh[2] = Base::mesh_.add_vertex(zero_point); + + // split three edges + split_edge(hh[0], new_vh[0], _target_state); + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh[2])); + split_edge(hh[1], new_vh[1], _target_state); + split_edge(hh[2], new_vh[2], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[0])).is_valid()) + { + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[0]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[1])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[1]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[2])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[2]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + + // splitted face, check for type + else { + + // define red halfedge handle + typename M::HalfedgeHandle red_hh(MOBJ(_fh).red_halfedge()); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))).is_valid() + && Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))).is_valid() + && MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))).red_halfedge() == red_hh + && MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))).red_halfedge() == red_hh) + { + + // three times divided face + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + new_vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + hh[0] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))); + hh[2] = Base::mesh_.NHEH(red_hh); + + eh = Base::mesh_.EH(red_hh); + } + + else + { + + if ((Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))).is_valid() && + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))).red_halfedge() + == red_hh ) + || (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))).is_valid() + && MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))).red_halfedge() == red_hh)) + { + + // double divided face + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))).red_halfedge() == red_hh) + { + // first case + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.add_vertex(zero_point); + new_vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + hh[0] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(red_hh)); + hh[2] = Base::mesh_.NHEH(red_hh); + + // split one edge + eh = Base::mesh_.EH(red_hh); + + split_edge(hh[1], new_vh[1], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[1])).is_valid()) + { + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[1]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + else + { + + // second case + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + new_vh[2] = Base::mesh_.add_vertex(zero_point); + + hh[0] = Base::mesh_.PHEH(red_hh); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))); + hh[2] = Base::mesh_.NHEH(red_hh); + + // split one edge + eh = Base::mesh_.EH(red_hh); + + split_edge(hh[2], new_vh[2], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[2])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[2]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + } + + else { + + // one time divided face + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.add_vertex(zero_point); + new_vh[2] = Base::mesh_.add_vertex(zero_point); + + hh[0] = Base::mesh_.PHEH(red_hh); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(red_hh)); + hh[2] = Base::mesh_.NHEH(red_hh); + + // split two edges + eh = Base::mesh_.EH(red_hh); + + split_edge(hh[1], new_vh[1], _target_state); + split_edge(hh[2], new_vh[2], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[1])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[1]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[2])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[2]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + } + } + + // continue here for all cases + + // flip edge + if (Base::mesh_.is_flip_ok(eh)) { + + Base::mesh_.flip(eh); + } + + // search new faces + fh[0] = Base::mesh_.FH(hh[0]); + fh[1] = Base::mesh_.FH(hh[1]); + fh[2] = Base::mesh_.FH(hh[2]); + fh[3] = Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(hh[0]))); + + assert(_fh == fh[0] || _fh == fh[1] || _fh == fh[2] || _fh == fh[3]); + + // init new faces + for (int i = 0; i <= 3; ++i) { + + MOBJ(fh[i]).set_state(_target_state); + MOBJ(fh[i]).set_final(); + MOBJ(fh[i]).set_position(_target_state, face_position); + MOBJ(fh[i]).set_red_halfedge(Base::mesh_.InvalidHalfedgeHandle); + } + + // init new vertices and edges + for (int i = 0; i <= 2; ++i) { + + MOBJ(new_vh[i]).set_position(_target_state, zero_point); + MOBJ(new_vh[i]).set_state(_target_state); + MOBJ(new_vh[i]).set_not_final(); + + Base::mesh_.set_point(new_vh[i], (Base::mesh_.point(vh[i]) + Base::mesh_.point(vh[(i + 2) % 3])) * 0.5); + + MOBJ(Base::mesh_.EH(hh[i])).set_state(_target_state); + MOBJ(Base::mesh_.EH(hh[i])).set_position(_target_state, zero_point); + MOBJ(Base::mesh_.EH(hh[i])).set_final(); + + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh[i]))).set_state(_target_state); + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh[i]))).set_position(_target_state, zero_point); + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh[i]))).set_final(); + + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh[i]))).set_state(_target_state); + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh[i]))).set_position(_target_state, zero_point); + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh[i]))).set_final(); + } + + // check, if opposite triangle needs splitting + while (!halfedge_vector.empty()) { + + temp_hh = halfedge_vector.back(); + halfedge_vector.pop_back(); + + check_edge(temp_hh, _target_state); + } + + assert(MOBJ(fh[0]).state() == _target_state); + assert(MOBJ(fh[1]).state() == _target_state); + assert(MOBJ(fh[2]).state() == _target_state); + assert(MOBJ(fh[3]).state() == _target_state); + } +} + + +template +void +Tvv4::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + + if (MOBJ(_vh).state() < _target_state) + { + + this->update(_vh, _target_state); + + // multiply old position by 4 + MOBJ(_vh).set_position(_target_state, MOBJ(_vh).position(_target_state - 1) * static_cast(4.0)); + + MOBJ(_vh).inc_state(); + } +} + + +template +void +Tvv4::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) + { + this->update(_eh, _target_state); + + typename M::FaceHandle fh(Base::mesh_.FH(Base::mesh_.HEH(_eh, 0))); + + if (!fh.is_valid()) + fh=Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + + raise(fh, _target_state); + + assert(MOBJ(_eh).state() == _target_state); + } +} + +#ifndef DOXY_IGNORE_THIS + +template +void +Tvv4::split_edge(typename M::HalfedgeHandle &_hh, + typename M::VertexHandle &_vh, + state_t _target_state) + { + typename M::HalfedgeHandle temp_hh; + + if (Base::mesh_.FH(Base::mesh_.OHEH(_hh)).is_valid()) + { + if (!MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).final()) + { + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).red_halfedge().is_valid()) + { + temp_hh = MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).red_halfedge(); + } + else + { + // two cases for divided, but not visited face + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh))))).state() + == MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).state()) + { + temp_hh = Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)); + } + + else if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(_hh))))).state() + == MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).state()) + { + temp_hh = Base::mesh_.NHEH(Base::mesh_.OHEH(_hh)); + } + } + } + else + temp_hh = Base::mesh_.InvalidHalfedgeHandle; + } + else + temp_hh = Base::mesh_.InvalidHalfedgeHandle; + + // split edge + Base::mesh_.split(Base::mesh_.EH(_hh), _vh); + + if (Base::mesh_.FVH(_hh) == _vh) + { + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(_hh))))).set_state(MOBJ(Base::mesh_.EH(_hh)).state()); + _hh = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(_hh))); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(_hh)).is_valid()) { + + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))).set_not_final(); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).set_state(_target_state-1); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))).set_state(_target_state-1); + + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).set_not_final(); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))).set_not_final(); + + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))).set_state(_target_state); + + if (temp_hh.is_valid()) { + + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).set_red_halfedge(temp_hh); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))).set_red_halfedge(temp_hh); + } + else { + + typename M::FaceHandle + fh1(Base::mesh_.FH(Base::mesh_.OHEH(_hh))), + fh2(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))); + + MOBJ(fh1).set_red_halfedge(Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))); + MOBJ(fh2).set_red_halfedge(Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))); + + const typename M::Point zero_point(0.0, 0.0, 0.0); + + MOBJ(fh1).set_position(_target_state - 1, zero_point); + MOBJ(fh2).set_position(_target_state - 1, zero_point); + } + } + + // init edges + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh))))).set_state(_target_state - 1); + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh))))).set_final(); + + MOBJ(Base::mesh_.EH(_hh)).set_state(_target_state - 1); + MOBJ(Base::mesh_.EH(_hh)).set_final(); +} + + +template +void Tvv4::check_edge(const typename M::HalfedgeHandle& _hh, + state_t _target_state) +{ + typename M::FaceHandle fh1(Base::mesh_.FH(_hh)), + fh2(Base::mesh_.FH(Base::mesh_.OHEH(_hh))); + + assert(fh1.is_valid()); + assert(fh2.is_valid()); + + typename M::HalfedgeHandle red_hh(MOBJ(fh1).red_halfedge()); + + if (!MOBJ(fh1).final()) { + + assert (MOBJ(fh1).final() == MOBJ(fh2).final()); + assert (!MOBJ(fh1).final()); + assert (MOBJ(fh1).red_halfedge() == MOBJ(fh2).red_halfedge()); + + const typename M::Point zero_point(0.0, 0.0, 0.0); + + MOBJ(fh1).set_position(_target_state - 1, zero_point); + MOBJ(fh2).set_position(_target_state - 1, zero_point); + + assert(red_hh.is_valid()); + + if (!red_hh.is_valid()) { + + MOBJ(fh1).set_state(_target_state - 1); + MOBJ(fh2).set_state(_target_state - 1); + + MOBJ(fh1).set_red_halfedge(_hh); + MOBJ(fh2).set_red_halfedge(_hh); + + MOBJ(Base::mesh_.EH(_hh)).set_not_final(); + MOBJ(Base::mesh_.EH(_hh)).set_state(_target_state - 1); + } + + else { + + MOBJ(Base::mesh_.EH(_hh)).set_not_final(); + MOBJ(Base::mesh_.EH(_hh)).set_state(_target_state - 1); + + raise(fh1, _target_state); + + assert(MOBJ(fh1).state() == _target_state); + } + } +} + + +// -------------------------------------------------------------------- VF ---- + + +template +void VF::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + if (MOBJ(_fh).state() < _target_state) { + + this->update(_fh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::FaceVertexIter fv_it; + typename M::VertexHandle vh; + std::vector vertex_vector; + + if (_target_state > 1) { + + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it.is_valid(); ++fv_it) { + + vertex_vector.push_back(*fv_it); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it.is_valid(); ++fv_it) { + + valence += 1.0; + position += Base::mesh_.data(*fv_it).position(_target_state - 1); + } + + position /= valence; + + // boundary rule + if (Base::number() == Base::subdiv_rule()->number() + 1 && + Base::mesh_.is_boundary(_fh) && + !MOBJ(_fh).final()) + position *= static_cast(0.5); + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + + assert(_target_state == MOBJ(_fh).state()); + } +} + + +// -------------------------------------------------------------------- FF ---- + + +template +void FF::raise(typename M::FaceHandle& _fh, state_t _target_state) { + + if (MOBJ(_fh).state() < _target_state) { + + this->update(_fh, _target_state); + + // raise all neighbor faces to level x-1 + typename M::FaceFaceIter ff_it; + typename M::FaceHandle fh; + std::vector face_vector; + + if (_target_state > 1) { + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it.is_valid(); ++ff_it) { + + face_vector.push_back(*ff_it); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it.is_valid(); ++ff_it) { + + face_vector.push_back(*ff_it); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it.is_valid(); ++ff_it) { + + valence += 1.0; + + position += Base::mesh_.data(*ff_it).position(_target_state - 1); + } + + position /= valence; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + } +} + + +// ------------------------------------------------------------------- FFc ---- + + +template +void FFc::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + if (MOBJ(_fh).state() < _target_state) { + + this->update(_fh, _target_state); + + // raise all neighbor faces to level x-1 + typename M::FaceFaceIter ff_it(Base::mesh_.ff_iter(_fh)); + typename M::FaceHandle fh; + std::vector face_vector; + + if (_target_state > 1) + { + for (; ff_it.is_valid(); ++ff_it) + face_vector.push_back(*ff_it); + + while (!face_vector.empty()) + { + fh = face_vector.back(); + face_vector.pop_back(); + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it.is_valid(); ++ff_it) + face_vector.push_back(*ff_it); + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it.is_valid(); ++ff_it) + { + valence += 1.0; + position += Base::mesh_.data(*ff_it).position(_target_state - 1); + } + + position /= valence; + + // choose coefficient c + typename M::Scalar c = Base::coeff(); + + position *= (static_cast(1.0) - c); + position += MOBJ(_fh).position(_target_state - 1) * c; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + } +} + + +// -------------------------------------------------------------------- FV ---- + + +template +void FV::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + + if (MOBJ(_vh).state() < _target_state) { + + this->update(_vh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::VertexFaceIter vf_it(Base::mesh_.vf_iter(_vh)); + typename M::FaceHandle fh; + std::vector face_vector; + + if (_target_state > 1) { + + for (; vf_it.is_valid(); ++vf_it) { + + face_vector.push_back(*vf_it); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (vf_it = Base::mesh_.vf_iter(_vh); vf_it.is_valid(); ++vf_it) { + + face_vector.push_back(*vf_it); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (vf_it = Base::mesh_.vf_iter(_vh); vf_it.is_valid(); ++vf_it) { + + valence += 1.0; + position += Base::mesh_.data(*vf_it).position(_target_state - 1); + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// ------------------------------------------------------------------- FVc ---- + + +template +void FVc::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) { + + this->update(_vh, _target_state); + + typename M::VertexOHalfedgeIter voh_it; + typename M::FaceHandle fh; + std::vector face_vector; + int valence(0); + + face_vector.clear(); + + // raise all neighbour faces to level x-1 + if (_target_state > 1) { + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + + if (Base::mesh_.FH(*voh_it).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(*voh_it)); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it))).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it)))); + } + } + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + + if (Base::mesh_.FH(*voh_it).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(*voh_it)); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it))).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it)))); + } + } + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + + if (Base::mesh_.FH(*voh_it).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(*voh_it)); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it))).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it)))); + } + } + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar c; +#if 0 + const typename M::Scalar _2pi(2.0*M_PI); + const typename M::Scalar _2over3(2.0/3.0); + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) + { + ++valence; + } + + // choose coefficient c + c = _2over3 * ( cos( _2pi / valence) + 1.0); +#else + valence = Base::mesh_.valence(_vh); + c = typename M::Scalar(coeff(valence)); +#endif + + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + + fh = Base::mesh_.FH(*voh_it); + if (fh.is_valid()) + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it))); + if (fh.is_valid()) + Base::prev_rule()->raise(fh, _target_state - 1); + + if (Base::mesh_.FH(*voh_it).is_valid()) { + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it))).is_valid()) { + + position += MOBJ(Base::mesh_.FH(*voh_it)).position(_target_state - 1) * c; + + position += MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(*voh_it)))).position(_target_state - 1) * ( typename M::Scalar(1.0) - c); + } + else { + + position += MOBJ(Base::mesh_.FH(*voh_it)).position(_target_state - 1); + } + } + + else { + + --valence; + } + } + + position /= typename M::Scalar(valence); + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + assert(MOBJ(_vh).state() == _target_state); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + +template +std::vector FVc::coeffs_; + +template +void FVc::init_coeffs(size_t _max_valence) +{ + if ( coeffs_.size() == _max_valence+1 ) + return; + + if ( coeffs_.size() < _max_valence+1 ) + { + const double _2pi(2.0*M_PI); + const double _2over3(2.0/3.0); + + if (coeffs_.empty()) + coeffs_.push_back(0.0); // dummy for valence 0 + + for(size_t v=coeffs_.size(); v <= _max_valence; ++v) + coeffs_.push_back(_2over3 * ( cos( _2pi / v) + 1.0)); + } +} + + +// -------------------------------------------------------------------- VV ---- + + +template +void VV::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) + { + this->update(_vh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::VertexVertexIter vv_it(Base::mesh_.vv_iter(_vh)); + typename M::VertexHandle vh; + std::vector vertex_vector; + + if (_target_state > 1) { + + for (; vv_it.is_valid(); ++vv_it) { + + vertex_vector.push_back(*vv_it); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + for (; vv_it.is_valid(); ++vv_it) { + + vertex_vector.push_back(*vv_it); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (vv_it = Base::mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it) { + + valence += 1.0; + position += Base::mesh_.data(*vv_it).position(_target_state - 1); + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// ------------------------------------------------------------------- VVc ---- + + +template +void VVc::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) { + + this->update(_vh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::VertexVertexIter vv_it(Base::mesh_.vv_iter(_vh)); + typename M::VertexHandle vh; + std::vector vertex_vector; + + if (_target_state > 1) { + + for (; vv_it.is_valid(); ++vv_it) { + + vertex_vector.push_back(*vv_it); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + for (; vv_it.is_valid(); ++vv_it) { + + vertex_vector.push_back(*vv_it); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + typename M::Scalar c; + + for (vv_it = Base::mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it) + { + valence += 1.0; + position += Base::mesh_.data(*vv_it).position(_target_state - 1); + } + + position /= valence; + + // choose coefficient c + c = Base::coeff(); + + position *= (static_cast(1.0) - c); + position += MOBJ(_vh).position(_target_state - 1) * c; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + if (Base::number() == Base::n_rules() - 1) + { + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// -------------------------------------------------------------------- VE ---- + + +template +void VE::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) { + + this->update(_eh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexHandle vh; + typename M::HalfedgeHandle hh1(Base::mesh_.HEH(_eh, 0)), + hh2(Base::mesh_.HEH(_eh, 1)); + + if (_target_state > 1) { + + vh = Base::mesh_.TVH(hh1); + + Base::prev_rule()->raise(vh, _target_state - 1); + + vh = Base::mesh_.TVH(hh2); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + const typename M::Scalar valence(2.0); + + position += MOBJ(Base::mesh_.TVH(hh1)).position(_target_state - 1); + position += MOBJ(Base::mesh_.TVH(hh2)).position(_target_state - 1); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------- VdE ---- + + +template +void VdE::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) + { + this->update(_eh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::VertexHandle vh; + typename M::HalfedgeHandle hh1(Base::mesh_.HEH(_eh, 0)), + hh2(Base::mesh_.HEH(_eh, 1)); + typename M::FaceHandle fh1, fh2; + + if (_target_state > 1) { + + fh1 = Base::mesh_.FH(hh1); + fh2 = Base::mesh_.FH(hh2); + + if (fh1.is_valid()) { + + Base::prev_rule()->raise(fh1, _target_state - 1); + + vh = Base::mesh_.TVH(Base::mesh_.NHEH(hh1)); + Base::prev_rule()->raise(vh, _target_state - 1); + } + + if (fh2.is_valid()) { + + Base::prev_rule()->raise(fh2, _target_state - 1); + + vh = Base::mesh_.TVH(Base::mesh_.NHEH(hh2)); + Base::prev_rule()->raise(vh, _target_state - 1); + } + + vh = Base::mesh_.TVH(hh1); + Base::prev_rule()->raise(vh, _target_state - 1); + + vh = Base::mesh_.TVH(hh2); + Base::prev_rule()->raise(vh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(2.0); + + position += MOBJ(Base::mesh_.TVH(hh1)).position(_target_state - 1); + position += MOBJ(Base::mesh_.TVH(hh2)).position(_target_state - 1); + + if (fh1.is_valid()) { + + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))).position(_target_state - 1); + valence += 1.0; + } + + if (fh2.is_valid()) { + + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))).position(_target_state - 1); + valence += 1.0; + } + + if (Base::number() == Base::subdiv_rule()->Base::number() + 1) + valence = 4.0; + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------ VdEc ---- + + +template +void +VdEc::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) + { + this->update(_eh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::VertexHandle vh; + typename M::HalfedgeHandle hh1(Base::mesh_.HEH(_eh, 0)), + hh2(Base::mesh_.HEH(_eh, 1)); + std::vector vertex_vector; + typename M::FaceHandle fh1, fh2; + + if (_target_state > 1) { + + fh1 = Base::mesh_.FH(Base::mesh_.HEH(_eh, 0)); + fh2 = Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + + Base::prev_rule()->raise(fh1, _target_state - 1); + Base::prev_rule()->raise(fh2, _target_state - 1); + + vertex_vector.push_back(Base::mesh_.TVH(hh1)); + vertex_vector.push_back(Base::mesh_.TVH(hh2)); + + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))); + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))); + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + vertex_vector.push_back(Base::mesh_.TVH(hh1)); + vertex_vector.push_back(Base::mesh_.TVH(hh2)); + + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))); + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))); + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + const typename M::Scalar valence(4.0); + typename M::Scalar c; + + // choose coefficient c + c = Base::coeff(); + + position += MOBJ(Base::mesh_.TVH(hh1)).position(_target_state - 1) * c; + position += MOBJ(Base::mesh_.TVH(hh2)).position(_target_state - 1) * c; + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))).position(_target_state - 1) * (0.5 - c); + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))).position(_target_state - 1) * (0.5 - c); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// -------------------------------------------------------------------- EV ---- + + +template +void EV::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) { + + this->update(_vh, _target_state); + + // raise all neighbor vertices to level x-1 + typename M::VertexEdgeIter ve_it(Base::mesh_.ve_iter(_vh)); + typename M::EdgeHandle eh; + std::vector edge_vector; + + if (_target_state > 1) { + + for (; ve_it.is_valid(); ++ve_it) { + + edge_vector.push_back(*ve_it); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + Base::prev_rule()->raise(eh, _target_state - 1); + } + + for (ve_it = Base::mesh_.ve_iter(_vh); ve_it.is_valid(); ++ve_it) { + + edge_vector.push_back(*ve_it); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + while (MOBJ(eh).state() < _target_state - 1) + Base::prev_rule()->raise(eh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (ve_it = Base::mesh_.ve_iter(_vh); ve_it.is_valid(); ++ve_it) { + + if (Base::mesh_.data(*ve_it).final()) { + + valence += 1.0; + + position += Base::mesh_.data(*ve_it).position(_target_state - 1); + } + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// ------------------------------------------------------------------- EVc ---- + +template +std::vector EVc::coeffs_; + +template +void EVc::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) + { + this->update(_vh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexOHalfedgeIter voh_it; + typename M::EdgeHandle eh; + typename M::FaceHandle fh; + std::vector edge_vector; + std::vector face_vector; + + if (_target_state > 1) { + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + + face_vector.push_back(Base::mesh_.FH(*voh_it)); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + if (fh.is_valid()) + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) { + + edge_vector.push_back(Base::mesh_.EH(*voh_it)); + + edge_vector.push_back(Base::mesh_.EH(Base::mesh_.NHEH(*voh_it))); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + while (MOBJ(eh).state() < _target_state - 1) + Base::prev_rule()->raise(eh, _target_state - 1); + } + } + + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar c; + typename M::Point zero_point(0.0, 0.0, 0.0); + size_t valence(0); + + valence = Base::mesh_.valence(_vh); + c = static_cast(coeff( valence )); + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it.is_valid(); ++voh_it) + { + if (MOBJ(Base::mesh_.EH(*voh_it)).final()) + { + position += MOBJ(Base::mesh_.EH(*voh_it)).position(_target_state-1)*c; + + if ( Base::mesh_.FH(*voh_it).is_valid() && + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(*voh_it))).final() && + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(*voh_it))).position(_target_state - 1) != zero_point) + { + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(*voh_it))).position(_target_state-1) * (1.0-c); + } + else { + position += MOBJ(Base::mesh_.EH(*voh_it)).position(_target_state - 1) * (1.0 - c); + } + } + else { + --valence; + } + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +template +void +EVc::init_coeffs(size_t _max_valence) +{ + if ( coeffs_.size() == _max_valence+1 ) // equal? do nothing + return; + + if (coeffs_.size() < _max_valence+1) // less than? add additional valences + { + const double _2pi = 2.0*M_PI; + + if (coeffs_.empty()) + coeffs_.push_back(0.0); // dummy for invalid valences 0,1,2 + + for(size_t v=coeffs_.size(); v <= _max_valence; ++v) + { + // ( 3/2 + cos ( 2 PI / valence ) )� / 2 - 1 + double c = 1.5 + cos( _2pi / v ); + c = c * c * 0.5 - 1.0; + coeffs_.push_back(c); + } + } +} + + +// -------------------------------------------------------------------- EF ---- + +template +void +EF::raise(typename M::FaceHandle& _fh, state_t _target_state) { + + if (MOBJ(_fh).state() < _target_state) { + + this->update(_fh, _target_state); + + // raise all neighbour edges to level x-1 + typename M::FaceEdgeIter fe_it(Base::mesh_.fe_iter(_fh)); + typename M::EdgeHandle eh; + std::vector edge_vector; + + if (_target_state > 1) { + + for (; fe_it.is_valid(); ++fe_it) { + + edge_vector.push_back(*fe_it); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + Base::prev_rule()->raise(eh, _target_state - 1); + } + + for (fe_it = Base::mesh_.fe_iter(_fh); fe_it.is_valid(); ++fe_it) { + + edge_vector.push_back(*fe_it); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + while (MOBJ(eh).state() < _target_state - 1) + Base::prev_rule()->raise(eh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar valence(0.0); + + for (fe_it = Base::mesh_.fe_iter(_fh); fe_it.is_valid(); ++fe_it) { + + if (Base::mesh_.data(*fe_it).final()) { + + valence += 1.0; + + position += Base::mesh_.data(*fe_it).position(_target_state - 1); + } + } + + assert (valence == 3.0); + + position /= valence; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + } +} + + +// -------------------------------------------------------------------- FE ---- + + +template +void +FE::raise(typename M::EdgeHandle& _eh, state_t _target_state) { + + if (MOBJ(_eh).state() < _target_state) { + + this->update(_eh, _target_state); + + // raise all neighbor faces to level x-1 + typename M::FaceHandle fh; + + if (_target_state > 1) { + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 0)); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 0)); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + Base::prev_rule()->raise(fh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + const typename M::Scalar valence(2.0); + + position += MOBJ(Base::mesh_.FH(Base::mesh_.HEH(_eh, 0))).position(_target_state - 1); + + position += MOBJ(Base::mesh_.FH(Base::mesh_.HEH(_eh, 1))).position(_target_state - 1); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------- EdE ---- + + +template +void +EdE::raise(typename M::EdgeHandle& _eh, state_t _target_state) { + + if (MOBJ(_eh).state() < _target_state) { + + this->update(_eh, _target_state); + + // raise all neighbor faces and edges to level x-1 + typename M::HalfedgeHandle hh1, hh2; + typename M::FaceHandle fh; + typename M::EdgeHandle eh; + + hh1 = Base::mesh_.HEH(_eh, 0); + hh2 = Base::mesh_.HEH(_eh, 1); + + if (_target_state > 1) { + + fh = Base::mesh_.FH(hh1); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(hh2); + Base::prev_rule()->raise(fh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + const typename M::Scalar valence(4.0); + + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh2))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh2))).position(_target_state - 1); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------ EdEc ---- + + +template +void +EdEc::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) { + + this->update(_eh, _target_state); + + // raise all neighbor faces and edges to level x-1 + typename M::HalfedgeHandle hh1, hh2; + typename M::FaceHandle fh; + typename M::EdgeHandle eh; + + hh1 = Base::mesh_.HEH(_eh, 0); + hh2 = Base::mesh_.HEH(_eh, 1); + + if (_target_state > 1) { + + fh = Base::mesh_.FH(hh1); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(hh2); + Base::prev_rule()->raise(fh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + const typename M::Scalar valence(4.0); + typename M::Scalar c; + + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh2))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh2))).position(_target_state - 1); + + position /= valence; + + // choose coefficient c + c = Base::coeff(); + + position *= ( static_cast(1.0) - c); + + position += MOBJ(_eh).position(_target_state - 1) * c; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + +#endif // DOXY_IGNORE_THIS + +#undef FH +#undef VH +#undef EH +#undef HEH +#undef M +#undef MOBJ + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RulesT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RulesT.hh new file mode 100644 index 0000000..75d2981 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/RulesT.hh @@ -0,0 +1,543 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file RulesT.hh + + */ + + +//============================================================================= +// +// Composite Subdivision and Averaging Rules +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- STL +#include + + +#if defined(OM_CC_MIPS) // avoid warnings +# define MIPS_WARN_WA( Item ) \ + void raise(typename M:: ## Item ## Handle &_h, state_t _target_state ) \ + { Inherited::raise(_h, _target_state); } +#else +# define MIPS_WARN_WA( Item ) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBDIVIDER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. +*/ + + +//============================================================================= + +/** Topological composite rule Tvv,3 doing a 1-3 split of a face. + */ +template class Tvv3 : public RuleInterfaceT +{ + COMPOSITE_RULE( Tvv3, M ); +private: + typedef RuleInterfaceT Base; + +public: + + typedef RuleInterfaceT Inherited; + + explicit Tvv3(M& _mesh) : Inherited(_mesh) { Base::set_subdiv_type(3); }; + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Edge) // avoid warning +}; + + +//============================================================================= + + +/** Topological composite rule Tvv,4 doing a 1-4 split of a face + */ +template class Tvv4 : public RuleInterfaceT +{ + COMPOSITE_RULE( Tvv4, M ); + +private: + typedef RuleInterfaceT Base; +public: + typedef typename M::HalfedgeHandle HEH; + typedef typename M::VertexHandle VH; + + typedef RuleInterfaceT Inherited; + + explicit Tvv4(M& _mesh) : Inherited(_mesh) { Base::set_subdiv_type(4); }; + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + void raise(typename M::VertexHandle& _vh, state_t _target_state); + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + +private: + + void split_edge(HEH& _hh, VH& _vh, state_t _target_state); + void check_edge(const typename M::HalfedgeHandle& _hh, + state_t _target_state); +}; + + +//============================================================================= + + +/** Composite rule VF + */ +template class VF : public RuleInterfaceT +{ + COMPOSITE_RULE( VF, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit VF(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Edge) + MIPS_WARN_WA(Vertex) +}; + + +//============================================================================= + + +/** Composite rule FF + */ +template class FF : public RuleInterfaceT +{ + COMPOSITE_RULE( FF, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit FF(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Vertex) // avoid warning + MIPS_WARN_WA(Edge ) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FFc + */ +template class FFc : public RuleInterfaceT +{ + COMPOSITE_RULE( FFc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit FFc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Vertex) // avoid warning + MIPS_WARN_WA(Edge ) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FV + */ +template class FV : public RuleInterfaceT +{ + COMPOSITE_RULE( FV, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit FV(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face) // avoid warning + MIPS_WARN_WA(Edge) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FVc + */ +template class FVc : public RuleInterfaceT +{ + COMPOSITE_RULE( FVc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit FVc(M& _mesh) : Inherited(_mesh) { init_coeffs(50); } + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face) // avoid warning + MIPS_WARN_WA(Edge) // avoid warning + + static void init_coeffs(size_t _max_valence); + static const std::vector& coeffs() { return coeffs_; } + + double coeff( size_t _valence ) + { + assert(_valence < coeffs_.size()); + return coeffs_[_valence]; + } + +private: + + static std::vector coeffs_; + +}; + + +//============================================================================= + + +/** Composite rule VV + */ +template class VV : public RuleInterfaceT +{ + COMPOSITE_RULE( VV, M ); +private: + typedef RuleInterfaceT Base; + +public: + + typedef RuleInterfaceT Inherited; + + explicit VV(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face) // avoid warning + MIPS_WARN_WA(Edge) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VVc + */ +template class VVc : public RuleInterfaceT +{ + COMPOSITE_RULE( VVc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit VVc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face) // avoid warning + MIPS_WARN_WA(Edge) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VE + */ +template class VE : public RuleInterfaceT +{ + COMPOSITE_RULE( VE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit VE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VdE + */ +template class VdE : public RuleInterfaceT +{ + COMPOSITE_RULE( VdE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit VdE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VdEc + */ +template class VdEc : public RuleInterfaceT +{ + COMPOSITE_RULE( VdEc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit VdEc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EV + */ +template class EV : public RuleInterfaceT +{ + COMPOSITE_RULE( EV, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit EV(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face) // avoid warning + MIPS_WARN_WA(Edge) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EVc + */ +template class EVc : public RuleInterfaceT +{ + COMPOSITE_RULE( EVc, M ); +private: + typedef RuleInterfaceT Base; + +public: + + typedef RuleInterfaceT Inherited; + + explicit EVc(M& _mesh) : Inherited(_mesh) { init_coeffs(50); } + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face) // avoid warning + MIPS_WARN_WA(Edge) // avoid warning + + static void init_coeffs(size_t _max_valence); + static const std::vector& coeffs() { return coeffs_; } + + double coeff( size_t _valence ) + { + assert(_valence < coeffs_.size()); + return coeffs_[_valence]; + } + +private: + + static std::vector coeffs_; + +}; + + +//============================================================================= + + +/** Composite rule EF + */ +template class EF : public RuleInterfaceT +{ + COMPOSITE_RULE( EF, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit EF(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Edge ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FE + */ +template class FE : public RuleInterfaceT +{ + COMPOSITE_RULE( FE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit FE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EdE + */ +template class EdE : public RuleInterfaceT +{ + COMPOSITE_RULE( EdE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit EdE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EdEc + */ +template class EdEc : public RuleInterfaceT +{ + COMPOSITE_RULE( EdEc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + explicit EdEc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ) // avoid warning + MIPS_WARN_WA(Vertex) // avoid warning +}; + +// ---------------------------------------------------------------------------- + +#undef MIPS_WARN_WA + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_CC) +# define OPENMESH_SUBDIVIDER_TEMPLATES +# include "RulesT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/Traits.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/Traits.hh new file mode 100644 index 0000000..a915c1f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Adaptive/Composite/Traits.hh @@ -0,0 +1,255 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Composite/Traits.hh + + */ + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_TRAITS_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_TRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. +*/ + +// typedef unsigned short state_t; +// const state_t mask_final = 1 << ((sizeof(state_t)*8)-1); +// const state_t mask_state = ~mask_final; + +typedef int state_t; +typedef bool final_t; + +struct State +{ + int state : 31; + unsigned final : 1; +}; + +struct Traits : public OpenMesh::DefaultTraits +{ + + // add face normals + FaceAttributes( OpenMesh::Attributes::Normal ); + + // add vertex normals + VertexAttributes( OpenMesh::Attributes::Normal ); + + // add previous halfedge handle + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + FaceTraits + { + + private: + + typedef typename Refs::Point Point; + typedef typename Refs::HalfedgeHandle HalfedgeHandle; + typedef std::map PositionHistory; + + State state_; + HalfedgeHandle red_halfedge_; + + PositionHistory pos_map_; + + public: + + // face state + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // face not final if divided (loop) or edge not flipped (sqrt(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // halfedge of dividing edge (red-green triangulation) + const HalfedgeHandle& red_halfedge() const { return red_halfedge_; } + void set_red_halfedge(const HalfedgeHandle& _h) { red_halfedge_ = _h; } + + // position of face, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + if (pos_map_.find(_i) != pos_map_.end()) + return pos_map_[_i]; + else { + + if (_i <= 0) { + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class FaceTraits + + + EdgeTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + PositionHistory pos_map_; + + public: + + typedef typename Refs::Scalar Scalar; + + // Scalar weight_; + + // state of edge + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // edge not final if dividing face (Loop) or edge not flipped (SQRT(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of edge, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + { + return pos_map_[_i]; + } + else + { + if (_i <= 0) + { + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class EdgeTraits + + + VertexTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + + PositionHistory pos_map_; + + public: + + // state of vertex + state_t state() const { return state_.state; } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + + // usually not needed by loop or sqrt(3) + final_t final() const { return state_.final; } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of vertex, depending on generation _i. (not for display) + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + + return pos_map_[_i]; + + else { + + if (_i <= 0) { + + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class VertexTraits +}; // end class Traits + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_TRAITS_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.cc new file mode 100644 index 0000000..1813c2f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.cc @@ -0,0 +1,407 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 520 $ * + * $Date: 2012-01-20 15:29:31 +0100 (Fr, 20 Jan 2012) $ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS CatmullClarkT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_SUBDIVIDER_UNIFORM_CATMULLCLARK_CC + +//== INCLUDES ================================================================= + +#include "CatmullClarkT.hh" +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBVIDER +namespace Uniform { // BEGIN_NS_UNIFORM + +//== IMPLEMENTATION ========================================================== + +template +bool +CatmullClarkT< MeshType, RealType >::prepare( MeshType& _m ) +{ + _m.add_property( vp_pos_ ); + _m.add_property( ep_pos_ ); + _m.add_property( fp_pos_ ); + _m.add_property( creaseWeights_ ); + + // initialize all weights to 0 (= smooth edge) + for( EdgeIter e_it = _m.edges_begin(); e_it != _m.edges_end(); ++e_it) + _m.property(creaseWeights_, *e_it ) = 0.0; + + return true; +} + +//----------------------------------------------------------------------------- + +template +bool +CatmullClarkT::cleanup( MeshType& _m ) +{ + _m.remove_property( vp_pos_ ); + _m.remove_property( ep_pos_ ); + _m.remove_property( fp_pos_ ); + _m.remove_property( creaseWeights_ ); + return true; +} + +//----------------------------------------------------------------------------- + +template +bool +CatmullClarkT::subdivide( MeshType& _m , size_t _n , const bool _update_points) +{ + // Do _n subdivisions + for ( size_t i = 0; i < _n; ++i) + { + + // Compute face centroid + FaceIter f_itr = _m.faces_begin(); + FaceIter f_end = _m.faces_end(); + for ( ; f_itr != f_end; ++f_itr) + { + Point centroid; + _m.calc_face_centroid( *f_itr, centroid); + _m.property( fp_pos_, *f_itr ) = centroid; + } + + // Compute position for new (edge-) vertices and store them in the edge property + EdgeIter e_itr = _m.edges_begin(); + EdgeIter e_end = _m.edges_end(); + for ( ; e_itr != e_end; ++e_itr) + compute_midpoint( _m, *e_itr, _update_points ); + + // position updates activated? + if(_update_points) + { + // compute new positions for old vertices + VertexIter v_itr = _m.vertices_begin(); + VertexIter v_end = _m.vertices_end(); + for ( ; v_itr != v_end; ++v_itr) + update_vertex( _m, *v_itr ); + + // Commit changes in geometry + v_itr = _m.vertices_begin(); + for ( ; v_itr != v_end; ++v_itr) + _m.set_point(*v_itr, _m.property( vp_pos_, *v_itr ) ); + } + + // Split each edge at midpoint stored in edge property ep_pos_; + // Attention! Creating new edges, hence make sure the loop ends correctly. + e_itr = _m.edges_begin(); + for ( ; e_itr != e_end; ++e_itr) + split_edge( _m, *e_itr ); + + // Commit changes in topology and reconsitute consistency + // Attention! Creating new faces, hence make sure the loop ends correctly. + f_itr = _m.faces_begin(); + for ( ; f_itr != f_end; ++f_itr) + split_face( _m, *f_itr); + + +#if defined(_DEBUG) || defined(DEBUG) + // Now we have an consistent mesh! + assert( OpenMesh::Utils::MeshCheckerT(_m).check() ); +#endif + } + + _m.update_normals(); + + return true; +} + +//----------------------------------------------------------------------------- + +template +void +CatmullClarkT::split_face( MeshType& _m, const FaceHandle& _fh) +{ + /* + Split an n-gon into n quads by connecting + each vertex of fh to vh. + + - _fh will remain valid (it will become one of the quads) + - the halfedge handles of the new quads will + point to the old halfedges + */ + + // Since edges already refined (valence*2) + size_t valence = _m.valence(_fh)/2; + + // new mesh vertex from face centroid + VertexHandle vh = _m.add_vertex(_m.property( fp_pos_, _fh )); + + HalfedgeHandle hend = _m.halfedge_handle(_fh); + HalfedgeHandle hh = _m.next_halfedge_handle(hend); + + HalfedgeHandle hold = _m.new_edge(_m.to_vertex_handle(hend), vh); + + _m.set_next_halfedge_handle(hend, hold); + _m.set_face_handle(hold, _fh); + + hold = _m.opposite_halfedge_handle(hold); + + for(size_t i = 1; i < valence; i++) + { + HalfedgeHandle hnext = _m.next_halfedge_handle(hh); + + FaceHandle fnew = _m.new_face(); + + _m.set_halfedge_handle(fnew, hh); + + HalfedgeHandle hnew = _m.new_edge(_m.to_vertex_handle(hnext), vh); + + _m.set_face_handle(hnew, fnew); + _m.set_face_handle(hold, fnew); + _m.set_face_handle(hh, fnew); + _m.set_face_handle(hnext, fnew); + + _m.set_next_halfedge_handle(hnew, hold); + _m.set_next_halfedge_handle(hold, hh); + _m.set_next_halfedge_handle(hh, hnext); + hh = _m.next_halfedge_handle(hnext); + _m.set_next_halfedge_handle(hnext, hnew); + + hold = _m.opposite_halfedge_handle(hnew); + } + + _m.set_next_halfedge_handle(hold, hh); + _m.set_next_halfedge_handle(hh, hend); + hh = _m.next_halfedge_handle(hend); + _m.set_next_halfedge_handle(hend, hh); + _m.set_next_halfedge_handle(hh, hold); + + _m.set_face_handle(hold, _fh); + + _m.set_halfedge_handle(vh, hold); +} + +//----------------------------------------------------------------------------- + +template +void +CatmullClarkT::split_edge( MeshType& _m, const EdgeHandle& _eh) +{ + HalfedgeHandle heh = _m.halfedge_handle(_eh, 0); + HalfedgeHandle opp_heh = _m.halfedge_handle(_eh, 1); + + HalfedgeHandle new_heh, opp_new_heh, t_heh; + VertexHandle vh; + VertexHandle vh1( _m.to_vertex_handle(heh)); + Point zero(0,0,0); + + // new vertex + vh = _m.new_vertex( zero ); + _m.set_point( vh, _m.property( ep_pos_, _eh ) ); + + // Re-link mesh entities + if (_m.is_boundary(_eh)) + { + for (t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + } + else + { + for (t_heh = _m.next_halfedge_handle(opp_heh); + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.next_halfedge_handle(t_heh) ) + {} + } + + new_heh = _m.new_edge(vh, vh1); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + _m.set_vertex_handle( heh, vh ); + + _m.set_next_halfedge_handle(t_heh, opp_new_heh); + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); + _m.set_next_halfedge_handle(heh, new_heh); + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); + + if (_m.face_handle(opp_heh).is_valid()) + { + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh); + } + + if( _m.face_handle(heh).is_valid()) + { + _m.set_face_handle( new_heh, _m.face_handle(heh) ); + _m.set_halfedge_handle( _m.face_handle(heh), heh ); + } + + _m.set_halfedge_handle( vh, new_heh); + _m.set_halfedge_handle( vh1, opp_new_heh ); + + // Never forget this, when playing with the topology + _m.adjust_outgoing_halfedge( vh ); + _m.adjust_outgoing_halfedge( vh1 ); +} + +//----------------------------------------------------------------------------- + +template +void +CatmullClarkT::compute_midpoint( MeshType& _m, const EdgeHandle& _eh, const bool _update_points) +{ + HalfedgeHandle heh, opp_heh; + + heh = _m.halfedge_handle( _eh, 0); + opp_heh = _m.halfedge_handle( _eh, 1); + + Point pos( _m.point( _m.to_vertex_handle( heh))); + + pos += _m.point( _m.to_vertex_handle( opp_heh)); + + // boundary edge: just average vertex positions + // this yields the [1/2 1/2] mask + if (_m.is_boundary(_eh) || !_update_points) + { + pos *= static_cast(0.5); + } +// else if (_m.status(_eh).selected() ) +// { +// pos *= 0.5; // change this +// } + + else // inner edge: add neighbouring Vertices to sum + // this yields the [1/16 1/16; 3/8 3/8; 1/16 1/16] mask + { + pos += _m.property(fp_pos_, _m.face_handle(heh)); + pos += _m.property(fp_pos_, _m.face_handle(opp_heh)); + pos *= static_cast(0.25); + } + _m.property( ep_pos_, _eh ) = pos; +} + +//----------------------------------------------------------------------------- + +template +void +CatmullClarkT::update_vertex( MeshType& _m, const VertexHandle& _vh) +{ + Point pos(0.0,0.0,0.0); + + // TODO boundary, Extraordinary Vertex and Creased Surfaces + // see "A Factored Approach to Subdivision Surfaces" + // http://faculty.cs.tamu.edu/schaefer/research/tutorial.pdf + // and http://www.cs.utah.edu/~lacewell/subdeval + if ( _m.is_boundary( _vh)) + { + Normal Vec; + pos = _m.point(_vh); + VertexEdgeIter ve_itr; + for ( ve_itr = _m.ve_iter( _vh); ve_itr.is_valid(); ++ve_itr) + if ( _m.is_boundary( *ve_itr)) + pos += _m.property( ep_pos_, *ve_itr); + pos /= static_cast::value_type>(3.0); + } + else // inner vertex + { + /* For each (non boundary) vertex V, introduce a new vertex whose + position is F/n + 2E/n + (n-3)V/n where F is the average of + the new face vertices of all faces adjacent to the old vertex + V, E is the average of the midpoints of all edges incident + on the old vertex V, and n is the number of edges incident on + the vertex. + */ + + /* + Normal Vec; + VertexEdgeIter ve_itr; + double valence(0.0); + + // R = Calculate Valence and sum of edge midpoints + for ( ve_itr = _m.ve_iter( _vh); ve_itr; ++ve_itr) + { + valence+=1.0; + pos += _m.property(ep_pos_, *ve_itr); + } + pos /= valence*valence; + */ + + RealType valence(0.0); + VOHIter voh_it = _m.voh_iter( _vh ); + for( ; voh_it.is_valid(); ++voh_it ) + { + pos += _m.point( _m.to_vertex_handle( *voh_it ) ); + valence+=1.0; + } + pos /= valence*valence; + + VertexFaceIter vf_itr; + Point Q(0, 0, 0); + + for ( vf_itr = _m.vf_iter( _vh); vf_itr.is_valid(); ++vf_itr) //, neigboring_faces += 1.0 ) + { + Q += _m.property(fp_pos_, *vf_itr); + } + + Q /= valence*valence;//neigboring_faces; + + pos += _m.point(_vh) * (valence - RealType(2.0) )/valence + Q; + // pos = vector_cast(_m.point(_vh)); + } + + _m.property( vp_pos_, _vh ) = pos; +} + +//----------------------------------------------------------------------------- + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.hh new file mode 100644 index 0000000..c756a0f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.hh @@ -0,0 +1,182 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision: 520 $ * + * $Date: 2012-01-20 15:29:31 +0100 (Fr, 20 Jan 2012) $ * + * * +\*===========================================================================*/ + +/** \file CatmullClarkT.hh + */ + +//============================================================================= +// +// CLASS CatmullClarkT +// +//============================================================================= + + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_CATMULLCLARKT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_CATMULLCLARKT_HH + + +//== INCLUDES ================================================================= + +#include + +// -------------------- STL +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBVIDER +namespace Uniform { // BEGIN_NS_UNIFORM + +//== CLASS DEFINITION ========================================================= + + +/** \class CatmullClarkT CatmullClarkT.hh + Based on code from Leon Kos, CAD lab, Mech.Eng., University of Ljubljana, Slovenia + (http://www.lecad.fs.uni-lj.si/~leon) + + \note Needs a PolyMesh to work on! +*/ +template +class CatmullClarkT : public SubdividerT< MeshType, RealType > +{ +public: + + typedef typename MeshType::FaceHandle FaceHandle; + typedef typename MeshType::VertexHandle VertexHandle; + typedef typename MeshType::EdgeHandle EdgeHandle; + typedef typename MeshType::HalfedgeHandle HalfedgeHandle; + + typedef typename MeshType::Point Point; + typedef typename MeshType::Normal Normal; + typedef typename MeshType::FaceIter FaceIter; + typedef typename MeshType::EdgeIter EdgeIter; + typedef typename MeshType::VertexIter VertexIter; + + typedef typename MeshType::VertexEdgeIter VertexEdgeIter; + typedef typename MeshType::VertexFaceIter VertexFaceIter; + + typedef typename MeshType::VOHIter VOHIter; + + typedef SubdividerT< MeshType, RealType > parent_t; + + /// Constructor + CatmullClarkT( ) : parent_t() { } + + /// Constructor + explicit CatmullClarkT(MeshType &_m) : parent_t(_m) { } + + virtual ~CatmullClarkT() {} + +public: + + const char *name() const { return "Uniform CatmullClark"; } + +protected: + + /// Initialize properties and weights + virtual bool prepare( MeshType& _m ); + + /// Remove properties and weights + virtual bool cleanup( MeshType& _m ); + + /** \brief Execute n subdivision steps + * + * @param _m Mesh to work on + * @param _n Number of iterations + * @param _update_points Unused here + * @return successful? + */ + virtual bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true); + +private: + + //=========================================================================== + /** @name Topology helpers + * @{ */ + //=========================================================================== + + void split_edge( MeshType& _m, const EdgeHandle& _eh); + + void split_face( MeshType& _m, const FaceHandle& _fh); + + void compute_midpoint( MeshType& _m, const EdgeHandle& _eh, const bool _update_points); + + void update_vertex(MeshType& _m, const VertexHandle& _vh); + + /** @} */ + + +private: + OpenMesh::VPropHandleT< Point > vp_pos_; // next vertex pos + OpenMesh::EPropHandleT< Point > ep_pos_; // new edge pts + OpenMesh::FPropHandleT< Point > fp_pos_; // new face pts + OpenMesh::EPropHandleT creaseWeights_;// crease weights + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_UNIFORM_CATMULLCLARK_CC) +# define OPENMESH_SUBDIVIDER_TEMPLATES +# include "CatmullClarkT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_CATMULLCLARKT_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeT.cc new file mode 100644 index 0000000..621d3b9 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeT.cc @@ -0,0 +1,1295 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Uniform/Composite/CompositeT.cc + + */ + +//============================================================================= +// +// CLASS CompositeT - IMPLEMENTATION +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== IMPLEMENTATION ========================================================== + + +template +bool CompositeT::prepare( MeshType& _m ) +{ + // store mesh for later usage in subdivide(), cleanup() and all rules. + p_mesh_ = &_m; + + typename MeshType::VertexIter v_it(_m.vertices_begin()); + + for (; v_it != _m.vertices_end(); ++v_it) + _m.data(*v_it).set_position(_m.point(*v_it)); + + return true; +} + + + +template +void CompositeT::Tvv3() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexHandle vh; + typename MeshType::FaceIter f_it; + typename MeshType::EdgeIter e_it; + typename MeshType::VertexIter v_it; + typename MeshType::Point zero_point(0.0, 0.0, 0.0); + size_t n_edges, n_faces, n_vertices, j; + + // Store number of original edges + n_faces = mesh_.n_faces(); + n_edges = mesh_.n_edges(); + n_vertices = mesh_.n_vertices(); + + // reserve enough memory for iterator + mesh_.reserve(n_vertices + n_faces, n_edges + 3 * n_faces, 3 * n_faces); + + // set new positions for vertices + v_it = mesh_.vertices_begin(); + for (j = 0; j < n_vertices; ++j) { + mesh_.data(*v_it).set_position(mesh_.data(*v_it).position() * static_cast(3.0) ); + ++v_it; + } + + // Split each face + f_it = mesh_.faces_begin(); + for (j = 0; j < n_faces; ++j) { + + vh = mesh_.add_vertex(zero_point); + + mesh_.data(vh).set_position(zero_point); + + mesh_.split(*f_it, vh); + + ++f_it; + } + + // Flip each old edge + std::vector edge_vector; + edge_vector.clear(); + + e_it = mesh_.edges_begin(); + for (j = 0; j < n_edges; ++j) { + if (mesh_.is_flip_ok(*e_it)) { + mesh_.flip(*e_it); + } else { + edge_vector.push_back(*e_it); + } + ++e_it; + } + + // split all boundary edges + while (!edge_vector.empty()) { + vh = mesh_.add_vertex(zero_point); + mesh_.data(vh).set_position(zero_point); + mesh_.split(edge_vector.back(), vh); + edge_vector.pop_back(); + } +} + + +template +void CompositeT::Tvv4() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexHandle vh; + typename MeshType::FaceIter f_it; + typename MeshType::EdgeIter e_it; + typename MeshType::VertexIter v_it; + typename MeshType::Point zero_point(0.0, 0.0, 0.0); + size_t n_edges, n_faces, n_vertices, j; + + // Store number of original edges + n_faces = mesh_.n_faces(); + n_edges = mesh_.n_edges(); + n_vertices = mesh_.n_vertices(); + + // reserve memory ahead for the succeeding operations + mesh_.reserve(n_vertices + n_edges, 2 * n_edges + 3 * n_faces, 4 * n_faces); + + // set new positions for vertices + v_it = mesh_.vertices_begin(); + for (j = 0; j < n_vertices; ++j) { + mesh_.data(*v_it).set_position(mesh_.data(*v_it).position() * static_cast(4.0) ); + ++v_it; + } + + // Split each edge + e_it = mesh_.edges_begin(); + for (j = 0; j < n_edges; ++j) { + + vh = split_edge(mesh_.halfedge_handle(*e_it, 0)); + mesh_.data(vh).set_position(zero_point); + + ++e_it; + } + + // Corner Cutting of Each Face + f_it = mesh_.faces_begin(); + for (j = 0; j < n_faces; ++j) { + typename MeshType::HalfedgeHandle heh1(mesh_.halfedge_handle(*f_it)); + typename MeshType::HalfedgeHandle heh2(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh1))); + typename MeshType::HalfedgeHandle heh3(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh2))); + + // Cutting off every corner of the 6_gon + + corner_cutting(heh1); + corner_cutting(heh2); + corner_cutting(heh3); + + ++f_it; + } +} + + +template +void CompositeT::Tfv() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexHandle vh; + typename MeshType::FaceIter f_it; + typename MeshType::EdgeIter e_it; + typename MeshType::VertexIter v_it; + typename MeshType::VertexFaceIter vf_it; + typename MeshType::FaceFaceIter ff_it; + typename MeshType::Point cog; + const typename MeshType::Point zero_point(0.0, 0.0, 0.0); + size_t n_edges, n_faces, n_vertices, j, valence; + + // Store number of original edges + n_faces = mesh_.n_faces(); + n_edges = mesh_.n_edges(); + n_vertices = mesh_.n_vertices(); + + // reserve enough space for iterator + mesh_.reserve(n_vertices + n_faces, n_edges + 3 * n_faces, 3 * n_faces); + + // set new positions for vertices + v_it = mesh_.vertices_begin(); + for (j = 0; j < n_vertices; ++j) { + valence = 0; + cog = zero_point; + for (vf_it = mesh_.vf_iter(*v_it); vf_it; ++vf_it) { + ++valence; + cog += vf_it->position(); + } + cog /= valence; + + v_it->set_position(cog); + ++v_it; + } + + // Split each face, insert new vertex and calculate position + f_it = mesh_.faces_begin(); + for (j = 0; j < n_faces; ++j) { + + vh = mesh_.add_vertex(); + + valence = 0; + cog = zero_point; + for (ff_it = mesh_.ff_iter(*f_it); ff_it; ++ff_it) { + ++valence; + cog += ff_it->position(); + } + cog /= valence; + + mesh_.split(*f_it, vh); + + for (vf_it = mesh_.vf_iter(vh); vf_it; ++vf_it) { + vf_it->set_position(f_it->position()); + } + + mesh_.deref(vh).set_position(cog); + + mesh_.set_point(vh, cog); + + ++f_it; + } + + // Flip each old edge + e_it = mesh_.edges_begin(); + for (j = 0; j < n_edges; ++j) { + if (mesh_.is_flip_ok(*e_it)) + mesh_.flip(*e_it); + ++e_it; + } +} + + + +template +void CompositeT::VF() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog,zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceVertexIter fv_it; + typename MeshType::FaceIter f_it; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (fv_it = mesh_.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) { + cog += mesh_.data(*fv_it).position(); + ++valence; + } + cog /= valence; + mesh_.data(*f_it).set_position(cog); + } +} + + +template +void CompositeT::VFa(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence[3], i; + typename MeshType::Point cog,zero_point(0.0, 0.0, 0.0); + typename MeshType::Scalar alpha; + typename MeshType::FaceIter f_it; + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexHandle vh[3]; + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::FaceVertexIter fv_it; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + heh = mesh_.halfedge_handle(*f_it); + for (i = 0; i <= 2; ++i) { + + valence[i] = 0; + vh[i] = mesh_.to_vertex_handle(heh); + + for (voh_it = mesh_.voh_iter(vh[i]); voh_it; ++voh_it) { + ++valence[i]; + } + + heh = mesh_.next_halfedge_handle(heh); + } + + if (valence[0] <= valence[1]) + if (valence[0] <= valence[2]) + i = 0; + else + i = 2; + else + if (valence[1] <= valence[2]) + i = 1; + else + i = 2; + + alpha = _coeff(valence[i]); + + cog = zero_point; + + for (fv_it = mesh_.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) { + if (*fv_it == vh[i]) { + cog += fv_it->position() * alpha; + } else { + cog += fv_it->position() * (1.0 - alpha) / 2.0; + } + } + + f_it->set_position(cog); + } +} + + +template +void CompositeT::VFa(scalar_t _alpha) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence[3], i; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceIter f_it; + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexHandle vh[3]; + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::FaceVertexIter fv_it; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + heh = mesh_.halfedge_handle(*f_it); + for (i = 0; i <= 2; ++i) { + + valence[i] = 0; + vh[i] = mesh_.to_vertex_handle(heh); + + for (voh_it = mesh_.voh_iter(vh[i]); voh_it; ++voh_it) { + ++valence[i]; + } + + heh = mesh_.next_halfedge_handle(heh); + } + + if (valence[0] <= valence[1]) + if (valence[0] <= valence[2]) + i = 0; + else + i = 2; + else + if (valence[1] <= valence[2]) + i = 1; + else + i = 2; + + cog = zero_point; + + for (fv_it = mesh_.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) { + if (*fv_it == vh[i]) { + cog += fv_it->position() * _alpha; + } else { + cog += fv_it->position() * (1.0 - _alpha) / 2.0; + } + } + + f_it->set_position(cog); + } +} + + +template +void CompositeT::FF() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceFaceIter ff_it; + typename MeshType::FaceIter f_it; + std::vector point_vector; + + point_vector.clear(); + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) + { + unsigned int valence = 0; + cog = zero_point; + + for (ff_it = mesh_.ff_iter(*f_it); ff_it.is_valid(); ++ff_it) + { + cog += mesh_.data(*ff_it).position(); + ++valence; + } + cog /= valence; + point_vector.push_back(cog); + } + + for (f_it = mesh_.faces_end(); f_it != mesh_.faces_begin(); ) + { + --f_it; + mesh_.data(*f_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::FFc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceFaceIter ff_it; + typename MeshType::FaceIter f_it; + typename MeshType::Scalar c; + std::vector point_vector; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (ff_it = mesh_.ff_iter(*f_it); ff_it; ++ff_it) { + cog += ff_it->position(); + ++valence; + } + cog /= valence; + + c = _coeff(valence); + + cog = cog * (1.0 - c) + f_it->position() * c; + + point_vector.push_back(cog); + + } + for (f_it = mesh_.faces_end(); f_it != mesh_.faces_begin(); ) { + + --f_it; + f_it->set_position(point_vector.back()); + point_vector.pop_back(); + + } +} + + +template +void CompositeT::FFc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceFaceIter ff_it; + typename MeshType::FaceIter f_it; + std::vector point_vector; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (ff_it = mesh_.ff_iter(*f_it); ff_it; ++ff_it) { + cog += ff_it->position(); + ++valence; + } + cog /= valence; + + cog = cog * (1.0 - _c) + f_it->position() * _c; + + point_vector.push_back(cog); + + } + for (f_it = mesh_.faces_end(); f_it != mesh_.faces_begin(); ) { + + --f_it; + f_it->set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::FV() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexFaceIter vf_it; + typename MeshType::VertexIter v_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (vf_it = mesh_.vf_iter(*v_it); vf_it; ++vf_it) { + cog += vf_it->position(); + ++valence; + } + cog /= valence; + v_it->set_position(cog); + } +} + + +template +void CompositeT::FVc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + scalar_t c; + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::VertexIter v_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(*v_it); voh_it.is_valid(); ++voh_it) { + ++valence; + } + + c = static_cast(_coeff(valence)); + + for (voh_it = mesh_.voh_iter(*v_it); voh_it.is_valid(); ++voh_it) { + + if (mesh_.face_handle(*voh_it).is_valid()) { + + if (mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(*voh_it))).is_valid()) { + cog += mesh_.data(mesh_.face_handle(*voh_it)).position() * c; + cog += mesh_.data(mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(*voh_it)))).position() * (static_cast(1.0) - c); + } else { + cog += mesh_.data(mesh_.face_handle(*voh_it)).position(); + } + } else { + --valence; + } + } + + if (valence > 0) + cog /= valence; + + mesh_.data(*v_it).set_position(cog); + } +} + + +template +void CompositeT::FVc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::VertexIter v_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(*v_it); voh_it; ++voh_it) { + ++valence; + } + + for (voh_it = mesh_.voh_iter(*v_it); voh_it; ++voh_it) { + + if (mesh_.face_handle(*voh_it).is_valid()) { + + if (mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(*voh_it))).is_valid()) { + cog += mesh_.deref(mesh_.face_handle(*voh_it)).position() * _c; + cog += mesh_.deref(mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(*voh_it)))).position() * (1.0 - _c); + } else { + cog += mesh_.deref(mesh_.face_handle(*voh_it)).position(); + } + } else { + --valence; + } + } + + if (valence > 0) + cog /= valence; + + v_it->set_position(cog); + } +} + + +template +void CompositeT::VdE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh1, heh2; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + unsigned int valence = 2; + + heh1 = mesh_.halfedge_handle(*e_it, 0); + heh2 = mesh_.opposite_halfedge_handle(heh1); + cog += mesh_.data(mesh_.to_vertex_handle(heh1)).position(); + cog += mesh_.data(mesh_.to_vertex_handle(heh2)).position(); + + if (!mesh_.is_boundary(heh1)) { + cog += mesh_.data(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh1))).position(); + ++valence; + } + + if (!mesh_.is_boundary(heh2)) { + cog += mesh_.data(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh2))).position(); + ++valence; + } + + cog /= valence; + + mesh_.data(*e_it).set_position(cog); + } +} + + +template +void CompositeT::VdEc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + + for (int i = 0; i <= 1; ++i) { + + heh = mesh_.halfedge_handle(*e_it, i); + if (!mesh_.is_boundary(heh)) + { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (0.5 - _c); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * _c; + } + else + { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position(); + } + } + + mesh_.data(*e_it).set_position(cog); + } +} + + +template +void CompositeT::VdEg(scalar_t _gamma) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexOHalfedgeIter voh_it; + unsigned int valence[2], i; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + + for (i = 0; i <= 1; ++i) + { + heh = mesh_.halfedge_handle(*e_it, i); + valence[i] = 0; + + // look for lowest valence vertex + for (voh_it = mesh_.voh_iter(mesh_.to_vertex_handle(heh)); voh_it; ++voh_it) + { + ++valence[i]; + } + } + + if (valence[0] < valence[1]) + i = 0; + else + i = 1; + + heh = mesh_.halfedge_handle(*e_it, i); + + if (!mesh_.is_boundary(heh)) { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (_gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 3.0 * _gamma); + } else { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 2.0 * _gamma); + } + + + heh = mesh_.halfedge_handle(*e_it, 1-i); + + if (!mesh_.is_boundary(heh)) + { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (_gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * _gamma; + } + else + { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * 2.0 * _gamma; + } + + mesh_.data(*e_it).set_position(cog); + } +} + + +template +void CompositeT::VdEg(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexOHalfedgeIter voh_it; + unsigned int valence[2], i; + scalar_t gamma; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + + for (i = 0; i <= 1; ++i) { + + heh = mesh_.halfedge_handle(*e_it, i); + valence[i] = 0; + + // look for lowest valence vertex + for (voh_it = mesh_.voh_iter(mesh_.to_vertex_handle(heh)); voh_it; ++voh_it) + { + ++valence[i]; + } + } + + if (valence[0] < valence[1]) + i = 0; + else + i = 1; + + gamma = _coeff(valence[i]); + + heh = mesh_.halfedge_handle(*e_it, i); + + if (!mesh_.is_boundary(heh)) + { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 3.0 * gamma); + } + else + { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 2.0 * gamma); + } + + + heh = mesh_.halfedge_handle(*e_it, 1-i); + + if (!mesh_.is_boundary(heh)) { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * gamma; + } else { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * 2.0 * gamma; + } + + mesh_.data(*e_it).set_position(cog); + } +} + + +template +void CompositeT::EV() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexIter v_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexEdgeIter ve_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + unsigned int valence = 0; + cog = zero_point; + + for (ve_it = mesh_.ve_iter(*v_it); ve_it; ++ve_it) { + cog += mesh_.data(ve_it).position(); + ++valence; + } + + cog /= valence; + + mesh_.data(*v_it).set_position(cog); + } +} + + +template +void CompositeT::EVc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexIter v_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexOHalfedgeIter voh_it; + scalar_t c; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + unsigned int valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(*v_it); voh_it.is_valid(); ++voh_it) + { + ++valence; + } + + // Coefficients always work on double so we cast them to the correct scalar here + c = static_cast(_coeff(valence)); + + for (voh_it = mesh_.voh_iter(*v_it); voh_it.is_valid(); ++voh_it) { + cog += mesh_.data(mesh_.edge_handle(*voh_it)).position() * c; + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(*voh_it))).position() * (1.0 - c); + } + + cog /= valence; + + mesh_.data(*v_it).set_position(cog); + } +} + + +template +void CompositeT::EVc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + typename MeshType::VertexIter v_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexOHalfedgeIter voh_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + unsigned int valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(*v_it); voh_it; ++voh_it) { + ++valence; + } + + for (voh_it = mesh_.voh_iter(*v_it); voh_it; ++voh_it) { + cog += mesh_.data(mesh_.edge_handle(*voh_it)).position() * _c; + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(*voh_it))).position() * (1.0 - _c); + } + + cog /= valence; + + mesh_.data(*v_it).set_position(cog); + } +} + + +template +void CompositeT::EF() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::FaceIter f_it; + typename MeshType::FaceEdgeIter fe_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + unsigned int valence = 0; + cog = zero_point; + + for (fe_it = mesh_.fe_iter(*f_it); fe_it; ++fe_it) { + ++valence; + cog += mesh_.data(fe_it).position(); + } + + cog /= valence; + mesh_.data(*f_it).set_position(cog); + } +} + + +template +void CompositeT::FE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + unsigned int valence = 0; + cog = zero_point; + + if (mesh_.face_handle(mesh_.halfedge_handle(*e_it, 0)).is_valid()) { + cog += mesh_.data(mesh_.face_handle(mesh_.halfedge_handle(*e_it, 0))).position(); + ++valence; + } + + if (mesh_.face_handle(mesh_.halfedge_handle(*e_it, 1)).is_valid()) { + cog += mesh_.data(mesh_.face_handle(mesh_.halfedge_handle(*e_it, 1))).position(); + ++valence; + } + + cog /= valence; + mesh_.data(*e_it).set_position(cog); + } +} + + +template +void CompositeT::VE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) + { + cog = mesh_.data(mesh_.to_vertex_handle(mesh_.halfedge_handle(*e_it, 0))).position(); + cog += mesh_.data(mesh_.to_vertex_handle(mesh_.halfedge_handle(*e_it, 1))).position(); + cog /= 2.0; + mesh_.data(*e_it).set_position(cog); + } +} + + +template +void CompositeT::VV() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexVertexIter vv_it; + typename MeshType::VertexIter v_it; + std::vector point_vector; + + point_vector.clear(); + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (vv_it = mesh_.vv_iter(*v_it); vv_it; ++vv_it) { + cog += vv_it->position(); + ++valence; + } + cog /= valence; + point_vector.push_back(cog); + } + + for (v_it = mesh_.vertices_end(); v_it != mesh_.vertices_begin(); ) + { + --v_it; + mesh_.data(*v_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::VVc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexVertexIter vv_it; + typename MeshType::VertexIter v_it; + scalar_t c; + std::vector point_vector; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + unsigned int valence = 0; + cog = zero_point; + + for (vv_it = mesh_.vv_iter(*v_it); vv_it; ++vv_it) + { + cog += vv_it->position(); + ++valence; + } + cog /= valence; + c = _coeff(valence); + cog = cog * (1 - c) + mesh_.data(*v_it).position() * c; + point_vector.push_back(cog); + } + for (v_it = mesh_.vertices_end(); v_it != mesh_.vertices_begin(); ) + { + --v_it; + mesh_.data(*v_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::VVc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexVertexIter vv_it; + typename MeshType::VertexIter v_it; + std::vector point_vector; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (vv_it = mesh_.vv_iter(*v_it); vv_it; ++vv_it) { + cog += mesh_.data(vv_it).position(); + ++valence; + } + cog /= valence; + + cog = cog * (1.0 - _c) + v_it->position() * _c; + + point_vector.push_back(cog); + + } + for (v_it = mesh_.vertices_end(); v_it != mesh_.vertices_begin(); ) { + + --v_it; + mesh_.data(*v_it).set_position(point_vector.back()); + point_vector.pop_back(); + + } +} + + +template +void CompositeT::EdE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::EdgeIter e_it; + typename MeshType::HalfedgeHandle heh; + std::vector point_vector; + + point_vector.clear(); + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + unsigned int valence = 0; + cog = zero_point; + + for (int i = 0; i <= 1; ++i) { + heh = mesh_.halfedge_handle(*e_it, i); + if (mesh_.face_handle(heh).is_valid()) + { + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(heh))).position(); + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh)))).position(); + ++valence; + ++valence; + } + } + + cog /= valence; + point_vector.push_back(cog); + } + + for (e_it = mesh_.edges_end(); e_it != mesh_.edges_begin(); ) + { + --e_it; + mesh_.data(*e_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::EdEc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::Point cog, zero_point(0.0, 0.0, 0.0); + typename MeshType::EdgeIter e_it; + typename MeshType::HalfedgeHandle heh; + std::vector point_vector; + + point_vector.clear(); + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) + { + unsigned int valence = 0; + cog = zero_point; + + for (int i = 0; i <= 1; ++i) { + heh = mesh_.halfedge_handle(*e_it, i); + if (mesh_.face_handle(heh).is_valid()) + { + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(heh))).position() * (1.0 - _c); + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh)))).position() * (1.0 - _c); + ++valence; + ++valence; + } + } + + cog /= valence; + cog += mesh_.data(e_it).position() * _c; + point_vector.push_back(cog); + } + + for (e_it = mesh_.edges_end(); e_it != mesh_.edges_begin(); ) { + + --e_it; + mesh_.data(*e_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +/// Corner Cutting +template +void CompositeT::corner_cutting(HalfedgeHandle _heh) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + // Define Halfedge Handles + typename MeshType::HalfedgeHandle heh5(_heh); + typename MeshType::HalfedgeHandle heh6(mesh_.next_halfedge_handle(_heh)); + + // Cycle around the polygon to find correct Halfedge + for (; mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh5)) != _heh; + heh5 = mesh_.next_halfedge_handle(heh5)) {}; + + typename MeshType::HalfedgeHandle heh2(mesh_.next_halfedge_handle(heh5)); + typename MeshType::HalfedgeHandle + heh3(mesh_.new_edge(mesh_.to_vertex_handle(_heh), + mesh_.to_vertex_handle(heh5))); + typename MeshType::HalfedgeHandle heh4(mesh_.opposite_halfedge_handle(heh3)); + + // Old and new Face + typename MeshType::FaceHandle fh_old(mesh_.face_handle(heh6)); + typename MeshType::FaceHandle fh_new(mesh_.new_face()); + + // Init new face + mesh_.data(fh_new).set_position(mesh_.data(fh_old).position()); + + // Re-Set Handles around old Face + mesh_.set_next_halfedge_handle(heh4, heh6); + mesh_.set_next_halfedge_handle(heh5, heh4); + + mesh_.set_face_handle(heh4, fh_old); + mesh_.set_face_handle(heh5, fh_old); + mesh_.set_face_handle(heh6, fh_old); + mesh_.set_halfedge_handle(fh_old, heh4); + + // Re-Set Handles around new Face + mesh_.set_next_halfedge_handle(_heh, heh3); + mesh_.set_next_halfedge_handle(heh3, heh2); + + mesh_.set_face_handle(_heh, fh_new); + mesh_.set_face_handle(heh2, fh_new); + mesh_.set_face_handle(heh3, fh_new); + + mesh_.set_halfedge_handle(fh_new, _heh); +} + + +/// Split Edge +template +typename MeshType::VertexHandle +CompositeT::split_edge(HalfedgeHandle _heh) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + HalfedgeHandle heh1; + HalfedgeHandle heh2; + HalfedgeHandle heh3; + HalfedgeHandle temp_heh; + + VertexHandle + vh, + vh1(mesh_.to_vertex_handle(_heh)), + vh2(mesh_.from_vertex_handle(_heh)); + + // Calculate and Insert Midpoint of Edge + vh = mesh_.add_vertex((mesh_.point(vh2) + mesh_.point(vh1)) / static_cast(2.0) ); + // Re-Set Handles + heh2 = mesh_.opposite_halfedge_handle(_heh); + + if (!mesh_.is_boundary(mesh_.edge_handle(_heh))) { + + for (temp_heh = mesh_.next_halfedge_handle(heh2); + mesh_.next_halfedge_handle(temp_heh) != heh2; + temp_heh = mesh_.next_halfedge_handle(temp_heh) ) {} + } else { + for (temp_heh = _heh; + mesh_.next_halfedge_handle(temp_heh) != heh2; + temp_heh = mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(temp_heh))) {} + } + + heh1 = mesh_.new_edge(vh, vh1); + heh3 = mesh_.opposite_halfedge_handle(heh1); + mesh_.set_vertex_handle(_heh, vh); + mesh_.set_next_halfedge_handle(temp_heh, heh3); + mesh_.set_next_halfedge_handle(heh1, mesh_.next_halfedge_handle(_heh)); + mesh_.set_next_halfedge_handle(_heh, heh1); + mesh_.set_next_halfedge_handle(heh3, heh2); + if (mesh_.face_handle(heh2).is_valid()) { + mesh_.set_face_handle(heh3, mesh_.face_handle(heh2)); + mesh_.set_halfedge_handle(mesh_.face_handle(heh3), heh3); + } + mesh_.set_face_handle(heh1, mesh_.face_handle(_heh)); + mesh_.set_halfedge_handle(vh, heh1); + mesh_.set_halfedge_handle(mesh_.face_handle(_heh), _heh); + mesh_.set_halfedge_handle(vh1, heh3); + + return vh; +} + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeT.hh new file mode 100644 index 0000000..6566d0a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeT.hh @@ -0,0 +1,251 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Uniform/Composite/CompositeT.hh + + */ + +//============================================================================= +// +// CLASS CompositeT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +/** This class provides the composite subdivision rules for the uniform case. + * + * To create a subdivider derive from this class and overload the functions + * name() and apply_rules(). In the latter one call the wanted rules. + * + * For details on the composite scheme refer to + * - P. Oswald, + * P. Schroeder "Composite primal/dual sqrt(3)-subdivision schemes", + * CAGD 20, 3, 2003, 135--164 + + * \note Not all rules are implemented! + * \see class Adaptive::CompositeT + */ +template +class CompositeT : public SubdividerT< MeshType, RealType > +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + +public: + + CompositeT(void) : parent_t(), p_mesh_(NULL) {} + explicit CompositeT(MeshType& _mesh) : parent_t(_mesh), p_mesh_(NULL) {}; + virtual ~CompositeT() { } + +public: // inherited interface + + virtual const char *name( void ) const = 0; + +protected: // inherited interface + + bool prepare( MeshType& _m ); + + bool subdivide( MeshType& _m, size_t _n, const bool _update_points = true ) + { + assert( p_mesh_ == &_m ); + + while(_n--) + { + apply_rules(); + commit(_m); + } + + return true; + } + +#ifdef NDEBUG + bool cleanup( MeshType& ) +#else + bool cleanup( MeshType& _m ) +#endif + { + assert( p_mesh_ == &_m ); + p_mesh_=NULL; + return true; + } + +protected: + + /// Assemble here the rule sequence, by calling the constructor + /// of the wanted rules. + virtual void apply_rules(void) = 0; + +protected: + + /// Move vertices to new positions after the rules have been applied + /// to the mesh (called by subdivide()). + void commit( MeshType &_m) + { + typename MeshType::VertexIter v_it; + + for (v_it=_m.vertices_begin(); v_it != _m.vertices_end(); ++v_it) + _m.set_point(*v_it, _m.data(*v_it).position()); + } + + +public: + + /// Abstract base class for coefficient functions + struct Coeff + { + virtual ~Coeff() { } + virtual double operator() (size_t _valence) = 0; + }; + + +protected: + + typedef typename MeshType::Scalar scalar_t; + typedef typename MeshType::VertexHandle VertexHandle; + typedef typename MeshType::FaceHandle FaceHandle; + typedef typename MeshType::EdgeHandle EdgeHandle; + typedef typename MeshType::HalfedgeHandle HalfedgeHandle; + + /// \name Uniform composite subdivision rules + //@{ + + + void Tvv3(); ///< Split Face, using Vertex information (1-3 split) + void Tvv4(); ///< Split Face, using Vertex information (1-4 split) + void Tfv(); ///< Split Face, using Face Information + + void FF(); ///< Face to face averaging. + void FFc(Coeff& _coeff); ///< Weighted face to face averaging. + void FFc(scalar_t _c); ///< Weighted face to face averaging. + + void FV(); ///< Face to vertex averaging. + void FVc(Coeff& _coeff); ///< Weighted face to vertex Averaging with flaps + void FVc(scalar_t _c); ///< Weighted face to vertex Averaging with flaps + + void FE(); ///< Face to edge averaging. + + void VF(); ///< Vertex to Face Averaging. + void VFa(Coeff& _coeff); ///< Vertex to Face Averaging, weighted. + void VFa(scalar_t _alpha); ///< Vertex to Face Averaging, weighted. + + void VV(); ///< Vertex to vertex averaging. + void VVc(Coeff& _coeff); ///< Vertex to vertex averaging, weighted. + void VVc(scalar_t _c); ///< Vertex to vertex averaging, weighted. + + void VE(); ///< VE Step (Vertex to Edge Averaging) + + + void VdE(); ///< Vertex to edge averaging, using diamond of edges. + void VdEc(scalar_t _c); ///< Weighted vertex to edge averaging, using diamond of edges + + /// Weigthed vertex to edge averaging, using diamond of edges for + /// irregular vertices. + void VdEg(Coeff& _coeff); + /// Weigthed vertex to edge averaging, using diamond of edges for + /// irregular vertices. + void VdEg(scalar_t _gamma); + + void EF(); ///< Edge to face averaging. + + void EV(); ///< Edge to vertex averaging. + void EVc(Coeff& _coeff); ///< Weighted edge to vertex averaging. + void EVc(scalar_t _c); ///< Weighted edge to vertex averaging. + + void EdE(); ///< Edge to edge averaging w/ flap rule. + void EdEc(scalar_t _c); ///< Weighted edge to edge averaging w/ flap rule. + + + //@} + + void corner_cutting(HalfedgeHandle _heh); + + VertexHandle split_edge(HalfedgeHandle _heh); + +private: + + MeshType* p_mesh_; + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC) +#define OPENMESH_SUBDIVIDER_TEMPLATES +#include "CompositeT.cc" +#endif +//============================================================================= +#endif // COMPOSITET_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeTraits.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeTraits.hh new file mode 100644 index 0000000..0ba352f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Composite/CompositeTraits.hh @@ -0,0 +1,168 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Uniform/Composite/CompositeTraits.hh + Mesh traits for uniform composite subdivision. + */ + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITETRAITS_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITETRAITS_HH + + +//== INCLUDES ================================================================= + +//#include "Config.hh" +// -------------------- +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + + +/** Uniform Composite Subdivision framework. +*/ + +struct CompositeTraits : public OpenMesh::DefaultTraits +{ + FaceAttributes( OpenMesh::Attributes::Normal ); + + VertexAttributes( OpenMesh::Attributes::Normal ); + + //HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + FaceTraits + { + private: + typedef typename Refs::HalfedgeHandle HalfedgeHandle; + typedef typename Refs::Scalar Scalar; + typedef typename Refs::Point Point; + HalfedgeHandle red_halfedge_handle_; + unsigned int generation_; + bool red_; + Scalar quality_; + Point midpoint_; + Point position_; + + public: + const unsigned int& generation() { return generation_; } + void set_generation(const unsigned int& _g) { generation_ = _g; } + void inc_generation() { ++generation_; } + void set_red() { red_ = 1; } + void set_green() {red_ = 0; } + bool is_red() { return red_; } + bool is_green() { return !red_; } + void set_red_halfedge_handle(HalfedgeHandle& _heh) + { red_halfedge_handle_ = _heh; } + HalfedgeHandle& red_halfedge_handle() { return red_halfedge_handle_; } + void set_quality(Scalar& _q) { quality_ = _q; } + Scalar& quality() { return quality_; } + const Point& midpoint() const { return midpoint_; } + void set_midpoint(const Point& _p) { midpoint_ = _p; } + const Point& position() const { return position_; } + void set_position(const Point& _p) { position_ = _p; } + }; + + EdgeTraits + { + private: + typedef typename Refs::Point Point; + typedef typename Refs::Scalar Scalar; + Point midpoint_; + Scalar length_; + Point position_; + public: + const Point& midpoint() const { return midpoint_; } + void set_midpoint(const Point& _vh) { midpoint_ = _vh; } + const Scalar& length() const { return length_; } + void set_length(const Scalar& _s) { length_ = _s; } + const Point& position() const { return position_; } + void set_position(const Point& _p) { position_ = _p; } + }; + + VertexTraits + { + private: + typedef typename Refs::Point Point; + Point new_pos_; + Point orig_pos_; + Point position_; + unsigned int generation_; + public: + const Point& new_pos() const { return new_pos_; } + void set_new_pos(const Point& _p) { new_pos_ = _p; } + const unsigned int& generation() const { return generation_; } + void set_generation(const unsigned int& _i) { generation_ = _i; } + const Point& orig_pos() const { return orig_pos_; } + void set_orig_pos(const Point& _p) { orig_pos_ = _p; } + const Point& position() const { return position_; } + void set_position(const Point& _p) { position_ = _p; } + }; +}; + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITETRAITS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CompositeLoopT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CompositeLoopT.hh new file mode 100644 index 0000000..ad2f3bf --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CompositeLoopT.hh @@ -0,0 +1,157 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file CompositeLoopT.hh + + */ + +//============================================================================= +// +// CLASS LoopT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH + + +//== INCLUDES ================================================================= + +#include "Composite/CompositeT.hh" +#include "Composite/CompositeTraits.hh" + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + +/** Uniform composite Loop subdivision algorithm + */ +template +class CompositeLoopT : public CompositeT +{ +public: + + typedef CompositeT Inherited; + +public: + + CompositeLoopT() : Inherited() {}; + CompositeLoopT(MeshType& _mesh) : Inherited(_mesh) {}; + ~CompositeLoopT() {} + +public: + + const char *name() const { return "Uniform Composite Loop"; } + +protected: // inherited interface + + void apply_rules(void) + { + Inherited::Tvv4(); + Inherited::VdE(); + Inherited::EVc(coeffs_); + Inherited::VdE(); + Inherited::EVc(coeffs_); + } + +protected: + + typedef typename Inherited::Coeff Coeff; + + + /** Helper struct + * \internal + */ + struct EVCoeff : public Coeff + { + EVCoeff() : Coeff() { init(50); } + + void init(size_t _max_valence) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), + weights_.end(), compute_weight() ); + } + + double operator()(size_t _valence) { return weights_[_valence]; } + + /// \internal + struct compute_weight + { + compute_weight() : val_(0) { } + + double operator()(void) // Loop weights for non-boundary vertices + { + // 1 3 2 * pi + // - * ( --- + cos ( ------- ) )� - 1.0 + // 2 2 valence + double f1 = 1.5 + cos(2.0*M_PI/val_++); + return 0.5 * f1 * f1 - 1.0; + } + size_t val_; + + }; + + std::vector weights_; + } coeffs_; + +}; + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CompositeSqrt3T.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CompositeSqrt3T.hh new file mode 100644 index 0000000..2870593 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/CompositeSqrt3T.hh @@ -0,0 +1,153 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file CompositeSqrt3T.hh + + */ + +//============================================================================= +// +// CLASS SQRT3T +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITESQRT3T_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITESQRT3T_HH + + +//== INCLUDES ================================================================= + +#include "Composite/CompositeT.hh" +#include "Composite/CompositeTraits.hh" + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +/** Uniform composite sqrt(3) subdivision algorithm + */ +template +class CompositeSqrt3T : public CompositeT +{ +public: + + typedef CompositeT Inherited; + +public: + + CompositeSqrt3T() : Inherited() {}; + CompositeSqrt3T(MeshType& _mesh) : Inherited(_mesh) {}; + ~CompositeSqrt3T() {} + +public: + + const char *name() const { return "Uniform Composite Sqrt3"; } + +protected: // inherited interface + + void apply_rules(void) + { + Inherited::Tvv3(); + Inherited::VF(); + Inherited::FF(); + Inherited::FVc(coeffs_); + } + +protected: + + typedef typename Inherited::Coeff Coeff; + + /** Helper class + * \internal + */ + struct FVCoeff : public Coeff + { + FVCoeff() : Coeff() { init(50); } + + void init(size_t _max_valence) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), + weights_.end(), compute_weight() ); + } + + double operator()(size_t _valence) { return weights_[_valence]; } + + /** \internal + */ + struct compute_weight + { + compute_weight() : val_(0) { } + + double operator()(void) // sqrt(3) weights for non-boundary vertices + { + return 2.0/3.0 * (cos(2.0*M_PI/val_++)+1.0); + } + size_t val_; + }; + + std::vector weights_; + + } coeffs_; + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITESQRT3T_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/LongestEdgeT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/LongestEdgeT.hh new file mode 100644 index 0000000..c689af3 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/LongestEdgeT.hh @@ -0,0 +1,225 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*==========================================================================*\ +* * +* $Revision: 410 $ * +* $Date: 2010-06-17 12:45:58 +0200 (Do, 17. Jun 2010) $ * +* * +\*==========================================================================*/ + +/** \file LongestEdgeT.hh + +*/ + +//============================================================================= +// +// CLASS LongestEdgeT +// +//============================================================================= + + +#ifndef LINEAR_H +#define LINEAR_H + +#include +#include +#include +// -------------------- STL +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +template +class CompareLengthFunction { + public: + + typedef std::pair queueElement; + + bool operator()(const queueElement& t1, const queueElement& t2) // Returns true if t1 is smaller than t2 + { + return (t1.second < t2.second); + } +}; + + +/** %Uniform LongestEdgeT subdivision algorithm + * + * Very simple algorithm splitting all edges which are longer than given via + * set_max_edge_length(). The split is always performed on the longest + * edge in the mesh. + */ +template +class LongestEdgeT : public SubdividerT +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::vector< std::vector > weights_t; + typedef std::vector weight_t; + + typedef std::pair< typename mesh_t::EdgeHandle, real_t > queueElement; + +public: + + + LongestEdgeT() : parent_t() + { } + + + LongestEdgeT( mesh_t& _m) : parent_t(_m) + { } + + + ~LongestEdgeT() {} + + +public: + + + const char *name() const { return "Longest Edge Split"; } + + void set_max_edge_length(double _value) { + max_edge_length_squared_ = _value * _value; + } + +protected: + + + bool prepare( mesh_t& _m ) + { + return true; + } + + + bool cleanup( mesh_t& _m ) + { + return true; + } + + + bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true) + { + + // Sorted queue containing all edges sorted by their decreasing length + std::priority_queue< queueElement, std::vector< queueElement > , CompareLengthFunction< mesh_t, real_t > > queue; + + // Build the initial queue + // First element should be longest edge + typename mesh_t::EdgeIter edgesEnd = _m.edges_end(); + for ( typename mesh_t::EdgeIter eit = _m.edges_begin(); eit != edgesEnd; ++eit) { + const typename MeshType::Point to = _m.point(_m.to_vertex_handle(_m.halfedge_handle(*eit,0))); + const typename MeshType::Point from = _m.point(_m.from_vertex_handle(_m.halfedge_handle(*eit,0))); + + real_t length = (to - from).sqrnorm(); + + // Only push the edges that need to be split + if ( length > max_edge_length_squared_ ) + queue.push( queueElement(*eit,length) ); + } + + bool stop = false; + while ( !stop && ! queue.empty() ) { + queueElement a = queue.top(); + queue.pop(); + + if ( a.second < max_edge_length_squared_ ) { + stop = true; + break; + } else { + const typename MeshType::Point to = _m.point(_m.to_vertex_handle(_m.halfedge_handle(a.first,0))); + const typename MeshType::Point from = _m.point(_m.from_vertex_handle(_m.halfedge_handle(a.first,0))); + const typename MeshType::Point midpoint = static_cast(0.5) * (to + from); + + const typename MeshType::VertexHandle newVertex = _m.add_vertex(midpoint); + _m.split(a.first,newVertex); + + for ( typename MeshType::VertexOHalfedgeIter voh_it(_m,newVertex); voh_it.is_valid(); ++voh_it) { + typename MeshType::EdgeHandle eh = _m.edge_handle(*voh_it); + const typename MeshType::Point to = _m.point(_m.to_vertex_handle(*voh_it)); + const typename MeshType::Point from = _m.point(_m.from_vertex_handle(*voh_it)); + real_t length = (to - from).sqrnorm(); + + // Only push the edges that need to be split + if ( length > max_edge_length_squared_ ) + queue.push( queueElement(eh,length) ); + + } + } + } + +#if defined(_DEBUG) || defined(DEBUG) + // Now we have an consistent mesh! + assert( OpenMesh::Utils::MeshCheckerT(_m).check() ); +#endif + + + return true; + } + + +private: // data + real_t max_edge_length_squared_; + +}; + +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +#endif + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/LoopT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/LoopT.hh new file mode 100644 index 0000000..7701b00 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/LoopT.hh @@ -0,0 +1,478 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file LoopT.hh + + */ + +//============================================================================= +// +// CLASS LoopT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_LOOPT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_LOOPT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + +/** %Uniform Loop subdivision algorithm. + * + * Implementation as described in + * + * C. T. Loop, "Smooth Subdivision Surfaces Based on Triangles", + * M.S. Thesis, Department of Mathematics, University of Utah, August 1987. + * + */ +template +class LoopT : public SubdividerT +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::pair< real_t, real_t > weight_t; + typedef std::vector< std::pair > weights_t; + +public: + + + LoopT(void) : parent_t(), _1over8( 1.0/8.0 ), _3over8( 3.0/8.0 ) + { init_weights(); } + + + LoopT( mesh_t& _m ) : parent_t(_m), _1over8( 1.0/8.0 ), _3over8( 3.0/8.0 ) + { init_weights(); } + + + ~LoopT() {} + + +public: + + + const char *name() const { return "Uniform Loop"; } + + + /// Pre-compute weights + void init_weights(size_t _max_valence=50) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), weights_.end(), compute_weight()); + } + + +protected: + + + bool prepare( mesh_t& _m ) + { + _m.add_property( vp_pos_ ); + _m.add_property( ep_pos_ ); + return true; + } + + + bool cleanup( mesh_t& _m ) + { + _m.remove_property( vp_pos_ ); + _m.remove_property( ep_pos_ ); + return true; + } + + + bool subdivide( mesh_t& _m, size_t _n, const bool _update_points = true) + { + + ///TODO:Implement fixed positions + + typename mesh_t::FaceIter fit, f_end; + typename mesh_t::EdgeIter eit, e_end; + typename mesh_t::VertexIter vit; + + // Do _n subdivisions + for (size_t i=0; i < _n; ++i) + { + + if(_update_points) { + // compute new positions for old vertices + for (vit = _m.vertices_begin(); vit != _m.vertices_end(); ++vit) { + smooth(_m, *vit); + } + } + + // Compute position for new vertices and store them in the edge property + for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) + compute_midpoint( _m, *eit ); + + // Split each edge at midpoint and store precomputed positions (stored in + // edge property ep_pos_) in the vertex property vp_pos_; + + // Attention! Creating new edges, hence make sure the loop ends correctly. + e_end = _m.edges_end(); + for (eit=_m.edges_begin(); eit != e_end; ++eit) + split_edge(_m, *eit ); + + + // Commit changes in topology and reconsitute consistency + + // Attention! Creating new faces, hence make sure the loop ends correctly. + f_end = _m.faces_end(); + for (fit = _m.faces_begin(); fit != f_end; ++fit) + split_face(_m, *fit ); + + if(_update_points) { + // Commit changes in geometry + for ( vit = _m.vertices_begin(); + vit != _m.vertices_end(); ++vit) { + _m.set_point(*vit, _m.property( vp_pos_, *vit ) ); + } + } + + +#if defined(_DEBUG) || defined(DEBUG) + // Now we have an consistent mesh! + assert( OpenMesh::Utils::MeshCheckerT(_m).check() ); +#endif + } + + return true; + } + +private: + + /// Helper functor to compute weights for Loop-subdivision + /// \internal + struct compute_weight + { + compute_weight() : valence(-1) { } + weight_t operator() (void) + { +#if !defined(OM_CC_MIPS) + using std::cos; +#endif + // 1 + // alpha(n) = ---- * (40 - ( 3 + 2 cos( 2 Pi / n ) )� ) + // 64 + + if (++valence) + { + double inv_v = 1.0/double(valence); + double t = (3.0 + 2.0 * cos( 2.0 * M_PI * inv_v) ); + double alpha = (40.0 - t * t)/64.0; + + return weight_t( static_cast(1.0-alpha), static_cast(inv_v*alpha) ); + } + return weight_t(static_cast(0.0), static_cast(0.0)); + } + int valence; + }; + +private: // topological modifiers + + void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh) + { + typename mesh_t::HalfedgeHandle + heh1(_m.halfedge_handle(_fh)), + heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))), + heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2))); + + // Cutting off every corner of the 6_gon + corner_cutting( _m, heh1 ); + corner_cutting( _m, heh2 ); + corner_cutting( _m, heh3 ); + } + + + void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he) + { + // Define Halfedge Handles + typename mesh_t::HalfedgeHandle + heh1(_he), + heh5(heh1), + heh6(_m.next_halfedge_handle(heh1)); + + // Cycle around the polygon to find correct Halfedge + for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1; + heh5 = _m.next_halfedge_handle(heh5)) + {} + + typename mesh_t::VertexHandle + vh1 = _m.to_vertex_handle(heh1), + vh2 = _m.to_vertex_handle(heh5); + + typename mesh_t::HalfedgeHandle + heh2(_m.next_halfedge_handle(heh5)), + heh3(_m.new_edge( vh1, vh2)), + heh4(_m.opposite_halfedge_handle(heh3)); + + /* Intermediate result + * + * * + * 5 /|\ + * /_ \ + * vh2> * * + * /|\3 |\ + * /_ \|4 \ + * *----\*----\* + * 1 ^ 6 + * vh1 (adjust_outgoing halfedge!) + */ + + // Old and new Face + typename mesh_t::FaceHandle fh_old(_m.face_handle(heh6)); + typename mesh_t::FaceHandle fh_new(_m.new_face()); + + + // Re-Set Handles around old Face + _m.set_next_halfedge_handle(heh4, heh6); + _m.set_next_halfedge_handle(heh5, heh4); + + _m.set_face_handle(heh4, fh_old); + _m.set_face_handle(heh5, fh_old); + _m.set_face_handle(heh6, fh_old); + _m.set_halfedge_handle(fh_old, heh4); + + // Re-Set Handles around new Face + _m.set_next_halfedge_handle(heh1, heh3); + _m.set_next_halfedge_handle(heh3, heh2); + + _m.set_face_handle(heh1, fh_new); + _m.set_face_handle(heh2, fh_new); + _m.set_face_handle(heh3, fh_new); + + _m.set_halfedge_handle(fh_new, heh1); + } + + + void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) + { + typename mesh_t::HalfedgeHandle + heh = _m.halfedge_handle(_eh, 0), + opp_heh = _m.halfedge_handle(_eh, 1); + + typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh; + typename mesh_t::VertexHandle vh; + typename mesh_t::VertexHandle vh1(_m.to_vertex_handle(heh)); + typename mesh_t::Point midP(_m.point(_m.to_vertex_handle(heh))); + midP += _m.point(_m.to_vertex_handle(opp_heh)); + midP *= static_cast(0.5); + + // new vertex + vh = _m.new_vertex( midP ); + + // memorize position, will be set later + _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh ); + + + // Re-link mesh entities + if (_m.is_boundary(_eh)) + { + for (t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + } + else + { + for (t_heh = _m.next_halfedge_handle(opp_heh); + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.next_halfedge_handle(t_heh) ) + {} + } + + new_heh = _m.new_edge(vh, vh1); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + _m.set_vertex_handle( heh, vh ); + + _m.set_next_halfedge_handle(t_heh, opp_new_heh); + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); + _m.set_next_halfedge_handle(heh, new_heh); + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); + + if (_m.face_handle(opp_heh).is_valid()) + { + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh); + } + + _m.set_face_handle( new_heh, _m.face_handle(heh) ); + _m.set_halfedge_handle( vh, new_heh); + _m.set_halfedge_handle( _m.face_handle(heh), heh ); + _m.set_halfedge_handle( vh1, opp_new_heh ); + + // Never forget this, when playing with the topology + _m.adjust_outgoing_halfedge( vh ); + _m.adjust_outgoing_halfedge( vh1 ); + } + +private: // geometry helper + + void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) + { +#define V( X ) vector_cast< typename mesh_t::Normal >( X ) + typename mesh_t::HalfedgeHandle heh, opp_heh; + + heh = _m.halfedge_handle( _eh, 0); + opp_heh = _m.halfedge_handle( _eh, 1); + + typename mesh_t::Point + pos(_m.point(_m.to_vertex_handle(heh))); + + pos += V( _m.point(_m.to_vertex_handle(opp_heh)) ); + + // boundary edge: just average vertex positions + if (_m.is_boundary(_eh) ) + { + pos *= static_cast(0.5); + } + else // inner edge: add neighbouring Vertices to sum + { + pos *= real_t(3.0); + pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)))); + pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh)))); + pos *= _1over8; + } + _m.property( ep_pos_, _eh ) = pos; +#undef V + } + + void smooth(mesh_t& _m, const typename mesh_t::VertexHandle& _vh) + { + typename mesh_t::Point pos(0.0,0.0,0.0); + + if (_m.is_boundary(_vh) ) // if boundary: Point 1-6-1 + { + typename mesh_t::HalfedgeHandle heh, prev_heh; + heh = _m.halfedge_handle( _vh ); + + if ( heh.is_valid() ) + { + assert( _m.is_boundary( _m.edge_handle( heh ) ) ); + + prev_heh = _m.prev_halfedge_handle( heh ); + + typename mesh_t::VertexHandle + to_vh = _m.to_vertex_handle( heh ), + from_vh = _m.from_vertex_handle( prev_heh ); + + // ( v_l + 6 v + v_r ) / 8 + pos = _m.point( _vh ); + pos *= real_t(6.0); + pos += vector_cast< typename mesh_t::Normal >( _m.point( to_vh ) ); + pos += vector_cast< typename mesh_t::Normal >( _m.point( from_vh ) ); + pos *= _1over8; + + } + else + return; + } + else // inner vertex: (1-a) * p + a/n * Sum q, q in one-ring of p + { + typedef typename mesh_t::Normal Vec; + typename mesh_t::VertexVertexIter vvit; + size_t valence(0); + + // Calculate Valence and sum up neighbour points + for (vvit=_m.vv_iter(_vh); vvit.is_valid(); ++vvit) { + ++valence; + pos += vector_cast< Vec >( _m.point(*vvit) ); + } + pos *= weights_[valence].second; // alpha(n)/n * Sum q, q in one-ring of p + pos += weights_[valence].first + * vector_cast(_m.point(_vh)); // + (1-a)*p + } + + _m.property( vp_pos_, _vh ) = pos; + } + +private: // data + + OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_; + OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_; + + weights_t weights_; + + const real_t _1over8; + const real_t _3over8; + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh new file mode 100644 index 0000000..3014449 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include + +#include + +namespace OpenMesh { +namespace Subdivider { +namespace Uniform { + +/** + * Midpoint subdivision algorithm. + * + * With every step, the set of vertices is replaced by the midpoints of all + * current edges. Then, two sets of faces are created to set up the new + * connectivity: From all midpoints of edges surrounding an original face, a new + * face is created. Also, for all midpoints of edges surrounding an original + * vertex, a new face is created. + * + * @note This algorithm ignores the _update_points option. + * @note This algorithm is best suited for closed meshes since boundaries tend + * to fragment into isolated faces after a few iterations. + */ +template +class MidpointT : public SubdividerT +{ +public: + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT parent_t; + + // Inherited constructors + MidpointT() : parent_t() {} + MidpointT(mesh_t& _m) : parent_t(_m) {} + + const char* name() const { return "midpoint"; } + +protected: // SubdividerT interface + bool prepare(mesh_t& _m) + { + return true; + } + + //! Performs one step of Midpoint subdivision. + //! @note The _update_points option is ignored + bool subdivide(mesh_t& _m, size_t _n, const bool _update_points = true) + { + _m.request_halfedge_status(); + _m.request_edge_status(); + _m.request_vertex_status(); + _m.request_face_status(); + PropertyManager, mesh_t> edge_midpoint(_m, "edge_midpoint"); + PropertyManager, mesh_t> is_original_vertex(_m, "is_original_vertex"); + + for (size_t iteration = 0; iteration < _n; ++iteration) { + is_original_vertex.set_range(_m.vertices_begin(), _m.vertices_end(), true); + // Create vertices on edge midpoints + for (typename mesh_t::EdgeIter it = _m.edges_begin(), end = _m.edges_end(); it != end; ++it) { + EdgeHandle eh = *it; + VertexHandle new_vh = _m.new_vertex(_m.calc_edge_midpoint(eh)); + edge_midpoint[eh] = new_vh; + is_original_vertex[new_vh] = false; + } + // Create new faces from original faces + for (typename mesh_t::FaceIter it = _m.faces_begin(), end = _m.faces_end(); it != end; ++it) { + FaceHandle fh = *it; + std::vector new_corners; + for (typename mesh_t::FaceEdgeIter it = _m.fe_begin(fh), end = _m.fe_end(fh); it != end; ++it) { + EdgeHandle eh = *it; + new_corners.push_back(edge_midpoint[eh]); + } + _m.add_face(new_corners); + } + // Create new faces from original vertices + for (typename mesh_t::VertexIter it = _m.vertices_begin(), end = _m.vertices_end(); it != end; ++it) { + VertexHandle vh = *it; + if (is_original_vertex[vh]) { + if (!_m.is_boundary(vh)) { + std::vector new_corners; + for (typename mesh_t::VertexEdgeIter it = _m.ve_begin(vh), end = _m.ve_end(vh); it != end; ++it) { + EdgeHandle eh = *it; + new_corners.push_back(edge_midpoint[eh]); + } + std::reverse(new_corners.begin(), new_corners.end()); + _m.add_face(new_corners); + } + } + } + for (typename mesh_t::VertexIter it = _m.vertices_begin(), end = _m.vertices_end(); it != end; ++it) { + VertexHandle vh = *it; + if (is_original_vertex[vh]) { + _m.delete_vertex(vh); + } + } + _m.garbage_collection(); + } + _m.release_face_status(); + _m.release_vertex_status(); + _m.release_edge_status(); + _m.release_halfedge_status(); + return true; + } + + bool cleanup(mesh_t& _m) + { + return true; + } +}; + +} // namespace Uniform +} // namespace Subdivider +} // namespace OpenMesh diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/ModifiedButterFlyT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/ModifiedButterFlyT.hh new file mode 100644 index 0000000..5825c9b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/ModifiedButterFlyT.hh @@ -0,0 +1,562 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*==========================================================================*\ +* * +* $Revision: 410 $ * +* $Date: 2010-06-17 12:45:58 +0200 (Do, 17. Jun 2010) $ * +* * +\*==========================================================================*/ + +/** \file ModifiedButterFlyT.hh + +The modified butterfly scheme of Denis Zorin, Peter Schröder and Wim Sweldens, +``Interpolating subdivision for meshes with arbitrary topology,'' in Proceedings +of SIGGRAPH 1996, ACM SIGGRAPH, 1996, pp. 189-192. + +Clement Courbet - clement.courbet@ecp.fr +*/ + +//============================================================================= +// +// CLASS ModifiedButterflyT +// +//============================================================================= + + +#ifndef SP_MODIFIED_BUTTERFLY_H +#define SP_MODIFIED_BUTTERFLY_H + +#include +#include +#include +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + + +/** Modified Butterfly subdivision algorithm + * + * Implementation of the modified butterfly scheme of Denis Zorin, Peter Schröder and Wim Sweldens, + * ``Interpolating subdivision for meshes with arbitrary topology,'' in Proceedings + * of SIGGRAPH 1996, ACM SIGGRAPH, 1996, pp. 189-192. + * + * Clement Courbet - clement.courbet@ecp.fr + */ +template +class ModifiedButterflyT : public SubdividerT +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::vector< std::vector > weights_t; + typedef std::vector weight_t; + +public: + + + ModifiedButterflyT() : parent_t() + { init_weights(); } + + + ModifiedButterflyT( mesh_t& _m) : parent_t(_m) + { init_weights(); } + + + ~ModifiedButterflyT() {} + + +public: + + + const char *name() const { return "Uniform Spectral"; } + + + /// Pre-compute weights + void init_weights(size_t _max_valence=30) + { + weights.resize(_max_valence); + + //special case: K==3, K==4 + weights[3].resize(4); + weights[3][0] = real_t(5.0)/12; + weights[3][1] = real_t(-1.0)/12; + weights[3][2] = real_t(-1.0)/12; + weights[3][3] = real_t(3.0)/4; + + weights[4].resize(5); + weights[4][0] = real_t(3.0)/8; + weights[4][1] = 0; + weights[4][2] = real_t(-1.0)/8; + weights[4][3] = 0; + weights[4][4] = real_t(3.0)/4; + + for(unsigned int K = 5; K<_max_valence; ++K) + { + weights[K].resize(K+1); + // s(j) = ( 1/4 + cos(2*pi*j/K) + 1/2 * cos(4*pi*j/K) )/K + double invK = 1.0/static_cast(K); + real_t sum = 0; + for(unsigned int j=0; j((0.25 + cos(2.0*M_PI*static_cast(j)*invK) + 0.5*cos(4.0*M_PI*static_cast(j)*invK))*invK); + sum += weights[K][j]; + } + weights[K][K] = static_cast(1.0) - sum; + } + } + + +protected: + + + bool prepare( mesh_t& _m ) + { + _m.add_property( vp_pos_ ); + _m.add_property( ep_pos_ ); + return true; + } + + + bool cleanup( mesh_t& _m ) + { + _m.remove_property( vp_pos_ ); + _m.remove_property( ep_pos_ ); + return true; + } + + + bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true) + { + + ///TODO:Implement fixed positions + + typename mesh_t::FaceIter fit, f_end; + typename mesh_t::EdgeIter eit, e_end; + typename mesh_t::VertexIter vit; + + // Do _n subdivisions + for (size_t i=0; i < _n; ++i) + { + + // This is an interpolating scheme, old vertices remain the same. + typename mesh_t::VertexIter initialVerticesEnd = _m.vertices_end(); + for ( vit = _m.vertices_begin(); vit != initialVerticesEnd; ++vit) + _m.property( vp_pos_, *vit ) = _m.point(*vit); + + // Compute position for new vertices and store them in the edge property + for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) + compute_midpoint( _m, *eit ); + + + // Split each edge at midpoint and store precomputed positions (stored in + // edge property ep_pos_) in the vertex property vp_pos_; + + // Attention! Creating new edges, hence make sure the loop ends correctly. + e_end = _m.edges_end(); + for (eit=_m.edges_begin(); eit != e_end; ++eit) + split_edge(_m, *eit ); + + + // Commit changes in topology and reconsitute consistency + + // Attention! Creating new faces, hence make sure the loop ends correctly. + f_end = _m.faces_end(); + for (fit = _m.faces_begin(); fit != f_end; ++fit) + split_face(_m, *fit ); + + + // Commit changes in geometry + for ( vit = /*initialVerticesEnd;*/_m.vertices_begin(); + vit != _m.vertices_end(); ++vit) + _m.set_point(*vit, _m.property( vp_pos_, *vit ) ); + +#if defined(_DEBUG) || defined(DEBUG) + // Now we have an consistent mesh! + assert( OpenMesh::Utils::MeshCheckerT(_m).check() ); +#endif + } + + return true; + } + +private: // topological modifiers + + void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh) + { + typename mesh_t::HalfedgeHandle + heh1(_m.halfedge_handle(_fh)), + heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))), + heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2))); + + // Cutting off every corner of the 6_gon + corner_cutting( _m, heh1 ); + corner_cutting( _m, heh2 ); + corner_cutting( _m, heh3 ); + } + + + void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he) + { + // Define Halfedge Handles + typename mesh_t::HalfedgeHandle + heh1(_he), + heh5(heh1), + heh6(_m.next_halfedge_handle(heh1)); + + // Cycle around the polygon to find correct Halfedge + for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1; + heh5 = _m.next_halfedge_handle(heh5)) + {} + + typename mesh_t::VertexHandle + vh1 = _m.to_vertex_handle(heh1), + vh2 = _m.to_vertex_handle(heh5); + + typename mesh_t::HalfedgeHandle + heh2(_m.next_halfedge_handle(heh5)), + heh3(_m.new_edge( vh1, vh2)), + heh4(_m.opposite_halfedge_handle(heh3)); + + /* Intermediate result + * + * * + * 5 /|\ + * /_ \ + * vh2> * * + * /|\3 |\ + * /_ \|4 \ + * *----\*----\* + * 1 ^ 6 + * vh1 (adjust_outgoing halfedge!) + */ + + // Old and new Face + typename mesh_t::FaceHandle fh_old(_m.face_handle(heh6)); + typename mesh_t::FaceHandle fh_new(_m.new_face()); + + + // Re-Set Handles around old Face + _m.set_next_halfedge_handle(heh4, heh6); + _m.set_next_halfedge_handle(heh5, heh4); + + _m.set_face_handle(heh4, fh_old); + _m.set_face_handle(heh5, fh_old); + _m.set_face_handle(heh6, fh_old); + _m.set_halfedge_handle(fh_old, heh4); + + // Re-Set Handles around new Face + _m.set_next_halfedge_handle(heh1, heh3); + _m.set_next_halfedge_handle(heh3, heh2); + + _m.set_face_handle(heh1, fh_new); + _m.set_face_handle(heh2, fh_new); + _m.set_face_handle(heh3, fh_new); + + _m.set_halfedge_handle(fh_new, heh1); + } + + + void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) + { + typename mesh_t::HalfedgeHandle + heh = _m.halfedge_handle(_eh, 0), + opp_heh = _m.halfedge_handle(_eh, 1); + + typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh; + typename mesh_t::VertexHandle vh; + typename mesh_t::VertexHandle vh1(_m.to_vertex_handle(heh)); + typename mesh_t::Point zero(0,0,0); + + // new vertex + vh = _m.new_vertex( zero ); + + // memorize position, will be set later + _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh ); + + + // Re-link mesh entities + if (_m.is_boundary(_eh)) + { + for (t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + } + else + { + for (t_heh = _m.next_halfedge_handle(opp_heh); + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.next_halfedge_handle(t_heh) ) + {} + } + + new_heh = _m.new_edge(vh, vh1); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + _m.set_vertex_handle( heh, vh ); + + _m.set_next_halfedge_handle(t_heh, opp_new_heh); + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); + _m.set_next_halfedge_handle(heh, new_heh); + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); + + if (_m.face_handle(opp_heh).is_valid()) + { + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh); + } + + _m.set_face_handle( new_heh, _m.face_handle(heh) ); + _m.set_halfedge_handle( vh, new_heh); + _m.set_halfedge_handle( _m.face_handle(heh), heh ); + _m.set_halfedge_handle( vh1, opp_new_heh ); + + // Never forget this, when playing with the topology + _m.adjust_outgoing_halfedge( vh ); + _m.adjust_outgoing_halfedge( vh1 ); + } + +private: // geometry helper + + void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) + { + typename mesh_t::HalfedgeHandle heh, opp_heh; + + heh = _m.halfedge_handle( _eh, 0); + opp_heh = _m.halfedge_handle( _eh, 1); + + typename mesh_t::Point pos(0,0,0); + + typename mesh_t::VertexHandle a_0(_m.to_vertex_handle(heh)); + typename mesh_t::VertexHandle a_1(_m.to_vertex_handle(opp_heh)); + + // boundary edge: 4-point scheme + if (_m.is_boundary(_eh) ) + { + pos = _m.point(a_0); + pos += _m.point(a_1); + pos *= static_cast(9.0/16.0); + typename mesh_t::Point tpos; + if(_m.is_boundary(heh)) + { + tpos = _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh))); + tpos += _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)))); + } + else + { + assert(_m.is_boundary(opp_heh)); + tpos = _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh))); + tpos += _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(opp_heh)))); + } + tpos *= static_cast(-1.0/16.0); + pos += tpos; + } + else + { + int valence_a_0 = _m.valence(a_0); + int valence_a_1 = _m.valence(a_1); + assert(valence_a_0>2); + assert(valence_a_1>2); + + if( (valence_a_0==6 && valence_a_1==6) || (_m.is_boundary(a_0) && valence_a_1==6) || (_m.is_boundary(a_1) && valence_a_0==6) || (_m.is_boundary(a_0) && _m.is_boundary(a_1)) )// use 8-point scheme + { + real_t alpha = real_t(1.0/2); + real_t beta = real_t(1.0/8); + real_t gamma = real_t(-1.0/16); + + //get points + typename mesh_t::VertexHandle b_0, b_1, c_0, c_1, c_2, c_3; + typename mesh_t::HalfedgeHandle t_he; + + t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(heh)); + b_0 = _m.to_vertex_handle(t_he); + if(!_m.is_boundary(_m.opposite_halfedge_handle(t_he))) + { + t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)); + c_0 = _m.to_vertex_handle(t_he); + } + + t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)); + b_1 = _m.to_vertex_handle(t_he); + if(!_m.is_boundary(t_he)) + { + t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(t_he)); + c_1 = _m.to_vertex_handle(t_he); + } + + t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(opp_heh)); + assert(b_1.idx()==_m.to_vertex_handle(t_he).idx()); + if(!_m.is_boundary(_m.opposite_halfedge_handle(t_he))) + { + t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)); + c_2 = _m.to_vertex_handle(t_he); + } + + t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(opp_heh)); + assert(b_0==_m.to_vertex_handle(t_he)); + if(!_m.is_boundary(t_he)) + { + t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(t_he)); + c_3 = _m.to_vertex_handle(t_he); + } + + //compute position. + //a0,a1,b0,b1 must exist. + assert(a_0.is_valid()); + assert(a_1.is_valid()); + assert(b_0.is_valid()); + assert(b_1.is_valid()); + //The other vertices may be created from symmetry is they are on the other side of the boundary. + + pos = _m.point(a_0); + pos += _m.point(a_1); + pos *= alpha; + + typename mesh_t::Point tpos ( _m.point(b_0) ); + tpos += _m.point(b_1); + tpos *= beta; + pos += tpos; + + typename mesh_t::Point pc_0, pc_1, pc_2, pc_3; + if(c_0.is_valid()) + pc_0 = _m.point(c_0); + else //create the point by symmetry + { + pc_0 = _m.point(a_1) + _m.point(b_0) - _m.point(a_0); + } + if(c_1.is_valid()) + pc_1 = _m.point(c_1); + else //create the point by symmetry + { + pc_1 = _m.point(a_1) + _m.point(b_1) - _m.point(a_0); + } + if(c_2.is_valid()) + pc_2 = _m.point(c_2); + else //create the point by symmetry + { + pc_2 = _m.point(a_0) + _m.point(b_1) - _m.point(a_1); + } + if(c_3.is_valid()) + pc_3 = _m.point(c_3); + else //create the point by symmetry + { + pc_3 = _m.point(a_0) + _m.point(b_0) - _m.point(a_1); + } + tpos = pc_0; + tpos += pc_1; + tpos += pc_2; + tpos += pc_3; + tpos *= gamma; + pos += tpos; + } + else //at least one endpoint is [irregular and not in boundary] + { + typename mesh_t::Point::value_type normFactor = static_cast(0.0); + + if(valence_a_0!=6 && !_m.is_boundary(a_0)) + { + assert((int)weights[valence_a_0].size()==valence_a_0+1); + typename mesh_t::HalfedgeHandle t_he = opp_heh; + for(int i = 0; i < valence_a_0 ; t_he=_m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)), ++i) + { + pos += weights[valence_a_0][i] * _m.point(_m.to_vertex_handle(t_he)); + } + assert(t_he==opp_heh); + + //add irregular vertex: + pos += weights[valence_a_0][valence_a_0] * _m.point(a_0); + ++normFactor; + } + + if(valence_a_1!=6 && !_m.is_boundary(a_1)) + { + assert((int)weights[valence_a_1].size()==valence_a_1+1); + typename mesh_t::HalfedgeHandle t_he = heh; + for(int i = 0; i < valence_a_1 ; t_he=_m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)), ++i) + { + pos += weights[valence_a_1][i] * _m.point(_m.to_vertex_handle(t_he)); + } + assert(t_he==heh); + //add irregular vertex: + pos += weights[valence_a_1][valence_a_1] * _m.point(a_1); + ++normFactor; + } + + assert(normFactor>0.1); //normFactor should be 1 or 2 + + //if both vertices are irregular, average positions: + pos /= normFactor; + } + } + _m.property( ep_pos_, _eh ) = pos; + } + +private: // data + + OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_; + OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_; + + weights_t weights; + +}; + +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +#endif + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Sqrt3InterpolatingSubdividerLabsikGreinerT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Sqrt3InterpolatingSubdividerLabsikGreinerT.hh new file mode 100644 index 0000000..903b39b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Sqrt3InterpolatingSubdividerLabsikGreinerT.hh @@ -0,0 +1,621 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*==========================================================================*\ +* * +* $Revision: 410 $ * +* $Date: 2010-06-17 12:45:58 +0200 (Do, 17. Jun 2010) $ * +* * +\*==========================================================================*/ + +/** \file Sqrt3InterpolatingSubdividerLabsikGreinerT.hh + * + * Interpolating Labsik Greiner Subdivider as described in + * "Interpolating sqrt(3) subdivision" Labsik & Greiner, 2000 + * + * Clement Courbet - clement.courbet@ecp.fr + * +*/ + +//============================================================================= +// +// CLASS InterpolatingSqrt3LGT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_INTERP_SQRT3T_LABSIK_GREINER_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_INTERP_SQRT3T_LABSIK_GREINER_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + +#if defined(_DEBUG) || defined(DEBUG) +// Makes life lot easier, when playing/messing around with low-level topology +// changing methods of OpenMesh +# include +# define ASSERT_CONSISTENCY( T, m ) \ + assert(OpenMesh::Utils::MeshCheckerT(m).check()) +#else +# define ASSERT_CONSISTENCY( T, m ) +#endif +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//#define MIRROR_TRIANGLES +//#define MIN_NORM + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + + +/** %Uniform Interpolating Sqrt3 subdivision algorithm + * + * Implementation of the interpolating Labsik Greiner Subdivider as described in + * "interpolating sqrt(3) subdivision" Labsik & Greiner, 2000 + * + * Clement Courbet - clement.courbet@ecp.fr +*/ + +template +class InterpolatingSqrt3LGT : public SubdividerT< MeshType, RealType > +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::vector< std::vector > weights_t; + +public: + + + InterpolatingSqrt3LGT(void) : parent_t() + { init_weights(); } + + InterpolatingSqrt3LGT(MeshType &_m) : parent_t(_m) + { init_weights(); } + + virtual ~InterpolatingSqrt3LGT() {} + + +public: + + + const char *name() const { return "Uniform Interpolating Sqrt3"; } + + /// Pre-compute weights + void init_weights(size_t _max_valence=50) + { + weights_.resize(_max_valence); + + weights_[3].resize(4); + weights_[3][0] = real_t(+4.0/27); + weights_[3][1] = real_t(-5.0/27); + weights_[3][2] = real_t(+4.0/27); + weights_[3][3] = real_t(+8.0/9); + + weights_[4].resize(5); + weights_[4][0] = real_t(+2.0/9); + weights_[4][1] = real_t(-1.0/9); + weights_[4][2] = real_t(-1.0/9); + weights_[4][3] = real_t(+2.0/9); + weights_[4][4] = real_t(+7.0/9); + + for(unsigned int K=5; K<_max_valence; ++K) + { + weights_[K].resize(K+1); + double aH = 2.0*cos(M_PI/static_cast(K))/3.0; + weights_[K][K] = static_cast(1.0 - aH*aH); + for(unsigned int i=0; i((aH*aH + 2.0*aH*cos(2.0*static_cast(i)*M_PI/static_cast(K) + M_PI/static_cast(K)) + + 2.0*aH*aH*cos(4.0*static_cast(i)*M_PI/static_cast(K) + 2.0*M_PI/static_cast(K)))/static_cast(K)); + } + } + + //just to be sure: + weights_[6].resize(0); + + } + + +protected: + + + bool prepare( MeshType& _m ) + { + _m.request_edge_status(); + _m.add_property( fp_pos_ ); + _m.add_property( ep_nv_ ); + _m.add_property( mp_gen_ ); + _m.property( mp_gen_ ) = 0; + + return _m.has_edge_status() + && ep_nv_.is_valid() && mp_gen_.is_valid(); + } + + + bool cleanup( MeshType& _m ) + { + _m.release_edge_status(); + _m.remove_property( fp_pos_ ); + _m.remove_property( ep_nv_ ); + _m.remove_property( mp_gen_ ); + return true; + } + + + bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true) + { + + ///TODO:Implement fixed positions + + typename MeshType::VertexIter vit; + typename MeshType::VertexVertexIter vvit; + typename MeshType::EdgeIter eit; + typename MeshType::FaceIter fit; + typename MeshType::FaceVertexIter fvit; + typename MeshType::FaceHalfedgeIter fheit; + typename MeshType::VertexHandle vh; + typename MeshType::HalfedgeHandle heh; + typename MeshType::Point pos(0,0,0), zero(0,0,0); + size_t &gen = _m.property( mp_gen_ ); + + for (size_t l=0; l<_n; ++l) + { + // tag existing edges + for (eit=_m.edges_begin(); eit != _m.edges_end();++eit) + { + _m.status( *eit ).set_tagged( true ); + if ( (gen%2) && _m.is_boundary(*eit) ) + compute_new_boundary_points( _m, *eit ); // *) creates new vertices + } + + // insert new vertices, and store pos in vp_pos_ + typename MeshType::FaceIter fend = _m.faces_end(); + for (fit = _m.faces_begin();fit != fend; ++fit) + { + if (_m.is_boundary(*fit)) + { + if(gen%2) + _m.property(fp_pos_, *fit).invalidate(); + else + { + //find the interior boundary halfedge + for( heh = _m.halfedge_handle(*fit); !_m.is_boundary( _m.opposite_halfedge_handle(heh) ); heh = _m.next_halfedge_handle(heh) ) + ; + assert(_m.is_boundary( _m.opposite_halfedge_handle(heh) )); + pos = zero; + //check for two boundaries case: + if( _m.is_boundary(_m.next_halfedge_handle(heh)) || _m.is_boundary(_m.prev_halfedge_handle(heh)) ) + { + if(_m.is_boundary(_m.prev_halfedge_handle(heh))) + heh = _m.prev_halfedge_handle(heh); //ensure that the boundary halfedges are heh and heh->next + //check for three boundaries case: + if(_m.is_boundary(_m.next_halfedge_handle(_m.next_halfedge_handle(heh)))) + { + //three boundaries, use COG of triangle + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh)); + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh))); + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh))); + } + else + { +#ifdef MIRROR_TRIANGLES + //two boundaries, mirror two triangles + pos += real_t(2.0/9) * _m.point(_m.to_vertex_handle(heh)); + pos += real_t(4.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh))); + pos += real_t(4.0/9) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh))); + pos += real_t(-1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))))); +#else + pos += real_t(7.0/24) * _m.point(_m.to_vertex_handle(heh)); + pos += real_t(3.0/8) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh))); + pos += real_t(3.0/8) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh))); + pos += real_t(-1.0/24) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))))); +#endif + } + } + else + { + vh = _m.to_vertex_handle(_m.next_halfedge_handle(heh)); + //check last vertex regularity + if((_m.valence(vh) == 6) || _m.is_boundary(vh)) + { +#ifdef MIRROR_TRIANGLES + //use regular rule and mirror one triangle + pos += real_t(5.0/9) * _m.point(vh); + pos += real_t(3.0/9) * _m.point(_m.to_vertex_handle(heh)); + pos += real_t(3.0/9) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh))); + pos += real_t(-1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.next_halfedge_handle(heh))))); + pos += real_t(-1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))))); +#else +#ifdef MIN_NORM + pos += real_t(1.0/9) * _m.point(vh); + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh)); + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh))); + pos += real_t(1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.next_halfedge_handle(heh))))); + pos += real_t(1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))))); +#else + pos += real_t(1.0/2) * _m.point(vh); + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh)); + pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh))); + pos += real_t(-1.0/12) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.next_halfedge_handle(heh))))); + pos += real_t(-1.0/12) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))))); +#endif +#endif + } + else + { + //irregular setting, use usual irregular rule + unsigned int K = _m.valence(vh); + pos += weights_[K][K]*_m.point(vh); + heh = _m.opposite_halfedge_handle( _m.next_halfedge_handle(heh) ); + for(unsigned int i = 0; iP3 (heh) in P2->pl (heh) and pl->P3 + boundary_split( _m, heh, vhl ); // split edge + pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle + boundary_split( _m, heh ); // split face + + // split pl->P3 in pl->pr and pr->P3 + boundary_split( _m, pl_P3, vhr ); + boundary_split( _m, pl_P3 ); + + assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() ); + assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() ); + } + + void boundary_split(MeshType& _m, + const typename MeshType::HalfedgeHandle& _heh, + const typename MeshType::VertexHandle& _vh) + { + assert( _m.is_boundary( _m.edge_handle(_heh) ) ); + + typename MeshType::HalfedgeHandle + heh(_heh), + opp_heh( _m.opposite_halfedge_handle(_heh) ), + new_heh, opp_new_heh; + typename MeshType::VertexHandle to_vh(_m.to_vertex_handle(heh)); + typename MeshType::HalfedgeHandle t_heh; + + /* + * P5 + * * + * /|\ + * / \ + * / \ + * / \ + * / \ + * /_ heh new \ + * *-----\*-----\*\-----* + * ^ ^ t_heh + * _vh to_vh + * + * P1 P2 P3 P4 + */ + // Re-Setting Handles + + // find halfedge point from P4 to P3 + for(t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + + assert( _m.is_boundary( t_heh ) ); + + new_heh = _m.new_edge( _vh, to_vh ); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + + // update halfedge connectivity + _m.set_next_halfedge_handle(t_heh, opp_new_heh); // P4-P3 -> P3-P2 + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); // P2-P3 -> P3-P5 + _m.set_next_halfedge_handle(heh, new_heh); // P1-P2 -> P2-P3 + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); // P3-P2 -> P2-P1 + + // both opposite halfedges point to same face + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + + // let heh finally point to new inserted vertex + _m.set_vertex_handle(heh, _vh); + + // let heh and new_heh point to same face + _m.set_face_handle(new_heh, _m.face_handle(heh)); + + // let opp_new_heh be the new outgoing halfedge for to_vh + // (replaces for opp_heh) + _m.set_halfedge_handle( to_vh, opp_new_heh ); + + // let opp_heh be the outgoing halfedge for _vh + _m.set_halfedge_handle( _vh, opp_heh ); + } + + void boundary_split( MeshType& _m, + const typename MeshType::HalfedgeHandle& _heh) + { + assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) ); + + typename MeshType::HalfedgeHandle + heh(_heh), + n_heh(_m.next_halfedge_handle(heh)); + + typename MeshType::VertexHandle + to_vh(_m.to_vertex_handle(heh)); + + typename MeshType::HalfedgeHandle + heh2(_m.new_edge(to_vh, + _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))), + heh3(_m.opposite_halfedge_handle(heh2)); + + typename MeshType::FaceHandle + new_fh(_m.new_face()), + fh(_m.face_handle(heh)); + + // Relink (half)edges + _m.set_face_handle(heh, new_fh); + _m.set_face_handle(heh2, new_fh); + _m.set_next_halfedge_handle(heh2, _m.next_halfedge_handle(_m.next_halfedge_handle(n_heh))); + _m.set_next_halfedge_handle(heh, heh2); + _m.set_face_handle( _m.next_halfedge_handle(heh2), new_fh); + + _m.set_next_halfedge_handle(heh3, n_heh); + _m.set_next_halfedge_handle(_m.next_halfedge_handle(n_heh), heh3); + _m.set_face_handle(heh3, fh); + + _m.set_halfedge_handle( fh, n_heh); + _m.set_halfedge_handle(new_fh, heh); + + + } + +private: + + weights_t weights_; + OpenMesh::FPropHandleT< typename MeshType::VertexHandle > fp_pos_; + OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle, + typename MeshType::VertexHandle> > ep_nv_; + OpenMesh::MPropHandleT< size_t > mp_gen_; +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Sqrt3T.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Sqrt3T.hh new file mode 100644 index 0000000..77e0e6b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/Sqrt3T.hh @@ -0,0 +1,527 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Sqrt3T.hh + + */ + +//============================================================================= +// +// CLASS Sqrt3T +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#if defined(_DEBUG) || defined(DEBUG) +// Makes life lot easier, when playing/messing around with low-level topology +// changing methods of OpenMesh +# include +# define ASSERT_CONSISTENCY( T, m ) \ + assert(OpenMesh::Utils::MeshCheckerT(m).check()) +#else +# define ASSERT_CONSISTENCY( T, m ) +#endif +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + + +/** %Uniform Sqrt3 subdivision algorithm + * + * Implementation as described in + * + * L. Kobbelt, "Sqrt(3) subdivision", Proceedings of SIGGRAPH 2000. + */ +template +class Sqrt3T : public SubdividerT< MeshType, RealType > +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::pair< real_t, real_t > weight_t; + typedef std::vector< std::pair > weights_t; + +public: + + + Sqrt3T(void) : parent_t(), _1over3( real_t(1.0/3.0) ), _1over27( real_t(1.0/27.0) ) + { init_weights(); } + + Sqrt3T(MeshType &_m) : parent_t(_m), _1over3( real_t(1.0/3.0) ), _1over27( real_t(1.0/27.0) ) + { init_weights(); } + + virtual ~Sqrt3T() {} + + +public: + + + const char *name() const { return "Uniform Sqrt3"; } + + + /// Pre-compute weights + void init_weights(size_t _max_valence=50) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), weights_.end(), compute_weight()); + } + + +protected: + + + bool prepare( MeshType& _m ) + { + _m.request_edge_status(); + _m.add_property( vp_pos_ ); + _m.add_property( ep_nv_ ); + _m.add_property( mp_gen_ ); + _m.property( mp_gen_ ) = 0; + + return _m.has_edge_status() && vp_pos_.is_valid() + && ep_nv_.is_valid() && mp_gen_.is_valid(); + } + + + bool cleanup( MeshType& _m ) + { + _m.release_edge_status(); + _m.remove_property( vp_pos_ ); + _m.remove_property( ep_nv_ ); + _m.remove_property( mp_gen_ ); + return true; + } + + bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true) + { + + ///TODO:Implement fixed positions + + typename MeshType::VertexIter vit; + typename MeshType::VertexVertexIter vvit; + typename MeshType::EdgeIter eit; + typename MeshType::FaceIter fit; + typename MeshType::FaceVertexIter fvit; + typename MeshType::VertexHandle vh; + typename MeshType::HalfedgeHandle heh; + typename MeshType::Point pos(0,0,0), zero(0,0,0); + size_t &gen = _m.property( mp_gen_ ); + + for (size_t l=0; l<_n; ++l) + { + // tag existing edges + for (eit=_m.edges_begin(); eit != _m.edges_end();++eit) + { + _m.status( *eit ).set_tagged( true ); + if ( (gen%2) && _m.is_boundary(*eit) ) + compute_new_boundary_points( _m, *eit ); // *) creates new vertices + } + + // do relaxation of old vertices, but store new pos in property vp_pos_ + + for (vit=_m.vertices_begin(); vit!=_m.vertices_end(); ++vit) + { + if ( _m.is_boundary(*vit) ) + { + if ( gen%2 ) + { + heh = _m.halfedge_handle(*vit); + if (heh.is_valid()) // skip isolated newly inserted vertices *) + { + typename OpenMesh::HalfedgeHandle + prev_heh = _m.prev_halfedge_handle(heh); + + assert( _m.is_boundary(heh ) ); + assert( _m.is_boundary(prev_heh) ); + + pos = _m.point(_m.to_vertex_handle(heh)); + pos += _m.point(_m.from_vertex_handle(prev_heh)); + pos *= real_t(4.0); + + pos += real_t(19.0) * _m.point( *vit ); + pos *= _1over27; + + _m.property( vp_pos_, *vit ) = pos; + } + } + else + _m.property( vp_pos_, *vit ) = _m.point( *vit ); + } + else + { + size_t valence=0; + + pos = zero; + for ( vvit = _m.vv_iter(*vit); vvit.is_valid(); ++vvit) + { + pos += _m.point( *vvit ); + ++valence; + } + pos *= weights_[ valence ].second; + pos += weights_[ valence ].first * _m.point(*vit); + _m.property( vp_pos_, *vit ) = pos; + } + } + + // insert new vertices, but store pos in vp_pos_ + typename MeshType::FaceIter fend = _m.faces_end(); + for (fit = _m.faces_begin();fit != fend; ++fit) + { + if ( (gen%2) && _m.is_boundary(*fit)) + { + boundary_split( _m, *fit ); + } + else + { + fvit = _m.fv_iter( *fit ); + pos = _m.point( *fvit); + pos += _m.point(*(++fvit)); + pos += _m.point(*(++fvit)); + pos *= _1over3; + vh = _m.add_vertex( zero ); + _m.property( vp_pos_, vh ) = pos; + _m.split( *fit, vh ); + } + } + + // commit new positions (now iterating over all vertices) + for (vit=_m.vertices_begin();vit != _m.vertices_end(); ++vit) + _m.set_point(*vit, _m.property( vp_pos_, *vit ) ); + + // flip old edges + for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) + if ( _m.status( *eit ).tagged() && !_m.is_boundary( *eit ) ) + _m.flip(*eit); + + // Now we have an consistent mesh! + ASSERT_CONSISTENCY( MeshType, _m ); + + // increase generation by one + ++gen; + } + return true; + } + +private: + + /// Helper functor to compute weights for sqrt(3)-subdivision + /// \internal + struct compute_weight + { + compute_weight() : valence(-1) { } + weight_t operator() (void) + { +#if !defined(OM_CC_MIPS) + using std::cos; +#endif + if (++valence) + { + real_t alpha = real_t( (4.0-2.0*cos(2.0*M_PI / real_t(valence)) )/9.0 ); + return weight_t( real_t(1)-alpha, alpha/real_t(valence) ); + } + return weight_t(real_t(0.0), real_t(0.0) ); + } + int valence; + }; + +private: + + // Pre-compute location of new boundary points for odd generations + // and store them in the edge property ep_nv_; + void compute_new_boundary_points( MeshType& _m, + const typename MeshType::EdgeHandle& _eh) + { + assert( _m.is_boundary(_eh) ); + + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexHandle vh1, vh2, vh3, vh4, vhl, vhr; + typename MeshType::Point zero(0,0,0), P1, P2, P3, P4; + + /* + // *---------*---------* + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // *---------*--#---#--*---------* + // + // ^ ^ ^ ^ ^ ^ + // P1 P2 pl pr P3 P4 + */ + // get halfedge pointing from P3 to P2 (outer boundary halfedge) + + heh = _m.halfedge_handle(_eh, + _m.is_boundary(_m.halfedge_handle(_eh,1))); + + assert( _m.is_boundary( _m.next_halfedge_handle( heh ) ) ); + assert( _m.is_boundary( _m.prev_halfedge_handle( heh ) ) ); + + vh1 = _m.to_vertex_handle( _m.next_halfedge_handle( heh ) ); + vh2 = _m.to_vertex_handle( heh ); + vh3 = _m.from_vertex_handle( heh ); + vh4 = _m.from_vertex_handle( _m.prev_halfedge_handle( heh )); + + P1 = _m.point(vh1); + P2 = _m.point(vh2); + P3 = _m.point(vh3); + P4 = _m.point(vh4); + + vhl = _m.add_vertex(zero); + vhr = _m.add_vertex(zero); + + _m.property(vp_pos_, vhl ) = (P1 + real_t(16.0f) * P2 + real_t(10.0f) * P3) * _1over27; + _m.property(vp_pos_, vhr ) = ( real_t(10.0f) * P2 + real_t(16.0f) * P3 + P4) * _1over27; + _m.property(ep_nv_, _eh).first = vhl; + _m.property(ep_nv_, _eh).second = vhr; + } + + + void boundary_split( MeshType& _m, const typename MeshType::FaceHandle& _fh ) + { + assert( _m.is_boundary(_fh) ); + + typename MeshType::VertexHandle vhl, vhr; + typename MeshType::FaceEdgeIter fe_it; + typename MeshType::HalfedgeHandle heh; + + // find boundary edge + for( fe_it=_m.fe_iter( _fh ); fe_it.is_valid() && !_m.is_boundary( *fe_it ); ++fe_it ) {}; + + // use precomputed, already inserted but not linked vertices + vhl = _m.property(ep_nv_, *fe_it).first; + vhr = _m.property(ep_nv_, *fe_it).second; + + /* + // *---------*---------* + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // *---------*--#---#--*---------* + // + // ^ ^ ^ ^ ^ ^ + // P1 P2 pl pr P3 P4 + */ + // get halfedge pointing from P2 to P3 (inner boundary halfedge) + + heh = _m.halfedge_handle(*fe_it, + _m.is_boundary(_m.halfedge_handle(*fe_it,0))); + + typename MeshType::HalfedgeHandle pl_P3; + + // split P2->P3 (heh) in P2->pl (heh) and pl->P3 + boundary_split( _m, heh, vhl ); // split edge + pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle + boundary_split( _m, heh ); // split face + + // split pl->P3 in pl->pr and pr->P3 + boundary_split( _m, pl_P3, vhr ); + boundary_split( _m, pl_P3 ); + + assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() ); + assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() ); + } + + void boundary_split(MeshType& _m, + const typename MeshType::HalfedgeHandle& _heh, + const typename MeshType::VertexHandle& _vh) + { + assert( _m.is_boundary( _m.edge_handle(_heh) ) ); + + typename MeshType::HalfedgeHandle + heh(_heh), + opp_heh( _m.opposite_halfedge_handle(_heh) ), + new_heh, opp_new_heh; + typename MeshType::VertexHandle to_vh(_m.to_vertex_handle(heh)); + typename MeshType::HalfedgeHandle t_heh; + + /* + * P5 + * * + * /|\ + * / \ + * / \ + * / \ + * / \ + * /_ heh new \ + * *-----\*-----\*\-----* + * ^ ^ t_heh + * _vh to_vh + * + * P1 P2 P3 P4 + */ + // Re-Setting Handles + + // find halfedge point from P4 to P3 + for(t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + + assert( _m.is_boundary( t_heh ) ); + + new_heh = _m.new_edge( _vh, to_vh ); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + + // update halfedge connectivity + + _m.set_next_halfedge_handle(t_heh, opp_new_heh); // P4-P3 -> P3-P2 + // P2-P3 -> P3-P5 + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); + _m.set_next_halfedge_handle(heh, new_heh); // P1-P2 -> P2-P3 + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); // P3-P2 -> P2-P1 + + // both opposite halfedges point to same face + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + + // let heh finally point to new inserted vertex + _m.set_vertex_handle(heh, _vh); + + // let heh and new_heh point to same face + _m.set_face_handle(new_heh, _m.face_handle(heh)); + + // let opp_new_heh be the new outgoing halfedge for to_vh + // (replaces for opp_heh) + _m.set_halfedge_handle( to_vh, opp_new_heh ); + + // let opp_heh be the outgoing halfedge for _vh + _m.set_halfedge_handle( _vh, opp_heh ); + } + + void boundary_split( MeshType& _m, + const typename MeshType::HalfedgeHandle& _heh) + { + assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) ); + + typename MeshType::HalfedgeHandle + heh(_heh), + n_heh(_m.next_halfedge_handle(heh)); + + typename MeshType::VertexHandle + to_vh(_m.to_vertex_handle(heh)); + + typename MeshType::HalfedgeHandle + heh2(_m.new_edge(to_vh, + _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))), + heh3(_m.opposite_halfedge_handle(heh2)); + + typename MeshType::FaceHandle + new_fh(_m.new_face()), + fh(_m.face_handle(heh)); + + // Relink (half)edges + +#define set_next_heh set_next_halfedge_handle +#define next_heh next_halfedge_handle + + _m.set_face_handle(heh, new_fh); + _m.set_face_handle(heh2, new_fh); + _m.set_next_heh(heh2, _m.next_heh(_m.next_heh(n_heh))); + _m.set_next_heh(heh, heh2); + _m.set_face_handle( _m.next_heh(heh2), new_fh); + + // _m.set_face_handle( _m.next_heh(_m.next_heh(heh2)), new_fh); + + _m.set_next_heh(heh3, n_heh); + _m.set_next_heh(_m.next_halfedge_handle(n_heh), heh3); + _m.set_face_handle(heh3, fh); + // _m.set_face_handle(n_heh, fh); + + _m.set_halfedge_handle( fh, n_heh); + _m.set_halfedge_handle(new_fh, heh); + +#undef set_next_halfedge_handle +#undef next_halfedge_handle + + } + +private: + + weights_t weights_; + OpenMesh::VPropHandleT< typename MeshType::Point > vp_pos_; + OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle, + typename MeshType::VertexHandle> > ep_nv_; + OpenMesh::MPropHandleT< size_t > mp_gen_; + + const real_t _1over3; + const real_t _1over27; +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh new file mode 100644 index 0000000..08b2c0b --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh @@ -0,0 +1,196 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file SubdividerT.hh + + */ + +//============================================================================= +// +// CLASS SubdividerT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_SUDIVIDERT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_SUDIVIDERT_HH + +//== INCLUDE ================================================================== + +#include +#include +#if defined(_DEBUG) || defined(DEBUG) +// Makes life lot easier, when playing/messing around with low-level topology +// changing methods of OpenMesh +# include +# define ASSERT_CONSISTENCY( T, m ) \ + assert(OpenMesh::Utils::MeshCheckerT(m).check()) +#else +# define ASSERT_CONSISTENCY( T, m ) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Subdivider { +namespace Uniform { + +//== CLASS DEFINITION ========================================================= + +/** Abstract base class for uniform subdivision algorithms. + * + * A derived class must overload the following functions: + * -# const char* name() const + * -# void prepare(MeshType&) + * -# void subdivide(MeshType&, size_t, bool) + * -# void cleanup(MeshType&) + */ +template +class SubdividerT : private Utils::Noncopyable +{ +public: + + typedef MeshType mesh_t; + typedef RealType real_t; + +public: + + /// \name Constructors + //@{ + /// Constructor to be used with interface 2 + /// \see attach(), operator()(size_t), detach() + SubdividerT(void) : attached_() { } + + /// Constructor to be used with interface 1 (calls attach()) + /// \see operator()( MeshType&, size_t ) + explicit SubdividerT( MeshType &_m ) : attached_(NULL) { attach(_m); } + + //@} + + /// Destructor (calls detach()) + virtual ~SubdividerT() + { detach(); } + + /// Return name of subdivision algorithm + virtual const char *name( void ) const = 0; + + +public: /// \name Interface 1 + + //@{ + /// Subdivide the mesh \c _m \c _n times. + /// \see SubdividerT(MeshType&) + bool operator () ( MeshType& _m, size_t _n , const bool _update_points = true) + { + return prepare(_m) && subdivide( _m, _n , _update_points ) && cleanup( _m ); + } + //@} + +public: /// \name Interface 2 + //@{ + /// Attach mesh \c _m to self + /// \see SubdividerT(), operator()(size_t), detach() + bool attach( MeshType& _m ) + { + if ( attached_ == &_m ) + return true; + + detach(); + if (prepare( _m )) + { + attached_ = &_m; + return true; + } + return false; + } + + /// Subdivide the attached \c _n times. + /// \see SubdividerT(), attach(), detach() + bool operator()( size_t _n , const bool _update_points = true) + { + return attached_ ? subdivide( *attached_, _n , _update_points) : false; + } + + /// Detach an eventually attached mesh. + /// \see SubdividerT(), attach(), operator()(size_t) + void detach(void) + { + if ( attached_ ) + { + cleanup( *attached_ ); + attached_ = NULL; + } + } + //@} + +protected: + + /// \name Overload theses methods + //@{ + /// Prepare mesh, e.g. add properties + virtual bool prepare( MeshType& _m ) = 0; + + /// Subdivide mesh \c _m \c _n times + virtual bool subdivide( MeshType& _m, size_t _n, const bool _update_points = true) = 0; + + /// Cleanup mesh after usage, e.g. remove added properties + virtual bool cleanup( MeshType& _m ) = 0; + //@} + +private: + + MeshType *attached_; + +}; + +//============================================================================= +} // namespace Uniform +} // namespace Subdivider +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_SUBDIVIDERT_HH +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Config.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Config.hh new file mode 100644 index 0000000..4bfe4e9 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Config.hh @@ -0,0 +1,75 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Tools/Utils/Config.hh + */ + +//============================================================================= +// +// Defines +// +//============================================================================= + +#ifndef OPENMESH_UTILS_CONFIG_HH +#define OPENMESH_UTILS_CONFIG_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +#define BEGIN_NS_UTILS namespace Utils { +#define END_NS_UTILS } + + +//============================================================================= +#endif // OPENMESH_UTILS_CONFIG_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/GLConstAsString.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/GLConstAsString.hh new file mode 100644 index 0000000..1e6bd7c --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/GLConstAsString.hh @@ -0,0 +1,103 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_GLCONSTASSTRING_HH +#define OPENMESH_UTILS_GLCONSTASSTRING_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Utils { + +//== CLASS DEFINITION ========================================================= + +inline +const char *GLenum_as_string( GLenum _m ) +{ +#define MODE(M) case M:return #M + switch( _m ) + { + MODE(GL_POINTS); + MODE(GL_LINES); + MODE(GL_LINE_STRIP); + MODE(GL_LINE_LOOP); + MODE(GL_TRIANGLES); + MODE(GL_TRIANGLE_STRIP); + MODE(GL_TRIANGLE_FAN); + MODE(GL_QUADS); + MODE(GL_QUAD_STRIP); + MODE(GL_POLYGON); + default: return ""; + } +#undef MODE +} + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_UTILS_GLCONSTASSTRING_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Gnuplot.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Gnuplot.cc new file mode 100644 index 0000000..a70ca1a --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Gnuplot.cc @@ -0,0 +1,504 @@ +//////////////////////////////////////////// +// +// A C++ interface to gnuplot. +// +// This is a direct translation from the C interface +// written by N. Devillard (which is available from +// http://ndevilla.free.fr/gnuplot/). +// +// As in the C interface this uses pipes and so wont +// run on a system that does'nt have POSIX pipe +// support +// +// Rajarshi Guha +// +// +// 07/03/03 +// +//////////////////////////////////////////// + +#include "Gnuplot.hh" +#include +#ifdef WIN32 +# include +#else +# include // X_OK +# include // access +# define PATH_MAXNAMESZ 4096 +#endif +#include +#include +#include +#include +#include + +#if defined(WIN32) +# define pclose _pclose +# define popen _popen +# define access _access +# define ACCESS_OK 0 +# define PATH_SEP ";" +# define MKTEMP_AND_CHECK_FAILED(name) (_mktemp(name) == NULL) +#else +# define ACCESS_OK X_OK +# define PATH_SEP ":" +# define MKTEMP_AND_CHECK_FAILED(name) (mkstemp(name) == -1) +#endif + +#ifndef WIN32 + +#include +#else + #ifdef __MINGW32__ + #include + #include + #endif +#endif + +using namespace std; + +///////////////////////////// +// +// A string tokenizer taken from +// http://www.sunsite.ualberta.ca/ +// Documentation/Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt +// +///////////////////////////// + +template +void +stringtok (Container &container, string const &in, + const char * const delimiters = " \t\n") +{ + const string::size_type len = in.length(); + + string::size_type i = 0; + + while ( i < len ) + { + // eat leading whitespace + i = in.find_first_not_of (delimiters, i); + if (i == string::npos) + return; // nothing left but white space + + // find the end of the token + string::size_type j = in.find_first_of (delimiters, i); + + // push token + if (j == string::npos) + { + container.push_back (in.substr(i)); + return; + } else + container.push_back (in.substr(i, j-i)); + + // set up for next loop + i = j + 1; + } +} + +// ---------------------------------------------------------------------------- + +#ifdef WIN32 + std::string Gnuplot::gnuplot_executable_ = "pgnuplot.exe"; +#else + std::string Gnuplot::gnuplot_executable_ = "gnuplot"; +#endif + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(void) +{ + init(); + set_style("points"); +} + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(const string &style) +{ + init(); + set_style(style); +} + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(const string &title, + const string &style, + const string &labelx, const string &labely, + vector x, vector y) +{ + init(); + + if (x.empty() || y.empty() ) + throw GnuplotException("vectors too small"); + + if (style == "") + this->set_style("lines"); + else + this->set_style(style); + + if (labelx == "") + this->set_xlabel("X"); + else + this->set_xlabel(labelx); + if (labely == "") + this->set_ylabel("Y"); + else + this->set_ylabel(labely); + + this->plot_xy(x,y,title); + + cout << "Press enter to continue" << endl; + while (getchar() != '\n'){} +} + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(const string &title, const string &style, + const string &labelx, const string &labely, + vector x) +{ + init(); + + if (x.empty() ) + throw GnuplotException("vector too small"); + if (!this->gnucmd) + throw GnuplotException("Could'nt open connection to gnuplot"); + + if (style == "") + this->set_style("lines"); + else + this->set_style(style); + + if (labelx == "") + this->set_xlabel("X"); + else + this->set_xlabel(labelx); + if (labely == "") + this->set_ylabel("Y"); + else + this->set_ylabel(labely); + + this->plot_x(x,title); + + cout << "Press enter to continue" << endl; + while (getchar() != '\n'){} +} + +// ---------------------------------------------------------------------------- + +Gnuplot::~Gnuplot() +{ + if ( !((this->to_delete).empty()) ) + { + for (size_t i = 0; i < this->to_delete.size(); i++) + remove(this->to_delete[i].c_str()); + } + + if (pclose(this->gnucmd) == -1) + cerr << "Problem closing communication to gnuplot" << endl; + + return; +} + +// ---------------------------------------------------------------------------- + +bool Gnuplot::get_program_path(const string& pname) +{ + list ls; + char *path; + + path = getenv("PATH"); + if (!path) + return false; + + stringtok(ls, path, PATH_SEP); + + for (list::const_iterator i = ls.begin(); i != ls.end(); ++i) + { + string tmp = (*i) + "/" + pname; + if ( access(tmp.c_str(), ACCESS_OK) == 0 ) + return true; + } + + return false; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::reset_plot(void) +{ + if ( !(this->to_delete.empty()) ) + { + for (size_t i = 0; i < this->to_delete.size(); i++) + remove(this->to_delete[i].c_str()); + } + this->nplots = 0; + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::set_style(const string &stylestr) +{ + if (stylestr != "lines" && + stylestr != "points" && + stylestr != "linespoints" && + stylestr != "impulses" && + stylestr != "dots" && + stylestr != "steps" && + stylestr != "errorbars" && + stylestr != "boxes" && + stylestr != "boxerrorbars") + this->pstyle = string("points"); + else + this->pstyle = stylestr; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::cmd(const char *_cmd, ...) +{ + va_list ap; + char local_cmd[GP_CMD_SIZE]; + + va_start(ap, _cmd); + vsprintf(local_cmd, _cmd, ap); + va_end(ap); + + strcat(local_cmd,"\n"); + fputs(local_cmd,this->gnucmd); + fflush(this->gnucmd); + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::set_ylabel(const string &label) +{ + ostringstream cmdstr; + + cmdstr << "set xlabel \"" << label << "\""; + this->cmd(cmdstr.str().c_str()); + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::set_xlabel(const string &label) +{ + ostringstream cmdstr; + + cmdstr << "set xlabel \"" << label << "\""; + this->cmd(cmdstr.str().c_str()); + + return; +} + +// ---------------------------------------------------------------------------- + +// Plots a linear equation (where you supply the +// slope and intercept) +// +void Gnuplot::plot_slope(double a, double b, const string &title) +{ + ostringstream stitle; + ostringstream cmdstr; + + if (title == "") + stitle << "no title"; + else + stitle << title; + + if (this->nplots > 0) + cmdstr << "replot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle; + else + cmdstr << "plot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle; + this->cmd(cmdstr.str().c_str()); + this->nplots++; + return; +} + +// ---------------------------------------------------------------------------- + +// Plot an equation which is supplied as a string +// +void Gnuplot::plot_equation(const string &equation, const string &title) +{ + string titlestr, plotstr; + ostringstream cmdstr; + + if (title == "") + titlestr = "no title"; + else + titlestr = title; + + if (this->nplots > 0) + plotstr = "replot"; + else + plotstr = "plot"; + + cmdstr << plotstr << " " << equation << " " << "title \"" << titlestr << "\" with " << this->pstyle; + this->cmd(cmdstr.str().c_str()); + this->nplots++; + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::plot_x(vector d, const string &title) +{ + ofstream tmp; + ostringstream cmdstr; +#ifdef WIN32 + char name[] = "gnuplotiXXXXXX"; +#else + char name[] = "/tmp/gnuplotiXXXXXX"; +#endif + + if (this->to_delete.size() == GP_MAX_TMP_FILES - 1) + { + cerr << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl; + return; + } + + // + //open temporary files for output +#ifdef WIN32 + if ( _mktemp(name) == NULL) +#else + if ( mkstemp(name) == -1 ) +#endif + { + cerr << "Cannot create temporary file: exiting plot" << endl; + return; + } + tmp.open(name); + if (tmp.bad()) + { + cerr << "Cannot create temorary file: exiting plot" << endl; + return; + } + + // + // Save the temporary filename + // + this->to_delete.push_back(name); + + // + // write the data to file + // + for (size_t i = 0; i < d.size(); i++) + tmp << d[i] << endl; + tmp.flush(); + tmp.close(); + + // + // command to be sent to gnuplot + // + cmdstr << ( (this->nplots > 0) ? "replot " : "plot "); + + if (title.empty()) + cmdstr << "\"" << name << "\" with " << this->pstyle; + else + cmdstr << "\"" << name << "\" title \"" << title << "\" with " + << this->pstyle; + + // + // Do the actual plot + // + this->cmd(cmdstr.str().c_str()); + this->nplots++; + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::plot_xy(vector x, vector y, const string &title) +{ + ofstream tmp; + ostringstream cmdstr; +#ifdef WIN32 + char name[] = "gnuplotiXXXXXX"; +#else + char name[] = "/tmp/gnuplotiXXXXXX"; +#endif + + // should raise an exception + if (x.size() != y.size()) + return; + + if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1) + { + std::stringstream s; + s << "Maximum number of temporary files reached (" + << GP_MAX_TMP_FILES << "): cannot open more files" << endl; + throw GnuplotException( s.str() ); + } + + //open temporary files for output + // + if (MKTEMP_AND_CHECK_FAILED(name)) + throw GnuplotException("Cannot create temporary file: exiting plot"); + + tmp.open(name); + if (tmp.bad()) + throw GnuplotException("Cannot create temorary file: exiting plot"); + + // Save the temporary filename + // + this->to_delete.push_back(name); + + // Write the data to file + // + size_t N = std::min(x.size(), y.size()); + for (size_t i = 0; i < N; i++) + tmp << x[i] << " " << y[i] << endl; + tmp.flush(); + tmp.close(); + + // + // command to be sent to gnuplot + // + if (this->nplots > 0) + cmdstr << "replot "; + else cmdstr << "plot "; + if (title == "") + cmdstr << "\"" << name << "\" with " << this->pstyle; + else + cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle; + + // + // Do the actual plot + // + this->cmd(cmdstr.str().c_str()); + this->nplots++; + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::init() +{ + if (!this->get_program_path(gnuplot_executable_)) + { + this->valid = false; + throw GnuplotException("Can't find gnuplot in your PATH"); + } + + this->gnucmd = popen(gnuplot_executable_.c_str(),"w"); + if (!this->gnucmd) + { + this->valid = false; + throw GnuplotException("Couldn't open connection to gnuplot"); + } + this->nplots = 0; + this->valid = true; +} + +// ============================================================================ diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Gnuplot.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Gnuplot.hh new file mode 100644 index 0000000..faf2e50 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Gnuplot.hh @@ -0,0 +1,184 @@ +//////////////////////////////////////////// +// +// A C++ interface to gnuplot. +// +// This is a direct translation from the C interface +// written by N. Devillard (which is available from +// http://ndevilla.free.fr/gnuplot/). +// +// As in the C interface this uses pipes and so wont +// run on a system that doesn't have POSIX pipe +// support +// +// Rajarshi Guha +// +// +// 07/03/03 +// +//////////////////////////////////////////// +// +// A little correction for Win32 compatibility +// and MS VC 6.0 done by V.Chyzhdzenka +// +// Notes: +// 1. Added private method Gnuplot::init(). +// 2. Temporary file is created in th current +// folder but not in /tmp. +// 3. Added #indef WIN32 e.t.c. where is needed. +// 4. Added private member m_sGNUPlotFileName is +// a name of executed GNUPlot file. +// +// Viktor Chyzhdzenka +// e-mail: chyzhdzenka@mail.ru +// +// 20/05/03 +// +//////////////////////////////////////////// + +#ifndef _GNUPLOT_HH +#define _GNUPLOT_HH + +#include +// #ifndef WIN32 +// # include +// #else +// # pragma warning (disable : 4786) // Disable 4786 warning for MS VC 6.0 +// #endif +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif +#include +#include +#include + +// ---------------------------------------------------------------------------- + +#ifdef WIN32 +# define GP_MAX_TMP_FILES 27 //27 temporary files it's Microsoft restriction +#else +# define GP_MAX_TMP_FILES 64 +# define GP_TMP_NAME_SIZE 512 +# define GP_TITLE_SIZE 80 +#endif +#define GP_CMD_SIZE 1024 + +// ---------------------------------------------------------------------------- + +using namespace std; + +// ---------------------------------------------------------------------------- + +/// Exception thrown by class Gnuplot +class GnuplotException : public runtime_error +{ +public: + explicit GnuplotException(const string &msg) : runtime_error(msg){} +}; + +// ---------------------------------------------------------------------------- + +/** Utility class interfacing with Gnuplot. + * + * \note The plot will be visible as long as the object is not destructed. + * + * \author Rajarshi Guha (C++ API based on the C API by Nicolas Devillard) + * + * \see http://ndevilla.free.fr/gnuplot/ + * more information. + */ +class Gnuplot +{ +private: + + FILE *gnucmd; + string pstyle; + vector to_delete; + int nplots; + bool get_program_path(const string& ); + bool valid; + + // Name of executed GNUPlot file + static string gnuplot_executable_; + + void init(); + +public: + + /// \name Constructors + //@{ + /// Default constructor. + Gnuplot(); + + /// Set a style during construction. + explicit Gnuplot(const string & _style); + + /// Constructor calling plot_xy(). + Gnuplot(const string & _title, + const string & _style, + const string & _xlabel, + const string & _ylabel, + vector _x, vector _y); + + /// Constructor calling plot_x(). + Gnuplot(const string &_title, + const string &_style, + const string &_xlabel, + const string &_ylabel, + vector _x); + //@} + + ~Gnuplot(); + + /// Send a command to gnuplot (low-level function use by all plot functions.) + void cmd(const char *_cmd, ...); + + /// \name Gnuplot settings + //@{ + void set_style(const string & _style); ///< set line style + void set_ylabel(const string & _ylabel); ///< set x axis label + void set_xlabel(const string & _xlabel); ///< set x axis label + //@} + + /// \name plot functions + //@{ + + /// Plot a single vector + void plot_x(vector _x, const string &_title); + + /// Plot x,y pairs + void plot_xy(vector _x, vector _y, const string &_title); + + /// Plot an equation of the form: y = ax + b + /// You supply a and b + void plot_slope( + double _a, + double _b, + const string & _title + ); + + /// Plot an equation supplied as a string + void plot_equation( + const string & _equation, + const string & _title + ); + + /// If multiple plots are present it will clear the plot area + void reset_plot(void); + + //@} + + /// Is \c Self valid? + bool is_valid(void) const { return valid; } + + /// Is \c Self active, i.e. does it have an active plot? + bool is_active(void) const { return this->nplots > 0; } +}; + + +// ---------------------------------------------------------------------------- +#endif // _GNUPLOT_HH +// ============================================================================ + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/HeapT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/HeapT.hh new file mode 100644 index 0000000..63c27c2 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/HeapT.hh @@ -0,0 +1,386 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Tools/Utils/HeapT.hh + A generic heap class +**/ +/** Martin, 26.12.2004: + 1) replaced resize(size()-1) with pop_back(), since the later is more efficient + 2) replaced interface_.set_heap_position(entry(0), -1); with reset_heap_position() + 3) added const modifier to various functions + TODO: in the moment the heap does not conform to the HeapInterface specification, + i.e., copies are passed instead of references. This is especially important + for set_heap_position(), where the reference argument is non-const. The + specification should be changed to reflect that the heap actually (only?) + works when the heap entry is nothing more but a handle. + TODO: change the specification of HeapInterface to make less(), greater() and + get_heap_position() const. Needs changing DecimaterT. Might break + someone's code. +*/ + + +//============================================================================= +// +// CLASS HeapT +// +//============================================================================= + +#ifndef OPENMESH_UTILS_HEAPT_HH +#define OPENMESH_UTILS_HEAPT_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) +#include +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Utils { // BEGIN_NS_UTILS + +//== CLASS DEFINITION ========================================================= + + +/** This class demonstrates the HeapInterface's interface. If you + * want to build your customized heap you will have to specify a heap + * interface class and use this class as a template parameter for the + * class HeapT. This class defines the interface that this heap + * interface has to implement. + * + * \see HeapT + */ +template +struct HeapInterfaceT +{ + /// Comparison of two HeapEntry's: strict less + bool less(const HeapEntry& _e1, const HeapEntry& _e2); + + /// Comparison of two HeapEntry's: strict greater + bool greater(const HeapEntry& _e1, const HeapEntry& _e2); + + /// Get the heap position of HeapEntry _e + int get_heap_position(const HeapEntry& _e); + + /// Set the heap position of HeapEntry _e + void set_heap_position(HeapEntry& _e, int _i); +}; + + + +/** \class HeapT HeapT.hh + * + * An efficient, highly customizable heap. + * + * The main difference (and performance boost) of this heap compared + * to e.g. the heap of the STL is that here the positions of the + * heap's elements are accessible from the elements themself. + * Therefore if one changes the priority of an element one does not + * have to remove and re-insert this element, but can just call the + * update(HeapEntry) method. + * + * This heap class is parameterized by two template arguments: + * \li the class \c HeapEntry, that will be stored in the heap + * \li the HeapInterface telling the heap how to compare heap entries and + * how to store the heap positions in the heap entries. + * + * As an example how to use the class see declaration of class + * Decimater::DecimaterT. + * + * \see HeapInterfaceT + */ + +template +class HeapT : private std::vector +{ +private: + typedef std::vector Base; + +public: + + /// Constructor + HeapT() : HeapVector() {} + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) + /// Construct with a given \c HeapIterface. + HeapT(HeapInterface _interface) + : HeapVector(), interface_(std::move(_interface)) + {} +#else + /// Construct with a given \c HeapIterface. + HeapT(const HeapInterface &_interface) + : HeapVector(), interface_(_interface) + {} +#endif + + /// Destructor. + ~HeapT(){}; + + HeapInterface &getInterface() { + return interface_; + } + + const HeapInterface &getInterface() const { + return interface_; + } + + /// clear the heap + void clear() { HeapVector::clear(); } + + /// is heap empty? + bool empty() const { return HeapVector::empty(); } + + /// returns the size of heap + size_t size() const { return HeapVector::size(); } + + /// reserve space for _n entries + void reserve(size_t _n) { HeapVector::reserve(_n); } + + /// reset heap position to -1 (not in heap) + void reset_heap_position(HeapEntry _h) + { interface_.set_heap_position(_h, -1); } + + /// is an entry in the heap? + bool is_stored(HeapEntry _h) + { return interface_.get_heap_position(_h) != -1; } + + /// insert the entry _h + void insert(HeapEntry _h) + { + this->push_back(_h); + upheap(size()-1); + } + + /// get the first entry + HeapEntry front() const + { + assert(!empty()); + return HeapVector::front(); + } + + /// delete the first entry + void pop_front() + { + assert(!empty()); + reset_heap_position(HeapVector::front()); + if (size() > 1) + { + entry(0, entry(size()-1)); + Base::pop_back(); + downheap(0); + } + else + { + Base::pop_back(); + } + } + + /// remove an entry + void remove(HeapEntry _h) + { + int pos = interface_.get_heap_position(_h); + reset_heap_position(_h); + + assert(pos != -1); + assert((unsigned int) pos < size()); + + // last item ? + if ((unsigned int) pos == size()-1) + { + Base::pop_back(); + } + else + { + entry(pos, entry(size()-1)); // move last elem to pos + Base::pop_back(); + downheap(pos); + upheap(pos); + } + } + + /** update an entry: change the key and update the position to + reestablish the heap property. + */ + void update(HeapEntry _h) + { + int pos = interface_.get_heap_position(_h); + assert(pos != -1); + assert((unsigned int)pos < size()); + downheap(pos); + upheap(pos); + } + + /// check heap condition + bool check() + { + bool ok(true); + unsigned int i, j; + for (i=0; i HeapVector; + + + /// Upheap. Establish heap property. + void upheap(size_t _idx); + + + /// Downheap. Establish heap property. + void downheap(size_t _idx); + + + /// Get the entry at index _idx + inline HeapEntry entry(size_t _idx) const + { + assert(_idx < size()); + return (Base::operator[](_idx)); + } + + + /// Set entry _h to index _idx and update _h's heap position. + inline void entry(size_t _idx, HeapEntry _h) + { + assert(_idx < size()); + Base::operator[](_idx) = _h; + interface_.set_heap_position(_h, int(_idx)); + } + + + /// Get parent's index + inline size_t parent(size_t _i) { return (_i-1)>>1; } + /// Get left child's index + inline size_t left(size_t _i) { return (_i<<1)+1; } + /// Get right child's index + inline size_t right(size_t _i) { return (_i<<1)+2; } + +}; + + + + +//== IMPLEMENTATION ========================================================== + + +template +void +HeapT:: +upheap(size_t _idx) +{ + HeapEntry h = entry(_idx); + size_t parentIdx; + + while ((_idx>0) && interface_.less(h, entry(parentIdx=parent(_idx)))) + { + entry(_idx, entry(parentIdx)); + _idx = parentIdx; + } + + entry(_idx, h); +} + + +//----------------------------------------------------------------------------- + + +template +void +HeapT:: +downheap(size_t _idx) +{ + const HeapEntry h = entry(_idx); + size_t childIdx; + const size_t s = size(); + + while(_idx < s) + { + childIdx = left(_idx); + if (childIdx >= s) break; + + if ((childIdx + 1 < s) && (interface_.less(entry(childIdx + 1), entry(childIdx)))) + ++childIdx; + + if (interface_.less(h, entry(childIdx))) break; + + entry(_idx, entry(childIdx)); + _idx = childIdx; + } + + entry(_idx, h); +} + + +//============================================================================= +} // END_NS_UTILS +} // END_NS_OPENMESH +//============================================================================= +#endif // OSG_HEAP_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/MeshCheckerT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/MeshCheckerT.cc new file mode 100644 index 0000000..2c5f80d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/MeshCheckerT.cc @@ -0,0 +1,238 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#define OPENMESH_MESHCHECKER_C + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace Utils { + +//== IMPLEMENTATION ========================================================== + + +template +bool +MeshCheckerT:: +check(unsigned int _targets, std::ostream& _os) +{ + bool ok(true); + + + + //--- vertex checks --- + + if (_targets & CHECK_VERTICES) + { + typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end()); + typename Mesh::VertexHandle vh; + typename Mesh::ConstVertexVertexCWIter vv_it; + typename Mesh::HalfedgeHandle heh; + unsigned int count; + const unsigned int max_valence(10000); + + + for (; v_it != v_end; ++v_it) + { + if (!is_deleted(*v_it)) + { + vh = *v_it; + + + /* The outgoing halfedge of a boundary vertex has to be a boundary halfedge */ + heh = mesh_.halfedge_handle(vh); + if (heh.is_valid() && !mesh_.is_boundary(heh)) + { + for (typename Mesh::ConstVertexOHalfedgeIter vh_it(mesh_, vh); + vh_it.is_valid(); ++vh_it) + { + if (mesh_.is_boundary(*vh_it)) + { + _os << "MeshChecker: vertex " << vh + << ": outgoing halfedge not on boundary error\n"; + ok = false; + } + } + } + + + + // outgoing halfedge has to refer back to vertex + if (mesh_.halfedge_handle(vh).is_valid() && + mesh_.from_vertex_handle(mesh_.halfedge_handle(vh)) != vh) + { + _os << "MeshChecker: vertex " << vh + << ": outgoing halfedge does not reference vertex\n"; + ok = false; + } + + + // check whether circulators are still in order + vv_it = mesh_.cvv_cwiter(vh); + for (count=0; vv_it.is_valid() && (count < max_valence); ++vv_it, ++count) {}; + if (count == max_valence) + { + _os << "MeshChecker: vertex " << vh + << ": ++circulator problem, one ring corrupt\n"; + ok = false; + } + vv_it = mesh_.cvv_cwiter(vh); + for (count=0; vv_it.is_valid() && (count < max_valence); --vv_it, ++count) {}; + if (count == max_valence) + { + _os << "MeshChecker: vertex " << vh + << ": --circulator problem, one ring corrupt\n"; + ok = false; + } + } + } + } + + + + //--- halfedge checks --- + + if (_targets & CHECK_EDGES) + { + typename Mesh::ConstHalfedgeIter h_it(mesh_.halfedges_begin()), + h_end(mesh_.halfedges_end()); + typename Mesh::HalfedgeHandle hh, hstart, hhh; + size_t count, n_halfedges = 2*mesh_.n_edges(); + + for (; h_it != h_end; ++h_it) + { + if (!is_deleted(mesh_.edge_handle(*h_it))) + { + hh = *h_it; + + + // degenerated halfedge ? + if (mesh_.from_vertex_handle(hh) == mesh_.to_vertex_handle(hh)) + { + _os << "MeshChecker: halfedge " << hh + << ": to-vertex == from-vertex\n"; + ok = false; + } + + + // next <-> prev check + if (mesh_.next_halfedge_handle(mesh_.prev_halfedge_handle(hh)) != hh) + { + _os << "MeshChecker: halfedge " << hh + << ": prev->next != this\n"; + ok = false; + } + + + // halfedges should form a cycle + count=0; hstart=hhh=hh; + do + { + hhh = mesh_.next_halfedge_handle(hhh); + ++count; + } while (hhh != hstart && count < n_halfedges); + + if (count == n_halfedges) + { + _os << "MeshChecker: halfedges starting from " << hh + << " do not form a cycle\n"; + ok = false; + } + } + } + } + + + + //--- face checks --- + + if (_targets & CHECK_FACES) + { + typename Mesh::ConstFaceIter f_it(mesh_.faces_begin()), + f_end(mesh_.faces_end()); + typename Mesh::FaceHandle fh; + typename Mesh::ConstFaceHalfedgeIter fh_it; + + for (; f_it != f_end; ++f_it) + { + if (!is_deleted(*f_it)) + { + fh = *f_it; + + for (fh_it=mesh_.cfh_iter(fh); fh_it.is_valid(); ++fh_it) + { + if (mesh_.face_handle(*fh_it) != fh) + { + _os << "MeshChecker: face " << fh + << ": its halfedge does not reference face\n"; + ok = false; + } + } + } + } + } + + + + return ok; +} + + +//============================================================================= +} // naespace Utils +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/MeshCheckerT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/MeshCheckerT.hh new file mode 100644 index 0000000..2357ab2 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/MeshCheckerT.hh @@ -0,0 +1,132 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_MESHCHECKER_HH +#define OPENMESH_MESHCHECKER_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Utils { + +//== CLASS DEFINITION ========================================================= + + +/** Check integrity of mesh. + * + * This class provides several functions to check the integrity of a mesh. + */ +template +class MeshCheckerT +{ +public: + + /// constructor + explicit MeshCheckerT(const Mesh& _mesh) : mesh_(_mesh) {} + + /// destructor + ~MeshCheckerT() {} + + + /// what should be checked? + enum CheckTargets + { + CHECK_EDGES = 1, + CHECK_VERTICES = 2, + CHECK_FACES = 4, + CHECK_ALL = 255 + }; + + + /// check it, return true iff ok + bool check( unsigned int _targets=CHECK_ALL, + std::ostream& _os= omerr()); + + +private: + + bool is_deleted(typename Mesh::VertexHandle _vh) + { return (mesh_.has_vertex_status() ? mesh_.status(_vh).deleted() : false); } + + bool is_deleted(typename Mesh::EdgeHandle _eh) + { return (mesh_.has_edge_status() ? mesh_.status(_eh).deleted() : false); } + + bool is_deleted(typename Mesh::FaceHandle _fh) + { return (mesh_.has_face_status() ? mesh_.status(_fh).deleted() : false); } + + + // ref to mesh + const Mesh& mesh_; +}; + + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MESHCHECKER_C) +#define OPENMESH_MESHCHECKER_TEMPLATES +#include "MeshCheckerT.cc" +#endif +//============================================================================= +#endif // OPENMESH_MESHCHECKER_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/NumLimitsT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/NumLimitsT.hh new file mode 100644 index 0000000..39117eb --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/NumLimitsT.hh @@ -0,0 +1,154 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +/** \file Tools/Utils/NumLimitsT.hh + Temporary solution until std::numeric_limits is standard. + */ + +//============================================================================= +// +// CLASS NumLimitsT +// +//============================================================================= + +#ifndef OPENMESH_UTILS_NUMLIMITS_HH +#define OPENMESH_UTILS_NUMLIMITS_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + + +//== NAMESPEACES ============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Utils { // BEGIN_NS_UTILS + + +//== CLASS DEFINITION ========================================================= + + +/** \class NumLimitsT Tools/Utils/NumLimitsT.hh + + This class provides the maximum and minimum values a certain + scalar type (\c int, \c float, or \c double) can store. You can + use it like this: + \code + #include + + int float_min = OpenMesh::NumLimitsT::min(); + float double_max = OpenMesh::NumLimitsT::max(); + \endcode + + \note This functionality should be provided by + std::numeric_limits. This template does not exist on gcc <= + 2.95.3. The class template NumLimitsT is just a workaround. +**/ +template +class NumLimitsT +{ +public: + /// Return the smallest \em absolte value a scalar type can store. + static inline Scalar min() { return 0; } + /// Return the maximum \em absolte value a scalar type can store. + static inline Scalar max() { return 0; } + + static inline bool is_float() { return false; } + static inline bool is_integer() { return !NumLimitsT::is_float(); } + static inline bool is_signed() { return true; } +}; + + // is_float + +template<> +inline bool NumLimitsT::is_float() { return true; } + +template<> +inline bool NumLimitsT::is_float() { return true; } + +template<> +inline bool NumLimitsT::is_float() { return true; } + + // is_signed + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + + // min/max +template<> inline int NumLimitsT::min() { return INT_MIN; } +template<> inline int NumLimitsT::max() { return INT_MAX; } + +template<> inline float NumLimitsT::min() { return FLT_MIN; } +template<> inline float NumLimitsT::max() { return FLT_MAX; } + +template<> inline double NumLimitsT::min() { return DBL_MIN; } +template<> inline double NumLimitsT::max() { return DBL_MAX; } + + +//============================================================================= +} // END_NS_UTILS +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_NUMLIMITS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/StripifierT.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/StripifierT.cc new file mode 100644 index 0000000..8bd3372 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/StripifierT.cc @@ -0,0 +1,284 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS StripifierT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_STRIPIFIERT_C + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + + //== IMPLEMENTATION ========================================================== + +template +StripifierT:: +StripifierT(Mesh& _mesh) : + mesh_(_mesh) +{ + +} + +template +StripifierT:: +~StripifierT() { + +} + +template +size_t +StripifierT:: +stripify() +{ + // preprocess: add new properties + mesh_.add_property( processed_ ); + mesh_.add_property( used_ ); + mesh_.request_face_status(); + + // build strips + clear(); + build_strips(); + + // postprocess: remove properties + mesh_.remove_property(processed_); + mesh_.remove_property(used_); + mesh_.release_face_status(); + + return n_strips(); +} + + +//----------------------------------------------------------------------------- + + +template +void +StripifierT:: +build_strips() +{ + Strip experiments[3]; + typename Mesh::HalfedgeHandle h[3]; + FaceHandles faces[3]; + typename FaceHandles::iterator fh_it, fh_end; + typename Mesh::FaceIter f_it, f_end=mesh_.faces_end(); + + + + // init faces to be un-processed and un-used + // deleted or hidden faces are marked processed + if (mesh_.has_face_status()) + { + for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it) + if (mesh_.status(*f_it).hidden() || mesh_.status(*f_it).deleted()) + processed(*f_it) = used(*f_it) = true; + else + processed(*f_it) = used(*f_it) = false; + } + else + { + for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it) + processed(*f_it) = used(*f_it) = false; + } + + + + for (f_it=mesh_.faces_begin(); true; ) + { + // find start face + for (; f_it!=f_end; ++f_it) + if (!processed(*f_it)) + break; + if (f_it==f_end) break; // stop if all have been processed + + + // collect starting halfedges + h[0] = mesh_.halfedge_handle(*f_it); + h[1] = mesh_.next_halfedge_handle(h[0]); + h[2] = mesh_.next_halfedge_handle(h[1]); + + + // build 3 strips, take best one + size_t best_length = 0; + size_t best_idx = 0; + + for (size_t i=0; i<3; ++i) + { + build_strip(h[i], experiments[i], faces[i]); + + const size_t length = experiments[i].size(); + if ( length > best_length) + { + best_length = length; + best_idx = i; + } + + for (fh_it=faces[i].begin(), fh_end=faces[i].end(); + fh_it!=fh_end; ++fh_it) + used(*fh_it) = false; + } + + + // update processed status + fh_it = faces[best_idx].begin(); + fh_end = faces[best_idx].end(); + for (; fh_it!=fh_end; ++fh_it) + processed(*fh_it) = true; + + + + // add best strip to strip-list + strips_.push_back(experiments[best_idx]); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +StripifierT:: +build_strip(typename Mesh::HalfedgeHandle _start_hh, + Strip& _strip, + FaceHandles& _faces) +{ + std::list strip; + typename Mesh::HalfedgeHandle hh; + typename Mesh::FaceHandle fh; + + + // reset face list + _faces.clear(); + + + // init strip + strip.push_back(mesh_.from_vertex_handle(_start_hh).idx()); + strip.push_back(mesh_.to_vertex_handle(_start_hh).idx()); + + + // walk along the strip: 1st direction + hh = mesh_.prev_halfedge_handle(mesh_.opposite_halfedge_handle(_start_hh)); + while (1) + { + // go right + hh = mesh_.next_halfedge_handle(hh); + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_back(mesh_.to_vertex_handle(hh).idx()); + + // go left + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_back(mesh_.to_vertex_handle(hh).idx()); + } + + + // walk along the strip: 2nd direction + bool flip(false); + hh = mesh_.prev_halfedge_handle(_start_hh); + while (1) + { + // go right + hh = mesh_.next_halfedge_handle(hh); + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_front(mesh_.to_vertex_handle(hh).idx()); + flip = true; + + // go left + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_front(mesh_.to_vertex_handle(hh).idx()); + flip = false; + } + + if (flip) strip.push_front(strip.front()); + + + + // copy final strip to _strip + _strip.clear(); + _strip.reserve(strip.size()); + std::copy(strip.begin(), strip.end(), std::back_inserter(_strip)); +} + + +//============================================================================= +} // namespace OpenMesh + //============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/StripifierT.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/StripifierT.hh new file mode 100644 index 0000000..61f5182 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/StripifierT.hh @@ -0,0 +1,158 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS StripifierT +// +//============================================================================= + + +#ifndef OPENMESH_STRIPIFIERT_HH +#define OPENMESH_STRIPIFIERT_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + + +/** \class StripifierT StripifierT.hh + This class decomposes a triangle mesh into several triangle strips. +*/ + +template +class StripifierT +{ +public: + + typedef unsigned int Index; + typedef std::vector Strip; + typedef typename Strip::const_iterator IndexIterator; + typedef std::vector Strips; + typedef typename Strips::const_iterator StripsIterator; + + + /// Default constructor + StripifierT(Mesh& _mesh); + + /// Destructor + ~StripifierT(); + + /// Compute triangle strips, returns number of strips + size_t stripify(); + + /// delete all strips + void clear() { Strips().swap(strips_); } + + /// returns number of strips + size_t n_strips() const { return strips_.size(); } + + /// are strips computed? + bool is_valid() const { return !strips_.empty(); } + + /// Access strips + StripsIterator begin() const { return strips_.begin(); } + /// Access strips + StripsIterator end() const { return strips_.end(); } + + +private: + + typedef std::vector FaceHandles; + + + /// this method does the main work + void build_strips(); + + /// build a strip from a given halfedge (in both directions) + void build_strip(typename Mesh::HalfedgeHandle _start_hh, + Strip& _strip, + FaceHandles& _faces); + + FPropHandleT::reference processed(typename Mesh::FaceHandle _fh) { + return mesh_.property(processed_, _fh); + } + FPropHandleT::reference used(typename Mesh::FaceHandle _fh) { + return mesh_.property(used_, _fh); + } + + + +private: + + Mesh& mesh_; + Strips strips_; + FPropHandleT processed_, used_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_STRIPIFIERT_C) +#define OPENMESH_STRIPIFIERT_TEMPLATES +#include "StripifierT.cc" +#endif +//============================================================================= +#endif // OPENMESH_STRIPIFIERT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/TestingFramework.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/TestingFramework.hh new file mode 100644 index 0000000..9c82438 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/TestingFramework.hh @@ -0,0 +1,375 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef TESTINGFRAMEWORK_HH +#define TESTINGFRAMEWORK_HH +// ---------------------------------------------------------------------------- + +/** \file TestingFramework.hh + This file contains a little framework for test programms +*/ + + +// ---------------------------------------------------------------------------- + +#include "Config.hh" +#include +#include +#include +#include +#include +#include + +// ------------------------------------------------------------- namespace ---- + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Utils { // BEGIN_NS_UTILS + + +// ----------------------------------------------------------------- class ---- +// +// Usage Example +// +// #include +// #include <.../TestingFramework.hh> +// +// struct test_func : public TestingFramework::TestFunc +// { +// typedef test_func Self; +// +// // define ctor and copy-ctor +// test_func( TestingFramework& _th, std::string _n ) : TestingFramework::TestFunc( _th, _n ) { } +// test_func( Self& _cpy ) : TestingFramework::TestFunc(_cpy) { } +// +// // overload body() +// void body() +// { +// +// // Do the tests +// // direct call to verify +// verify( testResult, expectedResult, "additional information" ); +// +// // or use the define TH_VERIFY. The test-expression will be used as the message string +// TH_VERIFY( testResult, expectedResult ); +// +// ... +// } +// }; +// +// int main(...) +// { +// TestingFramework testSuite(std::cout); // send output to stdout +// +// new test_func(testSuite); // create new test instance. It registers with testSuite. +// return testSuite.run(); +// } +// + +// +#define TH_VERIFY( expr, expt ) \ + verify( expr, expt, #expr ) + +// +#define TH_VERIFY_X( expr, expt ) \ + verify_x( expr, expt, #expr ) + +/** Helper class for test programms. + \internal + */ +class TestingFramework : Noncopyable +{ +public: + + typedef TestingFramework Self; + typedef std::logic_error verify_error; + +#ifndef DOXY_IGNORE_THIS + class TestFunc + { + public: + TestFunc( TestingFramework& _th, const std::string& _n ) + : th_(_th), name_(_n) + { + th_.reg(this); + } + + virtual ~TestFunc() + { } + + void operator() ( void ) + { + prolog(); + try + { + body(); + } + catch( std::exception& x ) + { + std::cerr << "<>: Cannot proceed test due to failure of last" + << " test: " << x.what() << std::endl; + } + catch(...) + { + std::cerr << "Fatal: cannot proceed test due to unknown error!" + << std::endl; + } + epilog(); + } + + const TestingFramework& testHelper() const { return th_; } + + protected: + + virtual void prolog(void) + { + begin(name_); + } + + virtual void body(void) = 0; + + virtual void epilog(void) + { + end(); + } + + protected: + + TestingFramework& testHelper() { return th_; } + + TestFunc( const TestFunc& _cpy ) : th_(_cpy.th_), name_(_cpy.name_) { } + + + // Use the following method in prolog() + TestFunc& begin(std::string _title, const std::string& _info = "") + { th_.begin(_title,_info); return *this; } + + + // Use the following method in epilog() + TestFunc& end(void) + { th_.end(); return *this; } + + + // Use the followin methods in body() + + template + bool + verify( const ValueType& _rc, const ValueType& _expected, + std::string _info ) + { return th_.verify( _rc, _expected, _info ); } + + template + void + verify_x( const ValueType& _rc, const ValueType& _expected, + std::string _info ) + { + if ( !verify(_rc, _expected, _info) ) + throw verify_error(_info); + } + + TestFunc& info(const std::string& _info) + { th_.info(_info); return *this; } + + TestFunc& info(const std::ostringstream& _ostr) + { th_.info(_ostr); return *this; } + + private: + TestFunc(); + + protected: + TestingFramework& th_; + std::string name_; + }; +#endif + + typedef TestFunc* TestFuncPtr; + typedef std::vector TestSet; + +public: + + TestingFramework(std::ostream& _os) + : errTotal_(0), errCount_(0), + verifyTotal_(0), verifyCount_(0), + testTotal_(0), testCount_(0), + os_(_os) + { } + +protected: + +#ifndef DOXY_IGNORE_THIS + struct TestDeleter + { + void operator() (TestFuncPtr _tfptr) { delete _tfptr; } + }; +#endif + +public: + + virtual ~TestingFramework() + { + std::for_each(tests_.begin(), tests_.end(), TestDeleter() ); + } + +public: + + template + bool verify(const ValueType& _rc, + const ValueType& _expected, + const std::string& _info) + { + ++verifyTotal_; + if ( _rc == _expected ) + { + os_ << " " << _info << ", result: " << _rc << ", OK!" << std::endl; + return true; + } + ++errTotal_; + os_ << " " << _info << ", result: " << _rc << " != " << _expected + << " <>" << std::endl; + return false; + } + + Self& begin(std::string _title, const std::string& _info = "") + { + std::ostringstream ostr; + + testTitle_ = _title; + errCount_ = errTotal_; + ++testTotal_; + + ostr << _title; + if ( !_info.empty() ) + ostr << " ["<< _info << "]"; + testTitle_ = ostr.str(); + os_ << "Begin " << testTitle_ << std::endl; + return *this; + } + + Self& end() + { + if (errorCount()==0) + ++testCount_; + + os_ << "End " << testTitle_ << ": " << errorCount() << " Error(s)." << std::endl; + return *this; + } + + Self& info(const std::string& _info) + { + os_ << " + " << _info << std::endl; + return *this; + } + + Self& info(const std::ostringstream& _ostr) + { + os_ << " + " << _ostr.str() << std::endl; + return *this; + } + + size_t errorTotal() const { return errTotal_; } + size_t errorCount() const { return errTotal_ - errCount_; } + size_t verifyTotal() const { return verifyTotal_; } + size_t verifyCount() const { return verifyTotal_ - verifyCount_; } + size_t goodTotal() const { return verifyTotal() - errorTotal(); } + size_t goodCount() const { return verifyCount() - errorCount(); } + + size_t testTotal() const { return testTotal_; } + size_t testCount() const { return testCount_; } + +public: + + int run(void) + { + os_ << "Test started\n"; + TestRunner executer; + std::for_each(tests_.begin(), tests_.end(), executer ); + os_ << std::endl; + os_ << "All tests completed" << std::endl + << " #Tests: " << testCount() << "/" << testTotal() << std::endl + << " #Errors: " << errorTotal() << "/" << verifyTotal() << std::endl; + return errorTotal(); + } + +protected: + +#ifndef DOXY_IGNORE_THIS + struct TestRunner + { + void operator() (TestFuncPtr _tfptr) { (*_tfptr)(); } + }; +#endif + + int reg(TestFuncPtr _tfptr) + { + tests_.push_back(_tfptr); + return true; + } + + friend class TestFunc; + +private: + + size_t errTotal_; + size_t errCount_; + size_t verifyTotal_; + size_t verifyCount_; + size_t testTotal_; // #Tests + size_t testCount_; // #Tests ohne Fehler + + std::string testTitle_; + std::ostream& os_; + + TestSet tests_; + +}; + +// ============================================================================ +} // END_NS_UTILS +} // END_NS_OPENMESH +// ============================================================================ +#endif // TESTINGFRMEWORK_HH +// ============================================================================ diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Timer.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Timer.cc new file mode 100644 index 0000000..98d6e40 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Timer.cc @@ -0,0 +1,447 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef DOXY_IGNORE_THIS +// ---------------------------------------------------------------------------- +#include +#if defined(OM_CC_MIPS) +# include +# include +#else +# include +# include +#endif +#include "Timer.hh" +// ---------------------------------------------------------------------------- + +// ------------------------------------------------------------- namespace ---- + +namespace OpenMesh { +namespace Utils { + + +// ---------------------------------------------------------------------------- + +using namespace std; + +// -------------------------------------------------------------- TimerImpl ---- +// just a base class for the implementation +class TimerImpl +{ +protected: +public: + TimerImpl() { ; } + virtual ~TimerImpl() { ; } + + virtual void reset(void) = 0; + virtual void start(void) = 0; + virtual void stop(void) = 0; + virtual void cont(void) = 0; + virtual double seconds(void) const = 0; +}; + +// compiler and os dependent implementation + +// ------------------------------------------------------------- windows 32 ---- +#if defined(WIN32) && (defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined (__MINGW32__) ) + +#ifndef DOXY_IGNORE_THIS +#include +#endif + +class TimerImplWin32 : public TimerImpl +{ +protected: + LARGE_INTEGER freq_; + LARGE_INTEGER count_; + LARGE_INTEGER start_; + +public: + TimerImplWin32(void); + ~TimerImplWin32(void) { ; } + + virtual void reset(void); + virtual void start(void); + virtual void stop(void); + virtual void cont(void); + virtual double seconds(void) const; +}; + +TimerImplWin32::TimerImplWin32(void) +{ + if (QueryPerformanceFrequency(&freq_)==FALSE) + throw std::runtime_error("Performance counter of of stock!"); + reset(); +} + +void TimerImplWin32::reset(void) +{ + memset(&count_,0,sizeof(count_)); + memset(&start_,0,sizeof(count_)); +} + +void TimerImplWin32::start(void) +{ + reset(); + QueryPerformanceCounter(&start_); +} + +void TimerImplWin32::stop(void) +{ + LARGE_INTEGER stop_; + + QueryPerformanceCounter(&stop_); + count_.QuadPart += stop_.QuadPart - start_.QuadPart; +} + +void TimerImplWin32::cont(void) +{ + QueryPerformanceCounter(&start_); +} + +double TimerImplWin32::seconds(void) const +{ + return (double)count_.QuadPart/(double)freq_.QuadPart; +} + +// ------------------------------------------------------------- posix time ---- +#elif defined(__GNUC__) && defined(__POSIX__) + +#ifndef DOXY_IGNORE_THIS +# include +#endif + +template +class TimerImplPosix : public TimerImpl +{ +public: + TimerImplPosix() : id_(N), seconds_(0.0) + { } + + ~TimerImplPosix() + { } + + virtual void reset(void) { seconds_ = 0.0; } + + virtual void start(void) { seconds_ = 0.0; clock_gettime( id_, &start_ ); } + virtual void stop(void) + { + timespec stop; + clock_gettime( id_, &stop ); + seconds_ += ( stop.tv_sec - start_.tv_sec ); + seconds_ += ( (double(stop.tv_nsec-start_.tv_nsec)*1e-9) ); + } + + virtual void cont(void) { clock_gettime( id_, &start_ ); } + + virtual double seconds() const { return seconds_; } + +protected: + clockid_t id_; + double seconds_; + timespec start_; +}; + +// ----------------------------------------------------------- gettimeofday ---- +#elif (defined(__GNUC__) || (defined(__INTEL_COMPILER) && !defined(WIN32))) && !defined(__MINGW32__) + +# include +# include +# include + +class TimerImplGToD: public TimerImpl +{ +public: + TimerImplGToD() : seconds_(0.0) + { } + + ~TimerImplGToD() + { } + + virtual void reset(void) { seconds_ = 0.0; } + virtual void start(void) { seconds_ = 0.0; gettimeofday( &start_, &tz_ ); } + + virtual void stop(void) + { + gettimeofday( &stop_, &tz_ ); + + seconds_ += (double)(stop_.tv_sec - start_.tv_sec); + seconds_ += (double)(stop_.tv_usec- start_.tv_usec)*1e-6; + } + + virtual void cont(void) { gettimeofday( &start_, &tz_); } + + virtual double seconds() const { return seconds_; } + +private: + + struct timeval start_, stop_; + struct timezone tz_; + + double seconds_; +}; + + +#else // ---------------------------------------- standard implementation ---- + +#include + +static const unsigned long clockticks = CLOCKS_PER_SEC; + +class TimerImplStd : public TimerImpl +{ +public: + TimerImplStd() : freq_(clockticks),count_(0),start_(0) { reset(); } + ~TimerImplStd() { ; } + + virtual void reset(void) { count_ = 0; } + virtual void start(void) { count_ = 0; start_ = clock(); } + virtual void stop(void); + virtual void cont(void) { start_ = clock(); } + virtual double seconds(void) const { return (double)count_/(double)freq_; } + +protected: + unsigned long freq_; + unsigned long count_; + unsigned long start_; +}; + +void TimerImplStd::stop(void) +{ + unsigned long stop_ = clock(); + count_ += stop_-start_; +} + +#endif + +// ----------------------------------------------------------------- Timer ---- + +Timer::Timer(void) : + state_(Stopped) +{ +#if defined(WIN32) && (defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__MINGW32__)) + impl_ = new TimerImplWin32; +#elif defined(__GNUC__) && defined(__POSIX__) +// CLOCK_REALTIME +// CLOCK_MONOTONIC - ? +// CLOCK_REALTIME_HR - RTlinux +// CLOCK_MONOTONIC_HR - ? +# if defined(CLOCK_REALTIME_HR) + impl_ = new TimerImplPosix; +# else + impl_ = new TimerImplPosix; +# endif +#elif (defined(__GNUC__) || (defined(__INTEL_COMPILER) && !defined(WIN32)) ) && !defined(__MINGW32__) + impl_ = new TimerImplGToD; +#else + impl_ = new TimerImplStd; +#endif + +} + +Timer::~Timer(void) +{ + delete impl_; + state_ = Stopped; +} + +void Timer::reset(void) +{ + state_ = Stopped; + impl_->reset(); +} + +void Timer::start(void) +{ + state_ = Running; + impl_->start(); +} + +void Timer::stop(void) +{ + impl_->stop(); + state_ = Stopped; +} + +void Timer::cont(void) +{ + impl_->cont(); + state_ = Running; +} + +double Timer::seconds(void) const +{ + return state_==Stopped ? impl_->seconds() : 0.0; +} + +std::string Timer::as_string(Timer::Format format) +{ + if (state_ == Running) + return "Running"; + return as_string(impl_->seconds(),format); +} + +std::string Timer::as_string(double seconds, Timer::Format format) +{ + char string[32]; + + double fraction; + double integer; + unsigned long t; +// double rest; + short hour,min,sec; + bool negative = false; + + if ( seconds < 0 ) + { + negative = true; + seconds *= -1; + } + + fraction = modf(seconds,&integer); + + t = (unsigned long)integer; + + hour = short( t / 3600L ); + t %= 3600L; + min = short( t / 60L ); + t %= 60L; + sec = short( t ); +// rest = (double)t + fraction; + + char *ptr = string; + if (negative) + *ptr++ = '-'; + + switch(format) + { + case Timer::Automatic: + if (hour) + ptr += sprintf(ptr,"%02dh:",hour); + + if (min) + ptr += sprintf(ptr,"%02dm:",min); + else if (ptr>string && hour) + ptr += sprintf(ptr,"00m:"); + + if (sec) + ptr += sprintf(ptr,"%02d",sec); + else if (ptr>string && min) + ptr += sprintf(ptr,"00"); + + if (!hour && !min) // higher resolution necessary + { + if (ptr > string && sec) + { + sprintf(ptr,".%.3fs",fraction); + ptr++; + while(*(ptr+2)) + { + *ptr = *(ptr+2); + ptr++; + } + *ptr = '\0'; + } + else if ( fraction * 1e2 > 0.1) + sprintf(ptr,"%.3fcs",fraction*1.e2); + else if ( fraction * 1e3 > 0.1) + sprintf(ptr,"%.3fms",fraction*1.e3); + else if ( fraction * 1e6 > 0.1) + sprintf(ptr,"%.1f\xb5s",fraction*1.e6); + else if ( fraction * 1e9 > 0.1) + sprintf(ptr,"%.1fns",fraction*1.e9); + else + sprintf(ptr,"%.1fps",fraction*1.e12); + } else // append a 's' for seconds! + { + ptr[0] = 's'; + ptr[1] = '\0'; + } + break; + case Timer::Long: + ptr += sprintf(ptr,"%02dh:%02dm:%02d",hour,min,sec); + sprintf(ptr,".%.12fs",fraction); + ptr++; + while(*(ptr+2)) + { + *ptr = *(ptr+2); + ptr++; + } + *ptr = '\0'; + break; + case Timer::Hours: + sprintf(ptr,"%02dh:%02dm:%02ds",hour,min,sec); break; + case Timer::Minutes: + ptr += sprintf(ptr,"%02dm:%02d", min, sec); + sprintf(ptr,".%.2fs",fraction); + ptr++; + while(*(ptr+2)) + { + *ptr = *(ptr+2); + ptr++; + } + *ptr = '\0'; + break; + case Timer::Seconds: sprintf(ptr,"%.3fs",seconds); break; + case Timer::HSeconds: sprintf(ptr,"%.3fcs",seconds*1e2); break; + case Timer::MSeconds: sprintf(ptr,"%.3fms",seconds*1e3); break; + case Timer::MicroSeconds: sprintf(ptr,"%.1f\xb5s",seconds*1e6); break; + case Timer::NanoSeconds: sprintf(ptr,"%.1fns",seconds*1e9); break; + } + return string; +} + +// ============================================================================ +} // END_NS_UTILS +} // END_NS_OPENMESH +// ---------------------------------------------------------------------------- +#endif // DOXY_IGNORE_THIS +// ============================================================================ +// end of file Timer.cc +// ============================================================================ + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Timer.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Timer.hh new file mode 100644 index 0000000..91347c2 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/Timer.hh @@ -0,0 +1,217 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef TIMER_HH +#define TIMER_HH +// ---------------------------------------------------------------------------- + +/** \file Timer.hh + A timer class +*/ + + +// ---------------------------------------------------------------------------- + +#include +// +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +// ------------------------------------------------------------- namespace ---- + +namespace OpenMesh { +namespace Utils { + + +// -------------------------------------------------------------- forwards ---- + + +class TimerImpl; + + +// ----------------------------------------------------------------- class ---- + +/** Timer class + */ +class OPENMESHDLLEXPORT Timer +{ +public: + + /// Formatting options for member Timer::as_string() + enum Format { + Automatic, + Long, + Hours, + Minutes, + Seconds, + HSeconds, + MSeconds, + MicroSeconds, + NanoSeconds + }; + + Timer(void); + + Timer(const Timer& _other) = delete; + + ~Timer(void); + + /// Returns true if self is in a valid state! + bool is_valid() const { return state_!=Invalid; } + + bool is_stopped() const { return state_==Stopped; } + + /// Reset the timer + void reset(void); + + /// Start measurement + void start(void); + + /// Stop measurement + void stop(void); + + /// Continue measurement + void cont(void); + + /// Give resolution of timer. Depends on the underlying measurement method. + float resolution() const; + + /// Returns measured time in seconds, if the timer is in state 'Stopped' + double seconds(void) const; + + /// Returns measured time in hundredth seconds, if the timer is in state 'Stopped' + double hseconds(void) const { return seconds()*1e2; } + + /// Returns measured time in milli seconds, if the timer is in state 'Stopped' + double mseconds(void) const { return seconds()*1e3; } + + /// Returns measured time in micro seconds, if the timer is in state 'Stopped' + double useconds(void) const { return seconds()*1e6; } + + /** Returns the measured time as a string. Use the format flags to specify + a wanted resolution. + */ + std::string as_string(Format format = Automatic); + + /** Returns a given measured time as a string. Use the format flags to + specify a wanted resolution. + */ + static std::string as_string(double seconds, Format format = Automatic); + +public: + + //@{ + /// Compare timer values + bool operator < (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() < t2.seconds()); + } + + bool operator > (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() > t2.seconds()); + } + + bool operator == (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() == t2.seconds()); + } + + bool operator <= (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() <= t2.seconds()); + } + + bool operator >=(const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() >= t2.seconds()); + } + //@} + +protected: + + TimerImpl *impl_; + + enum { + Invalid = -1, + Stopped = 0, + Running = 1 + } state_; + +}; + + +/** Write seconds to output stream. + * Timer must be stopped before. + * \relates Timer + */ +inline std::ostream& operator << (std::ostream& _o, const Timer& _t) +{ + return (_o << _t.seconds()); +} + + +// ============================================================================ +} // END_NS_UTILS +} // END_NS_OPENMESH +// ============================================================================ +#endif +// end of Timer.hh +// =========================================================================== + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/conio.cc b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/conio.cc new file mode 100644 index 0000000..985fbdd --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/conio.cc @@ -0,0 +1,243 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#include + +// ----------------------------------------------------------------- MSVC Compiler ---- +#ifdef _MSC_VER + +#include + +namespace OpenMesh { +namespace Utils { + +int kbhit() { return ::_kbhit(); } +int getch() { return ::_getch(); } +int getche() { return ::_getche(); } + +} // Tools +} // AS + +// ----------------------------------------------------------------- Win32 ---- +#elif defined(WIN32) || defined(__MINGW32__) + +#include + +namespace OpenMesh { +namespace Utils { + +int kbhit() { return ::kbhit(); } +int getch() { return ::getch(); } +int getche() { return ::getche(); } + +} // Tools +} // AS +// ----------------------------------------------------------------- Other ---- +#else + +// Based on code published by Floyd Davidson in a newsgroup. + +#include /* stdout, fflush() */ +#if !defined(POSIX_1003_1_2001) +# include +# include +#else +# include /* select() */ +#endif +#include /* tcsetattr() */ +#include /* ioctl() */ +#include /* timeval struct */ + +namespace OpenMesh { +namespace Utils { + +#ifdef CTIME +# undef CTIME +#endif +#define CTIME 1 +#define CMIN 1 + + +int kbhit(void) +{ + int cnt = 0; + int error; + static struct termios Otty, Ntty; + + tcgetattr(0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; /* input mode */ + Ntty.c_oflag = 0; /* output mode */ + Ntty.c_lflag &= ~ICANON; /* raw mode */ + Ntty.c_cc[VMIN] = CMIN; /* minimum chars to wait for */ + Ntty.c_cc[VTIME] = CTIME; /* minimum wait time */ + + if (0 == (error = tcsetattr(0, TCSANOW, &Ntty))) + { + struct timeval tv; + error += ioctl(0, FIONREAD, &cnt); + error += tcsetattr(0, TCSANOW, &Otty); + tv.tv_sec = 0; + tv.tv_usec = 100; /* insert at least a minimal delay */ + select(1, NULL, NULL, NULL, &tv); + } + return (error == 0 ? cnt : -1 ); +} + + +int getch(void) +{ + char ch = ' '; + int error; + static struct termios Otty, Ntty; + + fflush(stdout); + tcgetattr(0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; // input mode + Ntty.c_oflag = 0; // output mode + Ntty.c_lflag &= ~ICANON; // line settings + Ntty.c_lflag &= ~ECHO; // enable echo + Ntty.c_cc[VMIN] = CMIN; // minimum chars to wait for + Ntty.c_cc[VTIME] = CTIME; // minimum wait time + + // Conditionals allow compiling with or without flushing pre-existing + // existing buffered input before blocking. +#if 1 + // use this to flush the input buffer before blocking for new input +# define FLAG TCSAFLUSH +#else + // use this to return a char from the current input buffer, or block if + // no input is waiting. +# define FLAG TCSANOW +#endif + + if (0 == (error = tcsetattr(0, FLAG, &Ntty))) + { + error = read(0, &ch, 1 ); // get char from stdin + error += tcsetattr(0, FLAG, &Otty); // restore old settings + } + return (error == 1 ? (int) ch : -1 ); +} + + +int getche(void) +{ + char ch = ' '; + int error; + static struct termios Otty, Ntty; + + fflush(stdout); + tcgetattr(0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; // input mode + Ntty.c_oflag = 0; // output mode + Ntty.c_lflag &= ~ICANON; // line settings + Ntty.c_lflag |= ECHO; // enable echo + Ntty.c_cc[VMIN] = CMIN; // minimum chars to wait for + Ntty.c_cc[VTIME] = CTIME; // minimum wait time + + // Conditionals allow compiling with or without flushing pre-existing + // existing buffered input before blocking. +#if 1 + // use this to flush the input buffer before blocking for new input +# define FLAG TCSAFLUSH +#else + // use this to return a char from the current input buffer, or block if + // no input is waiting. +# define FLAG TCSANOW +#endif + + if (0 == (error = tcsetattr(0, FLAG, &Ntty))) { + error = read(0, &ch, 1 ); // get char from stdin + error += tcsetattr(0, FLAG, &Otty); // restore old settings + } + + return (error == 1 ? (int) ch : -1 ); +} + +} // namespace Tools +} // namespace AS +// ---------------------------------------------------------------------------- +#endif // System dependent parts +// ============================================================================ + +//#define Test +#if defined(Test) + +#include + +int main (void) +{ + char msg[] = "press key to continue..."; + char *ptr = msg; + + while ( !OpenMesh::Utils::kbhit() ) + { + char* tmp = *ptr; + *ptr = islower(tmp) ? toupper(tmp) : tolower(tmp); + printf("\r%s", msg); fflush(stdout); + *ptr = (char)tmp; + if (!*(++ptr)) + ptr = msg; + usleep(20000); + } + + printf("\r%s.", msg); fflush(stdout); + OpenMesh::Utils::getch(); + printf("\r%s..", msg); fflush(stdout); + OpenMesh::Utils::getche(); + return 0; +} + +#endif // Test + +// ============================================================================ diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/conio.hh b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/conio.hh new file mode 100644 index 0000000..b4db158 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/conio.hh @@ -0,0 +1,90 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_UTILS_CONIO_HH +#define OPENMESH_UTILS_CONIO_HH +// ---------------------------------------------------------------------------- +#include + +namespace OpenMesh { +namespace Utils { +// ---------------------------------------------------------------------------- + +/** Check if characters a pending in stdin. + * + * \return Number of characters available to read. + * + * \see getch(), getche() + */ +OPENMESHDLLEXPORT +int kbhit(void); + + +/** A blocking single character input from stdin + * + * \return Character, or -1 if an input error occurs. + * + * \see getche(), kbhit() + */ +OPENMESHDLLEXPORT +int getch(void); + +/** A blocking single character input from stdin with echo. + * + * \return Character, or -1 if an input error occurs. + * \see getch(), kbhit() + */ +OPENMESHDLLEXPORT +int getche(void); + +// ---------------------------------------------------------------------------- +} // namespace Utils +} // namespace OpenMesh +// ---------------------------------------------------------------------------- +#endif // OPENMESH_UTILS_CONIO_HH +// ============================================================================ diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/getopt.c b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/getopt.c new file mode 100644 index 0000000..e8d8f81 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/getopt.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include "getopt.h" + +OPENMESHDLLEXPORT int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +OPENMESHDLLEXPORT char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +OPENMESHDLLEXPORT int +getopt(int nargc, char * const *nargv, const char *ostr) +{ +# define __progname nargv[0] + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = (char *)strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/Utils/getopt.h b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/getopt.h new file mode 100644 index 0000000..59600d7 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/Utils/getopt.h @@ -0,0 +1,30 @@ +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#include +#include + +#if defined(_MSC_VER) + #if defined(__cplusplus) + + extern "C" { + + extern OPENMESHDLLEXPORT int opterr; + extern OPENMESHDLLEXPORT int optind; + extern OPENMESHDLLEXPORT int optopt; + extern OPENMESHDLLEXPORT int optreset; + extern OPENMESHDLLEXPORT char *optarg; + + OPENMESHDLLEXPORT extern int getopt(int nargc, char * const *nargv, const char *ostr); + + } + + #endif + +#elif defined __APPLE__ + #include +#else + #include +#endif + +#endif /* _GETOPT_H_ */ diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/MeshTraits.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/MeshTraits.hh new file mode 100644 index 0000000..438d926 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/MeshTraits.hh @@ -0,0 +1,125 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS VDPMTraits +// +//============================================================================= + + +#ifndef OPENMESH_VDPM_TRAITS_HH +#define OPENMESH_VDPM_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \class MeshTraits MeshTraits.hh + + Mesh traits for View Dependent Progressive Meshes +*/ + +struct OPENMESHDLLEXPORT MeshTraits : public DefaultTraits +{ + VertexTraits + { + public: + + VHierarchyNodeHandle vhierarchy_node_handle() + { + return node_handle_; + } + + void set_vhierarchy_node_handle(VHierarchyNodeHandle _node_handle) + { + node_handle_ = _node_handle; + } + + bool is_ancestor(const VHierarchyNodeIndex &_other) + { + return false; + } + + private: + + VHierarchyNodeHandle node_handle_; + + }; + + VertexAttributes(OpenMesh::Attributes::Status | + OpenMesh::Attributes::Normal); + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); + EdgeAttributes(OpenMesh::Attributes::Status); + FaceAttributes(OpenMesh::Attributes::Status | + OpenMesh::Attributes::Normal); +}; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPM_TRAITS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/StreamingDef.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/StreamingDef.hh new file mode 100644 index 0000000..d3539df --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/StreamingDef.hh @@ -0,0 +1,95 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + + +#ifndef OPENMESH_VDPM_STREAMINGDEF_HH +#define OPENMESH_VDPM_STREAMINGDEF_HH + +//== INCLUDES ================================================================= + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== CLASS DEFINITION ========================================================= + +#define VDPM_STREAMING_PORT 4096 + +//#define DEBUG_COUT +//#define QDATASTREAM + +#ifdef DEBUG_COUT +static bool debug_print_; +static bool debug_print() { return debug_print_; } +static void set_debug_print(bool flag) { debug_print_ = flag; } +#endif + +enum VDPMDownLinkStatus { kStarted, kFinished, kStartable }; +enum VDPMStreamingPhase { kBaseMesh, kVSplitHeader, kVSplits }; +enum VDPMClientMode { kStatic, kDynamic }; +enum VHierarchySearchMode { kBruteForce, kUseHashing }; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VDPMSTREAMINGDEF_HH defined +//============================================================================= + + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VFront.cc b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VFront.cc new file mode 100644 index 0000000..8c50e91 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VFront.cc @@ -0,0 +1,119 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== IMPLEMENTATION ========================================================== + + +VFront::VFront() +{ +} + + +void +VFront:: +add(VHierarchyNodeHandle _node_handle) +{ + front_location_[_node_handle.idx()] = front_.insert(front_.end(), _node_handle); +} + + +void +VFront:: +remove(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNodeHandleListIter node_it = front_location_[_node_handle.idx()]; + const bool isFront = (front_it_ == node_it); + VHierarchyNodeHandleListIter next_it = front_.erase(node_it); + front_location_[_node_handle.idx()] = front_.end(); + + if (isFront) + front_it_ = next_it; +} + +bool +VFront:: +is_active(VHierarchyNodeHandle _node_handle) +{ + return (front_location_[_node_handle.idx()] != front_.end()) ? true : false; +} + +void +VFront:: +init(VHierarchyNodeHandleContainer &_roots, unsigned int _n_details) +{ + unsigned int i; + + front_location_.resize(_roots.size() + 2*_n_details); + for (i=0; i +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Active nodes in vertex hierarchy. + \todo VFront documentation +*/ +class OPENMESHDLLEXPORT VFront +{ +private: + + typedef VHierarchyNodeHandleList::iterator VHierarchyNodeHandleListIter; + enum VHierarchyNodeStatus { kSplit, kActive, kCollapse }; + + VHierarchyNodeHandleList front_; + VHierarchyNodeHandleListIter front_it_; + std::vector front_location_; + +public: + + VFront(); + + void clear() { front_.clear(); front_location_.clear(); } + void begin() { front_it_ = front_.begin(); } + bool end() { return (front_it_ == front_.end()) ? true : false; } + void next() { ++front_it_; } + int size() { return (int) front_.size(); } + VHierarchyNodeHandle node_handle() { return *front_it_; } + + void add(VHierarchyNodeHandle _node_handle); + void remove(VHierarchyNodeHandle _node_handle); + bool is_active(VHierarchyNodeHandle _node_handle); + void init(VHierarchyNodeHandleContainer &_roots, unsigned int _n_details); +}; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VFRONT_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchy.cc b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchy.cc new file mode 100644 index 0000000..f28be46 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchy.cc @@ -0,0 +1,180 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== IMPLEMENTATION ========================================================== + + +VHierarchy:: +VHierarchy() : + n_roots_(0), tree_id_bits_(0) +{ + clear(); +} + +void +VHierarchy:: +set_num_roots(unsigned int _n_roots) +{ + n_roots_ = _n_roots; + + tree_id_bits_ = 0; + while (n_roots_ > ((unsigned int) 0x00000001 << tree_id_bits_)) + ++tree_id_bits_; +} + + +VHierarchyNodeHandle +VHierarchy:: +add_node() +{ + return add_node(VHierarchyNode()); +} + +VHierarchyNodeHandle +VHierarchy:: +add_node(const VHierarchyNode &_node) +{ + nodes_.push_back(_node); + + return VHierarchyNodeHandle(int(nodes_.size() - 1)); +} + + +void +VHierarchy:: +make_children(VHierarchyNodeHandle &_parent_handle) +{ + VHierarchyNodeHandle lchild_handle = add_node(); + VHierarchyNodeHandle rchild_handle = add_node(); + + VHierarchyNode &parent = node(_parent_handle); + VHierarchyNode &lchild = node(lchild_handle); + VHierarchyNode &rchild = node(rchild_handle); + + parent.set_children_handle(lchild_handle); + lchild.set_parent_handle(_parent_handle); + rchild.set_parent_handle(_parent_handle); + + lchild.set_index(VHierarchyNodeIndex(parent.node_index().tree_id(tree_id_bits_), 2*parent.node_index().node_id(tree_id_bits_), tree_id_bits_)); + rchild.set_index(VHierarchyNodeIndex(parent.node_index().tree_id(tree_id_bits_), 2*parent.node_index().node_id(tree_id_bits_)+1, tree_id_bits_)); +} + +VHierarchyNodeHandle +VHierarchy:: +node_handle(VHierarchyNodeIndex _node_index) +{ + if (_node_index.is_valid(tree_id_bits_) != true) + return InvalidVHierarchyNodeHandle; + + VHierarchyNodeHandle node_handle = root_handle(_node_index.tree_id(tree_id_bits_)); + unsigned int node_id = _node_index.node_id(tree_id_bits_); + unsigned int flag = 0x80000000; + + while (!(node_id & flag)) flag >>= 1; + flag >>= 1; + + while (flag > 0 && is_leaf_node(node_handle) != true) + { + if (node_id & flag) // 1: rchild + { + node_handle = rchild_handle(node_handle); + } + else // 0: lchild + { + node_handle = lchild_handle(node_handle); + } + flag >>= 1; + } + + return node_handle; +} + +bool +VHierarchy:: +is_ancestor(VHierarchyNodeIndex _ancestor_index, VHierarchyNodeIndex _descendent_index) +{ + if (_ancestor_index.tree_id(tree_id_bits_) != _descendent_index.tree_id(tree_id_bits_)) + return false; + + unsigned int ancestor_node_id = _ancestor_index.node_id(tree_id_bits_); + unsigned int descendent_node_id = _descendent_index.node_id(tree_id_bits_); + + if (ancestor_node_id > descendent_node_id) + return false; + + while (descendent_node_id > 0) + { + if (ancestor_node_id == descendent_node_id) + return true; + descendent_node_id >>= 1; // descendent_node_id /= 2 + } + + return false; +} + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchy.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchy.hh new file mode 100644 index 0000000..0eca2d6 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchy.hh @@ -0,0 +1,193 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHY_HH +#define OPENMESH_VDPROGMESH_VHIERARCHY_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Keeps the vertex hierarchy build during analyzing a progressive mesh. + */ +class OPENMESHDLLEXPORT VHierarchy +{ +public: + + typedef unsigned int id_t; ///< Type for tree and node ids + +private: + + VHierarchyNodeContainer nodes_; + unsigned int n_roots_; + unsigned char tree_id_bits_; // node_id_bits_ = 32-tree_id_bits_; + +public: + + VHierarchy(); + + void clear() { nodes_.clear(); n_roots_ = 0; } + unsigned char tree_id_bits() const { return tree_id_bits_; } + unsigned int num_roots() const { return n_roots_; } + size_t num_nodes() const { return nodes_.size(); } + + VHierarchyNodeIndex generate_node_index(id_t _tree_id, id_t _node_id) + { + return VHierarchyNodeIndex(_tree_id, _node_id, tree_id_bits_); + } + + + void set_num_roots(unsigned int _n_roots); + + VHierarchyNodeHandle root_handle(unsigned int i) const + { + return VHierarchyNodeHandle( (int)i ); + } + + + const VHierarchyNode& node(VHierarchyNodeHandle _vhierarchynode_handle) const + { + return nodes_[_vhierarchynode_handle.idx()]; + } + + + VHierarchyNode& node(VHierarchyNodeHandle _vhierarchynode_handle) + { + return nodes_[_vhierarchynode_handle.idx()]; + } + + VHierarchyNodeHandle add_node(); + VHierarchyNodeHandle add_node(const VHierarchyNode &_node); + + void make_children(VHierarchyNodeHandle &_parent_handle); + + bool is_ancestor(VHierarchyNodeIndex _ancestor_index, + VHierarchyNodeIndex _descendent_index); + + bool is_leaf_node(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].is_leaf(); } + + bool is_root_node(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].is_root(); } + + + const OpenMesh::Vec3f& normal(VHierarchyNodeHandle _node_handle) const + { + return nodes_[_node_handle.idx()].normal(); + } + + const VHierarchyNodeIndex& + node_index(VHierarchyNodeHandle _node_handle) const + { return nodes_[_node_handle.idx()].node_index(); } + + VHierarchyNodeIndex& node_index(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].node_index(); } + + const VHierarchyNodeIndex& + fund_lcut_index(VHierarchyNodeHandle _node_handle) const + { return nodes_[_node_handle.idx()].fund_lcut_index(); } + + VHierarchyNodeIndex& fund_lcut_index(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].fund_lcut_index(); } + + const VHierarchyNodeIndex& + fund_rcut_index(VHierarchyNodeHandle _node_handle) const + { return nodes_[_node_handle.idx()].fund_rcut_index(); } + + VHierarchyNodeIndex& fund_rcut_index(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].fund_rcut_index(); } + + VertexHandle vertex_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].vertex_handle(); } + + VHierarchyNodeHandle parent_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].parent_handle(); } + + VHierarchyNodeHandle lchild_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].lchild_handle(); } + + VHierarchyNodeHandle rchild_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].rchild_handle(); } + + VHierarchyNodeHandle node_handle(VHierarchyNodeIndex _node_index); + +private: + + VHierarchyNodeHandle compute_dependency(VHierarchyNodeIndex index0, + VHierarchyNodeIndex index1); + +}; + + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHY_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNode.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNode.hh new file mode 100644 index 0000000..435ba71 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNode.hh @@ -0,0 +1,199 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHYNODE_HH +#define OPENMESH_VDPROGMESH_VHIERARCHYNODE_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Handle for vertex hierarchy nodes + */ +struct VHierarchyNodeHandle : public BaseHandle +{ + explicit VHierarchyNodeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Invalid handle +static const VHierarchyNodeHandle InvalidVHierarchyNodeHandle; + + +/** Vertex hierarchy node + * \todo Complete documentation + */ +class VHierarchyNode +{ +public: + + VHierarchyNode() :radius_(0.0f), sin_square_(0.0f),mue_square_(0.0f), sigma_square_(0.0f) { } + + /// Returns true, if node is root else false. + bool is_root() const + { return (parent_handle_.is_valid() == false) ? true : false; } + + /// Returns true, if node is leaf else false. + bool is_leaf() const + { return (lchild_handle_.is_valid() == false) ? true : false; } + + /// Returns parent handle. + VHierarchyNodeHandle parent_handle() { return parent_handle_; } + + /// Returns handle to left child. + VHierarchyNodeHandle lchild_handle() { return lchild_handle_; } + + /// Returns handle to right child. + VHierarchyNodeHandle rchild_handle() + { return VHierarchyNodeHandle(lchild_handle_.idx()+1); } + + void set_parent_handle(VHierarchyNodeHandle _parent_handle) + { parent_handle_ = _parent_handle; } + + void set_children_handle(VHierarchyNodeHandle _lchild_handle) + { lchild_handle_ = _lchild_handle; } + + VertexHandle vertex_handle() const { return vh_; } + float radius() const { return radius_; } + const OpenMesh::Vec3f& normal() const { return normal_; } + float sin_square() const { return sin_square_; } + float mue_square() const { return mue_square_; } + float sigma_square() const { return sigma_square_; } + + void set_vertex_handle(OpenMesh::VertexHandle _vh) { vh_ = _vh; } + void set_radius(float _radius) { radius_ = _radius; } + void set_normal(const OpenMesh::Vec3f &_normal) { normal_ = _normal; } + + void set_sin_square(float _sin_square) { sin_square_ = _sin_square; } + void set_mue_square(float _mue_square) { mue_square_ = _mue_square; } + void set_sigma_square(float _sigma_square) { sigma_square_ = _sigma_square; } + + void set_semi_angle(float _semi_angle) + { float f=sinf(_semi_angle); sin_square_ = f*f; } + + void set_mue(float _mue) { mue_square_ = _mue * _mue; } + void set_sigma(float _sigma) { sigma_square_ = _sigma * _sigma; } + + const VHierarchyNodeIndex& node_index() const { return node_index_; } + const VHierarchyNodeIndex& fund_lcut_index() const + { return fund_cut_node_index_[0]; } + + const VHierarchyNodeIndex& fund_rcut_index() const + { return fund_cut_node_index_[1]; } + + VHierarchyNodeIndex& node_index() + { return node_index_; } + + VHierarchyNodeIndex& fund_lcut_index() { return fund_cut_node_index_[0]; } + VHierarchyNodeIndex& fund_rcut_index() { return fund_cut_node_index_[1]; } + + void set_index(const VHierarchyNodeIndex &_node_index) + { node_index_ = _node_index; } + + void set_fund_lcut(const VHierarchyNodeIndex &_node_index) + { fund_cut_node_index_[0] = _node_index; } + + void set_fund_rcut(const VHierarchyNodeIndex &_node_index) + { fund_cut_node_index_[1] = _node_index; } + +private: + VertexHandle vh_; + float radius_; + Vec3f normal_; + float sin_square_; + float mue_square_; + float sigma_square_; + + VHierarchyNodeHandle parent_handle_; + VHierarchyNodeHandle lchild_handle_; + + + VHierarchyNodeIndex node_index_; + VHierarchyNodeIndex fund_cut_node_index_[2]; +}; + +/// Container for vertex hierarchy nodes +typedef std::vector VHierarchyNodeContainer; + +/// Container for vertex hierarchy node handles +typedef std::vector VHierarchyNodeHandleContainer; + +/// Container for vertex hierarchy node handles +typedef std::list VHierarchyNodeHandleList; + + +//============================================================================= +} // namesapce VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHYNODE_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNodeIndex.cc b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNodeIndex.cc new file mode 100644 index 0000000..c5c1029 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNodeIndex.cc @@ -0,0 +1,78 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== IMPLEMENTATION ========================================================== + + +const VHierarchyNodeIndex +VHierarchyNodeIndex::InvalidIndex = VHierarchyNodeIndex(); + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNodeIndex.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNodeIndex.hh new file mode 100644 index 0000000..5b17d8e --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyNodeIndex.hh @@ -0,0 +1,133 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHYNODEINDEX_HH +#define OPENMESH_VDPROGMESH_VHIERARCHYNODEINDEX_HH + +//== INCLUDES ================================================================= + +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Index of vertex hierarchy node + */ + + +class VHierarchyNodeIndex +{ +private: + unsigned int value_; + +public: + + static const VHierarchyNodeIndex InvalidIndex; + +public: + + VHierarchyNodeIndex() + { value_ = 0; } + + explicit VHierarchyNodeIndex(unsigned int _value) + { value_ = _value; } + + VHierarchyNodeIndex(const VHierarchyNodeIndex &_other) + { value_ = _other.value_; } + + VHierarchyNodeIndex(unsigned int _tree_id, + unsigned int _node_id, + unsigned short _tree_id_bits) + { + assert(_tree_id < ((unsigned int) 0x00000001 << _tree_id_bits)); + assert(_node_id < ((unsigned int) 0x00000001 << (32 - _tree_id_bits))); + value_ = (_tree_id << (32 - _tree_id_bits)) | _node_id; + } + + bool is_valid(unsigned short _tree_id_bits) const + { return node_id(_tree_id_bits) != 0 ? true : false; } + + unsigned int tree_id(unsigned short _tree_id_bits) const + { return value_ >> (32 - _tree_id_bits); } + + unsigned int node_id(unsigned short _tree_id_bits) const + { return value_ & ((unsigned int) 0xFFFFFFFF >> _tree_id_bits); } + + bool operator< (const VHierarchyNodeIndex &other) const + { return (value_ < other.value_) ? true : false; } + + unsigned int value() const + { return value_; } +}; + + +/// Container for vertex hierarchy node indices +typedef std::vector VHierarchyNodeIndexContainer; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHYNODEINDEX_HH defined +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyWindow.cc b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyWindow.cc new file mode 100644 index 0000000..b3aea8f --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyWindow.cc @@ -0,0 +1,206 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + +#include + +#ifndef WIN32 +#else + #if defined(__MINGW32__) + #include + #include + #endif +#endif + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== IMPLEMENTATION ========================================================== + + +VHierarchyWindow:: +VHierarchyWindow() : + vhierarchy_(NULL), buffer_(NULL),buffer_min_ (0), buffer_max_(0), current_pos_(0) , window_min_(0), window_max_(0), n_shift_(0) +{ + +} + + +VHierarchyWindow:: +VHierarchyWindow(VHierarchy &_vhierarchy) : + vhierarchy_(&_vhierarchy),buffer_(NULL),buffer_min_ (0), buffer_max_(0), current_pos_(0) , window_min_(0), window_max_(0) ,n_shift_(0) +{ +} + + +VHierarchyWindow:: +~VHierarchyWindow(void) +{ + if (buffer_ != NULL) + free(buffer_); +} + + +bool +VHierarchyWindow:: +update_buffer(VHierarchyNodeHandle _node_handle) +{ + if (underflow(_node_handle) != true && overflow(_node_handle) != true) + return false; + + // tightly update window_min_ & window_max_ + int none_zero_pos; + for (none_zero_pos=int(buffer_size()-1); none_zero_pos >= 0; --none_zero_pos) + { + if (buffer_[none_zero_pos] != 0) break; + } + window_max_ = buffer_min_ + none_zero_pos + 1; + for(none_zero_pos=0; none_zero_pos < int(buffer_size()); ++none_zero_pos) + { + if (buffer_[none_zero_pos] != 0) break; + } + window_min_ = buffer_min_ + none_zero_pos; + + assert(window_min_ < window_max_); + + while (underflow(_node_handle) == true) buffer_min_ /= 2; + while (overflow(_node_handle) == true) + { + buffer_max_ *= 2; + if (buffer_max_ > vhierarchy_->num_nodes() / 8) + buffer_max_ = 1 + vhierarchy_->num_nodes() / 8; + } + + unsigned char *new_buffer = (unsigned char *) malloc(buffer_size()); + memset(new_buffer, 0, buffer_size()); + memcpy(&(new_buffer[window_min_-buffer_min_]), + &(buffer_[none_zero_pos]), + window_size()); + free(buffer_); + buffer_ = new_buffer; + + return true; +} + +void +VHierarchyWindow::init(VHierarchyNodeHandleContainer &_roots) +{ + if (buffer_ != NULL) + free(buffer_); + + buffer_min_ = 0; + buffer_max_ = _roots.size() / 8; + if (_roots.size() % 8 > 0) + ++buffer_max_; + + buffer_ = (unsigned char *) malloc(buffer_size()); + memset(buffer_, 0, buffer_size()); + + window_min_ = 0; + window_max_= 0; + current_pos_ = 0; + n_shift_ = 0; + + for (unsigned int i=0; i<_roots.size(); i++) + { + activate(VHierarchyNodeHandle((int) i)); + } +} + + +void +VHierarchyWindow:: +update_with_vsplit(VHierarchyNodeHandle _parent_handle) +{ + VHierarchyNodeHandle + lchild_handle = vhierarchy_->lchild_handle(_parent_handle), + rchild_handle = vhierarchy_->rchild_handle(_parent_handle); + + assert(is_active(_parent_handle) == true); + assert(is_active(lchild_handle) != true); + assert(is_active(rchild_handle) != true); + + inactivate(_parent_handle); + activate(rchild_handle); + activate(lchild_handle); +} + +void +VHierarchyWindow:: +update_with_ecol(VHierarchyNodeHandle _parent_handle) +{ + VHierarchyNodeHandle + lchild_handle = vhierarchy_->lchild_handle(_parent_handle), + rchild_handle = vhierarchy_->rchild_handle(_parent_handle); + + assert(is_active(_parent_handle) != true); + assert(is_active(lchild_handle) == true); + assert(is_active(rchild_handle) == true); + + activate(_parent_handle); + inactivate(rchild_handle); + inactivate(lchild_handle); +} + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyWindow.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyWindow.hh new file mode 100644 index 0000000..a490e57 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/VHierarchyWindow.hh @@ -0,0 +1,224 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHYWINDOWS_HH +#define OPENMESH_VDPROGMESH_VHIERARCHYWINDOWS_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \todo VHierarchyWindow documentation +*/ +class VHierarchyWindow +{ +private: + + // reference of vertex hierarchy + VHierarchy *vhierarchy_; + + // bits buffer (byte units) + unsigned char *buffer_; + int buffer_min_; + size_t buffer_max_; + int current_pos_; + + // window (byte units) + int window_min_; + int window_max_; + + + // # of right shift (bit units) + unsigned char n_shift_; // [0, 7] + + unsigned char flag8(unsigned char n_shift) const + { return 0x80 >> n_shift; } + + unsigned char flag8(VHierarchyNodeHandle _node_handle) const + { + assert(_node_handle.idx() >= 0); + return 0x80 >> (unsigned int) (_node_handle.idx() % 8); + } + int byte_idx(VHierarchyNodeHandle _node_handle) const + { + assert(_node_handle.idx() >= 0); + return _node_handle.idx() / 8; + } + int buffer_idx(VHierarchyNodeHandle _node_handle) const + { return byte_idx(_node_handle) - buffer_min_; } + + bool before_window(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < window_min_) ? true : false; } + + bool after_window(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < window_max_) ? false : true; } + + bool underflow(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < buffer_min_) ? true : false; } + + bool overflow(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < int(buffer_max_) ) ? false : true; } + + bool update_buffer(VHierarchyNodeHandle _node_handle); + +public: + VHierarchyWindow(); + VHierarchyWindow(VHierarchy &_vhierarchy); + ~VHierarchyWindow(void); + + void set_vertex_hierarchy(VHierarchy &_vhierarchy) + { vhierarchy_ = &_vhierarchy; } + + void begin() + { + int new_window_min = window_min_; + for (current_pos_=window_min_-buffer_min_; + current_pos_ < window_size(); ++current_pos_) + { + if (buffer_[current_pos_] == 0) + ++new_window_min; + else + { + n_shift_ = 0; + while ((buffer_[current_pos_] & flag8(n_shift_)) == 0) + ++n_shift_; + break; + } + } + window_min_ = new_window_min; + } + + void next() + { + ++n_shift_; + if (n_shift_ == 8) + { + n_shift_ = 0; + ++current_pos_; + } + + while (current_pos_ < window_max_-buffer_min_) + { + if (buffer_[current_pos_] != 0) // if the current byte has non-zero bits + { + while (n_shift_ != 8) + { + if ((buffer_[current_pos_] & flag8(n_shift_)) != 0) + return; // find 1 bit in the current byte + ++n_shift_; + } + } + n_shift_ = 0; + ++current_pos_; + } + } + bool end() { return !(current_pos_ < window_max_-buffer_min_); } + + int window_size() const { return window_max_ - window_min_; } + size_t buffer_size() const { return buffer_max_ - buffer_min_; } + + VHierarchyNodeHandle node_handle() + { + return VHierarchyNodeHandle(8*(buffer_min_+current_pos_) + (int)n_shift_); + } + + void activate(VHierarchyNodeHandle _node_handle) + { + update_buffer(_node_handle); + buffer_[buffer_idx(_node_handle)] |= flag8(_node_handle); + window_min_ = std::min(window_min_, byte_idx(_node_handle)); + window_max_ = std::max(window_max_, 1+byte_idx(_node_handle)); + } + + + void inactivate(VHierarchyNodeHandle _node_handle) + { + if (is_active(_node_handle) != true) return; + buffer_[buffer_idx(_node_handle)] ^= flag8(_node_handle); + } + + + bool is_active(VHierarchyNodeHandle _node_handle) const + { + if (before_window(_node_handle) == true || + after_window(_node_handle) == true) + return false; + return ((buffer_[buffer_idx(_node_handle)] & flag8(_node_handle)) > 0); + } + + void init(VHierarchyNodeHandleContainer &_roots); + void update_with_vsplit(VHierarchyNodeHandle _parent_handle); + void update_with_ecol(VHierarchyNodeHandle _parent_handle); +}; + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHYWINDOWS_HH +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/ViewingParameters.cc b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/ViewingParameters.cc new file mode 100644 index 0000000..f32cb80 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/ViewingParameters.cc @@ -0,0 +1,177 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== IMPLEMENTATION ========================================================== + + +ViewingParameters:: +ViewingParameters() +{ + for ( unsigned int i = 0; i < 16; ++i) + modelview_matrix_[i] = 0.0; + + fovy_ = 45.0f; + aspect_ = 1.0f; + tolerance_square_ = 0.001f; +} + +void +ViewingParameters:: +update_viewing_configurations() +{ + // |a11 a12 a13|-1 | a33a22-a32a23 -(a33a12-a32a13) a23a12-a22a13 | + // |a21 a22 a23| = 1/DET*|-(a33a21-a31a23) a33a11-a31a13 -(a23a11-a21a13)| + // |a31 a32 a33| | a32a21-a31a22 -(a32a11-a31a12) a22a11-a21a12 | + // DET = a11(a33a22-a32a23)-a21(a33a12-a32a13)+a31(a23a12-a22a13) + + float invdet; + float a11, a12, a13, a21, a22, a23, a31, a32, a33; + Vec3f trans; + +// Workaround for internal compiler error on Visual Studio 2015 Update 1 +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) ) + Vec3f inv_rot[3]{ {},{},{} }; + Vec3f normal[4]{ {},{},{},{} }; +#else + Vec3f inv_rot[3]; + Vec3f normal[4]; +#endif + + a11 = (float) modelview_matrix_[0]; + a12 = (float) modelview_matrix_[4]; + a13 = (float) modelview_matrix_[8]; + trans[0] = (float) modelview_matrix_[12]; + + a21 = (float) modelview_matrix_[1]; + a22 = (float) modelview_matrix_[5]; + a23 = (float) modelview_matrix_[9]; + trans[1] = (float) modelview_matrix_[13]; + + a31 = (float) modelview_matrix_[2]; + a32 = (float) modelview_matrix_[6]; + a33 = (float) modelview_matrix_[10]; + trans[2] = (float) modelview_matrix_[14]; + + invdet = a11*(a33*a22-a32*a23) - a21*(a33*a12-a32*a13) + a31*(a23*a12-a22*a13); + invdet= (float) 1.0/invdet; + + (inv_rot[0])[0] = (a33*a22-a32*a23) * invdet; + (inv_rot[0])[1] = -(a33*a12-a32*a13) * invdet; + (inv_rot[0])[2] = (a23*a12-a22*a13) * invdet; + (inv_rot[1])[0] = -(a33*a21-a31*a23) * invdet; + (inv_rot[1])[1] = (a33*a11-a31*a13) * invdet; + (inv_rot[1])[2] = -(a23*a11-a21*a13) * invdet; + (inv_rot[2])[0] = (a32*a21-a31*a22) * invdet; + (inv_rot[2])[1] = -(a32*a11-a31*a12) * invdet; + (inv_rot[2])[2] = (a22*a11-a21*a12) * invdet; + + eye_pos_ = - Vec3f(dot(inv_rot[0], trans), + dot(inv_rot[1], trans), + dot(inv_rot[2], trans)); + right_dir_ = Vec3f(a11, a12, a13); + up_dir_ = Vec3f(a21, a22, a23); + view_dir_ = - Vec3f(a31, a32, a33); + + //float aspect = width() / height(); + const float half_theta = fovy() * 0.5f; + const float half_phi = atanf(aspect() * tanf(half_theta)); + + const float sin1 = sinf(half_theta); + const float cos1 = cosf(half_theta); + const float sin2 = sinf(half_phi); + const float cos2 = cosf(half_phi); + + normal[0] = cos2 * right_dir_ + sin2 * view_dir_; + normal[1] = -cos1 * up_dir_ - sin1 * view_dir_; + normal[2] = -cos2 * right_dir_ + sin2 * view_dir_; + normal[3] = cos1 * up_dir_ - sin1 * view_dir_; + + for (int i=0; i<4; i++) + frustum_plane_[i] = Plane3d(normal[i], eye_pos_); +} + +void +ViewingParameters:: +PrintOut() +{ + std::cout << " ModelView matrix: " << std::endl; + std::cout << " |" << modelview_matrix_[0] << " " << modelview_matrix_[4] << " " << modelview_matrix_[8] << " " << modelview_matrix_[12] << "|" << std::endl; + std::cout << " |" << modelview_matrix_[1] << " " << modelview_matrix_[5] << " " << modelview_matrix_[9] << " " << modelview_matrix_[13] << "|" << std::endl; + std::cout << " |" << modelview_matrix_[2] << " " << modelview_matrix_[6] << " " << modelview_matrix_[10] << " " << modelview_matrix_[14] << "|" << std::endl; + std::cout << " |" << modelview_matrix_[3] << " " << modelview_matrix_[7] << " " << modelview_matrix_[11] << " " << modelview_matrix_[15] << "|" << std::endl; + std::cout << " Fovy: " << fovy_ << std::endl; + std::cout << " Aspect: " << aspect_ << std::endl; + std::cout << " Tolerance^2: " << tolerance_square_ << std::endl; + std::cout << " Eye Pos: " << eye_pos_ << std::endl; + std::cout << " Right dir: " << right_dir_ << std::endl; + std::cout << " Up dir: " << up_dir_ << std::endl; + std::cout << " View dir: " << view_dir_ << std::endl; +} + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/ViewingParameters.hh b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/ViewingParameters.hh new file mode 100644 index 0000000..a23d8fa --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/ViewingParameters.hh @@ -0,0 +1,148 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/*===========================================================================*\ + * * + * $Revision$ * + * $Date$ * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VIEWINGPARAMETERS_HH +#define OPENMESH_VDPROGMESH_VIEWINGPARAMETERS_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \todo ViewerParameters documentation + */ +class OPENMESHDLLEXPORT ViewingParameters +{ +private: + double modelview_matrix_[16]; + float fovy_; + float aspect_; + float tolerance_square_; + + Vec3f eye_pos_; + Vec3f right_dir_; + Vec3f up_dir_; + Vec3f view_dir_; + + Plane3d frustum_plane_[4]; + +public: + + ViewingParameters(); + + void increase_tolerance() { tolerance_square_ *= 5.0f; } + void decrease_tolerance() { tolerance_square_ /= 5.0f; } + + float fovy() const { return fovy_; } + float aspect() const { return aspect_; } + float tolerance_square() const { return tolerance_square_; } + + void set_fovy(float _fovy) { fovy_ = _fovy; } + void set_aspect(float _aspect) { aspect_ = _aspect; } + void set_tolerance_square(float _tolerance_square) { tolerance_square_ = _tolerance_square; } + + const Vec3f& eye_pos() const { return eye_pos_; } + const Vec3f& right_dir() const { return right_dir_; } + const Vec3f& up_dir() const { return up_dir_; } + const Vec3f& view_dir() const { return view_dir_; } + Vec3f& eye_pos() { return eye_pos_; } + Vec3f& right_dir() { return right_dir_; } + Vec3f& up_dir() { return up_dir_; } + Vec3f& view_dir() { return view_dir_; } + + void frustum_planes( Plane3d _plane[4] ) + { + for (unsigned int i=0; i<4; ++i) + _plane[i] = frustum_plane_[i]; + } + + void get_modelview_matrix(double _modelview_matrix[16]) + { + for (unsigned int i=0; i<16; ++i) + _modelview_matrix[i] = modelview_matrix_[i]; + } + + void set_modelview_matrix(const double _modelview_matrix[16]) + { + for (unsigned int i=0; i<16; ++i) + modelview_matrix_[i] = _modelview_matrix[i]; + } + + void update_viewing_configurations(); + + void PrintOut(); +}; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VIEWINGPARAMETERS_HH defined +//============================================================================= + diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/fileopen.xpm b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/fileopen.xpm new file mode 100644 index 0000000..a46d3f7 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/fileopen.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *fileopen[] = { +" 16 13 5 1", +". c #040404", +"# c #808304", +"a c None", +"b c #f3f704", +"c c #f3f7f3", +"aaaaaaaaa...aaaa", +"aaaaaaaa.aaa.a.a", +"aaaaaaaaaaaaa..a", +"a...aaaaaaaa...a", +".bcb.......aaaaa", +".cbcbcbcbc.aaaaa", +".bcbcbcbcb.aaaaa", +".cbcb...........", +".bcb.#########.a", +".cb.#########.aa", +".b.#########.aaa", +"..#########.aaaa", +"...........aaaaa" +}; diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/fileprint.xpm b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/fileprint.xpm new file mode 100644 index 0000000..629102d --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/fileprint.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *fileprint[] = { +" 16 14 6 1", +". c #000000", +"# c #848284", +"a c #c6c3c6", +"b c #ffff00", +"c c #ffffff", +"d c None", +"ddddd.........dd", +"dddd.cccccccc.dd", +"dddd.c.....c.ddd", +"ddd.cccccccc.ddd", +"ddd.c.....c....d", +"dd.cccccccc.a.a.", +"d..........a.a..", +".aaaaaaaaaa.a.a.", +".............aa.", +".aaaaaa###aa.a.d", +".aaaaaabbbaa...d", +".............a.d", +"d.aaaaaaaaa.a.dd", +"dd...........ddd" +}; diff --git a/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/filesave.xpm b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/filesave.xpm new file mode 100644 index 0000000..d944b63 --- /dev/null +++ b/libs/OpenMesh/inc/OpenMesh/Tools/VDPM/xpm/filesave.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *filesave[] = { +" 14 14 4 1", +". c #040404", +"# c #808304", +"a c #bfc2bf", +"b c None", +"..............", +".#.aaaaaaaa.a.", +".#.aaaaaaaa...", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".##........##.", +".############.", +".##.........#.", +".##......aa.#.", +".##......aa.#.", +".##......aa.#.", +"b............." +}; diff --git a/libs/OpenMesh/liblinux/libOpenMeshCore.a b/libs/OpenMesh/liblinux/libOpenMeshCore.a new file mode 100644 index 0000000..1f64d60 Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshCore.a differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshCore.so b/libs/OpenMesh/liblinux/libOpenMeshCore.so new file mode 100755 index 0000000..45ca36a Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshCore.so differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshCore.so.7.1 b/libs/OpenMesh/liblinux/libOpenMeshCore.so.7.1 new file mode 100755 index 0000000..45ca36a Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshCore.so.7.1 differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshCored.a b/libs/OpenMesh/liblinux/libOpenMeshCored.a new file mode 100644 index 0000000..50e2604 Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshCored.a differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshCored.so b/libs/OpenMesh/liblinux/libOpenMeshCored.so new file mode 100755 index 0000000..049efcf Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshCored.so differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshCored.so.7.1 b/libs/OpenMesh/liblinux/libOpenMeshCored.so.7.1 new file mode 100755 index 0000000..049efcf Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshCored.so.7.1 differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshTools.a b/libs/OpenMesh/liblinux/libOpenMeshTools.a new file mode 100644 index 0000000..10c44f8 Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshTools.a differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshTools.so b/libs/OpenMesh/liblinux/libOpenMeshTools.so new file mode 100755 index 0000000..52e6940 Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshTools.so differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshTools.so.7.1 b/libs/OpenMesh/liblinux/libOpenMeshTools.so.7.1 new file mode 100755 index 0000000..52e6940 Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshTools.so.7.1 differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshToolsd.a b/libs/OpenMesh/liblinux/libOpenMeshToolsd.a new file mode 100644 index 0000000..4ed7f7b Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshToolsd.a differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshToolsd.so b/libs/OpenMesh/liblinux/libOpenMeshToolsd.so new file mode 100755 index 0000000..a37b1ce Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshToolsd.so differ diff --git a/libs/OpenMesh/liblinux/libOpenMeshToolsd.so.7.1 b/libs/OpenMesh/liblinux/libOpenMeshToolsd.so.7.1 new file mode 100755 index 0000000..a37b1ce Binary files /dev/null and b/libs/OpenMesh/liblinux/libOpenMeshToolsd.so.7.1 differ diff --git a/libs/OpenMesh/libosx/libOpenMeshCore.7.1.dylib b/libs/OpenMesh/libosx/libOpenMeshCore.7.1.dylib new file mode 100755 index 0000000..aa6962e Binary files /dev/null and b/libs/OpenMesh/libosx/libOpenMeshCore.7.1.dylib differ diff --git a/libs/OpenMesh/libosx/libOpenMeshCore.a b/libs/OpenMesh/libosx/libOpenMeshCore.a new file mode 100644 index 0000000..27c5a72 Binary files /dev/null and b/libs/OpenMesh/libosx/libOpenMeshCore.a differ diff --git a/libs/OpenMesh/libosx/libOpenMeshCore.dylib b/libs/OpenMesh/libosx/libOpenMeshCore.dylib new file mode 100755 index 0000000..aa6962e Binary files /dev/null and b/libs/OpenMesh/libosx/libOpenMeshCore.dylib differ diff --git a/libs/OpenMesh/libosx/libOpenMeshTools.7.1.dylib b/libs/OpenMesh/libosx/libOpenMeshTools.7.1.dylib new file mode 100755 index 0000000..741a6fc Binary files /dev/null and b/libs/OpenMesh/libosx/libOpenMeshTools.7.1.dylib differ diff --git a/libs/OpenMesh/libosx/libOpenMeshTools.a b/libs/OpenMesh/libosx/libOpenMeshTools.a new file mode 100644 index 0000000..c0e5a34 Binary files /dev/null and b/libs/OpenMesh/libosx/libOpenMeshTools.a differ diff --git a/libs/OpenMesh/libosx/libOpenMeshTools.dylib b/libs/OpenMesh/libosx/libOpenMeshTools.dylib new file mode 100755 index 0000000..741a6fc Binary files /dev/null and b/libs/OpenMesh/libosx/libOpenMeshTools.dylib differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..a4a8e1d --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,25 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include +#include +#include +#include + + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { + ui->setupUi(this); + connect(ui->displayWidget, &MeshViewerWidget::initialized, + this, &MainWindow::on_gl_initialized); + OpenMesh::IO::read_mesh(mesh, "../data/bunnyLowPoly.obj"); +} + + +MainWindow::~MainWindow() { +} + +void MainWindow::on_gl_initialized() { + ui->displayWidget->addFromMesh(&mesh); +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..c4b21d3 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,29 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "mymesh.h" +#include +#include + + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow { + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + void displayMesh(MyMesh *_mesh); + +private slots: + void on_gl_initialized(); + +private: + MyMesh mesh; + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/src/meshviewerwidget.cpp b/src/meshviewerwidget.cpp new file mode 100644 index 0000000..88e9642 --- /dev/null +++ b/src/meshviewerwidget.cpp @@ -0,0 +1,230 @@ +#include + +#include "meshviewerwidget.h" + + +const GLchar *vertex_shader_source = R"glsl( +#version 150 core + +in vec3 pos; + +uniform mat4 proj; +uniform mat4 view; +uniform mat4 model; + +void main() { + gl_Position = proj * view * model * vec4(pos, 1.0); +} +)glsl"; + +const GLchar *fragment_shader_source = R"glsl( +#version 150 core + +out vec4 out_color; + +uniform vec3 col; +uniform float alpha; + +void main() { + out_color = vec4(col, alpha); +} +)glsl"; + + +MeshViewerWidget::MeshViewerWidget(QWidget *parent) : QOpenGLWidget(parent) { + setMouseTracking(true); + setFocus(); +} + + +void GLAPIENTRY +opengl_debug_cb(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam) { + (void) source; + (void) type; + (void) id; + (void) severity; + (void) length; + (void) userParam; + qDebug() << "OpenGL debug output:" << message; +} + + +void MeshViewerWidget::initializeGL() { + initializeOpenGLFunctions(); + + GLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + qDebug("OpenGL version %d.%d", major, minor); + + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(opengl_debug_cb, 0); + + /* Compile the vertex shader. */ + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); + glCompileShader(vertex_shader); + GLint status; + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + char log[1024]; + glGetShaderInfoLog(vertex_shader, sizeof log, NULL, log); + fprintf(stderr, "Failed to compile the vertex shader: %s\n", log); + exit(1); + } + + /* Compile the fragment shader. */ + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); + glCompileShader(fragment_shader); + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + char log[1024]; + glGetShaderInfoLog(fragment_shader, sizeof log, NULL, log); + fprintf(stderr, "Failed to compile the fragment shader: %s\n", log); + exit(1); + } + + /* Link the shader program. */ + GLuint shader_program = glCreateProgram(); + glAttachShader(shader_program, vertex_shader); + glAttachShader(shader_program, fragment_shader); + glBindFragDataLocation(shader_program, 0, "out_color"); + glLinkProgram(shader_program); + glGetProgramiv(shader_program, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + char log[1024]; + glGetProgramInfoLog(shader_program, sizeof log, NULL, log); + fprintf(stderr, "Failed to link the shader program: %s\n", log); + exit(1); + } + + /* Use it. */ + glUseProgram(shader_program); + + /* Get the position attribute. */ + pos_attr = glGetAttribLocation(shader_program, "pos"); + proj_attr = glGetUniformLocation(shader_program, "proj"); + view_attr = glGetUniformLocation(shader_program, "view"); + model_attr = glGetUniformLocation(shader_program, "model"); + col_attr = glGetUniformLocation(shader_program, "col"); + alpha_attr = glGetUniformLocation(shader_program, "alpha"); + + glUniform1f(alpha_attr, 1); + + glClearColor(1, 1, 1, 0); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_MULTISAMPLE); + + emit initialized(); +} + + +void MeshViewerWidget::resizeGL(int w, int h) { + QMatrix4x4 projection; + projection.perspective(FOV, (float) w/h, .01, 100); + glUniformMatrix4fv(proj_attr, 1, GL_FALSE, projection.data()); +} + + +void MeshViewerWidget::paintGL() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + QMatrix4x4 trans; + trans.translate(0, 0, -cam_dist); + QMatrix4x4 view = trans * rot; + glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data()); + for (const MeshView mv : mesh_views) { + glUniformMatrix4fv(model_attr, 1, GL_FALSE, mv.mat.data()); + + /* Mesh */ + glUniform3f(col_attr, mv.col.redF(), mv.col.greenF(), mv.col.blueF()); + glBindVertexArray(mv.vao); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0, 2); + glDrawArrays(GL_TRIANGLES, 0, mv.nverts); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDisable(GL_POLYGON_OFFSET_FILL); + + /* Wireframe */ + glUniform3f(col_attr, WIREFRAME_COLOR); + glDrawArrays(GL_TRIANGLES, 0, mv.nverts); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1); + } +} + + +void MeshViewerWidget::add(size_t nverts, const GLfloat *verts, QMatrix4x4 mat, QColor col) { + makeCurrent(); + + GLuint vao, vbo; + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); + + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, nverts * 3 * sizeof (GLfloat), verts, GL_DYNAMIC_DRAW); + glVertexAttribPointer(pos_attr, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(pos_attr); + + glBindVertexArray(0); + + doneCurrent(); + update(); +} + + +void MeshViewerWidget::addFromMesh(MyMesh* mesh, QMatrix4x4 mat, QColor col) { + GLfloat *verts = new GLfloat[mesh->n_faces() * 3 * 3]; + size_t i = 0; + + for (MyMesh::FaceHandle face : mesh->faces()) { + for (MyMesh::VertexHandle vec : mesh->fv_range(face)) { + verts[3*i+0] = mesh->point(vec)[0]; + verts[3*i+1] = mesh->point(vec)[1]; + verts[3*i+2] = mesh->point(vec)[2]; + i++; + } + } + + add(i, verts, mat, col); + delete[] verts; + return ret; +} + + +void MeshViewerWidget::mousePressEvent(QMouseEvent *e) { + if (e->button() == Qt::LeftButton) { + mouse_pos = e->pos(); + } +} + + +void MeshViewerWidget::mouseReleaseEvent(QMouseEvent *e) { + (void) e; + rot_start = rot; +} + + +void MeshViewerWidget::mouseMoveEvent(QMouseEvent *e) { + if (e->buttons() & Qt::LeftButton) { + QPoint delta = e->pos() - mouse_pos; + rot = rot_start; + rot.rotate(delta.x() / 5., 0, 1, 0); + rot.rotate(delta.y() / 5., QVector3D(1, 0, 0) * rot); + update(); + } +} + + +void MeshViewerWidget::wheelEvent(QWheelEvent *e) { + cam_dist -= e->angleDelta().y() / 1000. * cam_dist; + update(); +} diff --git a/src/meshviewerwidget.h b/src/meshviewerwidget.h new file mode 100644 index 0000000..6215479 --- /dev/null +++ b/src/meshviewerwidget.h @@ -0,0 +1,52 @@ +#ifndef MESHVIEWERWIDGET_H +#define MESHVIEWERWIDGET_H + +#define GL_GLEXT_PROTOTYPES +#include "mymesh.h" +#include +#include +#include +#include +#include +#include +#include + + +#define WIREFRAME_COLOR 0, 0, 0 +#define FOV 70 + + +using namespace OpenMesh; + +class MeshViewerWidget : public QOpenGLWidget, protected QOpenGLFunctions { + Q_OBJECT + +public: + MeshViewerWidget(QWidget* parent=nullptr); + + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; + + void add(size_t nverts, const GLfloat *verts, QMatrix4x4 mat=QMatrix4x4(), QColor col={153, 153, 153}); + void addFromMesh(MyMesh* _mesh, QMatrix4x4 mat=QMatrix4x4(), QColor col={153, 153, 153}); + +private: + GLint pos_attr, proj_attr, view_attr, model_attr; + GLint col_attr, alpha_attr; + QMatrix4x4 proj; + QMatrix4x4 rot, rot_start; + GLfloat cam_dist = 1; + QPoint mouse_pos; + +protected: + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseReleaseEvent(QMouseEvent *e); + virtual void mouseMoveEvent(QMouseEvent *e); + virtual void wheelEvent(QWheelEvent *e); + +signals: + void initialized(); +}; + +#endif diff --git a/src/mymesh.cpp b/src/mymesh.cpp new file mode 100644 index 0000000..ca0d05d --- /dev/null +++ b/src/mymesh.cpp @@ -0,0 +1,14 @@ +#include "mymesh.h" + +#include + + +void transform(MyMesh *mesh, const QMatrix4x4 *mat) { + QVector3D vec; + for (MyMesh::VertexHandle v : mesh->vertices()) { + MyMesh::Point &p = mesh->point(v); + vec = {p[0], p[1], p[2]}; + vec = *mat * vec; + p = {vec[0], vec[1], vec[2]}; + } +} diff --git a/src/mymesh.h b/src/mymesh.h new file mode 100644 index 0000000..3234312 --- /dev/null +++ b/src/mymesh.h @@ -0,0 +1,31 @@ +#ifndef MYMESH_H +#define MYMESH_H + +#include +#include +#include +#include + + +using namespace OpenMesh; +using namespace OpenMesh::Attributes; + +struct MyTraits : public OpenMesh::DefaultTraits { + // use vertex normals and vertex colors + VertexAttributes( OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color ); + // store the previous halfedge + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + // use face normals face colors + FaceAttributes( OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color ); + EdgeAttributes( OpenMesh::Attributes::Color ); + // vertex thickness + VertexTraits{float thickness; float value; Color faceShadingColor;}; + // edge thickness + EdgeTraits{float thickness;}; +}; +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + +void transform(MyMesh *mesh, const QMatrix4x4 *mat); + + +#endif diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui new file mode 100644 index 0000000..8a6a751 --- /dev/null +++ b/ui/mainwindow.ui @@ -0,0 +1,110 @@ + + + MainWindow + + + + 0 + 0 + 632 + 408 + + + + MainWindow + + + + + + + + 150 + 0 + + + + + 150 + 0 + + + + + 4 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + false + + + Lancer + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + 0 + 0 + 632 + 20 + + + + + + TopToolBarArea + + + false + + + + + + + + MeshViewerWidget + QWidget +
meshviewerwidget.h
+ 1 +
+
+ + +